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