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.  */
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
print_with_dot_prefix(CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,void * dis_info,long value,unsigned attrs ATTRIBUTE_UNUSED,bfd_vma pc ATTRIBUTE_UNUSED,int length ATTRIBUTE_UNUSED)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
print_with_pof_prefix(CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,void * dis_info,bfd_vma value,unsigned attrs ATTRIBUTE_UNUSED,bfd_vma pc ATTRIBUTE_UNUSED,int length ATTRIBUTE_UNUSED)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
print_with_pag_prefix(CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,void * dis_info,long value,unsigned attrs ATTRIBUTE_UNUSED,bfd_vma pc ATTRIBUTE_UNUSED,int length ATTRIBUTE_UNUSED)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
print_pof(CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,void * dis_info ATTRIBUTE_UNUSED,long value ATTRIBUTE_UNUSED,unsigned int attrs ATTRIBUTE_UNUSED,bfd_vma pc ATTRIBUTE_UNUSED,int length ATTRIBUTE_UNUSED)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
print_pag(CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,void * dis_info ATTRIBUTE_UNUSED,long value ATTRIBUTE_UNUSED,unsigned int attrs ATTRIBUTE_UNUSED,bfd_vma pc ATTRIBUTE_UNUSED,int length ATTRIBUTE_UNUSED)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
print_sof(CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,void * dis_info,long value ATTRIBUTE_UNUSED,unsigned int attrs ATTRIBUTE_UNUSED,bfd_vma pc ATTRIBUTE_UNUSED,int length ATTRIBUTE_UNUSED)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
print_seg(CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,void * dis_info,long value ATTRIBUTE_UNUSED,unsigned int attrs ATTRIBUTE_UNUSED,bfd_vma pc ATTRIBUTE_UNUSED,int length ATTRIBUTE_UNUSED)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
print_hash(CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,void * dis_info,long value ATTRIBUTE_UNUSED,unsigned int attrs ATTRIBUTE_UNUSED,bfd_vma pc ATTRIBUTE_UNUSED,int length ATTRIBUTE_UNUSED)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
print_dot(CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,void * dis_info ATTRIBUTE_UNUSED,long value ATTRIBUTE_UNUSED,unsigned int attrs ATTRIBUTE_UNUSED,bfd_vma pc ATTRIBUTE_UNUSED,int length ATTRIBUTE_UNUSED)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
xc16x_cgen_print_operand(CGEN_CPU_DESC cd,int opindex,void * xinfo,CGEN_FIELDS * fields,void const * attrs ATTRIBUTE_UNUSED,bfd_vma pc,int length)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
xc16x_cgen_init_dis(CGEN_CPU_DESC cd)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 
441 /* Default print handler.  */
442 
443 static void
print_normal(CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,void * dis_info,long value,unsigned int attrs,bfd_vma pc ATTRIBUTE_UNUSED,int length ATTRIBUTE_UNUSED)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
print_address(CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,void * dis_info,bfd_vma value,unsigned int attrs,bfd_vma pc ATTRIBUTE_UNUSED,int length ATTRIBUTE_UNUSED)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
print_keyword(CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,void * dis_info,CGEN_KEYWORD * keyword_table,long value,unsigned int attrs ATTRIBUTE_UNUSED)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 
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
print_insn_normal(CGEN_CPU_DESC cd,void * dis_info,const CGEN_INSN * insn,CGEN_FIELDS * fields,bfd_vma pc,int length)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 
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
read_insn(CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,bfd_vma pc,disassemble_info * info,bfd_byte * buf,int buflen,CGEN_EXTRACT_INFO * ex_info,unsigned long * insn_value)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
print_insn(CGEN_CPU_DESC cd,bfd_vma pc,disassemble_info * info,bfd_byte * buf,unsigned int buflen)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
default_print_insn(CGEN_CPU_DESC cd,bfd_vma pc,disassemble_info * info)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
print_insn_xc16x(bfd_vma pc,disassemble_info * info)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 }
841