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