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