Home | History | Annotate | Download | only in opcodes
      1 /* Disassembler interface for targets using CGEN. -*- C -*-
      2    CGEN: Cpu tools GENerator
      3 
      4    THIS FILE IS MACHINE GENERATED WITH CGEN.
      5    - the resultant file is machine generated, cgen-dis.in isn't
      6 
      7    Copyright (C) 1996-2014 Free Software Foundation, Inc.
      8 
      9    This file is part of libopcodes.
     10 
     11    This library is free software; you can redistribute it and/or modify
     12    it under the terms of the GNU General Public License as published by
     13    the Free Software Foundation; either version 3, or (at your option)
     14    any later version.
     15 
     16    It is distributed in the hope that it will be useful, but WITHOUT
     17    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
     18    or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
     19    License for more details.
     20 
     21    You should have received a copy of the GNU General Public License
     22    along with this program; if not, write to the Free Software Foundation, Inc.,
     23    51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.  */
     24 
     25 /* ??? Eventually more and more of this stuff can go to cpu-independent files.
     26    Keep that in mind.  */
     27 
     28 #include "sysdep.h"
     29 #include <stdio.h>
     30 #include "ansidecl.h"
     31 #include "dis-asm.h"
     32 #include "bfd.h"
     33 #include "symcat.h"
     34 #include "libiberty.h"
     35 #include "epiphany-desc.h"
     36 #include "epiphany-opc.h"
     37 #include "opintl.h"
     38 
     39 /* Default text to print if an instruction isn't recognized.  */
     40 #define UNKNOWN_INSN_MSG _("*unknown*")
     41 
     42 static void print_normal
     43   (CGEN_CPU_DESC, void *, long, unsigned int, bfd_vma, int);
     44 static void print_address
     45   (CGEN_CPU_DESC, void *, bfd_vma, unsigned int, bfd_vma, int) ATTRIBUTE_UNUSED;
     46 static void print_keyword
     47   (CGEN_CPU_DESC, void *, CGEN_KEYWORD *, long, unsigned int) ATTRIBUTE_UNUSED;
     48 static void print_insn_normal
     49   (CGEN_CPU_DESC, void *, const CGEN_INSN *, CGEN_FIELDS *, bfd_vma, int);
     50 static int print_insn
     51   (CGEN_CPU_DESC, bfd_vma,  disassemble_info *, bfd_byte *, unsigned);
     52 static int default_print_insn
     53   (CGEN_CPU_DESC, bfd_vma, disassemble_info *) ATTRIBUTE_UNUSED;
     54 static int read_insn
     55   (CGEN_CPU_DESC, bfd_vma, disassemble_info *, bfd_byte *, int, CGEN_EXTRACT_INFO *,
     56    unsigned long *);
     57 
     58 /* -- 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 
     74   /* Attempt to read the base part of the insn.  */
     75   info->bytes_per_line = buflen = cd->base_insn_bitsize / 8;
     76   status = (*info->read_memory_func) (pc, buf, buflen, info);
     77 
     78   /* Try again with the minimum part, if min < base.  */
     79   if (status != 0 && (cd->min_insn_bitsize < cd->base_insn_bitsize))
     80     {
     81       info->bytes_per_line = buflen = cd->min_insn_bitsize / 8;
     82       status = (*info->read_memory_func) (pc, buf, buflen, info);
     83     }
     84 
     85   if (status != 0)
     86     {
     87       (*info->memory_error_func) (status, pc, info);
     88       return -1;
     89     }
     90 
     91   return print_insn (cd, pc, info, buf, buflen);
     92 }
     93 
     94 
     95 static void
     96 print_postindex (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
     97 		 void * dis_info,
     98 		 long value,
     99 		 unsigned int attrs ATTRIBUTE_UNUSED,
    100 		 bfd_vma pc ATTRIBUTE_UNUSED,
    101 		 int length ATTRIBUTE_UNUSED)
    102 {
    103   disassemble_info *info = (disassemble_info *) dis_info;
    104   (*info->fprintf_func) (info->stream, value ? "-" : "+");
    105 }
    106 
    107 static void
    108 print_simm_not_reg (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
    109 		    void * dis_info,
    110 		    long value,
    111 		    unsigned int attrs ATTRIBUTE_UNUSED,
    112 		    bfd_vma pc ATTRIBUTE_UNUSED,
    113 		    int length ATTRIBUTE_UNUSED)
    114 {
    115   print_address (cd, dis_info, value, attrs, pc, length);
    116 }
    117 
    118 static void
    119 print_uimm_not_reg (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
    120 		    void * dis_info,
    121 		    unsigned long value,
    122 		    unsigned int attrs ATTRIBUTE_UNUSED,
    123 		    bfd_vma pc ATTRIBUTE_UNUSED,
    124 		    int length ATTRIBUTE_UNUSED)
    125 {
    126   disassemble_info *info = (disassemble_info *)dis_info;
    127 
    128   if (value & 0x800)
    129     (*info->fprintf_func) (info->stream, "-");
    130 
    131   value &= 0x7ff;
    132   print_address (cd, dis_info, value, attrs, pc, length);
    133 }
    134 
    135 
    136 /* -- */
    138 
    139 void epiphany_cgen_print_operand
    140   (CGEN_CPU_DESC, int, PTR, 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       fprintf (stderr, _("Unrecognized field %d while printing insn.\n"),
    279 	       opindex);
    280     abort ();
    281   }
    282 }
    283 
    284 cgen_print_fn * const epiphany_cgen_print_handlers[] =
    285 {
    286   print_insn_normal,
    287 };
    288 
    289 
    290 void
    291 epiphany_cgen_init_dis (CGEN_CPU_DESC cd)
    292 {
    293   epiphany_cgen_init_opcode_table (cd);
    294   epiphany_cgen_init_ibld_table (cd);
    295   cd->print_handlers = & epiphany_cgen_print_handlers[0];
    296   cd->print_operand = epiphany_cgen_print_operand;
    297 }
    298 
    299 
    300 /* 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.
    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       epiphany_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
    407    the extract info.
    408    Returns 0 if all is well, non-zero otherwise.  */
    409 
    410 static int
    411 read_insn (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
    412 	   bfd_vma pc,
    413 	   disassemble_info *info,
    414 	   bfd_byte *buf,
    415 	   int buflen,
    416 	   CGEN_EXTRACT_INFO *ex_info,
    417 	   unsigned long *insn_value)
    418 {
    419   int status = (*info->read_memory_func) (pc, buf, buflen, info);
    420 
    421   if (status != 0)
    422     {
    423       (*info->memory_error_func) (status, pc, info);
    424       return -1;
    425     }
    426 
    427   ex_info->dis_info = info;
    428   ex_info->valid = (1 << buflen) - 1;
    429   ex_info->insn_bytes = buf;
    430 
    431   *insn_value = bfd_get_bits (buf, buflen * 8, info->endian == BFD_ENDIAN_BIG);
    432   return 0;
    433 }
    434 
    435 /* Utility to print an insn.
    436    BUF is the base part of the insn, target byte order, BUFLEN bytes long.
    437    The result is the size of the insn in bytes or zero for an unknown insn
    438    or -1 if an error occurs fetching data (memory_error_func will have
    439    been called).  */
    440 
    441 static int
    442 print_insn (CGEN_CPU_DESC cd,
    443 	    bfd_vma pc,
    444 	    disassemble_info *info,
    445 	    bfd_byte *buf,
    446 	    unsigned int buflen)
    447 {
    448   CGEN_INSN_INT insn_value;
    449   const CGEN_INSN_LIST *insn_list;
    450   CGEN_EXTRACT_INFO ex_info;
    451   int basesize;
    452 
    453   /* Extract base part of instruction, just in case CGEN_DIS_* uses it. */
    454   basesize = cd->base_insn_bitsize < buflen * 8 ?
    455                                      cd->base_insn_bitsize : buflen * 8;
    456   insn_value = cgen_get_insn_value (cd, buf, basesize);
    457 
    458 
    459   /* Fill in ex_info fields like read_insn would.  Don't actually call
    460      read_insn, since the incoming buffer is already read (and possibly
    461      modified a la m32r).  */
    462   ex_info.valid = (1 << buflen) - 1;
    463   ex_info.dis_info = info;
    464   ex_info.insn_bytes = buf;
    465 
    466   /* The instructions are stored in hash lists.
    467      Pick the first one and keep trying until we find the right one.  */
    468 
    469   insn_list = CGEN_DIS_LOOKUP_INSN (cd, (char *) buf, insn_value);
    470   while (insn_list != NULL)
    471     {
    472       const CGEN_INSN *insn = insn_list->insn;
    473       CGEN_FIELDS fields;
    474       int length;
    475       unsigned long insn_value_cropped;
    476 
    477 #ifdef CGEN_VALIDATE_INSN_SUPPORTED
    478       /* Not needed as insn shouldn't be in hash lists if not supported.  */
    479       /* Supported by this cpu?  */
    480       if (! epiphany_cgen_insn_supported (cd, insn))
    481         {
    482           insn_list = CGEN_DIS_NEXT_INSN (insn_list);
    483 	  continue;
    484         }
    485 #endif
    486 
    487       /* Basic bit mask must be correct.  */
    488       /* ??? May wish to allow target to defer this check until the extract
    489 	 handler.  */
    490 
    491       /* Base size may exceed this instruction's size.  Extract the
    492          relevant part from the buffer. */
    493       if ((unsigned) (CGEN_INSN_BITSIZE (insn) / 8) < buflen &&
    494 	  (unsigned) (CGEN_INSN_BITSIZE (insn) / 8) <= sizeof (unsigned long))
    495 	insn_value_cropped = bfd_get_bits (buf, CGEN_INSN_BITSIZE (insn),
    496 					   info->endian == BFD_ENDIAN_BIG);
    497       else
    498 	insn_value_cropped = insn_value;
    499 
    500       if ((insn_value_cropped & CGEN_INSN_BASE_MASK (insn))
    501 	  == CGEN_INSN_BASE_VALUE (insn))
    502 	{
    503 	  /* Printing is handled in two passes.  The first pass parses the
    504 	     machine insn and extracts the fields.  The second pass prints
    505 	     them.  */
    506 
    507 	  /* Make sure the entire insn is loaded into insn_value, if it
    508 	     can fit.  */
    509 	  if (((unsigned) CGEN_INSN_BITSIZE (insn) > cd->base_insn_bitsize) &&
    510 	      (unsigned) (CGEN_INSN_BITSIZE (insn) / 8) <= sizeof (unsigned long))
    511 	    {
    512 	      unsigned long full_insn_value;
    513 	      int rc = read_insn (cd, pc, info, buf,
    514 				  CGEN_INSN_BITSIZE (insn) / 8,
    515 				  & ex_info, & full_insn_value);
    516 	      if (rc != 0)
    517 		return rc;
    518 	      length = CGEN_EXTRACT_FN (cd, insn)
    519 		(cd, insn, &ex_info, full_insn_value, &fields, pc);
    520 	    }
    521 	  else
    522 	    length = CGEN_EXTRACT_FN (cd, insn)
    523 	      (cd, insn, &ex_info, insn_value_cropped, &fields, pc);
    524 
    525 	  /* Length < 0 -> error.  */
    526 	  if (length < 0)
    527 	    return length;
    528 	  if (length > 0)
    529 	    {
    530 	      CGEN_PRINT_FN (cd, insn) (cd, info, insn, &fields, pc, length);
    531 	      /* Length is in bits, result is in bytes.  */
    532 	      return length / 8;
    533 	    }
    534 	}
    535 
    536       insn_list = CGEN_DIS_NEXT_INSN (insn_list);
    537     }
    538 
    539   return 0;
    540 }
    541 
    542 /* Default value for CGEN_PRINT_INSN.
    543    The result is the size of the insn in bytes or zero for an unknown insn
    544    or -1 if an error occured fetching bytes.  */
    545 
    546 #ifndef CGEN_PRINT_INSN
    547 #define CGEN_PRINT_INSN default_print_insn
    548 #endif
    549 
    550 static int
    551 default_print_insn (CGEN_CPU_DESC cd, bfd_vma pc, disassemble_info *info)
    552 {
    553   bfd_byte buf[CGEN_MAX_INSN_SIZE];
    554   int buflen;
    555   int status;
    556 
    557   /* Attempt to read the base part of the insn.  */
    558   buflen = cd->base_insn_bitsize / 8;
    559   status = (*info->read_memory_func) (pc, buf, buflen, info);
    560 
    561   /* Try again with the minimum part, if min < base.  */
    562   if (status != 0 && (cd->min_insn_bitsize < cd->base_insn_bitsize))
    563     {
    564       buflen = cd->min_insn_bitsize / 8;
    565       status = (*info->read_memory_func) (pc, buf, buflen, info);
    566     }
    567 
    568   if (status != 0)
    569     {
    570       (*info->memory_error_func) (status, pc, info);
    571       return -1;
    572     }
    573 
    574   return print_insn (cd, pc, info, buf, buflen);
    575 }
    576 
    577 /* Main entry point.
    578    Print one instruction from PC on INFO->STREAM.
    579    Return the size of the instruction (in bytes).  */
    580 
    581 typedef struct cpu_desc_list
    582 {
    583   struct cpu_desc_list *next;
    584   CGEN_BITSET *isa;
    585   int mach;
    586   int endian;
    587   CGEN_CPU_DESC cd;
    588 } cpu_desc_list;
    589 
    590 int
    591 print_insn_epiphany (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   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   enum bfd_architecture arch;
    606 
    607   /* ??? gdb will set mach but leave the architecture as "unknown" */
    608 #ifndef CGEN_BFD_ARCH
    609 #define CGEN_BFD_ARCH bfd_arch_epiphany
    610 #endif
    611   arch = info->arch;
    612   if (arch == bfd_arch_unknown)
    613     arch = CGEN_BFD_ARCH;
    614 
    615   /* There's no standard way to compute the machine or isa number
    616      so we leave it to the target.  */
    617 #ifdef CGEN_COMPUTE_MACH
    618   mach = CGEN_COMPUTE_MACH (info);
    619 #else
    620   mach = info->mach;
    621 #endif
    622 
    623 #ifdef CGEN_COMPUTE_ISA
    624   {
    625     static CGEN_BITSET *permanent_isa;
    626 
    627     if (!permanent_isa)
    628       permanent_isa = cgen_bitset_create (MAX_ISAS);
    629     isa = permanent_isa;
    630     cgen_bitset_clear (isa);
    631     cgen_bitset_add (isa, CGEN_COMPUTE_ISA (info));
    632   }
    633 #else
    634   isa = info->insn_sets;
    635 #endif
    636 
    637   /* If we've switched cpu's, try to find a handle we've used before */
    638   if (cd
    639       && (cgen_bitset_compare (isa, prev_isa) != 0
    640 	  || mach != prev_mach
    641 	  || endian != prev_endian))
    642     {
    643       cd = 0;
    644       for (cl = cd_list; cl; cl = cl->next)
    645 	{
    646 	  if (cgen_bitset_compare (cl->isa, isa) == 0 &&
    647 	      cl->mach == mach &&
    648 	      cl->endian == endian)
    649 	    {
    650 	      cd = cl->cd;
    651  	      prev_isa = cd->isas;
    652 	      break;
    653 	    }
    654 	}
    655     }
    656 
    657   /* If we haven't initialized yet, initialize the opcode table.  */
    658   if (! cd)
    659     {
    660       const bfd_arch_info_type *arch_type = bfd_lookup_arch (arch, mach);
    661       const char *mach_name;
    662 
    663       if (!arch_type)
    664 	abort ();
    665       mach_name = arch_type->printable_name;
    666 
    667       prev_isa = cgen_bitset_copy (isa);
    668       prev_mach = mach;
    669       prev_endian = endian;
    670       cd = epiphany_cgen_cpu_open (CGEN_CPU_OPEN_ISAS, prev_isa,
    671 				 CGEN_CPU_OPEN_BFDMACH, mach_name,
    672 				 CGEN_CPU_OPEN_ENDIAN, prev_endian,
    673 				 CGEN_CPU_OPEN_END);
    674       if (!cd)
    675 	abort ();
    676 
    677       /* Save this away for future reference.  */
    678       cl = xmalloc (sizeof (struct cpu_desc_list));
    679       cl->cd = cd;
    680       cl->isa = prev_isa;
    681       cl->mach = mach;
    682       cl->endian = endian;
    683       cl->next = cd_list;
    684       cd_list = cl;
    685 
    686       epiphany_cgen_init_dis (cd);
    687     }
    688 
    689   /* We try to have as much common code as possible.
    690      But at this point some targets need to take over.  */
    691   /* ??? Some targets may need a hook elsewhere.  Try to avoid this,
    692      but if not possible try to move this hook elsewhere rather than
    693      have two hooks.  */
    694   length = CGEN_PRINT_INSN (cd, pc, info);
    695   if (length > 0)
    696     return length;
    697   if (length < 0)
    698     return -1;
    699 
    700   (*info->fprintf_func) (info->stream, UNKNOWN_INSN_MSG);
    701   return cd->default_insn_bitsize / 8;
    702 }
    703