Back to index

cell-binutils  2.17cvs20070401
xc16x-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 "xc16x-desc.h"
00037 #include "xc16x-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 
00063 #define CGEN_PRINT_NORMAL(cd, info, value, attrs, pc, length)  \
00064   do                                                    \
00065     {                                                   \
00066       if (CGEN_BOOL_ATTR ((attrs), CGEN_OPERAND_DOT_PREFIX))   \
00067         info->fprintf_func (info->stream, ".");                \
00068       if (CGEN_BOOL_ATTR ((attrs), CGEN_OPERAND_POF_PREFIX))   \
00069         info->fprintf_func (info->stream, "#pof:");            \
00070       if (CGEN_BOOL_ATTR ((attrs), CGEN_OPERAND_PAG_PREFIX))   \
00071         info->fprintf_func (info->stream, "#pag:");            \
00072     }                                                   \
00073   while (0)
00074 
00075 /* Print a 'pof:' prefix to an operand.  */
00076 
00077 static void
00078 print_pof (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
00079           void * dis_info ATTRIBUTE_UNUSED,
00080           long value ATTRIBUTE_UNUSED,
00081           unsigned int attrs ATTRIBUTE_UNUSED,
00082           bfd_vma pc ATTRIBUTE_UNUSED,
00083           int length ATTRIBUTE_UNUSED)
00084 {
00085 }
00086 
00087 /* Print a 'pag:' prefix to an operand.  */
00088 
00089 static void
00090 print_pag (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
00091           void * dis_info ATTRIBUTE_UNUSED,
00092           long value ATTRIBUTE_UNUSED,
00093           unsigned int attrs ATTRIBUTE_UNUSED,
00094           bfd_vma pc ATTRIBUTE_UNUSED,
00095           int length ATTRIBUTE_UNUSED)
00096 {
00097 }
00098 
00099 /* Print a 'sof:' prefix to an operand.  */
00100 
00101 static void
00102 print_sof (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
00103           void * dis_info,
00104           long value ATTRIBUTE_UNUSED,
00105           unsigned int attrs ATTRIBUTE_UNUSED,
00106           bfd_vma pc ATTRIBUTE_UNUSED,
00107           int length ATTRIBUTE_UNUSED)
00108 {
00109   disassemble_info *info = (disassemble_info *) dis_info;
00110 
00111   info->fprintf_func (info->stream, "sof:");
00112 }
00113 
00114 /* Print a 'seg:' prefix to an operand.  */
00115 
00116 static void
00117 print_seg (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
00118           void * dis_info,
00119           long value ATTRIBUTE_UNUSED,
00120           unsigned int attrs ATTRIBUTE_UNUSED,
00121           bfd_vma pc ATTRIBUTE_UNUSED,
00122           int length ATTRIBUTE_UNUSED)
00123 {
00124   disassemble_info *info = (disassemble_info *) dis_info;
00125 
00126   info->fprintf_func (info->stream, "seg:");
00127 }
00128 
00129 /* Print a '#' prefix to an operand.  */
00130 
00131 static void
00132 print_hash (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
00133            void * dis_info,
00134            long value ATTRIBUTE_UNUSED,
00135            unsigned int attrs ATTRIBUTE_UNUSED,
00136            bfd_vma pc ATTRIBUTE_UNUSED,
00137            int length ATTRIBUTE_UNUSED)
00138 {
00139   disassemble_info *info = (disassemble_info *) dis_info;
00140 
00141   info->fprintf_func (info->stream, "#");
00142 }
00143 
00144 /* Print a '.' prefix to an operand.  */
00145 
00146 static void
00147 print_dot (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
00148           void * dis_info ATTRIBUTE_UNUSED,
00149           long value ATTRIBUTE_UNUSED,
00150           unsigned int attrs ATTRIBUTE_UNUSED,
00151           bfd_vma pc ATTRIBUTE_UNUSED,
00152           int length ATTRIBUTE_UNUSED)
00153 {
00154 }
00155 
00156 /* -- */
00157 
00158 void xc16x_cgen_print_operand
00159   (CGEN_CPU_DESC, int, PTR, CGEN_FIELDS *, void const *, bfd_vma, int);
00160 
00161 /* Main entry point for printing operands.
00162    XINFO is a `void *' and not a `disassemble_info *' to not put a requirement
00163    of dis-asm.h on cgen.h.
00164 
00165    This function is basically just a big switch statement.  Earlier versions
00166    used tables to look up the function to use, but
00167    - if the table contains both assembler and disassembler functions then
00168      the disassembler contains much of the assembler and vice-versa,
00169    - there's a lot of inlining possibilities as things grow,
00170    - using a switch statement avoids the function call overhead.
00171 
00172    This function could be moved into `print_insn_normal', but keeping it
00173    separate makes clear the interface between `print_insn_normal' and each of
00174    the handlers.  */
00175 
00176 void
00177 xc16x_cgen_print_operand (CGEN_CPU_DESC cd,
00178                         int opindex,
00179                         void * xinfo,
00180                         CGEN_FIELDS *fields,
00181                         void const *attrs ATTRIBUTE_UNUSED,
00182                         bfd_vma pc,
00183                         int length)
00184 {
00185   disassemble_info *info = (disassemble_info *) xinfo;
00186 
00187   switch (opindex)
00188     {
00189     case XC16X_OPERAND_REGNAM :
00190       print_keyword (cd, info, & xc16x_cgen_opval_psw_names, fields->f_reg8, 0);
00191       break;
00192     case XC16X_OPERAND_BIT01 :
00193       print_normal (cd, info, fields->f_op_1bit, 0, pc, length);
00194       break;
00195     case XC16X_OPERAND_BIT1 :
00196       print_normal (cd, info, fields->f_op_bit1, 0, pc, length);
00197       break;
00198     case XC16X_OPERAND_BIT2 :
00199       print_normal (cd, info, fields->f_op_bit2, 0, pc, length);
00200       break;
00201     case XC16X_OPERAND_BIT4 :
00202       print_normal (cd, info, fields->f_op_bit4, 0, pc, length);
00203       break;
00204     case XC16X_OPERAND_BIT8 :
00205       print_normal (cd, info, fields->f_op_bit8, 0, pc, length);
00206       break;
00207     case XC16X_OPERAND_BITONE :
00208       print_normal (cd, info, fields->f_op_onebit, 0, pc, length);
00209       break;
00210     case XC16X_OPERAND_CADDR :
00211       print_address (cd, info, fields->f_offset16, 0|(1<<CGEN_OPERAND_RELOC)|(1<<CGEN_OPERAND_ABS_ADDR), pc, length);
00212       break;
00213     case XC16X_OPERAND_COND :
00214       print_keyword (cd, info, & xc16x_cgen_opval_conditioncode_names, fields->f_condcode, 0);
00215       break;
00216     case XC16X_OPERAND_DATA8 :
00217       print_normal (cd, info, fields->f_data8, 0|(1<<CGEN_OPERAND_HASH_PREFIX), pc, length);
00218       break;
00219     case XC16X_OPERAND_DATAHI8 :
00220       print_normal (cd, info, fields->f_datahi8, 0|(1<<CGEN_OPERAND_HASH_PREFIX), pc, length);
00221       break;
00222     case XC16X_OPERAND_DOT :
00223       print_dot (cd, info, 0, 0|(1<<CGEN_OPERAND_SIGNED), pc, length);
00224       break;
00225     case XC16X_OPERAND_DR :
00226       print_keyword (cd, info, & xc16x_cgen_opval_gr_names, fields->f_r1, 0);
00227       break;
00228     case XC16X_OPERAND_DRB :
00229       print_keyword (cd, info, & xc16x_cgen_opval_grb_names, fields->f_r1, 0);
00230       break;
00231     case XC16X_OPERAND_DRI :
00232       print_keyword (cd, info, & xc16x_cgen_opval_gr_names, fields->f_r4, 0);
00233       break;
00234     case XC16X_OPERAND_EXTCOND :
00235       print_keyword (cd, info, & xc16x_cgen_opval_extconditioncode_names, fields->f_extccode, 0);
00236       break;
00237     case XC16X_OPERAND_GENREG :
00238       print_keyword (cd, info, & xc16x_cgen_opval_r8_names, fields->f_regb8, 0);
00239       break;
00240     case XC16X_OPERAND_HASH :
00241       print_hash (cd, info, 0, 0|(1<<CGEN_OPERAND_SIGNED), pc, length);
00242       break;
00243     case XC16X_OPERAND_ICOND :
00244       print_keyword (cd, info, & xc16x_cgen_opval_conditioncode_names, fields->f_icondcode, 0);
00245       break;
00246     case XC16X_OPERAND_LBIT2 :
00247       print_normal (cd, info, fields->f_op_lbit2, 0, pc, length);
00248       break;
00249     case XC16X_OPERAND_LBIT4 :
00250       print_normal (cd, info, fields->f_op_lbit4, 0, pc, length);
00251       break;
00252     case XC16X_OPERAND_MASK8 :
00253       print_normal (cd, info, fields->f_mask8, 0|(1<<CGEN_OPERAND_HASH_PREFIX), pc, length);
00254       break;
00255     case XC16X_OPERAND_MASKLO8 :
00256       print_normal (cd, info, fields->f_datahi8, 0|(1<<CGEN_OPERAND_HASH_PREFIX), pc, length);
00257       break;
00258     case XC16X_OPERAND_MEMGR8 :
00259       print_keyword (cd, info, & xc16x_cgen_opval_memgr8_names, fields->f_memgr8, 0);
00260       break;
00261     case XC16X_OPERAND_MEMORY :
00262       print_address (cd, info, fields->f_memory, 0, pc, length);
00263       break;
00264     case XC16X_OPERAND_PAG :
00265       print_pag (cd, info, 0, 0|(1<<CGEN_OPERAND_SIGNED), pc, length);
00266       break;
00267     case XC16X_OPERAND_PAGENUM :
00268       print_normal (cd, info, fields->f_pagenum, 0|(1<<CGEN_OPERAND_HASH_PREFIX), pc, length);
00269       break;
00270     case XC16X_OPERAND_POF :
00271       print_pof (cd, info, 0, 0|(1<<CGEN_OPERAND_SIGNED), pc, length);
00272       break;
00273     case XC16X_OPERAND_QBIT :
00274       print_normal (cd, info, fields->f_qbit, 0|(1<<CGEN_OPERAND_DOT_PREFIX), pc, length);
00275       break;
00276     case XC16X_OPERAND_QHIBIT :
00277       print_normal (cd, info, fields->f_qhibit, 0|(1<<CGEN_OPERAND_DOT_PREFIX), pc, length);
00278       break;
00279     case XC16X_OPERAND_QLOBIT :
00280       print_normal (cd, info, fields->f_qlobit, 0|(1<<CGEN_OPERAND_DOT_PREFIX), pc, length);
00281       break;
00282     case XC16X_OPERAND_REG8 :
00283       print_keyword (cd, info, & xc16x_cgen_opval_r8_names, fields->f_reg8, 0);
00284       break;
00285     case XC16X_OPERAND_REGB8 :
00286       print_keyword (cd, info, & xc16x_cgen_opval_grb8_names, fields->f_regb8, 0);
00287       break;
00288     case XC16X_OPERAND_REGBMEM8 :
00289       print_keyword (cd, info, & xc16x_cgen_opval_regbmem8_names, fields->f_regmem8, 0);
00290       break;
00291     case XC16X_OPERAND_REGHI8 :
00292       print_keyword (cd, info, & xc16x_cgen_opval_r8_names, fields->f_reghi8, 0);
00293       break;
00294     case XC16X_OPERAND_REGMEM8 :
00295       print_keyword (cd, info, & xc16x_cgen_opval_regmem8_names, fields->f_regmem8, 0);
00296       break;
00297     case XC16X_OPERAND_REGOFF8 :
00298       print_keyword (cd, info, & xc16x_cgen_opval_r8_names, fields->f_regoff8, 0);
00299       break;
00300     case XC16X_OPERAND_REL :
00301       print_normal (cd, info, fields->f_rel8, 0|(1<<CGEN_OPERAND_SIGNED)|(1<<CGEN_OPERAND_RELOC)|(1<<CGEN_OPERAND_PCREL_ADDR), pc, length);
00302       break;
00303     case XC16X_OPERAND_RELHI :
00304       print_normal (cd, info, fields->f_relhi8, 0|(1<<CGEN_OPERAND_SIGNED)|(1<<CGEN_OPERAND_RELOC)|(1<<CGEN_OPERAND_PCREL_ADDR), pc, length);
00305       break;
00306     case XC16X_OPERAND_SEG :
00307       print_normal (cd, info, fields->f_seg8, 0, pc, length);
00308       break;
00309     case XC16X_OPERAND_SEGHI8 :
00310       print_normal (cd, info, fields->f_segnum8, 0, pc, length);
00311       break;
00312     case XC16X_OPERAND_SEGM :
00313       print_seg (cd, info, 0, 0|(1<<CGEN_OPERAND_SIGNED), pc, length);
00314       break;
00315     case XC16X_OPERAND_SOF :
00316       print_sof (cd, info, 0, 0|(1<<CGEN_OPERAND_SIGNED), pc, length);
00317       break;
00318     case XC16X_OPERAND_SR :
00319       print_keyword (cd, info, & xc16x_cgen_opval_gr_names, fields->f_r2, 0);
00320       break;
00321     case XC16X_OPERAND_SR2 :
00322       print_keyword (cd, info, & xc16x_cgen_opval_gr_names, fields->f_r0, 0);
00323       break;
00324     case XC16X_OPERAND_SRB :
00325       print_keyword (cd, info, & xc16x_cgen_opval_grb_names, fields->f_r2, 0);
00326       break;
00327     case XC16X_OPERAND_SRC1 :
00328       print_keyword (cd, info, & xc16x_cgen_opval_gr_names, fields->f_r1, 0);
00329       break;
00330     case XC16X_OPERAND_SRC2 :
00331       print_keyword (cd, info, & xc16x_cgen_opval_gr_names, fields->f_r2, 0);
00332       break;
00333     case XC16X_OPERAND_SRDIV :
00334       print_keyword (cd, info, & xc16x_cgen_opval_regdiv8_names, fields->f_reg8, 0);
00335       break;
00336     case XC16X_OPERAND_U4 :
00337       print_keyword (cd, info, & xc16x_cgen_opval_reg0_name, fields->f_uimm4, 0);
00338       break;
00339     case XC16X_OPERAND_UIMM16 :
00340       print_normal (cd, info, fields->f_uimm16, 0|(1<<CGEN_OPERAND_HASH_PREFIX), pc, length);
00341       break;
00342     case XC16X_OPERAND_UIMM2 :
00343       print_keyword (cd, info, & xc16x_cgen_opval_ext_names, fields->f_uimm2, 0|(1<<CGEN_OPERAND_HASH_PREFIX));
00344       break;
00345     case XC16X_OPERAND_UIMM3 :
00346       print_keyword (cd, info, & xc16x_cgen_opval_reg0_name1, fields->f_uimm3, 0|(1<<CGEN_OPERAND_HASH_PREFIX));
00347       break;
00348     case XC16X_OPERAND_UIMM4 :
00349       print_normal (cd, info, fields->f_uimm4, 0|(1<<CGEN_OPERAND_HASH_PREFIX), pc, length);
00350       break;
00351     case XC16X_OPERAND_UIMM7 :
00352       print_normal (cd, info, fields->f_uimm7, 0|(1<<CGEN_OPERAND_HASH_PREFIX)|(1<<CGEN_OPERAND_RELOC)|(1<<CGEN_OPERAND_PCREL_ADDR), pc, length);
00353       break;
00354     case XC16X_OPERAND_UIMM8 :
00355       print_normal (cd, info, fields->f_uimm8, 0|(1<<CGEN_OPERAND_HASH_PREFIX), pc, length);
00356       break;
00357     case XC16X_OPERAND_UPAG16 :
00358       print_normal (cd, info, fields->f_uimm16, 0|(1<<CGEN_OPERAND_PAG_PREFIX), pc, length);
00359       break;
00360     case XC16X_OPERAND_UPOF16 :
00361       print_address (cd, info, fields->f_memory, 0|(1<<CGEN_OPERAND_POF_PREFIX), pc, length);
00362       break;
00363     case XC16X_OPERAND_USEG16 :
00364       print_normal (cd, info, fields->f_offset16, 0|(1<<CGEN_OPERAND_SEG_PREFIX)|(1<<CGEN_OPERAND_RELOC)|(1<<CGEN_OPERAND_ABS_ADDR), pc, length);
00365       break;
00366     case XC16X_OPERAND_USEG8 :
00367       print_normal (cd, info, fields->f_seg8, 0|(1<<CGEN_OPERAND_SEG_PREFIX), pc, length);
00368       break;
00369     case XC16X_OPERAND_USOF16 :
00370       print_normal (cd, info, fields->f_offset16, 0|(1<<CGEN_OPERAND_SOF_PREFIX)|(1<<CGEN_OPERAND_RELOC)|(1<<CGEN_OPERAND_ABS_ADDR), pc, length);
00371       break;
00372 
00373     default :
00374       /* xgettext:c-format */
00375       fprintf (stderr, _("Unrecognized field %d while printing insn.\n"),
00376               opindex);
00377     abort ();
00378   }
00379 }
00380 
00381 cgen_print_fn * const xc16x_cgen_print_handlers[] = 
00382 {
00383   print_insn_normal,
00384 };
00385 
00386 
00387 void
00388 xc16x_cgen_init_dis (CGEN_CPU_DESC cd)
00389 {
00390   xc16x_cgen_init_opcode_table (cd);
00391   xc16x_cgen_init_ibld_table (cd);
00392   cd->print_handlers = & xc16x_cgen_print_handlers[0];
00393   cd->print_operand = xc16x_cgen_print_operand;
00394 }
00395 
00396 
00397 /* Default print handler.  */
00398 
00399 static void
00400 print_normal (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
00401              void *dis_info,
00402              long value,
00403              unsigned int attrs,
00404              bfd_vma pc ATTRIBUTE_UNUSED,
00405              int length ATTRIBUTE_UNUSED)
00406 {
00407   disassemble_info *info = (disassemble_info *) dis_info;
00408 
00409 #ifdef CGEN_PRINT_NORMAL
00410   CGEN_PRINT_NORMAL (cd, info, value, attrs, pc, length);
00411 #endif
00412 
00413   /* Print the operand as directed by the attributes.  */
00414   if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SEM_ONLY))
00415     ; /* nothing to do */
00416   else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SIGNED))
00417     (*info->fprintf_func) (info->stream, "%ld", value);
00418   else
00419     (*info->fprintf_func) (info->stream, "0x%lx", value);
00420 }
00421 
00422 /* Default address handler.  */
00423 
00424 static void
00425 print_address (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
00426               void *dis_info,
00427               bfd_vma value,
00428               unsigned int attrs,
00429               bfd_vma pc ATTRIBUTE_UNUSED,
00430               int length ATTRIBUTE_UNUSED)
00431 {
00432   disassemble_info *info = (disassemble_info *) dis_info;
00433 
00434 #ifdef CGEN_PRINT_ADDRESS
00435   CGEN_PRINT_ADDRESS (cd, info, value, attrs, pc, length);
00436 #endif
00437 
00438   /* Print the operand as directed by the attributes.  */
00439   if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SEM_ONLY))
00440     ; /* Nothing to do.  */
00441   else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_PCREL_ADDR))
00442     (*info->print_address_func) (value, info);
00443   else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_ABS_ADDR))
00444     (*info->print_address_func) (value, info);
00445   else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SIGNED))
00446     (*info->fprintf_func) (info->stream, "%ld", (long) value);
00447   else
00448     (*info->fprintf_func) (info->stream, "0x%lx", (long) value);
00449 }
00450 
00451 /* Keyword print handler.  */
00452 
00453 static void
00454 print_keyword (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
00455               void *dis_info,
00456               CGEN_KEYWORD *keyword_table,
00457               long value,
00458               unsigned int attrs ATTRIBUTE_UNUSED)
00459 {
00460   disassemble_info *info = (disassemble_info *) dis_info;
00461   const CGEN_KEYWORD_ENTRY *ke;
00462 
00463   ke = cgen_keyword_lookup_value (keyword_table, value);
00464   if (ke != NULL)
00465     (*info->fprintf_func) (info->stream, "%s", ke->name);
00466   else
00467     (*info->fprintf_func) (info->stream, "???");
00468 }
00469 
00470 /* Default insn printer.
00471 
00472    DIS_INFO is defined as `void *' so the disassembler needn't know anything
00473    about disassemble_info.  */
00474 
00475 static void
00476 print_insn_normal (CGEN_CPU_DESC cd,
00477                  void *dis_info,
00478                  const CGEN_INSN *insn,
00479                  CGEN_FIELDS *fields,
00480                  bfd_vma pc,
00481                  int length)
00482 {
00483   const CGEN_SYNTAX *syntax = CGEN_INSN_SYNTAX (insn);
00484   disassemble_info *info = (disassemble_info *) dis_info;
00485   const CGEN_SYNTAX_CHAR_TYPE *syn;
00486 
00487   CGEN_INIT_PRINT (cd);
00488 
00489   for (syn = CGEN_SYNTAX_STRING (syntax); *syn; ++syn)
00490     {
00491       if (CGEN_SYNTAX_MNEMONIC_P (*syn))
00492        {
00493          (*info->fprintf_func) (info->stream, "%s", CGEN_INSN_MNEMONIC (insn));
00494          continue;
00495        }
00496       if (CGEN_SYNTAX_CHAR_P (*syn))
00497        {
00498          (*info->fprintf_func) (info->stream, "%c", CGEN_SYNTAX_CHAR (*syn));
00499          continue;
00500        }
00501 
00502       /* We have an operand.  */
00503       xc16x_cgen_print_operand (cd, CGEN_SYNTAX_FIELD (*syn), info,
00504                              fields, CGEN_INSN_ATTRS (insn), pc, length);
00505     }
00506 }
00507 
00508 /* Subroutine of print_insn. Reads an insn into the given buffers and updates
00509    the extract info.
00510    Returns 0 if all is well, non-zero otherwise.  */
00511 
00512 static int
00513 read_insn (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
00514           bfd_vma pc,
00515           disassemble_info *info,
00516           bfd_byte *buf,
00517           int buflen,
00518           CGEN_EXTRACT_INFO *ex_info,
00519           unsigned long *insn_value)
00520 {
00521   int status = (*info->read_memory_func) (pc, buf, buflen, info);
00522 
00523   if (status != 0)
00524     {
00525       (*info->memory_error_func) (status, pc, info);
00526       return -1;
00527     }
00528 
00529   ex_info->dis_info = info;
00530   ex_info->valid = (1 << buflen) - 1;
00531   ex_info->insn_bytes = buf;
00532 
00533   *insn_value = bfd_get_bits (buf, buflen * 8, info->endian == BFD_ENDIAN_BIG);
00534   return 0;
00535 }
00536 
00537 /* Utility to print an insn.
00538    BUF is the base part of the insn, target byte order, BUFLEN bytes long.
00539    The result is the size of the insn in bytes or zero for an unknown insn
00540    or -1 if an error occurs fetching data (memory_error_func will have
00541    been called).  */
00542 
00543 static int
00544 print_insn (CGEN_CPU_DESC cd,
00545            bfd_vma pc,
00546            disassemble_info *info,
00547            bfd_byte *buf,
00548            unsigned int buflen)
00549 {
00550   CGEN_INSN_INT insn_value;
00551   const CGEN_INSN_LIST *insn_list;
00552   CGEN_EXTRACT_INFO ex_info;
00553   int basesize;
00554 
00555   /* Extract base part of instruction, just in case CGEN_DIS_* uses it. */
00556   basesize = cd->base_insn_bitsize < buflen * 8 ?
00557                                      cd->base_insn_bitsize : buflen * 8;
00558   insn_value = cgen_get_insn_value (cd, buf, basesize);
00559 
00560 
00561   /* Fill in ex_info fields like read_insn would.  Don't actually call
00562      read_insn, since the incoming buffer is already read (and possibly
00563      modified a la m32r).  */
00564   ex_info.valid = (1 << buflen) - 1;
00565   ex_info.dis_info = info;
00566   ex_info.insn_bytes = buf;
00567 
00568   /* The instructions are stored in hash lists.
00569      Pick the first one and keep trying until we find the right one.  */
00570 
00571   insn_list = CGEN_DIS_LOOKUP_INSN (cd, (char *) buf, insn_value);
00572   while (insn_list != NULL)
00573     {
00574       const CGEN_INSN *insn = insn_list->insn;
00575       CGEN_FIELDS fields;
00576       int length;
00577       unsigned long insn_value_cropped;
00578 
00579 #ifdef CGEN_VALIDATE_INSN_SUPPORTED 
00580       /* Not needed as insn shouldn't be in hash lists if not supported.  */
00581       /* Supported by this cpu?  */
00582       if (! xc16x_cgen_insn_supported (cd, insn))
00583         {
00584           insn_list = CGEN_DIS_NEXT_INSN (insn_list);
00585          continue;
00586         }
00587 #endif
00588 
00589       /* Basic bit mask must be correct.  */
00590       /* ??? May wish to allow target to defer this check until the extract
00591         handler.  */
00592 
00593       /* Base size may exceed this instruction's size.  Extract the
00594          relevant part from the buffer. */
00595       if ((unsigned) (CGEN_INSN_BITSIZE (insn) / 8) < buflen &&
00596          (unsigned) (CGEN_INSN_BITSIZE (insn) / 8) <= sizeof (unsigned long))
00597        insn_value_cropped = bfd_get_bits (buf, CGEN_INSN_BITSIZE (insn), 
00598                                       info->endian == BFD_ENDIAN_BIG);
00599       else
00600        insn_value_cropped = insn_value;
00601 
00602       if ((insn_value_cropped & CGEN_INSN_BASE_MASK (insn))
00603          == CGEN_INSN_BASE_VALUE (insn))
00604        {
00605          /* Printing is handled in two passes.  The first pass parses the
00606             machine insn and extracts the fields.  The second pass prints
00607             them.  */
00608 
00609          /* Make sure the entire insn is loaded into insn_value, if it
00610             can fit.  */
00611          if (((unsigned) CGEN_INSN_BITSIZE (insn) > cd->base_insn_bitsize) &&
00612              (unsigned) (CGEN_INSN_BITSIZE (insn) / 8) <= sizeof (unsigned long))
00613            {
00614              unsigned long full_insn_value;
00615              int rc = read_insn (cd, pc, info, buf,
00616                               CGEN_INSN_BITSIZE (insn) / 8,
00617                               & ex_info, & full_insn_value);
00618              if (rc != 0)
00619               return rc;
00620              length = CGEN_EXTRACT_FN (cd, insn)
00621               (cd, insn, &ex_info, full_insn_value, &fields, pc);
00622            }
00623          else
00624            length = CGEN_EXTRACT_FN (cd, insn)
00625              (cd, insn, &ex_info, insn_value_cropped, &fields, pc);
00626 
00627          /* Length < 0 -> error.  */
00628          if (length < 0)
00629            return length;
00630          if (length > 0)
00631            {
00632              CGEN_PRINT_FN (cd, insn) (cd, info, insn, &fields, pc, length);
00633              /* Length is in bits, result is in bytes.  */
00634              return length / 8;
00635            }
00636        }
00637 
00638       insn_list = CGEN_DIS_NEXT_INSN (insn_list);
00639     }
00640 
00641   return 0;
00642 }
00643 
00644 /* Default value for CGEN_PRINT_INSN.
00645    The result is the size of the insn in bytes or zero for an unknown insn
00646    or -1 if an error occured fetching bytes.  */
00647 
00648 #ifndef CGEN_PRINT_INSN
00649 #define CGEN_PRINT_INSN default_print_insn
00650 #endif
00651 
00652 static int
00653 default_print_insn (CGEN_CPU_DESC cd, bfd_vma pc, disassemble_info *info)
00654 {
00655   bfd_byte buf[CGEN_MAX_INSN_SIZE];
00656   int buflen;
00657   int status;
00658 
00659   /* Attempt to read the base part of the insn.  */
00660   buflen = cd->base_insn_bitsize / 8;
00661   status = (*info->read_memory_func) (pc, buf, buflen, info);
00662 
00663   /* Try again with the minimum part, if min < base.  */
00664   if (status != 0 && (cd->min_insn_bitsize < cd->base_insn_bitsize))
00665     {
00666       buflen = cd->min_insn_bitsize / 8;
00667       status = (*info->read_memory_func) (pc, buf, buflen, info);
00668     }
00669 
00670   if (status != 0)
00671     {
00672       (*info->memory_error_func) (status, pc, info);
00673       return -1;
00674     }
00675 
00676   return print_insn (cd, pc, info, buf, buflen);
00677 }
00678 
00679 /* Main entry point.
00680    Print one instruction from PC on INFO->STREAM.
00681    Return the size of the instruction (in bytes).  */
00682 
00683 typedef struct cpu_desc_list
00684 {
00685   struct cpu_desc_list *next;
00686   CGEN_BITSET *isa;
00687   int mach;
00688   int endian;
00689   CGEN_CPU_DESC cd;
00690 } cpu_desc_list;
00691 
00692 int
00693 print_insn_xc16x (bfd_vma pc, disassemble_info *info)
00694 {
00695   static cpu_desc_list *cd_list = 0;
00696   cpu_desc_list *cl = 0;
00697   static CGEN_CPU_DESC cd = 0;
00698   static CGEN_BITSET *prev_isa;
00699   static int prev_mach;
00700   static int prev_endian;
00701   int length;
00702   CGEN_BITSET *isa;
00703   int mach;
00704   int endian = (info->endian == BFD_ENDIAN_BIG
00705               ? CGEN_ENDIAN_BIG
00706               : CGEN_ENDIAN_LITTLE);
00707   enum bfd_architecture arch;
00708 
00709   /* ??? gdb will set mach but leave the architecture as "unknown" */
00710 #ifndef CGEN_BFD_ARCH
00711 #define CGEN_BFD_ARCH bfd_arch_xc16x
00712 #endif
00713   arch = info->arch;
00714   if (arch == bfd_arch_unknown)
00715     arch = CGEN_BFD_ARCH;
00716    
00717   /* There's no standard way to compute the machine or isa number
00718      so we leave it to the target.  */
00719 #ifdef CGEN_COMPUTE_MACH
00720   mach = CGEN_COMPUTE_MACH (info);
00721 #else
00722   mach = info->mach;
00723 #endif
00724 
00725 #ifdef CGEN_COMPUTE_ISA
00726   {
00727     static CGEN_BITSET *permanent_isa;
00728 
00729     if (!permanent_isa)
00730       permanent_isa = cgen_bitset_create (MAX_ISAS);
00731     isa = permanent_isa;
00732     cgen_bitset_clear (isa);
00733     cgen_bitset_add (isa, CGEN_COMPUTE_ISA (info));
00734   }
00735 #else
00736   isa = info->insn_sets;
00737 #endif
00738 
00739   /* If we've switched cpu's, try to find a handle we've used before */
00740   if (cd
00741       && (cgen_bitset_compare (isa, prev_isa) != 0
00742          || mach != prev_mach
00743          || endian != prev_endian))
00744     {
00745       cd = 0;
00746       for (cl = cd_list; cl; cl = cl->next)
00747        {
00748          if (cgen_bitset_compare (cl->isa, isa) == 0 &&
00749              cl->mach == mach &&
00750              cl->endian == endian)
00751            {
00752              cd = cl->cd;
00753              prev_isa = cd->isas;
00754              break;
00755            }
00756        }
00757     } 
00758 
00759   /* If we haven't initialized yet, initialize the opcode table.  */
00760   if (! cd)
00761     {
00762       const bfd_arch_info_type *arch_type = bfd_lookup_arch (arch, mach);
00763       const char *mach_name;
00764 
00765       if (!arch_type)
00766        abort ();
00767       mach_name = arch_type->printable_name;
00768 
00769       prev_isa = cgen_bitset_copy (isa);
00770       prev_mach = mach;
00771       prev_endian = endian;
00772       cd = xc16x_cgen_cpu_open (CGEN_CPU_OPEN_ISAS, prev_isa,
00773                              CGEN_CPU_OPEN_BFDMACH, mach_name,
00774                              CGEN_CPU_OPEN_ENDIAN, prev_endian,
00775                              CGEN_CPU_OPEN_END);
00776       if (!cd)
00777        abort ();
00778 
00779       /* Save this away for future reference.  */
00780       cl = xmalloc (sizeof (struct cpu_desc_list));
00781       cl->cd = cd;
00782       cl->isa = prev_isa;
00783       cl->mach = mach;
00784       cl->endian = endian;
00785       cl->next = cd_list;
00786       cd_list = cl;
00787 
00788       xc16x_cgen_init_dis (cd);
00789     }
00790 
00791   /* We try to have as much common code as possible.
00792      But at this point some targets need to take over.  */
00793   /* ??? Some targets may need a hook elsewhere.  Try to avoid this,
00794      but if not possible try to move this hook elsewhere rather than
00795      have two hooks.  */
00796   length = CGEN_PRINT_INSN (cd, pc, info);
00797   if (length > 0)
00798     return length;
00799   if (length < 0)
00800     return -1;
00801 
00802   (*info->fprintf_func) (info->stream, UNKNOWN_INSN_MSG);
00803   return cd->default_insn_bitsize / 8;
00804 }