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