Back to index

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