Back to index

cell-binutils  2.17cvs20070401
iq2000-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 "iq2000-desc.h"
00037 #include "iq2000-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 
00062 void iq2000_cgen_print_operand
00063   (CGEN_CPU_DESC, int, PTR, CGEN_FIELDS *, void const *, bfd_vma, int);
00064 
00065 /* Main entry point for printing operands.
00066    XINFO is a `void *' and not a `disassemble_info *' to not put a requirement
00067    of dis-asm.h on cgen.h.
00068 
00069    This function is basically just a big switch statement.  Earlier versions
00070    used tables to look up the function to use, but
00071    - if the table contains both assembler and disassembler functions then
00072      the disassembler contains much of the assembler and vice-versa,
00073    - there's a lot of inlining possibilities as things grow,
00074    - using a switch statement avoids the function call overhead.
00075 
00076    This function could be moved into `print_insn_normal', but keeping it
00077    separate makes clear the interface between `print_insn_normal' and each of
00078    the handlers.  */
00079 
00080 void
00081 iq2000_cgen_print_operand (CGEN_CPU_DESC cd,
00082                         int opindex,
00083                         void * xinfo,
00084                         CGEN_FIELDS *fields,
00085                         void const *attrs ATTRIBUTE_UNUSED,
00086                         bfd_vma pc,
00087                         int length)
00088 {
00089   disassemble_info *info = (disassemble_info *) xinfo;
00090 
00091   switch (opindex)
00092     {
00093     case IQ2000_OPERAND__INDEX :
00094       print_normal (cd, info, fields->f_index, 0, pc, length);
00095       break;
00096     case IQ2000_OPERAND_BASE :
00097       print_keyword (cd, info, & iq2000_cgen_opval_gr_names, fields->f_rs, 0);
00098       break;
00099     case IQ2000_OPERAND_BASEOFF :
00100       print_address (cd, info, fields->f_imm, 0, pc, length);
00101       break;
00102     case IQ2000_OPERAND_BITNUM :
00103       print_normal (cd, info, fields->f_rt, 0, pc, length);
00104       break;
00105     case IQ2000_OPERAND_BYTECOUNT :
00106       print_normal (cd, info, fields->f_bytecount, 0, pc, length);
00107       break;
00108     case IQ2000_OPERAND_CAM_Y :
00109       print_normal (cd, info, fields->f_cam_y, 0, pc, length);
00110       break;
00111     case IQ2000_OPERAND_CAM_Z :
00112       print_normal (cd, info, fields->f_cam_z, 0, pc, length);
00113       break;
00114     case IQ2000_OPERAND_CM_3FUNC :
00115       print_normal (cd, info, fields->f_cm_3func, 0, pc, length);
00116       break;
00117     case IQ2000_OPERAND_CM_3Z :
00118       print_normal (cd, info, fields->f_cm_3z, 0, pc, length);
00119       break;
00120     case IQ2000_OPERAND_CM_4FUNC :
00121       print_normal (cd, info, fields->f_cm_4func, 0, pc, length);
00122       break;
00123     case IQ2000_OPERAND_CM_4Z :
00124       print_normal (cd, info, fields->f_cm_4z, 0, pc, length);
00125       break;
00126     case IQ2000_OPERAND_COUNT :
00127       print_normal (cd, info, fields->f_count, 0, pc, length);
00128       break;
00129     case IQ2000_OPERAND_EXECODE :
00130       print_normal (cd, info, fields->f_excode, 0, pc, length);
00131       break;
00132     case IQ2000_OPERAND_HI16 :
00133       print_normal (cd, info, fields->f_imm, 0, pc, length);
00134       break;
00135     case IQ2000_OPERAND_IMM :
00136       print_normal (cd, info, fields->f_imm, 0, pc, length);
00137       break;
00138     case IQ2000_OPERAND_JMPTARG :
00139       print_address (cd, info, fields->f_jtarg, 0|(1<<CGEN_OPERAND_ABS_ADDR), pc, length);
00140       break;
00141     case IQ2000_OPERAND_JMPTARGQ10 :
00142       print_address (cd, info, fields->f_jtargq10, 0|(1<<CGEN_OPERAND_ABS_ADDR), pc, length);
00143       break;
00144     case IQ2000_OPERAND_LO16 :
00145       print_normal (cd, info, fields->f_imm, 0, pc, length);
00146       break;
00147     case IQ2000_OPERAND_MASK :
00148       print_normal (cd, info, fields->f_mask, 0, pc, length);
00149       break;
00150     case IQ2000_OPERAND_MASKL :
00151       print_normal (cd, info, fields->f_maskl, 0, pc, length);
00152       break;
00153     case IQ2000_OPERAND_MASKQ10 :
00154       print_normal (cd, info, fields->f_maskq10, 0, pc, length);
00155       break;
00156     case IQ2000_OPERAND_MASKR :
00157       print_normal (cd, info, fields->f_rs, 0, pc, length);
00158       break;
00159     case IQ2000_OPERAND_MLO16 :
00160       print_normal (cd, info, fields->f_imm, 0, pc, length);
00161       break;
00162     case IQ2000_OPERAND_OFFSET :
00163       print_address (cd, info, fields->f_offset, 0|(1<<CGEN_OPERAND_PCREL_ADDR), pc, length);
00164       break;
00165     case IQ2000_OPERAND_RD :
00166       print_keyword (cd, info, & iq2000_cgen_opval_gr_names, fields->f_rd, 0);
00167       break;
00168     case IQ2000_OPERAND_RD_RS :
00169       print_keyword (cd, info, & iq2000_cgen_opval_gr_names, fields->f_rd_rs, 0|(1<<CGEN_OPERAND_VIRTUAL));
00170       break;
00171     case IQ2000_OPERAND_RD_RT :
00172       print_keyword (cd, info, & iq2000_cgen_opval_gr_names, fields->f_rd_rt, 0|(1<<CGEN_OPERAND_VIRTUAL));
00173       break;
00174     case IQ2000_OPERAND_RS :
00175       print_keyword (cd, info, & iq2000_cgen_opval_gr_names, fields->f_rs, 0);
00176       break;
00177     case IQ2000_OPERAND_RT :
00178       print_keyword (cd, info, & iq2000_cgen_opval_gr_names, fields->f_rt, 0);
00179       break;
00180     case IQ2000_OPERAND_RT_RS :
00181       print_keyword (cd, info, & iq2000_cgen_opval_gr_names, fields->f_rt_rs, 0|(1<<CGEN_OPERAND_VIRTUAL));
00182       break;
00183     case IQ2000_OPERAND_SHAMT :
00184       print_normal (cd, info, fields->f_shamt, 0, pc, length);
00185       break;
00186 
00187     default :
00188       /* xgettext:c-format */
00189       fprintf (stderr, _("Unrecognized field %d while printing insn.\n"),
00190               opindex);
00191     abort ();
00192   }
00193 }
00194 
00195 cgen_print_fn * const iq2000_cgen_print_handlers[] = 
00196 {
00197   print_insn_normal,
00198 };
00199 
00200 
00201 void
00202 iq2000_cgen_init_dis (CGEN_CPU_DESC cd)
00203 {
00204   iq2000_cgen_init_opcode_table (cd);
00205   iq2000_cgen_init_ibld_table (cd);
00206   cd->print_handlers = & iq2000_cgen_print_handlers[0];
00207   cd->print_operand = iq2000_cgen_print_operand;
00208 }
00209 
00210 
00211 /* Default print handler.  */
00212 
00213 static void
00214 print_normal (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
00215              void *dis_info,
00216              long value,
00217              unsigned int attrs,
00218              bfd_vma pc ATTRIBUTE_UNUSED,
00219              int length ATTRIBUTE_UNUSED)
00220 {
00221   disassemble_info *info = (disassemble_info *) dis_info;
00222 
00223 #ifdef CGEN_PRINT_NORMAL
00224   CGEN_PRINT_NORMAL (cd, info, value, attrs, pc, length);
00225 #endif
00226 
00227   /* Print the operand as directed by the attributes.  */
00228   if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SEM_ONLY))
00229     ; /* nothing to do */
00230   else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SIGNED))
00231     (*info->fprintf_func) (info->stream, "%ld", value);
00232   else
00233     (*info->fprintf_func) (info->stream, "0x%lx", value);
00234 }
00235 
00236 /* Default address handler.  */
00237 
00238 static void
00239 print_address (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
00240               void *dis_info,
00241               bfd_vma value,
00242               unsigned int attrs,
00243               bfd_vma pc ATTRIBUTE_UNUSED,
00244               int length ATTRIBUTE_UNUSED)
00245 {
00246   disassemble_info *info = (disassemble_info *) dis_info;
00247 
00248 #ifdef CGEN_PRINT_ADDRESS
00249   CGEN_PRINT_ADDRESS (cd, info, value, attrs, pc, length);
00250 #endif
00251 
00252   /* Print the operand as directed by the attributes.  */
00253   if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SEM_ONLY))
00254     ; /* Nothing to do.  */
00255   else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_PCREL_ADDR))
00256     (*info->print_address_func) (value, info);
00257   else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_ABS_ADDR))
00258     (*info->print_address_func) (value, info);
00259   else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SIGNED))
00260     (*info->fprintf_func) (info->stream, "%ld", (long) value);
00261   else
00262     (*info->fprintf_func) (info->stream, "0x%lx", (long) value);
00263 }
00264 
00265 /* Keyword print handler.  */
00266 
00267 static void
00268 print_keyword (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
00269               void *dis_info,
00270               CGEN_KEYWORD *keyword_table,
00271               long value,
00272               unsigned int attrs ATTRIBUTE_UNUSED)
00273 {
00274   disassemble_info *info = (disassemble_info *) dis_info;
00275   const CGEN_KEYWORD_ENTRY *ke;
00276 
00277   ke = cgen_keyword_lookup_value (keyword_table, value);
00278   if (ke != NULL)
00279     (*info->fprintf_func) (info->stream, "%s", ke->name);
00280   else
00281     (*info->fprintf_func) (info->stream, "???");
00282 }
00283 
00284 /* Default insn printer.
00285 
00286    DIS_INFO is defined as `void *' so the disassembler needn't know anything
00287    about disassemble_info.  */
00288 
00289 static void
00290 print_insn_normal (CGEN_CPU_DESC cd,
00291                  void *dis_info,
00292                  const CGEN_INSN *insn,
00293                  CGEN_FIELDS *fields,
00294                  bfd_vma pc,
00295                  int length)
00296 {
00297   const CGEN_SYNTAX *syntax = CGEN_INSN_SYNTAX (insn);
00298   disassemble_info *info = (disassemble_info *) dis_info;
00299   const CGEN_SYNTAX_CHAR_TYPE *syn;
00300 
00301   CGEN_INIT_PRINT (cd);
00302 
00303   for (syn = CGEN_SYNTAX_STRING (syntax); *syn; ++syn)
00304     {
00305       if (CGEN_SYNTAX_MNEMONIC_P (*syn))
00306        {
00307          (*info->fprintf_func) (info->stream, "%s", CGEN_INSN_MNEMONIC (insn));
00308          continue;
00309        }
00310       if (CGEN_SYNTAX_CHAR_P (*syn))
00311        {
00312          (*info->fprintf_func) (info->stream, "%c", CGEN_SYNTAX_CHAR (*syn));
00313          continue;
00314        }
00315 
00316       /* We have an operand.  */
00317       iq2000_cgen_print_operand (cd, CGEN_SYNTAX_FIELD (*syn), info,
00318                              fields, CGEN_INSN_ATTRS (insn), pc, length);
00319     }
00320 }
00321 
00322 /* Subroutine of print_insn. Reads an insn into the given buffers and updates
00323    the extract info.
00324    Returns 0 if all is well, non-zero otherwise.  */
00325 
00326 static int
00327 read_insn (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
00328           bfd_vma pc,
00329           disassemble_info *info,
00330           bfd_byte *buf,
00331           int buflen,
00332           CGEN_EXTRACT_INFO *ex_info,
00333           unsigned long *insn_value)
00334 {
00335   int status = (*info->read_memory_func) (pc, buf, buflen, info);
00336 
00337   if (status != 0)
00338     {
00339       (*info->memory_error_func) (status, pc, info);
00340       return -1;
00341     }
00342 
00343   ex_info->dis_info = info;
00344   ex_info->valid = (1 << buflen) - 1;
00345   ex_info->insn_bytes = buf;
00346 
00347   *insn_value = bfd_get_bits (buf, buflen * 8, info->endian == BFD_ENDIAN_BIG);
00348   return 0;
00349 }
00350 
00351 /* Utility to print an insn.
00352    BUF is the base part of the insn, target byte order, BUFLEN bytes long.
00353    The result is the size of the insn in bytes or zero for an unknown insn
00354    or -1 if an error occurs fetching data (memory_error_func will have
00355    been called).  */
00356 
00357 static int
00358 print_insn (CGEN_CPU_DESC cd,
00359            bfd_vma pc,
00360            disassemble_info *info,
00361            bfd_byte *buf,
00362            unsigned int buflen)
00363 {
00364   CGEN_INSN_INT insn_value;
00365   const CGEN_INSN_LIST *insn_list;
00366   CGEN_EXTRACT_INFO ex_info;
00367   int basesize;
00368 
00369   /* Extract base part of instruction, just in case CGEN_DIS_* uses it. */
00370   basesize = cd->base_insn_bitsize < buflen * 8 ?
00371                                      cd->base_insn_bitsize : buflen * 8;
00372   insn_value = cgen_get_insn_value (cd, buf, basesize);
00373 
00374 
00375   /* Fill in ex_info fields like read_insn would.  Don't actually call
00376      read_insn, since the incoming buffer is already read (and possibly
00377      modified a la m32r).  */
00378   ex_info.valid = (1 << buflen) - 1;
00379   ex_info.dis_info = info;
00380   ex_info.insn_bytes = buf;
00381 
00382   /* The instructions are stored in hash lists.
00383      Pick the first one and keep trying until we find the right one.  */
00384 
00385   insn_list = CGEN_DIS_LOOKUP_INSN (cd, (char *) buf, insn_value);
00386   while (insn_list != NULL)
00387     {
00388       const CGEN_INSN *insn = insn_list->insn;
00389       CGEN_FIELDS fields;
00390       int length;
00391       unsigned long insn_value_cropped;
00392 
00393 #ifdef CGEN_VALIDATE_INSN_SUPPORTED 
00394       /* Not needed as insn shouldn't be in hash lists if not supported.  */
00395       /* Supported by this cpu?  */
00396       if (! iq2000_cgen_insn_supported (cd, insn))
00397         {
00398           insn_list = CGEN_DIS_NEXT_INSN (insn_list);
00399          continue;
00400         }
00401 #endif
00402 
00403       /* Basic bit mask must be correct.  */
00404       /* ??? May wish to allow target to defer this check until the extract
00405         handler.  */
00406 
00407       /* Base size may exceed this instruction's size.  Extract the
00408          relevant part from the buffer. */
00409       if ((unsigned) (CGEN_INSN_BITSIZE (insn) / 8) < buflen &&
00410          (unsigned) (CGEN_INSN_BITSIZE (insn) / 8) <= sizeof (unsigned long))
00411        insn_value_cropped = bfd_get_bits (buf, CGEN_INSN_BITSIZE (insn), 
00412                                       info->endian == BFD_ENDIAN_BIG);
00413       else
00414        insn_value_cropped = insn_value;
00415 
00416       if ((insn_value_cropped & CGEN_INSN_BASE_MASK (insn))
00417          == CGEN_INSN_BASE_VALUE (insn))
00418        {
00419          /* Printing is handled in two passes.  The first pass parses the
00420             machine insn and extracts the fields.  The second pass prints
00421             them.  */
00422 
00423          /* Make sure the entire insn is loaded into insn_value, if it
00424             can fit.  */
00425          if (((unsigned) CGEN_INSN_BITSIZE (insn) > cd->base_insn_bitsize) &&
00426              (unsigned) (CGEN_INSN_BITSIZE (insn) / 8) <= sizeof (unsigned long))
00427            {
00428              unsigned long full_insn_value;
00429              int rc = read_insn (cd, pc, info, buf,
00430                               CGEN_INSN_BITSIZE (insn) / 8,
00431                               & ex_info, & full_insn_value);
00432              if (rc != 0)
00433               return rc;
00434              length = CGEN_EXTRACT_FN (cd, insn)
00435               (cd, insn, &ex_info, full_insn_value, &fields, pc);
00436            }
00437          else
00438            length = CGEN_EXTRACT_FN (cd, insn)
00439              (cd, insn, &ex_info, insn_value_cropped, &fields, pc);
00440 
00441          /* Length < 0 -> error.  */
00442          if (length < 0)
00443            return length;
00444          if (length > 0)
00445            {
00446              CGEN_PRINT_FN (cd, insn) (cd, info, insn, &fields, pc, length);
00447              /* Length is in bits, result is in bytes.  */
00448              return length / 8;
00449            }
00450        }
00451 
00452       insn_list = CGEN_DIS_NEXT_INSN (insn_list);
00453     }
00454 
00455   return 0;
00456 }
00457 
00458 /* Default value for CGEN_PRINT_INSN.
00459    The result is the size of the insn in bytes or zero for an unknown insn
00460    or -1 if an error occured fetching bytes.  */
00461 
00462 #ifndef CGEN_PRINT_INSN
00463 #define CGEN_PRINT_INSN default_print_insn
00464 #endif
00465 
00466 static int
00467 default_print_insn (CGEN_CPU_DESC cd, bfd_vma pc, disassemble_info *info)
00468 {
00469   bfd_byte buf[CGEN_MAX_INSN_SIZE];
00470   int buflen;
00471   int status;
00472 
00473   /* Attempt to read the base part of the insn.  */
00474   buflen = cd->base_insn_bitsize / 8;
00475   status = (*info->read_memory_func) (pc, buf, buflen, info);
00476 
00477   /* Try again with the minimum part, if min < base.  */
00478   if (status != 0 && (cd->min_insn_bitsize < cd->base_insn_bitsize))
00479     {
00480       buflen = cd->min_insn_bitsize / 8;
00481       status = (*info->read_memory_func) (pc, buf, buflen, info);
00482     }
00483 
00484   if (status != 0)
00485     {
00486       (*info->memory_error_func) (status, pc, info);
00487       return -1;
00488     }
00489 
00490   return print_insn (cd, pc, info, buf, buflen);
00491 }
00492 
00493 /* Main entry point.
00494    Print one instruction from PC on INFO->STREAM.
00495    Return the size of the instruction (in bytes).  */
00496 
00497 typedef struct cpu_desc_list
00498 {
00499   struct cpu_desc_list *next;
00500   CGEN_BITSET *isa;
00501   int mach;
00502   int endian;
00503   CGEN_CPU_DESC cd;
00504 } cpu_desc_list;
00505 
00506 int
00507 print_insn_iq2000 (bfd_vma pc, disassemble_info *info)
00508 {
00509   static cpu_desc_list *cd_list = 0;
00510   cpu_desc_list *cl = 0;
00511   static CGEN_CPU_DESC cd = 0;
00512   static CGEN_BITSET *prev_isa;
00513   static int prev_mach;
00514   static int prev_endian;
00515   int length;
00516   CGEN_BITSET *isa;
00517   int mach;
00518   int endian = (info->endian == BFD_ENDIAN_BIG
00519               ? CGEN_ENDIAN_BIG
00520               : CGEN_ENDIAN_LITTLE);
00521   enum bfd_architecture arch;
00522 
00523   /* ??? gdb will set mach but leave the architecture as "unknown" */
00524 #ifndef CGEN_BFD_ARCH
00525 #define CGEN_BFD_ARCH bfd_arch_iq2000
00526 #endif
00527   arch = info->arch;
00528   if (arch == bfd_arch_unknown)
00529     arch = CGEN_BFD_ARCH;
00530    
00531   /* There's no standard way to compute the machine or isa number
00532      so we leave it to the target.  */
00533 #ifdef CGEN_COMPUTE_MACH
00534   mach = CGEN_COMPUTE_MACH (info);
00535 #else
00536   mach = info->mach;
00537 #endif
00538 
00539 #ifdef CGEN_COMPUTE_ISA
00540   {
00541     static CGEN_BITSET *permanent_isa;
00542 
00543     if (!permanent_isa)
00544       permanent_isa = cgen_bitset_create (MAX_ISAS);
00545     isa = permanent_isa;
00546     cgen_bitset_clear (isa);
00547     cgen_bitset_add (isa, CGEN_COMPUTE_ISA (info));
00548   }
00549 #else
00550   isa = info->insn_sets;
00551 #endif
00552 
00553   /* If we've switched cpu's, try to find a handle we've used before */
00554   if (cd
00555       && (cgen_bitset_compare (isa, prev_isa) != 0
00556          || mach != prev_mach
00557          || endian != prev_endian))
00558     {
00559       cd = 0;
00560       for (cl = cd_list; cl; cl = cl->next)
00561        {
00562          if (cgen_bitset_compare (cl->isa, isa) == 0 &&
00563              cl->mach == mach &&
00564              cl->endian == endian)
00565            {
00566              cd = cl->cd;
00567              prev_isa = cd->isas;
00568              break;
00569            }
00570        }
00571     } 
00572 
00573   /* If we haven't initialized yet, initialize the opcode table.  */
00574   if (! cd)
00575     {
00576       const bfd_arch_info_type *arch_type = bfd_lookup_arch (arch, mach);
00577       const char *mach_name;
00578 
00579       if (!arch_type)
00580        abort ();
00581       mach_name = arch_type->printable_name;
00582 
00583       prev_isa = cgen_bitset_copy (isa);
00584       prev_mach = mach;
00585       prev_endian = endian;
00586       cd = iq2000_cgen_cpu_open (CGEN_CPU_OPEN_ISAS, prev_isa,
00587                              CGEN_CPU_OPEN_BFDMACH, mach_name,
00588                              CGEN_CPU_OPEN_ENDIAN, prev_endian,
00589                              CGEN_CPU_OPEN_END);
00590       if (!cd)
00591        abort ();
00592 
00593       /* Save this away for future reference.  */
00594       cl = xmalloc (sizeof (struct cpu_desc_list));
00595       cl->cd = cd;
00596       cl->isa = prev_isa;
00597       cl->mach = mach;
00598       cl->endian = endian;
00599       cl->next = cd_list;
00600       cd_list = cl;
00601 
00602       iq2000_cgen_init_dis (cd);
00603     }
00604 
00605   /* We try to have as much common code as possible.
00606      But at this point some targets need to take over.  */
00607   /* ??? Some targets may need a hook elsewhere.  Try to avoid this,
00608      but if not possible try to move this hook elsewhere rather than
00609      have two hooks.  */
00610   length = CGEN_PRINT_INSN (cd, pc, info);
00611   if (length > 0)
00612     return length;
00613   if (length < 0)
00614     return -1;
00615 
00616   (*info->fprintf_func) (info->stream, UNKNOWN_INSN_MSG);
00617   return cd->default_insn_bitsize / 8;
00618 }