Home | History | Annotate | Download | only in opcodes
      1 /* Disassembler interface for targets using CGEN. -*- C -*-
      2    CGEN: Cpu tools GENerator
      3 
      4    THIS FILE IS MACHINE GENERATED WITH CGEN.
      5    - the resultant file is machine generated, cgen-dis.in isn't
      6 
      7    Copyright (C) 1996-2016 Free Software Foundation, Inc.
      8 
      9    This file is part of libopcodes.
     10 
     11    This library is free software; you can redistribute it and/or modify
     12    it under the terms of the GNU General Public License as published by
     13    the Free Software Foundation; either version 3, or (at your option)
     14    any later version.
     15 
     16    It is distributed in the hope that it will be useful, but WITHOUT
     17    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
     18    or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
     19    License for more details.
     20 
     21    You should have received a copy of the GNU General Public License
     22    along with this program; if not, write to the Free Software Foundation, Inc.,
     23    51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.  */
     24 
     25 /* ??? Eventually more and more of this stuff can go to cpu-independent files.
     26    Keep that in mind.  */
     27 
     28 #include "sysdep.h"
     29 #include <stdio.h>
     30 #include "ansidecl.h"
     31 #include "dis-asm.h"
     32 #include "bfd.h"
     33 #include "symcat.h"
     34 #include "libiberty.h"
     35 #include "xc16x-desc.h"
     36 #include "xc16x-opc.h"
     37 #include "opintl.h"
     38 
     39 /* Default text to print if an instruction isn't recognized.  */
     40 #define UNKNOWN_INSN_MSG _("*unknown*")
     41 
     42 static void print_normal
     43   (CGEN_CPU_DESC, void *, long, unsigned int, bfd_vma, int);
     44 static void print_address
     45   (CGEN_CPU_DESC, void *, bfd_vma, unsigned int, bfd_vma, int) ATTRIBUTE_UNUSED;
     46 static void print_keyword
     47   (CGEN_CPU_DESC, void *, CGEN_KEYWORD *, long, unsigned int) ATTRIBUTE_UNUSED;
     48 static void print_insn_normal
     49   (CGEN_CPU_DESC, void *, const CGEN_INSN *, CGEN_FIELDS *, bfd_vma, int);
     50 static int print_insn
     51   (CGEN_CPU_DESC, bfd_vma,  disassemble_info *, bfd_byte *, unsigned);
     52 static int default_print_insn
     53   (CGEN_CPU_DESC, bfd_vma, disassemble_info *) ATTRIBUTE_UNUSED;
     54 static int read_insn
     55   (CGEN_CPU_DESC, bfd_vma, disassemble_info *, bfd_byte *, int, CGEN_EXTRACT_INFO *,
     56    unsigned long *);
     57 
     58 /* -- disassembler routines inserted here.  */
     60 
     61 /* -- dis.c */
     62 
     63 /* Print an operand with a "." prefix.
     64    NOTE: This prints the operand in hex.
     65    ??? This exists to maintain disassembler compatibility with previous
     66    versions.  Ideally we'd print the "." in print_dot.  */
     67 
     68 static void
     69 print_with_dot_prefix (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
     70 		       void * dis_info,
     71 		       long value,
     72 		       unsigned attrs ATTRIBUTE_UNUSED,
     73 		       bfd_vma pc ATTRIBUTE_UNUSED,
     74 		       int length ATTRIBUTE_UNUSED)
     75 {
     76   disassemble_info *info = (disassemble_info *) dis_info;
     77 
     78   info->fprintf_func (info->stream, ".");
     79   info->fprintf_func (info->stream, "0x%lx", value);
     80 }
     81 
     82 /* Print an operand with a "#pof:" prefix.
     83    NOTE: This prints the operand as an address.
     84    ??? This exists to maintain disassembler compatibility with previous
     85    versions.  Ideally we'd print "#pof:" in print_pof.  */
     86 
     87 static void
     88 print_with_pof_prefix (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
     89 		       void * dis_info,
     90 		       bfd_vma value,
     91 		       unsigned attrs ATTRIBUTE_UNUSED,
     92 		       bfd_vma pc ATTRIBUTE_UNUSED,
     93 		       int length ATTRIBUTE_UNUSED)
     94 {
     95   disassemble_info *info = (disassemble_info *) dis_info;
     96 
     97   info->fprintf_func (info->stream, "#pof:");
     98   info->fprintf_func (info->stream, "0x%lx", (long) value);
     99 }
    100 
    101 /* Print an operand with a "#pag:" prefix.
    102    NOTE: This prints the operand in hex.
    103    ??? This exists to maintain disassembler compatibility with previous
    104    versions.  Ideally we'd print "#pag:" in print_pag.  */
    105 
    106 static void
    107 print_with_pag_prefix (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
    108 		       void * dis_info,
    109 		       long value,
    110 		       unsigned attrs ATTRIBUTE_UNUSED,
    111 		       bfd_vma pc ATTRIBUTE_UNUSED,
    112 		       int length ATTRIBUTE_UNUSED)
    113 {
    114   disassemble_info *info = (disassemble_info *) dis_info;
    115 
    116   info->fprintf_func (info->stream, "#pag:");
    117   info->fprintf_func (info->stream, "0x%lx", value);
    118 }
    119 
    120 /* Print a 'pof:' prefix to an operand.  */
    121 
    122 static void
    123 print_pof (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
    124 	   void * dis_info ATTRIBUTE_UNUSED,
    125 	   long value ATTRIBUTE_UNUSED,
    126 	   unsigned int attrs ATTRIBUTE_UNUSED,
    127 	   bfd_vma pc ATTRIBUTE_UNUSED,
    128 	   int length ATTRIBUTE_UNUSED)
    129 {
    130 }
    131 
    132 /* Print a 'pag:' prefix to an operand.  */
    133 
    134 static void
    135 print_pag (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
    136 	   void * dis_info ATTRIBUTE_UNUSED,
    137 	   long value ATTRIBUTE_UNUSED,
    138 	   unsigned int attrs ATTRIBUTE_UNUSED,
    139 	   bfd_vma pc ATTRIBUTE_UNUSED,
    140 	   int length ATTRIBUTE_UNUSED)
    141 {
    142 }
    143 
    144 /* Print a 'sof:' prefix to an operand.  */
    145 
    146 static void
    147 print_sof (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
    148 	   void * dis_info,
    149 	   long value ATTRIBUTE_UNUSED,
    150 	   unsigned int attrs ATTRIBUTE_UNUSED,
    151 	   bfd_vma pc ATTRIBUTE_UNUSED,
    152 	   int length ATTRIBUTE_UNUSED)
    153 {
    154   disassemble_info *info = (disassemble_info *) dis_info;
    155 
    156   info->fprintf_func (info->stream, "sof:");
    157 }
    158 
    159 /* Print a 'seg:' prefix to an operand.  */
    160 
    161 static void
    162 print_seg (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
    163 	   void * dis_info,
    164 	   long value ATTRIBUTE_UNUSED,
    165 	   unsigned int attrs ATTRIBUTE_UNUSED,
    166 	   bfd_vma pc ATTRIBUTE_UNUSED,
    167 	   int length ATTRIBUTE_UNUSED)
    168 {
    169   disassemble_info *info = (disassemble_info *) dis_info;
    170 
    171   info->fprintf_func (info->stream, "seg:");
    172 }
    173 
    174 /* Print a '#' prefix to an operand.  */
    175 
    176 static void
    177 print_hash (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
    178 	    void * dis_info,
    179 	    long value ATTRIBUTE_UNUSED,
    180 	    unsigned int attrs ATTRIBUTE_UNUSED,
    181 	    bfd_vma pc ATTRIBUTE_UNUSED,
    182 	    int length ATTRIBUTE_UNUSED)
    183 {
    184   disassemble_info *info = (disassemble_info *) dis_info;
    185 
    186   info->fprintf_func (info->stream, "#");
    187 }
    188 
    189 /* Print a '.' prefix to an operand.  */
    190 
    191 static void
    192 print_dot (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
    193 	   void * dis_info ATTRIBUTE_UNUSED,
    194 	   long value ATTRIBUTE_UNUSED,
    195 	   unsigned int attrs ATTRIBUTE_UNUSED,
    196 	   bfd_vma pc ATTRIBUTE_UNUSED,
    197 	   int length ATTRIBUTE_UNUSED)
    198 {
    199 }
    200 
    201 /* -- */
    202 
    203 void xc16x_cgen_print_operand
    204   (CGEN_CPU_DESC, int, PTR, CGEN_FIELDS *, void const *, bfd_vma, int);
    205 
    206 /* Main entry point for printing operands.
    207    XINFO is a `void *' and not a `disassemble_info *' to not put a requirement
    208    of dis-asm.h on cgen.h.
    209 
    210    This function is basically just a big switch statement.  Earlier versions
    211    used tables to look up the function to use, but
    212    - if the table contains both assembler and disassembler functions then
    213      the disassembler contains much of the assembler and vice-versa,
    214    - there's a lot of inlining possibilities as things grow,
    215    - using a switch statement avoids the function call overhead.
    216 
    217    This function could be moved into `print_insn_normal', but keeping it
    218    separate makes clear the interface between `print_insn_normal' and each of
    219    the handlers.  */
    220 
    221 void
    222 xc16x_cgen_print_operand (CGEN_CPU_DESC cd,
    223 			   int opindex,
    224 			   void * xinfo,
    225 			   CGEN_FIELDS *fields,
    226 			   void const *attrs ATTRIBUTE_UNUSED,
    227 			   bfd_vma pc,
    228 			   int length)
    229 {
    230   disassemble_info *info = (disassemble_info *) xinfo;
    231 
    232   switch (opindex)
    233     {
    234     case XC16X_OPERAND_REGNAM :
    235       print_keyword (cd, info, & xc16x_cgen_opval_psw_names, fields->f_reg8, 0);
    236       break;
    237     case XC16X_OPERAND_BIT01 :
    238       print_normal (cd, info, fields->f_op_1bit, 0, pc, length);
    239       break;
    240     case XC16X_OPERAND_BIT1 :
    241       print_normal (cd, info, fields->f_op_bit1, 0, pc, length);
    242       break;
    243     case XC16X_OPERAND_BIT2 :
    244       print_normal (cd, info, fields->f_op_bit2, 0, pc, length);
    245       break;
    246     case XC16X_OPERAND_BIT4 :
    247       print_normal (cd, info, fields->f_op_bit4, 0, pc, length);
    248       break;
    249     case XC16X_OPERAND_BIT8 :
    250       print_normal (cd, info, fields->f_op_bit8, 0, pc, length);
    251       break;
    252     case XC16X_OPERAND_BITONE :
    253       print_normal (cd, info, fields->f_op_onebit, 0, pc, length);
    254       break;
    255     case XC16X_OPERAND_CADDR :
    256       print_address (cd, info, fields->f_offset16, 0|(1<<CGEN_OPERAND_RELOC)|(1<<CGEN_OPERAND_ABS_ADDR), pc, length);
    257       break;
    258     case XC16X_OPERAND_COND :
    259       print_keyword (cd, info, & xc16x_cgen_opval_conditioncode_names, fields->f_condcode, 0);
    260       break;
    261     case XC16X_OPERAND_DATA8 :
    262       print_normal (cd, info, fields->f_data8, 0|(1<<CGEN_OPERAND_HASH_PREFIX), pc, length);
    263       break;
    264     case XC16X_OPERAND_DATAHI8 :
    265       print_normal (cd, info, fields->f_datahi8, 0|(1<<CGEN_OPERAND_HASH_PREFIX), pc, length);
    266       break;
    267     case XC16X_OPERAND_DOT :
    268       print_dot (cd, info, 0, 0|(1<<CGEN_OPERAND_SIGNED), pc, length);
    269       break;
    270     case XC16X_OPERAND_DR :
    271       print_keyword (cd, info, & xc16x_cgen_opval_gr_names, fields->f_r1, 0);
    272       break;
    273     case XC16X_OPERAND_DRB :
    274       print_keyword (cd, info, & xc16x_cgen_opval_grb_names, fields->f_r1, 0);
    275       break;
    276     case XC16X_OPERAND_DRI :
    277       print_keyword (cd, info, & xc16x_cgen_opval_gr_names, fields->f_r4, 0);
    278       break;
    279     case XC16X_OPERAND_EXTCOND :
    280       print_keyword (cd, info, & xc16x_cgen_opval_extconditioncode_names, fields->f_extccode, 0);
    281       break;
    282     case XC16X_OPERAND_GENREG :
    283       print_keyword (cd, info, & xc16x_cgen_opval_r8_names, fields->f_regb8, 0);
    284       break;
    285     case XC16X_OPERAND_HASH :
    286       print_hash (cd, info, 0, 0|(1<<CGEN_OPERAND_SIGNED), pc, length);
    287       break;
    288     case XC16X_OPERAND_ICOND :
    289       print_keyword (cd, info, & xc16x_cgen_opval_conditioncode_names, fields->f_icondcode, 0);
    290       break;
    291     case XC16X_OPERAND_LBIT2 :
    292       print_normal (cd, info, fields->f_op_lbit2, 0, pc, length);
    293       break;
    294     case XC16X_OPERAND_LBIT4 :
    295       print_normal (cd, info, fields->f_op_lbit4, 0, pc, length);
    296       break;
    297     case XC16X_OPERAND_MASK8 :
    298       print_normal (cd, info, fields->f_mask8, 0|(1<<CGEN_OPERAND_HASH_PREFIX), pc, length);
    299       break;
    300     case XC16X_OPERAND_MASKLO8 :
    301       print_normal (cd, info, fields->f_datahi8, 0|(1<<CGEN_OPERAND_HASH_PREFIX), pc, length);
    302       break;
    303     case XC16X_OPERAND_MEMGR8 :
    304       print_keyword (cd, info, & xc16x_cgen_opval_memgr8_names, fields->f_memgr8, 0);
    305       break;
    306     case XC16X_OPERAND_MEMORY :
    307       print_address (cd, info, fields->f_memory, 0, pc, length);
    308       break;
    309     case XC16X_OPERAND_PAG :
    310       print_pag (cd, info, 0, 0|(1<<CGEN_OPERAND_SIGNED), pc, length);
    311       break;
    312     case XC16X_OPERAND_PAGENUM :
    313       print_normal (cd, info, fields->f_pagenum, 0|(1<<CGEN_OPERAND_HASH_PREFIX), pc, length);
    314       break;
    315     case XC16X_OPERAND_POF :
    316       print_pof (cd, info, 0, 0|(1<<CGEN_OPERAND_SIGNED), pc, length);
    317       break;
    318     case XC16X_OPERAND_QBIT :
    319       print_with_dot_prefix (cd, info, fields->f_qbit, 0|(1<<CGEN_OPERAND_DOT_PREFIX), pc, length);
    320       break;
    321     case XC16X_OPERAND_QHIBIT :
    322       print_with_dot_prefix (cd, info, fields->f_qhibit, 0|(1<<CGEN_OPERAND_DOT_PREFIX), pc, length);
    323       break;
    324     case XC16X_OPERAND_QLOBIT :
    325       print_with_dot_prefix (cd, info, fields->f_qlobit, 0|(1<<CGEN_OPERAND_DOT_PREFIX), pc, length);
    326       break;
    327     case XC16X_OPERAND_REG8 :
    328       print_keyword (cd, info, & xc16x_cgen_opval_r8_names, fields->f_reg8, 0);
    329       break;
    330     case XC16X_OPERAND_REGB8 :
    331       print_keyword (cd, info, & xc16x_cgen_opval_grb8_names, fields->f_regb8, 0);
    332       break;
    333     case XC16X_OPERAND_REGBMEM8 :
    334       print_keyword (cd, info, & xc16x_cgen_opval_regbmem8_names, fields->f_regmem8, 0);
    335       break;
    336     case XC16X_OPERAND_REGHI8 :
    337       print_keyword (cd, info, & xc16x_cgen_opval_r8_names, fields->f_reghi8, 0);
    338       break;
    339     case XC16X_OPERAND_REGMEM8 :
    340       print_keyword (cd, info, & xc16x_cgen_opval_regmem8_names, fields->f_regmem8, 0);
    341       break;
    342     case XC16X_OPERAND_REGOFF8 :
    343       print_keyword (cd, info, & xc16x_cgen_opval_r8_names, fields->f_regoff8, 0);
    344       break;
    345     case XC16X_OPERAND_REL :
    346       print_normal (cd, info, fields->f_rel8, 0|(1<<CGEN_OPERAND_SIGNED)|(1<<CGEN_OPERAND_RELOC)|(1<<CGEN_OPERAND_PCREL_ADDR), pc, length);
    347       break;
    348     case XC16X_OPERAND_RELHI :
    349       print_normal (cd, info, fields->f_relhi8, 0|(1<<CGEN_OPERAND_SIGNED)|(1<<CGEN_OPERAND_RELOC)|(1<<CGEN_OPERAND_PCREL_ADDR), pc, length);
    350       break;
    351     case XC16X_OPERAND_SEG :
    352       print_normal (cd, info, fields->f_seg8, 0, pc, length);
    353       break;
    354     case XC16X_OPERAND_SEGHI8 :
    355       print_normal (cd, info, fields->f_segnum8, 0, pc, length);
    356       break;
    357     case XC16X_OPERAND_SEGM :
    358       print_seg (cd, info, 0, 0|(1<<CGEN_OPERAND_SIGNED), pc, length);
    359       break;
    360     case XC16X_OPERAND_SOF :
    361       print_sof (cd, info, 0, 0|(1<<CGEN_OPERAND_SIGNED), pc, length);
    362       break;
    363     case XC16X_OPERAND_SR :
    364       print_keyword (cd, info, & xc16x_cgen_opval_gr_names, fields->f_r2, 0);
    365       break;
    366     case XC16X_OPERAND_SR2 :
    367       print_keyword (cd, info, & xc16x_cgen_opval_gr_names, fields->f_r0, 0);
    368       break;
    369     case XC16X_OPERAND_SRB :
    370       print_keyword (cd, info, & xc16x_cgen_opval_grb_names, fields->f_r2, 0);
    371       break;
    372     case XC16X_OPERAND_SRC1 :
    373       print_keyword (cd, info, & xc16x_cgen_opval_gr_names, fields->f_r1, 0);
    374       break;
    375     case XC16X_OPERAND_SRC2 :
    376       print_keyword (cd, info, & xc16x_cgen_opval_gr_names, fields->f_r2, 0);
    377       break;
    378     case XC16X_OPERAND_SRDIV :
    379       print_keyword (cd, info, & xc16x_cgen_opval_regdiv8_names, fields->f_reg8, 0);
    380       break;
    381     case XC16X_OPERAND_U4 :
    382       print_keyword (cd, info, & xc16x_cgen_opval_reg0_name, fields->f_uimm4, 0);
    383       break;
    384     case XC16X_OPERAND_UIMM16 :
    385       print_normal (cd, info, fields->f_uimm16, 0|(1<<CGEN_OPERAND_HASH_PREFIX), pc, length);
    386       break;
    387     case XC16X_OPERAND_UIMM2 :
    388       print_keyword (cd, info, & xc16x_cgen_opval_ext_names, fields->f_uimm2, 0|(1<<CGEN_OPERAND_HASH_PREFIX));
    389       break;
    390     case XC16X_OPERAND_UIMM3 :
    391       print_keyword (cd, info, & xc16x_cgen_opval_reg0_name1, fields->f_uimm3, 0|(1<<CGEN_OPERAND_HASH_PREFIX));
    392       break;
    393     case XC16X_OPERAND_UIMM4 :
    394       print_normal (cd, info, fields->f_uimm4, 0|(1<<CGEN_OPERAND_HASH_PREFIX), pc, length);
    395       break;
    396     case XC16X_OPERAND_UIMM7 :
    397       print_normal (cd, info, fields->f_uimm7, 0|(1<<CGEN_OPERAND_HASH_PREFIX)|(1<<CGEN_OPERAND_RELOC)|(1<<CGEN_OPERAND_PCREL_ADDR), pc, length);
    398       break;
    399     case XC16X_OPERAND_UIMM8 :
    400       print_normal (cd, info, fields->f_uimm8, 0|(1<<CGEN_OPERAND_HASH_PREFIX), pc, length);
    401       break;
    402     case XC16X_OPERAND_UPAG16 :
    403       print_with_pag_prefix (cd, info, fields->f_uimm16, 0|(1<<CGEN_OPERAND_PAG_PREFIX), pc, length);
    404       break;
    405     case XC16X_OPERAND_UPOF16 :
    406       print_with_pof_prefix (cd, info, fields->f_memory, 0|(1<<CGEN_OPERAND_POF_PREFIX), pc, length);
    407       break;
    408     case XC16X_OPERAND_USEG16 :
    409       print_normal (cd, info, fields->f_offset16, 0|(1<<CGEN_OPERAND_SEG_PREFIX)|(1<<CGEN_OPERAND_RELOC)|(1<<CGEN_OPERAND_ABS_ADDR), pc, length);
    410       break;
    411     case XC16X_OPERAND_USEG8 :
    412       print_normal (cd, info, fields->f_seg8, 0|(1<<CGEN_OPERAND_SEG_PREFIX), pc, length);
    413       break;
    414     case XC16X_OPERAND_USOF16 :
    415       print_normal (cd, info, fields->f_offset16, 0|(1<<CGEN_OPERAND_SOF_PREFIX)|(1<<CGEN_OPERAND_RELOC)|(1<<CGEN_OPERAND_ABS_ADDR), pc, length);
    416       break;
    417 
    418     default :
    419       /* xgettext:c-format */
    420       fprintf (stderr, _("Unrecognized field %d while printing insn.\n"),
    421 	       opindex);
    422     abort ();
    423   }
    424 }
    425 
    426 cgen_print_fn * const xc16x_cgen_print_handlers[] =
    427 {
    428   print_insn_normal,
    429 };
    430 
    431 
    432 void
    433 xc16x_cgen_init_dis (CGEN_CPU_DESC cd)
    434 {
    435   xc16x_cgen_init_opcode_table (cd);
    436   xc16x_cgen_init_ibld_table (cd);
    437   cd->print_handlers = & xc16x_cgen_print_handlers[0];
    438   cd->print_operand = xc16x_cgen_print_operand;
    439 }
    440 
    441 
    442 /* Default print handler.  */
    444 
    445 static void
    446 print_normal (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
    447 	      void *dis_info,
    448 	      long value,
    449 	      unsigned int attrs,
    450 	      bfd_vma pc ATTRIBUTE_UNUSED,
    451 	      int length ATTRIBUTE_UNUSED)
    452 {
    453   disassemble_info *info = (disassemble_info *) dis_info;
    454 
    455   /* Print the operand as directed by the attributes.  */
    456   if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SEM_ONLY))
    457     ; /* nothing to do */
    458   else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SIGNED))
    459     (*info->fprintf_func) (info->stream, "%ld", value);
    460   else
    461     (*info->fprintf_func) (info->stream, "0x%lx", value);
    462 }
    463 
    464 /* Default address handler.  */
    465 
    466 static void
    467 print_address (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
    468 	       void *dis_info,
    469 	       bfd_vma value,
    470 	       unsigned int attrs,
    471 	       bfd_vma pc ATTRIBUTE_UNUSED,
    472 	       int length ATTRIBUTE_UNUSED)
    473 {
    474   disassemble_info *info = (disassemble_info *) dis_info;
    475 
    476   /* Print the operand as directed by the attributes.  */
    477   if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SEM_ONLY))
    478     ; /* Nothing to do.  */
    479   else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_PCREL_ADDR))
    480     (*info->print_address_func) (value, info);
    481   else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_ABS_ADDR))
    482     (*info->print_address_func) (value, info);
    483   else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SIGNED))
    484     (*info->fprintf_func) (info->stream, "%ld", (long) value);
    485   else
    486     (*info->fprintf_func) (info->stream, "0x%lx", (long) value);
    487 }
    488 
    489 /* Keyword print handler.  */
    490 
    491 static void
    492 print_keyword (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
    493 	       void *dis_info,
    494 	       CGEN_KEYWORD *keyword_table,
    495 	       long value,
    496 	       unsigned int attrs ATTRIBUTE_UNUSED)
    497 {
    498   disassemble_info *info = (disassemble_info *) dis_info;
    499   const CGEN_KEYWORD_ENTRY *ke;
    500 
    501   ke = cgen_keyword_lookup_value (keyword_table, value);
    502   if (ke != NULL)
    503     (*info->fprintf_func) (info->stream, "%s", ke->name);
    504   else
    505     (*info->fprintf_func) (info->stream, "???");
    506 }
    507 
    508 /* Default insn printer.
    510 
    511    DIS_INFO is defined as `void *' so the disassembler needn't know anything
    512    about disassemble_info.  */
    513 
    514 static void
    515 print_insn_normal (CGEN_CPU_DESC cd,
    516 		   void *dis_info,
    517 		   const CGEN_INSN *insn,
    518 		   CGEN_FIELDS *fields,
    519 		   bfd_vma pc,
    520 		   int length)
    521 {
    522   const CGEN_SYNTAX *syntax = CGEN_INSN_SYNTAX (insn);
    523   disassemble_info *info = (disassemble_info *) dis_info;
    524   const CGEN_SYNTAX_CHAR_TYPE *syn;
    525 
    526   CGEN_INIT_PRINT (cd);
    527 
    528   for (syn = CGEN_SYNTAX_STRING (syntax); *syn; ++syn)
    529     {
    530       if (CGEN_SYNTAX_MNEMONIC_P (*syn))
    531 	{
    532 	  (*info->fprintf_func) (info->stream, "%s", CGEN_INSN_MNEMONIC (insn));
    533 	  continue;
    534 	}
    535       if (CGEN_SYNTAX_CHAR_P (*syn))
    536 	{
    537 	  (*info->fprintf_func) (info->stream, "%c", CGEN_SYNTAX_CHAR (*syn));
    538 	  continue;
    539 	}
    540 
    541       /* We have an operand.  */
    542       xc16x_cgen_print_operand (cd, CGEN_SYNTAX_FIELD (*syn), info,
    543 				 fields, CGEN_INSN_ATTRS (insn), pc, length);
    544     }
    545 }
    546 
    547 /* Subroutine of print_insn. Reads an insn into the given buffers and updates
    549    the extract info.
    550    Returns 0 if all is well, non-zero otherwise.  */
    551 
    552 static int
    553 read_insn (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
    554 	   bfd_vma pc,
    555 	   disassemble_info *info,
    556 	   bfd_byte *buf,
    557 	   int buflen,
    558 	   CGEN_EXTRACT_INFO *ex_info,
    559 	   unsigned long *insn_value)
    560 {
    561   int status = (*info->read_memory_func) (pc, buf, buflen, info);
    562 
    563   if (status != 0)
    564     {
    565       (*info->memory_error_func) (status, pc, info);
    566       return -1;
    567     }
    568 
    569   ex_info->dis_info = info;
    570   ex_info->valid = (1 << buflen) - 1;
    571   ex_info->insn_bytes = buf;
    572 
    573   *insn_value = bfd_get_bits (buf, buflen * 8, info->endian == BFD_ENDIAN_BIG);
    574   return 0;
    575 }
    576 
    577 /* Utility to print an insn.
    578    BUF is the base part of the insn, target byte order, BUFLEN bytes long.
    579    The result is the size of the insn in bytes or zero for an unknown insn
    580    or -1 if an error occurs fetching data (memory_error_func will have
    581    been called).  */
    582 
    583 static int
    584 print_insn (CGEN_CPU_DESC cd,
    585 	    bfd_vma pc,
    586 	    disassemble_info *info,
    587 	    bfd_byte *buf,
    588 	    unsigned int buflen)
    589 {
    590   CGEN_INSN_INT insn_value;
    591   const CGEN_INSN_LIST *insn_list;
    592   CGEN_EXTRACT_INFO ex_info;
    593   int basesize;
    594 
    595   /* Extract base part of instruction, just in case CGEN_DIS_* uses it. */
    596   basesize = cd->base_insn_bitsize < buflen * 8 ?
    597                                      cd->base_insn_bitsize : buflen * 8;
    598   insn_value = cgen_get_insn_value (cd, buf, basesize);
    599 
    600 
    601   /* Fill in ex_info fields like read_insn would.  Don't actually call
    602      read_insn, since the incoming buffer is already read (and possibly
    603      modified a la m32r).  */
    604   ex_info.valid = (1 << buflen) - 1;
    605   ex_info.dis_info = info;
    606   ex_info.insn_bytes = buf;
    607 
    608   /* The instructions are stored in hash lists.
    609      Pick the first one and keep trying until we find the right one.  */
    610 
    611   insn_list = CGEN_DIS_LOOKUP_INSN (cd, (char *) buf, insn_value);
    612   while (insn_list != NULL)
    613     {
    614       const CGEN_INSN *insn = insn_list->insn;
    615       CGEN_FIELDS fields;
    616       int length;
    617       unsigned long insn_value_cropped;
    618 
    619 #ifdef CGEN_VALIDATE_INSN_SUPPORTED
    620       /* Not needed as insn shouldn't be in hash lists if not supported.  */
    621       /* Supported by this cpu?  */
    622       if (! xc16x_cgen_insn_supported (cd, insn))
    623         {
    624           insn_list = CGEN_DIS_NEXT_INSN (insn_list);
    625 	  continue;
    626         }
    627 #endif
    628 
    629       /* Basic bit mask must be correct.  */
    630       /* ??? May wish to allow target to defer this check until the extract
    631 	 handler.  */
    632 
    633       /* Base size may exceed this instruction's size.  Extract the
    634          relevant part from the buffer. */
    635       if ((unsigned) (CGEN_INSN_BITSIZE (insn) / 8) < buflen &&
    636 	  (unsigned) (CGEN_INSN_BITSIZE (insn) / 8) <= sizeof (unsigned long))
    637 	insn_value_cropped = bfd_get_bits (buf, CGEN_INSN_BITSIZE (insn),
    638 					   info->endian == BFD_ENDIAN_BIG);
    639       else
    640 	insn_value_cropped = insn_value;
    641 
    642       if ((insn_value_cropped & CGEN_INSN_BASE_MASK (insn))
    643 	  == CGEN_INSN_BASE_VALUE (insn))
    644 	{
    645 	  /* Printing is handled in two passes.  The first pass parses the
    646 	     machine insn and extracts the fields.  The second pass prints
    647 	     them.  */
    648 
    649 	  /* Make sure the entire insn is loaded into insn_value, if it
    650 	     can fit.  */
    651 	  if (((unsigned) CGEN_INSN_BITSIZE (insn) > cd->base_insn_bitsize) &&
    652 	      (unsigned) (CGEN_INSN_BITSIZE (insn) / 8) <= sizeof (unsigned long))
    653 	    {
    654 	      unsigned long full_insn_value;
    655 	      int rc = read_insn (cd, pc, info, buf,
    656 				  CGEN_INSN_BITSIZE (insn) / 8,
    657 				  & ex_info, & full_insn_value);
    658 	      if (rc != 0)
    659 		return rc;
    660 	      length = CGEN_EXTRACT_FN (cd, insn)
    661 		(cd, insn, &ex_info, full_insn_value, &fields, pc);
    662 	    }
    663 	  else
    664 	    length = CGEN_EXTRACT_FN (cd, insn)
    665 	      (cd, insn, &ex_info, insn_value_cropped, &fields, pc);
    666 
    667 	  /* Length < 0 -> error.  */
    668 	  if (length < 0)
    669 	    return length;
    670 	  if (length > 0)
    671 	    {
    672 	      CGEN_PRINT_FN (cd, insn) (cd, info, insn, &fields, pc, length);
    673 	      /* Length is in bits, result is in bytes.  */
    674 	      return length / 8;
    675 	    }
    676 	}
    677 
    678       insn_list = CGEN_DIS_NEXT_INSN (insn_list);
    679     }
    680 
    681   return 0;
    682 }
    683 
    684 /* Default value for CGEN_PRINT_INSN.
    685    The result is the size of the insn in bytes or zero for an unknown insn
    686    or -1 if an error occured fetching bytes.  */
    687 
    688 #ifndef CGEN_PRINT_INSN
    689 #define CGEN_PRINT_INSN default_print_insn
    690 #endif
    691 
    692 static int
    693 default_print_insn (CGEN_CPU_DESC cd, bfd_vma pc, disassemble_info *info)
    694 {
    695   bfd_byte buf[CGEN_MAX_INSN_SIZE];
    696   int buflen;
    697   int status;
    698 
    699   /* Attempt to read the base part of the insn.  */
    700   buflen = cd->base_insn_bitsize / 8;
    701   status = (*info->read_memory_func) (pc, buf, buflen, info);
    702 
    703   /* Try again with the minimum part, if min < base.  */
    704   if (status != 0 && (cd->min_insn_bitsize < cd->base_insn_bitsize))
    705     {
    706       buflen = cd->min_insn_bitsize / 8;
    707       status = (*info->read_memory_func) (pc, buf, buflen, info);
    708     }
    709 
    710   if (status != 0)
    711     {
    712       (*info->memory_error_func) (status, pc, info);
    713       return -1;
    714     }
    715 
    716   return print_insn (cd, pc, info, buf, buflen);
    717 }
    718 
    719 /* Main entry point.
    720    Print one instruction from PC on INFO->STREAM.
    721    Return the size of the instruction (in bytes).  */
    722 
    723 typedef struct cpu_desc_list
    724 {
    725   struct cpu_desc_list *next;
    726   CGEN_BITSET *isa;
    727   int mach;
    728   int endian;
    729   CGEN_CPU_DESC cd;
    730 } cpu_desc_list;
    731 
    732 int
    733 print_insn_xc16x (bfd_vma pc, disassemble_info *info)
    734 {
    735   static cpu_desc_list *cd_list = 0;
    736   cpu_desc_list *cl = 0;
    737   static CGEN_CPU_DESC cd = 0;
    738   static CGEN_BITSET *prev_isa;
    739   static int prev_mach;
    740   static int prev_endian;
    741   int length;
    742   CGEN_BITSET *isa;
    743   int mach;
    744   int endian = (info->endian == BFD_ENDIAN_BIG
    745 		? CGEN_ENDIAN_BIG
    746 		: CGEN_ENDIAN_LITTLE);
    747   enum bfd_architecture arch;
    748 
    749   /* ??? gdb will set mach but leave the architecture as "unknown" */
    750 #ifndef CGEN_BFD_ARCH
    751 #define CGEN_BFD_ARCH bfd_arch_xc16x
    752 #endif
    753   arch = info->arch;
    754   if (arch == bfd_arch_unknown)
    755     arch = CGEN_BFD_ARCH;
    756 
    757   /* There's no standard way to compute the machine or isa number
    758      so we leave it to the target.  */
    759 #ifdef CGEN_COMPUTE_MACH
    760   mach = CGEN_COMPUTE_MACH (info);
    761 #else
    762   mach = info->mach;
    763 #endif
    764 
    765 #ifdef CGEN_COMPUTE_ISA
    766   {
    767     static CGEN_BITSET *permanent_isa;
    768 
    769     if (!permanent_isa)
    770       permanent_isa = cgen_bitset_create (MAX_ISAS);
    771     isa = permanent_isa;
    772     cgen_bitset_clear (isa);
    773     cgen_bitset_add (isa, CGEN_COMPUTE_ISA (info));
    774   }
    775 #else
    776   isa = info->insn_sets;
    777 #endif
    778 
    779   /* If we've switched cpu's, try to find a handle we've used before */
    780   if (cd
    781       && (cgen_bitset_compare (isa, prev_isa) != 0
    782 	  || mach != prev_mach
    783 	  || endian != prev_endian))
    784     {
    785       cd = 0;
    786       for (cl = cd_list; cl; cl = cl->next)
    787 	{
    788 	  if (cgen_bitset_compare (cl->isa, isa) == 0 &&
    789 	      cl->mach == mach &&
    790 	      cl->endian == endian)
    791 	    {
    792 	      cd = cl->cd;
    793  	      prev_isa = cd->isas;
    794 	      break;
    795 	    }
    796 	}
    797     }
    798 
    799   /* If we haven't initialized yet, initialize the opcode table.  */
    800   if (! cd)
    801     {
    802       const bfd_arch_info_type *arch_type = bfd_lookup_arch (arch, mach);
    803       const char *mach_name;
    804 
    805       if (!arch_type)
    806 	abort ();
    807       mach_name = arch_type->printable_name;
    808 
    809       prev_isa = cgen_bitset_copy (isa);
    810       prev_mach = mach;
    811       prev_endian = endian;
    812       cd = xc16x_cgen_cpu_open (CGEN_CPU_OPEN_ISAS, prev_isa,
    813 				 CGEN_CPU_OPEN_BFDMACH, mach_name,
    814 				 CGEN_CPU_OPEN_ENDIAN, prev_endian,
    815 				 CGEN_CPU_OPEN_END);
    816       if (!cd)
    817 	abort ();
    818 
    819       /* Save this away for future reference.  */
    820       cl = xmalloc (sizeof (struct cpu_desc_list));
    821       cl->cd = cd;
    822       cl->isa = prev_isa;
    823       cl->mach = mach;
    824       cl->endian = endian;
    825       cl->next = cd_list;
    826       cd_list = cl;
    827 
    828       xc16x_cgen_init_dis (cd);
    829     }
    830 
    831   /* We try to have as much common code as possible.
    832      But at this point some targets need to take over.  */
    833   /* ??? Some targets may need a hook elsewhere.  Try to avoid this,
    834      but if not possible try to move this hook elsewhere rather than
    835      have two hooks.  */
    836   length = CGEN_PRINT_INSN (cd, pc, info);
    837   if (length > 0)
    838     return length;
    839   if (length < 0)
    840     return -1;
    841 
    842   (*info->fprintf_func) (info->stream, UNKNOWN_INSN_MSG);
    843   return cd->default_insn_bitsize / 8;
    844 }
    845