Imported Upstream version 7.9
[platform/upstream/gdb.git] / opcodes / xc16x-dis.c
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-2015 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 \f
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
67 static void
68 print_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
86 static void
87 print_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
105 static void
106 print_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
121 static void
122 print_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
133 static void
134 print_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
145 static void
146 print_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
160 static void
161 print_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
175 static void
176 print_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
190 static void
191 print_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
202 void 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
220 void
221 xc16x_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
425 cgen_print_fn * const xc16x_cgen_print_handlers[] = 
426 {
427   print_insn_normal,
428 };
429
430
431 void
432 xc16x_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 \f
441 /* Default print handler.  */
442
443 static void
444 print_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
464 static void
465 print_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
489 static void
490 print_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 \f
506 /* Default insn printer.
507
508    DIS_INFO is defined as `void *' so the disassembler needn't know anything
509    about disassemble_info.  */
510
511 static void
512 print_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 \f
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
548 static int
549 read_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
579 static int
580 print_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
688 static int
689 default_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
719 typedef 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
728 int
729 print_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 }