Back to index

cell-binutils  2.17cvs20070401
fr30-dis.c
Go to the documentation of this file.
00001 /* Disassembler interface for targets using CGEN. -*- C -*-
00002    CGEN: Cpu tools GENerator
00003 
00004    THIS FILE IS MACHINE GENERATED WITH CGEN.
00005    - the resultant file is machine generated, cgen-dis.in isn't
00006 
00007    Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2005
00008    Free Software Foundation, Inc.
00009 
00010    This file is part of the GNU Binutils and GDB, the GNU debugger.
00011 
00012    This program is free software; you can redistribute it and/or modify
00013    it under the terms of the GNU General Public License as published by
00014    the Free Software Foundation; either version 2, or (at your option)
00015    any later version.
00016 
00017    This program is distributed in the hope that it will be useful,
00018    but WITHOUT ANY WARRANTY; without even the implied warranty of
00019    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00020    GNU General Public License for more details.
00021 
00022    You should have received a copy of the GNU General Public License
00023    along with this program; if not, write to the Free Software Foundation, Inc.,
00024    51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.  */
00025 
00026 /* ??? Eventually more and more of this stuff can go to cpu-independent files.
00027    Keep that in mind.  */
00028 
00029 #include "sysdep.h"
00030 #include <stdio.h>
00031 #include "ansidecl.h"
00032 #include "dis-asm.h"
00033 #include "bfd.h"
00034 #include "symcat.h"
00035 #include "libiberty.h"
00036 #include "fr30-desc.h"
00037 #include "fr30-opc.h"
00038 #include "opintl.h"
00039 
00040 /* Default text to print if an instruction isn't recognized.  */
00041 #define UNKNOWN_INSN_MSG _("*unknown*")
00042 
00043 static void print_normal
00044   (CGEN_CPU_DESC, void *, long, unsigned int, bfd_vma, int);
00045 static void print_address
00046   (CGEN_CPU_DESC, void *, bfd_vma, unsigned int, bfd_vma, int) ATTRIBUTE_UNUSED;
00047 static void print_keyword
00048   (CGEN_CPU_DESC, void *, CGEN_KEYWORD *, long, unsigned int) ATTRIBUTE_UNUSED;
00049 static void print_insn_normal
00050   (CGEN_CPU_DESC, void *, const CGEN_INSN *, CGEN_FIELDS *, bfd_vma, int);
00051 static int print_insn
00052   (CGEN_CPU_DESC, bfd_vma,  disassemble_info *, bfd_byte *, unsigned);
00053 static int default_print_insn
00054   (CGEN_CPU_DESC, bfd_vma, disassemble_info *) ATTRIBUTE_UNUSED;
00055 static int read_insn
00056   (CGEN_CPU_DESC, bfd_vma, disassemble_info *, bfd_byte *, int, CGEN_EXTRACT_INFO *,
00057    unsigned long *);
00058 
00059 /* -- disassembler routines inserted here.  */
00060 
00061 /* -- dis.c */
00062 static void
00063 print_register_list (void * dis_info,
00064                    long value,
00065                    long offset,
00066                    int load_store) /* 0 == load, 1 == store.  */
00067 {
00068   disassemble_info *info = dis_info;
00069   int mask;
00070   int index = 0;
00071   char * comma = "";
00072 
00073   if (load_store)
00074     mask = 0x80;
00075   else
00076     mask = 1;
00077 
00078   if (value & mask)
00079     {
00080       (*info->fprintf_func) (info->stream, "r%li", index + offset);
00081       comma = ",";
00082     }
00083     
00084   for (index = 1; index <= 7; ++index)
00085     {
00086       if (load_store)
00087        mask >>= 1;
00088       else
00089        mask <<= 1;
00090 
00091       if (value & mask)
00092        {
00093          (*info->fprintf_func) (info->stream, "%sr%li", comma, index + offset);
00094          comma = ",";
00095        }
00096     }
00097 }
00098 
00099 static void
00100 print_hi_register_list_ld (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
00101                         void * dis_info,
00102                         long value,
00103                         unsigned int attrs ATTRIBUTE_UNUSED,
00104                         bfd_vma pc ATTRIBUTE_UNUSED,
00105                         int length ATTRIBUTE_UNUSED)
00106 {
00107   print_register_list (dis_info, value, 8, 0 /* Load.  */);
00108 }
00109 
00110 static void
00111 print_low_register_list_ld (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
00112                          void * dis_info,
00113                          long value,
00114                          unsigned int attrs ATTRIBUTE_UNUSED,
00115                          bfd_vma pc ATTRIBUTE_UNUSED,
00116                          int length ATTRIBUTE_UNUSED)
00117 {
00118   print_register_list (dis_info, value, 0, 0 /* Load.  */);
00119 }
00120 
00121 static void
00122 print_hi_register_list_st (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
00123                         void * dis_info,
00124                         long value,
00125                         unsigned int attrs ATTRIBUTE_UNUSED,
00126                         bfd_vma pc ATTRIBUTE_UNUSED,
00127                         int length ATTRIBUTE_UNUSED)
00128 {
00129   print_register_list (dis_info, value, 8, 1 /* Store.  */);
00130 }
00131 
00132 static void
00133 print_low_register_list_st (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
00134                          void * dis_info,
00135                          long value,
00136                          unsigned int attrs ATTRIBUTE_UNUSED,
00137                          bfd_vma pc ATTRIBUTE_UNUSED,
00138                          int length ATTRIBUTE_UNUSED)
00139 {
00140   print_register_list (dis_info, value, 0, 1 /* Store.  */);
00141 }
00142 
00143 static void
00144 print_m4 (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
00145          void * dis_info,
00146          long value,
00147          unsigned int attrs ATTRIBUTE_UNUSED,
00148          bfd_vma pc ATTRIBUTE_UNUSED,
00149          int length ATTRIBUTE_UNUSED)
00150 {
00151   disassemble_info *info = (disassemble_info *) dis_info;
00152 
00153   (*info->fprintf_func) (info->stream, "%ld", value);
00154 }
00155 /* -- */
00156 
00157 void fr30_cgen_print_operand
00158   (CGEN_CPU_DESC, int, PTR, CGEN_FIELDS *, void const *, bfd_vma, int);
00159 
00160 /* Main entry point for printing operands.
00161    XINFO is a `void *' and not a `disassemble_info *' to not put a requirement
00162    of dis-asm.h on cgen.h.
00163 
00164    This function is basically just a big switch statement.  Earlier versions
00165    used tables to look up the function to use, but
00166    - if the table contains both assembler and disassembler functions then
00167      the disassembler contains much of the assembler and vice-versa,
00168    - there's a lot of inlining possibilities as things grow,
00169    - using a switch statement avoids the function call overhead.
00170 
00171    This function could be moved into `print_insn_normal', but keeping it
00172    separate makes clear the interface between `print_insn_normal' and each of
00173    the handlers.  */
00174 
00175 void
00176 fr30_cgen_print_operand (CGEN_CPU_DESC cd,
00177                         int opindex,
00178                         void * xinfo,
00179                         CGEN_FIELDS *fields,
00180                         void const *attrs ATTRIBUTE_UNUSED,
00181                         bfd_vma pc,
00182                         int length)
00183 {
00184   disassemble_info *info = (disassemble_info *) xinfo;
00185 
00186   switch (opindex)
00187     {
00188     case FR30_OPERAND_CRI :
00189       print_keyword (cd, info, & fr30_cgen_opval_cr_names, fields->f_CRi, 0);
00190       break;
00191     case FR30_OPERAND_CRJ :
00192       print_keyword (cd, info, & fr30_cgen_opval_cr_names, fields->f_CRj, 0);
00193       break;
00194     case FR30_OPERAND_R13 :
00195       print_keyword (cd, info, & fr30_cgen_opval_h_r13, 0, 0);
00196       break;
00197     case FR30_OPERAND_R14 :
00198       print_keyword (cd, info, & fr30_cgen_opval_h_r14, 0, 0);
00199       break;
00200     case FR30_OPERAND_R15 :
00201       print_keyword (cd, info, & fr30_cgen_opval_h_r15, 0, 0);
00202       break;
00203     case FR30_OPERAND_RI :
00204       print_keyword (cd, info, & fr30_cgen_opval_gr_names, fields->f_Ri, 0);
00205       break;
00206     case FR30_OPERAND_RIC :
00207       print_keyword (cd, info, & fr30_cgen_opval_gr_names, fields->f_Ric, 0);
00208       break;
00209     case FR30_OPERAND_RJ :
00210       print_keyword (cd, info, & fr30_cgen_opval_gr_names, fields->f_Rj, 0);
00211       break;
00212     case FR30_OPERAND_RJC :
00213       print_keyword (cd, info, & fr30_cgen_opval_gr_names, fields->f_Rjc, 0);
00214       break;
00215     case FR30_OPERAND_RS1 :
00216       print_keyword (cd, info, & fr30_cgen_opval_dr_names, fields->f_Rs1, 0);
00217       break;
00218     case FR30_OPERAND_RS2 :
00219       print_keyword (cd, info, & fr30_cgen_opval_dr_names, fields->f_Rs2, 0);
00220       break;
00221     case FR30_OPERAND_CC :
00222       print_normal (cd, info, fields->f_cc, 0, pc, length);
00223       break;
00224     case FR30_OPERAND_CCC :
00225       print_normal (cd, info, fields->f_ccc, 0|(1<<CGEN_OPERAND_HASH_PREFIX), pc, length);
00226       break;
00227     case FR30_OPERAND_DIR10 :
00228       print_normal (cd, info, fields->f_dir10, 0, pc, length);
00229       break;
00230     case FR30_OPERAND_DIR8 :
00231       print_normal (cd, info, fields->f_dir8, 0, pc, length);
00232       break;
00233     case FR30_OPERAND_DIR9 :
00234       print_normal (cd, info, fields->f_dir9, 0, pc, length);
00235       break;
00236     case FR30_OPERAND_DISP10 :
00237       print_normal (cd, info, fields->f_disp10, 0|(1<<CGEN_OPERAND_SIGNED)|(1<<CGEN_OPERAND_HASH_PREFIX), pc, length);
00238       break;
00239     case FR30_OPERAND_DISP8 :
00240       print_normal (cd, info, fields->f_disp8, 0|(1<<CGEN_OPERAND_SIGNED)|(1<<CGEN_OPERAND_HASH_PREFIX), pc, length);
00241       break;
00242     case FR30_OPERAND_DISP9 :
00243       print_normal (cd, info, fields->f_disp9, 0|(1<<CGEN_OPERAND_SIGNED)|(1<<CGEN_OPERAND_HASH_PREFIX), pc, length);
00244       break;
00245     case FR30_OPERAND_I20 :
00246       print_normal (cd, info, fields->f_i20, 0|(1<<CGEN_OPERAND_HASH_PREFIX)|(1<<CGEN_OPERAND_VIRTUAL), pc, length);
00247       break;
00248     case FR30_OPERAND_I32 :
00249       print_normal (cd, info, fields->f_i32, 0|(1<<CGEN_OPERAND_HASH_PREFIX)|(1<<CGEN_OPERAND_SIGN_OPT), pc, length);
00250       break;
00251     case FR30_OPERAND_I8 :
00252       print_normal (cd, info, fields->f_i8, 0|(1<<CGEN_OPERAND_HASH_PREFIX), pc, length);
00253       break;
00254     case FR30_OPERAND_LABEL12 :
00255       print_address (cd, info, fields->f_rel12, 0|(1<<CGEN_OPERAND_PCREL_ADDR), pc, length);
00256       break;
00257     case FR30_OPERAND_LABEL9 :
00258       print_address (cd, info, fields->f_rel9, 0|(1<<CGEN_OPERAND_PCREL_ADDR), pc, length);
00259       break;
00260     case FR30_OPERAND_M4 :
00261       print_m4 (cd, info, fields->f_m4, 0|(1<<CGEN_OPERAND_SIGNED)|(1<<CGEN_OPERAND_HASH_PREFIX), pc, length);
00262       break;
00263     case FR30_OPERAND_PS :
00264       print_keyword (cd, info, & fr30_cgen_opval_h_ps, 0, 0);
00265       break;
00266     case FR30_OPERAND_REGLIST_HI_LD :
00267       print_hi_register_list_ld (cd, info, fields->f_reglist_hi_ld, 0, pc, length);
00268       break;
00269     case FR30_OPERAND_REGLIST_HI_ST :
00270       print_hi_register_list_st (cd, info, fields->f_reglist_hi_st, 0, pc, length);
00271       break;
00272     case FR30_OPERAND_REGLIST_LOW_LD :
00273       print_low_register_list_ld (cd, info, fields->f_reglist_low_ld, 0, pc, length);
00274       break;
00275     case FR30_OPERAND_REGLIST_LOW_ST :
00276       print_low_register_list_st (cd, info, fields->f_reglist_low_st, 0, pc, length);
00277       break;
00278     case FR30_OPERAND_S10 :
00279       print_normal (cd, info, fields->f_s10, 0|(1<<CGEN_OPERAND_SIGNED)|(1<<CGEN_OPERAND_HASH_PREFIX), pc, length);
00280       break;
00281     case FR30_OPERAND_U10 :
00282       print_normal (cd, info, fields->f_u10, 0|(1<<CGEN_OPERAND_HASH_PREFIX), pc, length);
00283       break;
00284     case FR30_OPERAND_U4 :
00285       print_normal (cd, info, fields->f_u4, 0|(1<<CGEN_OPERAND_HASH_PREFIX), pc, length);
00286       break;
00287     case FR30_OPERAND_U4C :
00288       print_normal (cd, info, fields->f_u4c, 0|(1<<CGEN_OPERAND_HASH_PREFIX), pc, length);
00289       break;
00290     case FR30_OPERAND_U8 :
00291       print_normal (cd, info, fields->f_u8, 0|(1<<CGEN_OPERAND_HASH_PREFIX), pc, length);
00292       break;
00293     case FR30_OPERAND_UDISP6 :
00294       print_normal (cd, info, fields->f_udisp6, 0|(1<<CGEN_OPERAND_HASH_PREFIX), pc, length);
00295       break;
00296 
00297     default :
00298       /* xgettext:c-format */
00299       fprintf (stderr, _("Unrecognized field %d while printing insn.\n"),
00300               opindex);
00301     abort ();
00302   }
00303 }
00304 
00305 cgen_print_fn * const fr30_cgen_print_handlers[] = 
00306 {
00307   print_insn_normal,
00308 };
00309 
00310 
00311 void
00312 fr30_cgen_init_dis (CGEN_CPU_DESC cd)
00313 {
00314   fr30_cgen_init_opcode_table (cd);
00315   fr30_cgen_init_ibld_table (cd);
00316   cd->print_handlers = & fr30_cgen_print_handlers[0];
00317   cd->print_operand = fr30_cgen_print_operand;
00318 }
00319 
00320 
00321 /* Default print handler.  */
00322 
00323 static void
00324 print_normal (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
00325              void *dis_info,
00326              long value,
00327              unsigned int attrs,
00328              bfd_vma pc ATTRIBUTE_UNUSED,
00329              int length ATTRIBUTE_UNUSED)
00330 {
00331   disassemble_info *info = (disassemble_info *) dis_info;
00332 
00333 #ifdef CGEN_PRINT_NORMAL
00334   CGEN_PRINT_NORMAL (cd, info, value, attrs, pc, length);
00335 #endif
00336 
00337   /* Print the operand as directed by the attributes.  */
00338   if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SEM_ONLY))
00339     ; /* nothing to do */
00340   else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SIGNED))
00341     (*info->fprintf_func) (info->stream, "%ld", value);
00342   else
00343     (*info->fprintf_func) (info->stream, "0x%lx", value);
00344 }
00345 
00346 /* Default address handler.  */
00347 
00348 static void
00349 print_address (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
00350               void *dis_info,
00351               bfd_vma value,
00352               unsigned int attrs,
00353               bfd_vma pc ATTRIBUTE_UNUSED,
00354               int length ATTRIBUTE_UNUSED)
00355 {
00356   disassemble_info *info = (disassemble_info *) dis_info;
00357 
00358 #ifdef CGEN_PRINT_ADDRESS
00359   CGEN_PRINT_ADDRESS (cd, info, value, attrs, pc, length);
00360 #endif
00361 
00362   /* Print the operand as directed by the attributes.  */
00363   if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SEM_ONLY))
00364     ; /* Nothing to do.  */
00365   else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_PCREL_ADDR))
00366     (*info->print_address_func) (value, info);
00367   else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_ABS_ADDR))
00368     (*info->print_address_func) (value, info);
00369   else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SIGNED))
00370     (*info->fprintf_func) (info->stream, "%ld", (long) value);
00371   else
00372     (*info->fprintf_func) (info->stream, "0x%lx", (long) value);
00373 }
00374 
00375 /* Keyword print handler.  */
00376 
00377 static void
00378 print_keyword (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
00379               void *dis_info,
00380               CGEN_KEYWORD *keyword_table,
00381               long value,
00382               unsigned int attrs ATTRIBUTE_UNUSED)
00383 {
00384   disassemble_info *info = (disassemble_info *) dis_info;
00385   const CGEN_KEYWORD_ENTRY *ke;
00386 
00387   ke = cgen_keyword_lookup_value (keyword_table, value);
00388   if (ke != NULL)
00389     (*info->fprintf_func) (info->stream, "%s", ke->name);
00390   else
00391     (*info->fprintf_func) (info->stream, "???");
00392 }
00393 
00394 /* Default insn printer.
00395 
00396    DIS_INFO is defined as `void *' so the disassembler needn't know anything
00397    about disassemble_info.  */
00398 
00399 static void
00400 print_insn_normal (CGEN_CPU_DESC cd,
00401                  void *dis_info,
00402                  const CGEN_INSN *insn,
00403                  CGEN_FIELDS *fields,
00404                  bfd_vma pc,
00405                  int length)
00406 {
00407   const CGEN_SYNTAX *syntax = CGEN_INSN_SYNTAX (insn);
00408   disassemble_info *info = (disassemble_info *) dis_info;
00409   const CGEN_SYNTAX_CHAR_TYPE *syn;
00410 
00411   CGEN_INIT_PRINT (cd);
00412 
00413   for (syn = CGEN_SYNTAX_STRING (syntax); *syn; ++syn)
00414     {
00415       if (CGEN_SYNTAX_MNEMONIC_P (*syn))
00416        {
00417          (*info->fprintf_func) (info->stream, "%s", CGEN_INSN_MNEMONIC (insn));
00418          continue;
00419        }
00420       if (CGEN_SYNTAX_CHAR_P (*syn))
00421        {
00422          (*info->fprintf_func) (info->stream, "%c", CGEN_SYNTAX_CHAR (*syn));
00423          continue;
00424        }
00425 
00426       /* We have an operand.  */
00427       fr30_cgen_print_operand (cd, CGEN_SYNTAX_FIELD (*syn), info,
00428                              fields, CGEN_INSN_ATTRS (insn), pc, length);
00429     }
00430 }
00431 
00432 /* Subroutine of print_insn. Reads an insn into the given buffers and updates
00433    the extract info.
00434    Returns 0 if all is well, non-zero otherwise.  */
00435 
00436 static int
00437 read_insn (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
00438           bfd_vma pc,
00439           disassemble_info *info,
00440           bfd_byte *buf,
00441           int buflen,
00442           CGEN_EXTRACT_INFO *ex_info,
00443           unsigned long *insn_value)
00444 {
00445   int status = (*info->read_memory_func) (pc, buf, buflen, info);
00446 
00447   if (status != 0)
00448     {
00449       (*info->memory_error_func) (status, pc, info);
00450       return -1;
00451     }
00452 
00453   ex_info->dis_info = info;
00454   ex_info->valid = (1 << buflen) - 1;
00455   ex_info->insn_bytes = buf;
00456 
00457   *insn_value = bfd_get_bits (buf, buflen * 8, info->endian == BFD_ENDIAN_BIG);
00458   return 0;
00459 }
00460 
00461 /* Utility to print an insn.
00462    BUF is the base part of the insn, target byte order, BUFLEN bytes long.
00463    The result is the size of the insn in bytes or zero for an unknown insn
00464    or -1 if an error occurs fetching data (memory_error_func will have
00465    been called).  */
00466 
00467 static int
00468 print_insn (CGEN_CPU_DESC cd,
00469            bfd_vma pc,
00470            disassemble_info *info,
00471            bfd_byte *buf,
00472            unsigned int buflen)
00473 {
00474   CGEN_INSN_INT insn_value;
00475   const CGEN_INSN_LIST *insn_list;
00476   CGEN_EXTRACT_INFO ex_info;
00477   int basesize;
00478 
00479   /* Extract base part of instruction, just in case CGEN_DIS_* uses it. */
00480   basesize = cd->base_insn_bitsize < buflen * 8 ?
00481                                      cd->base_insn_bitsize : buflen * 8;
00482   insn_value = cgen_get_insn_value (cd, buf, basesize);
00483 
00484 
00485   /* Fill in ex_info fields like read_insn would.  Don't actually call
00486      read_insn, since the incoming buffer is already read (and possibly
00487      modified a la m32r).  */
00488   ex_info.valid = (1 << buflen) - 1;
00489   ex_info.dis_info = info;
00490   ex_info.insn_bytes = buf;
00491 
00492   /* The instructions are stored in hash lists.
00493      Pick the first one and keep trying until we find the right one.  */
00494 
00495   insn_list = CGEN_DIS_LOOKUP_INSN (cd, (char *) buf, insn_value);
00496   while (insn_list != NULL)
00497     {
00498       const CGEN_INSN *insn = insn_list->insn;
00499       CGEN_FIELDS fields;
00500       int length;
00501       unsigned long insn_value_cropped;
00502 
00503 #ifdef CGEN_VALIDATE_INSN_SUPPORTED 
00504       /* Not needed as insn shouldn't be in hash lists if not supported.  */
00505       /* Supported by this cpu?  */
00506       if (! fr30_cgen_insn_supported (cd, insn))
00507         {
00508           insn_list = CGEN_DIS_NEXT_INSN (insn_list);
00509          continue;
00510         }
00511 #endif
00512 
00513       /* Basic bit mask must be correct.  */
00514       /* ??? May wish to allow target to defer this check until the extract
00515         handler.  */
00516 
00517       /* Base size may exceed this instruction's size.  Extract the
00518          relevant part from the buffer. */
00519       if ((unsigned) (CGEN_INSN_BITSIZE (insn) / 8) < buflen &&
00520          (unsigned) (CGEN_INSN_BITSIZE (insn) / 8) <= sizeof (unsigned long))
00521        insn_value_cropped = bfd_get_bits (buf, CGEN_INSN_BITSIZE (insn), 
00522                                       info->endian == BFD_ENDIAN_BIG);
00523       else
00524        insn_value_cropped = insn_value;
00525 
00526       if ((insn_value_cropped & CGEN_INSN_BASE_MASK (insn))
00527          == CGEN_INSN_BASE_VALUE (insn))
00528        {
00529          /* Printing is handled in two passes.  The first pass parses the
00530             machine insn and extracts the fields.  The second pass prints
00531             them.  */
00532 
00533          /* Make sure the entire insn is loaded into insn_value, if it
00534             can fit.  */
00535          if (((unsigned) CGEN_INSN_BITSIZE (insn) > cd->base_insn_bitsize) &&
00536              (unsigned) (CGEN_INSN_BITSIZE (insn) / 8) <= sizeof (unsigned long))
00537            {
00538              unsigned long full_insn_value;
00539              int rc = read_insn (cd, pc, info, buf,
00540                               CGEN_INSN_BITSIZE (insn) / 8,
00541                               & ex_info, & full_insn_value);
00542              if (rc != 0)
00543               return rc;
00544              length = CGEN_EXTRACT_FN (cd, insn)
00545               (cd, insn, &ex_info, full_insn_value, &fields, pc);
00546            }
00547          else
00548            length = CGEN_EXTRACT_FN (cd, insn)
00549              (cd, insn, &ex_info, insn_value_cropped, &fields, pc);
00550 
00551          /* Length < 0 -> error.  */
00552          if (length < 0)
00553            return length;
00554          if (length > 0)
00555            {
00556              CGEN_PRINT_FN (cd, insn) (cd, info, insn, &fields, pc, length);
00557              /* Length is in bits, result is in bytes.  */
00558              return length / 8;
00559            }
00560        }
00561 
00562       insn_list = CGEN_DIS_NEXT_INSN (insn_list);
00563     }
00564 
00565   return 0;
00566 }
00567 
00568 /* Default value for CGEN_PRINT_INSN.
00569    The result is the size of the insn in bytes or zero for an unknown insn
00570    or -1 if an error occured fetching bytes.  */
00571 
00572 #ifndef CGEN_PRINT_INSN
00573 #define CGEN_PRINT_INSN default_print_insn
00574 #endif
00575 
00576 static int
00577 default_print_insn (CGEN_CPU_DESC cd, bfd_vma pc, disassemble_info *info)
00578 {
00579   bfd_byte buf[CGEN_MAX_INSN_SIZE];
00580   int buflen;
00581   int status;
00582 
00583   /* Attempt to read the base part of the insn.  */
00584   buflen = cd->base_insn_bitsize / 8;
00585   status = (*info->read_memory_func) (pc, buf, buflen, info);
00586 
00587   /* Try again with the minimum part, if min < base.  */
00588   if (status != 0 && (cd->min_insn_bitsize < cd->base_insn_bitsize))
00589     {
00590       buflen = cd->min_insn_bitsize / 8;
00591       status = (*info->read_memory_func) (pc, buf, buflen, info);
00592     }
00593 
00594   if (status != 0)
00595     {
00596       (*info->memory_error_func) (status, pc, info);
00597       return -1;
00598     }
00599 
00600   return print_insn (cd, pc, info, buf, buflen);
00601 }
00602 
00603 /* Main entry point.
00604    Print one instruction from PC on INFO->STREAM.
00605    Return the size of the instruction (in bytes).  */
00606 
00607 typedef struct cpu_desc_list
00608 {
00609   struct cpu_desc_list *next;
00610   CGEN_BITSET *isa;
00611   int mach;
00612   int endian;
00613   CGEN_CPU_DESC cd;
00614 } cpu_desc_list;
00615 
00616 int
00617 print_insn_fr30 (bfd_vma pc, disassemble_info *info)
00618 {
00619   static cpu_desc_list *cd_list = 0;
00620   cpu_desc_list *cl = 0;
00621   static CGEN_CPU_DESC cd = 0;
00622   static CGEN_BITSET *prev_isa;
00623   static int prev_mach;
00624   static int prev_endian;
00625   int length;
00626   CGEN_BITSET *isa;
00627   int mach;
00628   int endian = (info->endian == BFD_ENDIAN_BIG
00629               ? CGEN_ENDIAN_BIG
00630               : CGEN_ENDIAN_LITTLE);
00631   enum bfd_architecture arch;
00632 
00633   /* ??? gdb will set mach but leave the architecture as "unknown" */
00634 #ifndef CGEN_BFD_ARCH
00635 #define CGEN_BFD_ARCH bfd_arch_fr30
00636 #endif
00637   arch = info->arch;
00638   if (arch == bfd_arch_unknown)
00639     arch = CGEN_BFD_ARCH;
00640    
00641   /* There's no standard way to compute the machine or isa number
00642      so we leave it to the target.  */
00643 #ifdef CGEN_COMPUTE_MACH
00644   mach = CGEN_COMPUTE_MACH (info);
00645 #else
00646   mach = info->mach;
00647 #endif
00648 
00649 #ifdef CGEN_COMPUTE_ISA
00650   {
00651     static CGEN_BITSET *permanent_isa;
00652 
00653     if (!permanent_isa)
00654       permanent_isa = cgen_bitset_create (MAX_ISAS);
00655     isa = permanent_isa;
00656     cgen_bitset_clear (isa);
00657     cgen_bitset_add (isa, CGEN_COMPUTE_ISA (info));
00658   }
00659 #else
00660   isa = info->insn_sets;
00661 #endif
00662 
00663   /* If we've switched cpu's, try to find a handle we've used before */
00664   if (cd
00665       && (cgen_bitset_compare (isa, prev_isa) != 0
00666          || mach != prev_mach
00667          || endian != prev_endian))
00668     {
00669       cd = 0;
00670       for (cl = cd_list; cl; cl = cl->next)
00671        {
00672          if (cgen_bitset_compare (cl->isa, isa) == 0 &&
00673              cl->mach == mach &&
00674              cl->endian == endian)
00675            {
00676              cd = cl->cd;
00677              prev_isa = cd->isas;
00678              break;
00679            }
00680        }
00681     } 
00682 
00683   /* If we haven't initialized yet, initialize the opcode table.  */
00684   if (! cd)
00685     {
00686       const bfd_arch_info_type *arch_type = bfd_lookup_arch (arch, mach);
00687       const char *mach_name;
00688 
00689       if (!arch_type)
00690        abort ();
00691       mach_name = arch_type->printable_name;
00692 
00693       prev_isa = cgen_bitset_copy (isa);
00694       prev_mach = mach;
00695       prev_endian = endian;
00696       cd = fr30_cgen_cpu_open (CGEN_CPU_OPEN_ISAS, prev_isa,
00697                              CGEN_CPU_OPEN_BFDMACH, mach_name,
00698                              CGEN_CPU_OPEN_ENDIAN, prev_endian,
00699                              CGEN_CPU_OPEN_END);
00700       if (!cd)
00701        abort ();
00702 
00703       /* Save this away for future reference.  */
00704       cl = xmalloc (sizeof (struct cpu_desc_list));
00705       cl->cd = cd;
00706       cl->isa = prev_isa;
00707       cl->mach = mach;
00708       cl->endian = endian;
00709       cl->next = cd_list;
00710       cd_list = cl;
00711 
00712       fr30_cgen_init_dis (cd);
00713     }
00714 
00715   /* We try to have as much common code as possible.
00716      But at this point some targets need to take over.  */
00717   /* ??? Some targets may need a hook elsewhere.  Try to avoid this,
00718      but if not possible try to move this hook elsewhere rather than
00719      have two hooks.  */
00720   length = CGEN_PRINT_INSN (cd, pc, info);
00721   if (length > 0)
00722     return length;
00723   if (length < 0)
00724     return -1;
00725 
00726   (*info->fprintf_func) (info->stream, UNKNOWN_INSN_MSG);
00727   return cd->default_insn_bitsize / 8;
00728 }