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