1  /* DO NOT EDIT!  -*- buffer-read-only: t -*- vi:set ro:  */
       2  /* Disassembler interface for targets using CGEN. -*- C -*-
       3     CGEN: Cpu tools GENerator
       4  
       5     THIS FILE IS MACHINE GENERATED WITH CGEN.
       6     - the resultant file is machine generated, cgen-dis.in isn't
       7  
       8     Copyright (C) 1996-2023 Free Software Foundation, Inc.
       9  
      10     This file is part of libopcodes.
      11  
      12     This library is free software; you can redistribute it and/or modify
      13     it under the terms of the GNU General Public License as published by
      14     the Free Software Foundation; either version 3, or (at your option)
      15     any later version.
      16  
      17     It is distributed in the hope that it will be useful, but WITHOUT
      18     ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
      19     or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
      20     License for more details.
      21  
      22     You should have received a copy of the GNU General Public License
      23     along with this program; if not, write to the Free Software Foundation, Inc.,
      24     51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.  */
      25  
      26  /* ??? Eventually more and more of this stuff can go to cpu-independent files.
      27     Keep that in mind.  */
      28  
      29  #include "sysdep.h"
      30  #include <stdio.h>
      31  #include "ansidecl.h"
      32  #include "disassemble.h"
      33  #include "bfd.h"
      34  #include "symcat.h"
      35  #include "libiberty.h"
      36  #include "mt-desc.h"
      37  #include "mt-opc.h"
      38  #include "opintl.h"
      39  
      40  /* Default text to print if an instruction isn't recognized.  */
      41  #define UNKNOWN_INSN_MSG _("*unknown*")
      42  
      43  static void print_normal
      44    (CGEN_CPU_DESC, void *, long, unsigned int, bfd_vma, int);
      45  static void print_address
      46    (CGEN_CPU_DESC, void *, bfd_vma, unsigned int, bfd_vma, int) ATTRIBUTE_UNUSED;
      47  static void print_keyword
      48    (CGEN_CPU_DESC, void *, CGEN_KEYWORD *, long, unsigned int) ATTRIBUTE_UNUSED;
      49  static void print_insn_normal
      50    (CGEN_CPU_DESC, void *, const CGEN_INSN *, CGEN_FIELDS *, bfd_vma, int);
      51  static int print_insn
      52    (CGEN_CPU_DESC, bfd_vma,  disassemble_info *, bfd_byte *, unsigned);
      53  static int default_print_insn
      54    (CGEN_CPU_DESC, bfd_vma, disassemble_info *) ATTRIBUTE_UNUSED;
      55  static int read_insn
      56    (CGEN_CPU_DESC, bfd_vma, disassemble_info *, bfd_byte *, int, CGEN_EXTRACT_INFO *,
      57     unsigned long *);
      58  
      59  /* -- disassembler routines inserted here.  */
      60  
      61  /* -- dis.c */
      62  static void
      63  print_dollarhex (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
      64  		 void * dis_info,
      65  		 long value,
      66  		 unsigned int attrs ATTRIBUTE_UNUSED,
      67  		 bfd_vma pc ATTRIBUTE_UNUSED,
      68  		 int length ATTRIBUTE_UNUSED)
      69  {
      70    disassemble_info *info = (disassemble_info *) dis_info;
      71  
      72    info->fprintf_func (info->stream, "$%lx", value & 0xffffffff);
      73  
      74    if (0)
      75      print_normal (cd, dis_info, value, attrs, pc, length);
      76  }
      77  
      78  static void
      79  print_pcrel (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
      80  	     void * dis_info,
      81  	     long value,
      82  	     unsigned int attrs ATTRIBUTE_UNUSED,
      83  	     bfd_vma pc ATTRIBUTE_UNUSED,
      84  	     int length ATTRIBUTE_UNUSED)
      85  {
      86    print_address (cd, dis_info, value + pc, attrs, pc, length);
      87  }
      88  
      89  /* -- */
      90  
      91  void mt_cgen_print_operand
      92    (CGEN_CPU_DESC, int, void *, CGEN_FIELDS *, void const *, bfd_vma, int);
      93  
      94  /* Main entry point for printing operands.
      95     XINFO is a `void *' and not a `disassemble_info *' to not put a requirement
      96     of dis-asm.h on cgen.h.
      97  
      98     This function is basically just a big switch statement.  Earlier versions
      99     used tables to look up the function to use, but
     100     - if the table contains both assembler and disassembler functions then
     101       the disassembler contains much of the assembler and vice-versa,
     102     - there's a lot of inlining possibilities as things grow,
     103     - using a switch statement avoids the function call overhead.
     104  
     105     This function could be moved into `print_insn_normal', but keeping it
     106     separate makes clear the interface between `print_insn_normal' and each of
     107     the handlers.  */
     108  
     109  void
     110  mt_cgen_print_operand (CGEN_CPU_DESC cd,
     111  			   int opindex,
     112  			   void * xinfo,
     113  			   CGEN_FIELDS *fields,
     114  			   void const *attrs ATTRIBUTE_UNUSED,
     115  			   bfd_vma pc,
     116  			   int length)
     117  {
     118    disassemble_info *info = (disassemble_info *) xinfo;
     119  
     120    switch (opindex)
     121      {
     122      case MT_OPERAND_A23 :
     123        print_dollarhex (cd, info, fields->f_a23, 0, pc, length);
     124        break;
     125      case MT_OPERAND_BALL :
     126        print_dollarhex (cd, info, fields->f_ball, 0, pc, length);
     127        break;
     128      case MT_OPERAND_BALL2 :
     129        print_dollarhex (cd, info, fields->f_ball2, 0, pc, length);
     130        break;
     131      case MT_OPERAND_BANKADDR :
     132        print_dollarhex (cd, info, fields->f_bankaddr, 0, pc, length);
     133        break;
     134      case MT_OPERAND_BRC :
     135        print_dollarhex (cd, info, fields->f_brc, 0, pc, length);
     136        break;
     137      case MT_OPERAND_BRC2 :
     138        print_dollarhex (cd, info, fields->f_brc2, 0, pc, length);
     139        break;
     140      case MT_OPERAND_CB1INCR :
     141        print_dollarhex (cd, info, fields->f_cb1incr, 0|(1<<CGEN_OPERAND_SIGNED), pc, length);
     142        break;
     143      case MT_OPERAND_CB1SEL :
     144        print_dollarhex (cd, info, fields->f_cb1sel, 0, pc, length);
     145        break;
     146      case MT_OPERAND_CB2INCR :
     147        print_dollarhex (cd, info, fields->f_cb2incr, 0|(1<<CGEN_OPERAND_SIGNED), pc, length);
     148        break;
     149      case MT_OPERAND_CB2SEL :
     150        print_dollarhex (cd, info, fields->f_cb2sel, 0, pc, length);
     151        break;
     152      case MT_OPERAND_CBRB :
     153        print_dollarhex (cd, info, fields->f_cbrb, 0, pc, length);
     154        break;
     155      case MT_OPERAND_CBS :
     156        print_dollarhex (cd, info, fields->f_cbs, 0, pc, length);
     157        break;
     158      case MT_OPERAND_CBX :
     159        print_dollarhex (cd, info, fields->f_cbx, 0, pc, length);
     160        break;
     161      case MT_OPERAND_CCB :
     162        print_dollarhex (cd, info, fields->f_ccb, 0, pc, length);
     163        break;
     164      case MT_OPERAND_CDB :
     165        print_dollarhex (cd, info, fields->f_cdb, 0, pc, length);
     166        break;
     167      case MT_OPERAND_CELL :
     168        print_dollarhex (cd, info, fields->f_cell, 0, pc, length);
     169        break;
     170      case MT_OPERAND_COLNUM :
     171        print_dollarhex (cd, info, fields->f_colnum, 0, pc, length);
     172        break;
     173      case MT_OPERAND_CONTNUM :
     174        print_dollarhex (cd, info, fields->f_contnum, 0, pc, length);
     175        break;
     176      case MT_OPERAND_CR :
     177        print_dollarhex (cd, info, fields->f_cr, 0, pc, length);
     178        break;
     179      case MT_OPERAND_CTXDISP :
     180        print_dollarhex (cd, info, fields->f_ctxdisp, 0, pc, length);
     181        break;
     182      case MT_OPERAND_DUP :
     183        print_dollarhex (cd, info, fields->f_dup, 0, pc, length);
     184        break;
     185      case MT_OPERAND_FBDISP :
     186        print_dollarhex (cd, info, fields->f_fbdisp, 0, pc, length);
     187        break;
     188      case MT_OPERAND_FBINCR :
     189        print_dollarhex (cd, info, fields->f_fbincr, 0, pc, length);
     190        break;
     191      case MT_OPERAND_FRDR :
     192        print_keyword (cd, info, & mt_cgen_opval_h_spr, fields->f_dr, 0|(1<<CGEN_OPERAND_ABS_ADDR));
     193        break;
     194      case MT_OPERAND_FRDRRR :
     195        print_keyword (cd, info, & mt_cgen_opval_h_spr, fields->f_drrr, 0|(1<<CGEN_OPERAND_ABS_ADDR));
     196        break;
     197      case MT_OPERAND_FRSR1 :
     198        print_keyword (cd, info, & mt_cgen_opval_h_spr, fields->f_sr1, 0|(1<<CGEN_OPERAND_ABS_ADDR));
     199        break;
     200      case MT_OPERAND_FRSR2 :
     201        print_keyword (cd, info, & mt_cgen_opval_h_spr, fields->f_sr2, 0|(1<<CGEN_OPERAND_ABS_ADDR));
     202        break;
     203      case MT_OPERAND_ID :
     204        print_dollarhex (cd, info, fields->f_id, 0, pc, length);
     205        break;
     206      case MT_OPERAND_IMM16 :
     207        print_dollarhex (cd, info, fields->f_imm16s, 0|(1<<CGEN_OPERAND_SIGNED), pc, length);
     208        break;
     209      case MT_OPERAND_IMM16L :
     210        print_dollarhex (cd, info, fields->f_imm16l, 0, pc, length);
     211        break;
     212      case MT_OPERAND_IMM16O :
     213        print_pcrel (cd, info, fields->f_imm16s, 0|(1<<CGEN_OPERAND_PCREL_ADDR), pc, length);
     214        break;
     215      case MT_OPERAND_IMM16Z :
     216        print_dollarhex (cd, info, fields->f_imm16u, 0, pc, length);
     217        break;
     218      case MT_OPERAND_INCAMT :
     219        print_dollarhex (cd, info, fields->f_incamt, 0, pc, length);
     220        break;
     221      case MT_OPERAND_INCR :
     222        print_dollarhex (cd, info, fields->f_incr, 0, pc, length);
     223        break;
     224      case MT_OPERAND_LENGTH :
     225        print_dollarhex (cd, info, fields->f_length, 0, pc, length);
     226        break;
     227      case MT_OPERAND_LOOPSIZE :
     228        print_pcrel (cd, info, fields->f_loopo, 0|(1<<CGEN_OPERAND_PCREL_ADDR), pc, length);
     229        break;
     230      case MT_OPERAND_MASK :
     231        print_dollarhex (cd, info, fields->f_mask, 0, pc, length);
     232        break;
     233      case MT_OPERAND_MASK1 :
     234        print_dollarhex (cd, info, fields->f_mask1, 0, pc, length);
     235        break;
     236      case MT_OPERAND_MODE :
     237        print_dollarhex (cd, info, fields->f_mode, 0, pc, length);
     238        break;
     239      case MT_OPERAND_PERM :
     240        print_dollarhex (cd, info, fields->f_perm, 0, pc, length);
     241        break;
     242      case MT_OPERAND_RBBC :
     243        print_dollarhex (cd, info, fields->f_rbbc, 0, pc, length);
     244        break;
     245      case MT_OPERAND_RC :
     246        print_dollarhex (cd, info, fields->f_rc, 0, pc, length);
     247        break;
     248      case MT_OPERAND_RC1 :
     249        print_dollarhex (cd, info, fields->f_rc1, 0, pc, length);
     250        break;
     251      case MT_OPERAND_RC2 :
     252        print_dollarhex (cd, info, fields->f_rc2, 0, pc, length);
     253        break;
     254      case MT_OPERAND_RC3 :
     255        print_dollarhex (cd, info, fields->f_rc3, 0, pc, length);
     256        break;
     257      case MT_OPERAND_RCNUM :
     258        print_dollarhex (cd, info, fields->f_rcnum, 0, pc, length);
     259        break;
     260      case MT_OPERAND_RDA :
     261        print_dollarhex (cd, info, fields->f_rda, 0, pc, length);
     262        break;
     263      case MT_OPERAND_ROWNUM :
     264        print_dollarhex (cd, info, fields->f_rownum, 0, pc, length);
     265        break;
     266      case MT_OPERAND_ROWNUM1 :
     267        print_dollarhex (cd, info, fields->f_rownum1, 0, pc, length);
     268        break;
     269      case MT_OPERAND_ROWNUM2 :
     270        print_dollarhex (cd, info, fields->f_rownum2, 0, pc, length);
     271        break;
     272      case MT_OPERAND_SIZE :
     273        print_dollarhex (cd, info, fields->f_size, 0, pc, length);
     274        break;
     275      case MT_OPERAND_TYPE :
     276        print_dollarhex (cd, info, fields->f_type, 0, pc, length);
     277        break;
     278      case MT_OPERAND_WR :
     279        print_dollarhex (cd, info, fields->f_wr, 0, pc, length);
     280        break;
     281      case MT_OPERAND_XMODE :
     282        print_dollarhex (cd, info, fields->f_xmode, 0, pc, length);
     283        break;
     284  
     285      default :
     286        /* xgettext:c-format */
     287        opcodes_error_handler
     288  	(_("internal error: unrecognized field %d while printing insn"),
     289  	 opindex);
     290        abort ();
     291    }
     292  }
     293  
     294  cgen_print_fn * const mt_cgen_print_handlers[] =
     295  {
     296    print_insn_normal,
     297  };
     298  
     299  
     300  void
     301  mt_cgen_init_dis (CGEN_CPU_DESC cd)
     302  {
     303    mt_cgen_init_opcode_table (cd);
     304    mt_cgen_init_ibld_table (cd);
     305    cd->print_handlers = & mt_cgen_print_handlers[0];
     306    cd->print_operand = mt_cgen_print_operand;
     307  }
     308  
     309  
     310  /* Default print handler.  */
     311  
     312  static void
     313  print_normal (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
     314  	      void *dis_info,
     315  	      long value,
     316  	      unsigned int attrs,
     317  	      bfd_vma pc ATTRIBUTE_UNUSED,
     318  	      int length ATTRIBUTE_UNUSED)
     319  {
     320    disassemble_info *info = (disassemble_info *) dis_info;
     321  
     322    /* Print the operand as directed by the attributes.  */
     323    if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SEM_ONLY))
     324      ; /* nothing to do */
     325    else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SIGNED))
     326      (*info->fprintf_func) (info->stream, "%ld", value);
     327    else
     328      (*info->fprintf_func) (info->stream, "0x%lx", value);
     329  }
     330  
     331  /* Default address handler.  */
     332  
     333  static void
     334  print_address (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
     335  	       void *dis_info,
     336  	       bfd_vma value,
     337  	       unsigned int attrs,
     338  	       bfd_vma pc ATTRIBUTE_UNUSED,
     339  	       int length ATTRIBUTE_UNUSED)
     340  {
     341    disassemble_info *info = (disassemble_info *) dis_info;
     342  
     343    /* Print the operand as directed by the attributes.  */
     344    if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SEM_ONLY))
     345      ; /* Nothing to do.  */
     346    else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_PCREL_ADDR))
     347      (*info->print_address_func) (value, info);
     348    else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_ABS_ADDR))
     349      (*info->print_address_func) (value, info);
     350    else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SIGNED))
     351      (*info->fprintf_func) (info->stream, "%ld", (long) value);
     352    else
     353      (*info->fprintf_func) (info->stream, "0x%lx", (long) value);
     354  }
     355  
     356  /* Keyword print handler.  */
     357  
     358  static void
     359  print_keyword (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
     360  	       void *dis_info,
     361  	       CGEN_KEYWORD *keyword_table,
     362  	       long value,
     363  	       unsigned int attrs ATTRIBUTE_UNUSED)
     364  {
     365    disassemble_info *info = (disassemble_info *) dis_info;
     366    const CGEN_KEYWORD_ENTRY *ke;
     367  
     368    ke = cgen_keyword_lookup_value (keyword_table, value);
     369    if (ke != NULL)
     370      (*info->fprintf_func) (info->stream, "%s", ke->name);
     371    else
     372      (*info->fprintf_func) (info->stream, "???");
     373  }
     374  
     375  /* Default insn printer.
     376  
     377     DIS_INFO is defined as `void *' so the disassembler needn't know anything
     378     about disassemble_info.  */
     379  
     380  static void
     381  print_insn_normal (CGEN_CPU_DESC cd,
     382  		   void *dis_info,
     383  		   const CGEN_INSN *insn,
     384  		   CGEN_FIELDS *fields,
     385  		   bfd_vma pc,
     386  		   int length)
     387  {
     388    const CGEN_SYNTAX *syntax = CGEN_INSN_SYNTAX (insn);
     389    disassemble_info *info = (disassemble_info *) dis_info;
     390    const CGEN_SYNTAX_CHAR_TYPE *syn;
     391  
     392    CGEN_INIT_PRINT (cd);
     393  
     394    for (syn = CGEN_SYNTAX_STRING (syntax); *syn; ++syn)
     395      {
     396        if (CGEN_SYNTAX_MNEMONIC_P (*syn))
     397  	{
     398  	  (*info->fprintf_func) (info->stream, "%s", CGEN_INSN_MNEMONIC (insn));
     399  	  continue;
     400  	}
     401        if (CGEN_SYNTAX_CHAR_P (*syn))
     402  	{
     403  	  (*info->fprintf_func) (info->stream, "%c", CGEN_SYNTAX_CHAR (*syn));
     404  	  continue;
     405  	}
     406  
     407        /* We have an operand.  */
     408        mt_cgen_print_operand (cd, CGEN_SYNTAX_FIELD (*syn), info,
     409  				 fields, CGEN_INSN_ATTRS (insn), pc, length);
     410      }
     411  }
     412  
     413  /* Subroutine of print_insn. Reads an insn into the given buffers and updates
     414     the extract info.
     415     Returns 0 if all is well, non-zero otherwise.  */
     416  
     417  static int
     418  read_insn (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
     419  	   bfd_vma pc,
     420  	   disassemble_info *info,
     421  	   bfd_byte *buf,
     422  	   int buflen,
     423  	   CGEN_EXTRACT_INFO *ex_info,
     424  	   unsigned long *insn_value)
     425  {
     426    int status = (*info->read_memory_func) (pc, buf, buflen, info);
     427  
     428    if (status != 0)
     429      {
     430        (*info->memory_error_func) (status, pc, info);
     431        return -1;
     432      }
     433  
     434    ex_info->dis_info = info;
     435    ex_info->valid = (1 << buflen) - 1;
     436    ex_info->insn_bytes = buf;
     437  
     438    *insn_value = bfd_get_bits (buf, buflen * 8, info->endian == BFD_ENDIAN_BIG);
     439    return 0;
     440  }
     441  
     442  /* Utility to print an insn.
     443     BUF is the base part of the insn, target byte order, BUFLEN bytes long.
     444     The result is the size of the insn in bytes or zero for an unknown insn
     445     or -1 if an error occurs fetching data (memory_error_func will have
     446     been called).  */
     447  
     448  static int
     449  print_insn (CGEN_CPU_DESC cd,
     450  	    bfd_vma pc,
     451  	    disassemble_info *info,
     452  	    bfd_byte *buf,
     453  	    unsigned int buflen)
     454  {
     455    CGEN_INSN_INT insn_value;
     456    const CGEN_INSN_LIST *insn_list;
     457    CGEN_EXTRACT_INFO ex_info;
     458    int basesize;
     459  
     460    /* Extract base part of instruction, just in case CGEN_DIS_* uses it. */
     461    basesize = cd->base_insn_bitsize < buflen * 8 ?
     462                                       cd->base_insn_bitsize : buflen * 8;
     463    insn_value = cgen_get_insn_value (cd, buf, basesize, cd->insn_endian);
     464  
     465  
     466    /* Fill in ex_info fields like read_insn would.  Don't actually call
     467       read_insn, since the incoming buffer is already read (and possibly
     468       modified a la m32r).  */
     469    ex_info.valid = (1 << buflen) - 1;
     470    ex_info.dis_info = info;
     471    ex_info.insn_bytes = buf;
     472  
     473    /* The instructions are stored in hash lists.
     474       Pick the first one and keep trying until we find the right one.  */
     475  
     476    insn_list = CGEN_DIS_LOOKUP_INSN (cd, (char *) buf, insn_value);
     477    while (insn_list != NULL)
     478      {
     479        const CGEN_INSN *insn = insn_list->insn;
     480        CGEN_FIELDS fields;
     481        int length;
     482        unsigned long insn_value_cropped;
     483  
     484  #ifdef CGEN_VALIDATE_INSN_SUPPORTED
     485        /* Not needed as insn shouldn't be in hash lists if not supported.  */
     486        /* Supported by this cpu?  */
     487        if (! mt_cgen_insn_supported (cd, insn))
     488          {
     489            insn_list = CGEN_DIS_NEXT_INSN (insn_list);
     490  	  continue;
     491          }
     492  #endif
     493  
     494        /* Basic bit mask must be correct.  */
     495        /* ??? May wish to allow target to defer this check until the extract
     496  	 handler.  */
     497  
     498        /* Base size may exceed this instruction's size.  Extract the
     499           relevant part from the buffer. */
     500        if ((unsigned) (CGEN_INSN_BITSIZE (insn) / 8) < buflen &&
     501  	  (unsigned) (CGEN_INSN_BITSIZE (insn) / 8) <= sizeof (unsigned long))
     502  	insn_value_cropped = bfd_get_bits (buf, CGEN_INSN_BITSIZE (insn),
     503  					   info->endian == BFD_ENDIAN_BIG);
     504        else
     505  	insn_value_cropped = insn_value;
     506  
     507        if ((insn_value_cropped & CGEN_INSN_BASE_MASK (insn))
     508  	  == CGEN_INSN_BASE_VALUE (insn))
     509  	{
     510  	  /* Printing is handled in two passes.  The first pass parses the
     511  	     machine insn and extracts the fields.  The second pass prints
     512  	     them.  */
     513  
     514  	  /* Make sure the entire insn is loaded into insn_value, if it
     515  	     can fit.  */
     516  	  if (((unsigned) CGEN_INSN_BITSIZE (insn) > cd->base_insn_bitsize) &&
     517  	      (unsigned) (CGEN_INSN_BITSIZE (insn) / 8) <= sizeof (unsigned long))
     518  	    {
     519  	      unsigned long full_insn_value;
     520  	      int rc = read_insn (cd, pc, info, buf,
     521  				  CGEN_INSN_BITSIZE (insn) / 8,
     522  				  & ex_info, & full_insn_value);
     523  	      if (rc != 0)
     524  		return rc;
     525  	      length = CGEN_EXTRACT_FN (cd, insn)
     526  		(cd, insn, &ex_info, full_insn_value, &fields, pc);
     527  	    }
     528  	  else
     529  	    length = CGEN_EXTRACT_FN (cd, insn)
     530  	      (cd, insn, &ex_info, insn_value_cropped, &fields, pc);
     531  
     532  	  /* Length < 0 -> error.  */
     533  	  if (length < 0)
     534  	    return length;
     535  	  if (length > 0)
     536  	    {
     537  	      CGEN_PRINT_FN (cd, insn) (cd, info, insn, &fields, pc, length);
     538  	      /* Length is in bits, result is in bytes.  */
     539  	      return length / 8;
     540  	    }
     541  	}
     542  
     543        insn_list = CGEN_DIS_NEXT_INSN (insn_list);
     544      }
     545  
     546    return 0;
     547  }
     548  
     549  /* Default value for CGEN_PRINT_INSN.
     550     The result is the size of the insn in bytes or zero for an unknown insn
     551     or -1 if an error occured fetching bytes.  */
     552  
     553  #ifndef CGEN_PRINT_INSN
     554  #define CGEN_PRINT_INSN default_print_insn
     555  #endif
     556  
     557  static int
     558  default_print_insn (CGEN_CPU_DESC cd, bfd_vma pc, disassemble_info *info)
     559  {
     560    bfd_byte buf[CGEN_MAX_INSN_SIZE];
     561    int buflen;
     562    int status;
     563  
     564    /* Attempt to read the base part of the insn.  */
     565    buflen = cd->base_insn_bitsize / 8;
     566    status = (*info->read_memory_func) (pc, buf, buflen, info);
     567  
     568    /* Try again with the minimum part, if min < base.  */
     569    if (status != 0 && (cd->min_insn_bitsize < cd->base_insn_bitsize))
     570      {
     571        buflen = cd->min_insn_bitsize / 8;
     572        status = (*info->read_memory_func) (pc, buf, buflen, info);
     573      }
     574  
     575    if (status != 0)
     576      {
     577        (*info->memory_error_func) (status, pc, info);
     578        return -1;
     579      }
     580  
     581    return print_insn (cd, pc, info, buf, buflen);
     582  }
     583  
     584  /* Main entry point.
     585     Print one instruction from PC on INFO->STREAM.
     586     Return the size of the instruction (in bytes).  */
     587  
     588  typedef struct cpu_desc_list
     589  {
     590    struct cpu_desc_list *next;
     591    CGEN_BITSET *isa;
     592    int mach;
     593    int endian;
     594    int insn_endian;
     595    CGEN_CPU_DESC cd;
     596  } cpu_desc_list;
     597  
     598  int
     599  print_insn_mt (bfd_vma pc, disassemble_info *info)
     600  {
     601    static cpu_desc_list *cd_list = 0;
     602    cpu_desc_list *cl = 0;
     603    static CGEN_CPU_DESC cd = 0;
     604    static CGEN_BITSET *prev_isa;
     605    static int prev_mach;
     606    static int prev_endian;
     607    static int prev_insn_endian;
     608    int length;
     609    CGEN_BITSET *isa;
     610    int mach;
     611    int endian = (info->endian == BFD_ENDIAN_BIG
     612  		? CGEN_ENDIAN_BIG
     613  		: CGEN_ENDIAN_LITTLE);
     614    int insn_endian = (info->endian_code == BFD_ENDIAN_BIG
     615                       ? CGEN_ENDIAN_BIG
     616                       : CGEN_ENDIAN_LITTLE);
     617    enum bfd_architecture arch;
     618  
     619    /* ??? gdb will set mach but leave the architecture as "unknown" */
     620  #ifndef CGEN_BFD_ARCH
     621  #define CGEN_BFD_ARCH bfd_arch_mt
     622  #endif
     623    arch = info->arch;
     624    if (arch == bfd_arch_unknown)
     625      arch = CGEN_BFD_ARCH;
     626  
     627    /* There's no standard way to compute the machine or isa number
     628       so we leave it to the target.  */
     629  #ifdef CGEN_COMPUTE_MACH
     630    mach = CGEN_COMPUTE_MACH (info);
     631  #else
     632    mach = info->mach;
     633  #endif
     634  
     635  #ifdef CGEN_COMPUTE_ISA
     636    {
     637      static CGEN_BITSET *permanent_isa;
     638  
     639      if (!permanent_isa)
     640        permanent_isa = cgen_bitset_create (MAX_ISAS);
     641      isa = permanent_isa;
     642      cgen_bitset_clear (isa);
     643      cgen_bitset_add (isa, CGEN_COMPUTE_ISA (info));
     644    }
     645  #else
     646    isa = info->private_data;
     647  #endif
     648  
     649    /* If we've switched cpu's, try to find a handle we've used before */
     650    if (cd
     651        && (cgen_bitset_compare (isa, prev_isa) != 0
     652  	  || mach != prev_mach
     653  	  || endian != prev_endian))
     654      {
     655        cd = 0;
     656        for (cl = cd_list; cl; cl = cl->next)
     657  	{
     658  	  if (cgen_bitset_compare (cl->isa, isa) == 0 &&
     659  	      cl->mach == mach &&
     660  	      cl->endian == endian)
     661  	    {
     662  	      cd = cl->cd;
     663   	      prev_isa = cd->isas;
     664  	      break;
     665  	    }
     666  	}
     667      }
     668  
     669    /* If we haven't initialized yet, initialize the opcode table.  */
     670    if (! cd)
     671      {
     672        const bfd_arch_info_type *arch_type = bfd_lookup_arch (arch, mach);
     673        const char *mach_name;
     674  
     675        if (!arch_type)
     676  	abort ();
     677        mach_name = arch_type->printable_name;
     678  
     679        prev_isa = cgen_bitset_copy (isa);
     680        prev_mach = mach;
     681        prev_endian = endian;
     682        prev_insn_endian = insn_endian;
     683        cd = mt_cgen_cpu_open (CGEN_CPU_OPEN_ISAS, prev_isa,
     684  				 CGEN_CPU_OPEN_BFDMACH, mach_name,
     685  				 CGEN_CPU_OPEN_ENDIAN, prev_endian,
     686                                   CGEN_CPU_OPEN_INSN_ENDIAN, prev_insn_endian,
     687  				 CGEN_CPU_OPEN_END);
     688        if (!cd)
     689  	abort ();
     690  
     691        /* Save this away for future reference.  */
     692        cl = xmalloc (sizeof (struct cpu_desc_list));
     693        cl->cd = cd;
     694        cl->isa = prev_isa;
     695        cl->mach = mach;
     696        cl->endian = endian;
     697        cl->next = cd_list;
     698        cd_list = cl;
     699  
     700        mt_cgen_init_dis (cd);
     701      }
     702  
     703    /* We try to have as much common code as possible.
     704       But at this point some targets need to take over.  */
     705    /* ??? Some targets may need a hook elsewhere.  Try to avoid this,
     706       but if not possible try to move this hook elsewhere rather than
     707       have two hooks.  */
     708    length = CGEN_PRINT_INSN (cd, pc, info);
     709    if (length > 0)
     710      return length;
     711    if (length < 0)
     712      return -1;
     713  
     714    (*info->fprintf_func) (info->stream, UNKNOWN_INSN_MSG);
     715    return cd->default_insn_bitsize / 8;
     716  }