xref: /netbsd-src/external/gpl3/binutils.old/dist/opcodes/or1k-dis.c (revision 82d56013d7b633d116a93943de88e08335357a7c)
1 /* DO NOT EDIT!  -*- buffer-read-only: t -*- vi:set ro:  */
2 /* Disassembler interface for targets using CGEN. -*- C -*-
3    CGEN: Cpu tools GENerator
4 
5    THIS FILE IS MACHINE GENERATED WITH CGEN.
6    - the resultant file is machine generated, cgen-dis.in isn't
7 
8    Copyright (C) 1996-2018 Free Software Foundation, Inc.
9 
10    This file is part of libopcodes.
11 
12    This library 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 3, or (at your option)
15    any later version.
16 
17    It is distributed in the hope that it will be useful, but WITHOUT
18    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
19    or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
20    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 "disassemble.h"
33 #include "bfd.h"
34 #include "symcat.h"
35 #include "libiberty.h"
36 #include "or1k-desc.h"
37 #include "or1k-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 
43 static void print_normal
44   (CGEN_CPU_DESC, void *, long, unsigned int, bfd_vma, int);
45 static void print_address
46   (CGEN_CPU_DESC, void *, bfd_vma, unsigned int, bfd_vma, int) ATTRIBUTE_UNUSED;
47 static void print_keyword
48   (CGEN_CPU_DESC, void *, CGEN_KEYWORD *, long, unsigned int) ATTRIBUTE_UNUSED;
49 static void print_insn_normal
50   (CGEN_CPU_DESC, void *, const CGEN_INSN *, CGEN_FIELDS *, bfd_vma, int);
51 static int print_insn
52   (CGEN_CPU_DESC, bfd_vma,  disassemble_info *, bfd_byte *, unsigned);
53 static int default_print_insn
54   (CGEN_CPU_DESC, bfd_vma, disassemble_info *) ATTRIBUTE_UNUSED;
55 static 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 
62 void or1k_cgen_print_operand
63   (CGEN_CPU_DESC, int, PTR, CGEN_FIELDS *, void const *, bfd_vma, int);
64 
65 /* Main entry point for printing operands.
66    XINFO is a `void *' and not a `disassemble_info *' to not put a requirement
67    of dis-asm.h on cgen.h.
68 
69    This function is basically just a big switch statement.  Earlier versions
70    used tables to look up the function to use, but
71    - if the table contains both assembler and disassembler functions then
72      the disassembler contains much of the assembler and vice-versa,
73    - there's a lot of inlining possibilities as things grow,
74    - using a switch statement avoids the function call overhead.
75 
76    This function could be moved into `print_insn_normal', but keeping it
77    separate makes clear the interface between `print_insn_normal' and each of
78    the handlers.  */
79 
80 void
81 or1k_cgen_print_operand (CGEN_CPU_DESC cd,
82 			   int opindex,
83 			   void * xinfo,
84 			   CGEN_FIELDS *fields,
85 			   void const *attrs ATTRIBUTE_UNUSED,
86 			   bfd_vma pc,
87 			   int length)
88 {
89   disassemble_info *info = (disassemble_info *) xinfo;
90 
91   switch (opindex)
92     {
93     case OR1K_OPERAND_DISP26 :
94       print_address (cd, info, fields->f_disp26, 0|(1<<CGEN_OPERAND_PCREL_ADDR), pc, length);
95       break;
96     case OR1K_OPERAND_RA :
97       print_keyword (cd, info, & or1k_cgen_opval_h_gpr, fields->f_r2, 0);
98       break;
99     case OR1K_OPERAND_RADF :
100       print_keyword (cd, info, & or1k_cgen_opval_h_fdr, fields->f_r1, 0);
101       break;
102     case OR1K_OPERAND_RASF :
103       print_keyword (cd, info, & or1k_cgen_opval_h_fsr, fields->f_r2, 0);
104       break;
105     case OR1K_OPERAND_RB :
106       print_keyword (cd, info, & or1k_cgen_opval_h_gpr, fields->f_r3, 0);
107       break;
108     case OR1K_OPERAND_RBDF :
109       print_keyword (cd, info, & or1k_cgen_opval_h_fdr, fields->f_r1, 0);
110       break;
111     case OR1K_OPERAND_RBSF :
112       print_keyword (cd, info, & or1k_cgen_opval_h_fsr, fields->f_r3, 0);
113       break;
114     case OR1K_OPERAND_RD :
115       print_keyword (cd, info, & or1k_cgen_opval_h_gpr, fields->f_r1, 0);
116       break;
117     case OR1K_OPERAND_RDDF :
118       print_keyword (cd, info, & or1k_cgen_opval_h_fdr, fields->f_r1, 0);
119       break;
120     case OR1K_OPERAND_RDSF :
121       print_keyword (cd, info, & or1k_cgen_opval_h_fsr, fields->f_r1, 0);
122       break;
123     case OR1K_OPERAND_SIMM16 :
124       print_normal (cd, info, fields->f_simm16, 0|(1<<CGEN_OPERAND_SIGNED)|(1<<CGEN_OPERAND_SIGN_OPT), pc, length);
125       break;
126     case OR1K_OPERAND_SIMM16_SPLIT :
127       print_normal (cd, info, fields->f_simm16_split, 0|(1<<CGEN_OPERAND_SIGNED)|(1<<CGEN_OPERAND_SIGN_OPT)|(1<<CGEN_OPERAND_VIRTUAL), pc, length);
128       break;
129     case OR1K_OPERAND_UIMM16 :
130       print_normal (cd, info, fields->f_uimm16, 0, pc, length);
131       break;
132     case OR1K_OPERAND_UIMM16_SPLIT :
133       print_normal (cd, info, fields->f_uimm16_split, 0|(1<<CGEN_OPERAND_VIRTUAL), pc, length);
134       break;
135     case OR1K_OPERAND_UIMM6 :
136       print_normal (cd, info, fields->f_uimm6, 0, pc, length);
137       break;
138 
139     default :
140       /* xgettext:c-format */
141       opcodes_error_handler
142 	(_("internal error: unrecognized field %d while printing insn"),
143 	 opindex);
144       abort ();
145   }
146 }
147 
148 cgen_print_fn * const or1k_cgen_print_handlers[] =
149 {
150   print_insn_normal,
151 };
152 
153 
154 void
155 or1k_cgen_init_dis (CGEN_CPU_DESC cd)
156 {
157   or1k_cgen_init_opcode_table (cd);
158   or1k_cgen_init_ibld_table (cd);
159   cd->print_handlers = & or1k_cgen_print_handlers[0];
160   cd->print_operand = or1k_cgen_print_operand;
161 }
162 
163 
164 /* Default print handler.  */
165 
166 static void
167 print_normal (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
168 	      void *dis_info,
169 	      long value,
170 	      unsigned int attrs,
171 	      bfd_vma pc ATTRIBUTE_UNUSED,
172 	      int length ATTRIBUTE_UNUSED)
173 {
174   disassemble_info *info = (disassemble_info *) dis_info;
175 
176   /* Print the operand as directed by the attributes.  */
177   if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SEM_ONLY))
178     ; /* nothing to do */
179   else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SIGNED))
180     (*info->fprintf_func) (info->stream, "%ld", value);
181   else
182     (*info->fprintf_func) (info->stream, "0x%lx", value);
183 }
184 
185 /* Default address handler.  */
186 
187 static void
188 print_address (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
189 	       void *dis_info,
190 	       bfd_vma value,
191 	       unsigned int attrs,
192 	       bfd_vma pc ATTRIBUTE_UNUSED,
193 	       int length ATTRIBUTE_UNUSED)
194 {
195   disassemble_info *info = (disassemble_info *) dis_info;
196 
197   /* Print the operand as directed by the attributes.  */
198   if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SEM_ONLY))
199     ; /* Nothing to do.  */
200   else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_PCREL_ADDR))
201     (*info->print_address_func) (value, info);
202   else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_ABS_ADDR))
203     (*info->print_address_func) (value, info);
204   else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SIGNED))
205     (*info->fprintf_func) (info->stream, "%ld", (long) value);
206   else
207     (*info->fprintf_func) (info->stream, "0x%lx", (long) value);
208 }
209 
210 /* Keyword print handler.  */
211 
212 static void
213 print_keyword (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
214 	       void *dis_info,
215 	       CGEN_KEYWORD *keyword_table,
216 	       long value,
217 	       unsigned int attrs ATTRIBUTE_UNUSED)
218 {
219   disassemble_info *info = (disassemble_info *) dis_info;
220   const CGEN_KEYWORD_ENTRY *ke;
221 
222   ke = cgen_keyword_lookup_value (keyword_table, value);
223   if (ke != NULL)
224     (*info->fprintf_func) (info->stream, "%s", ke->name);
225   else
226     (*info->fprintf_func) (info->stream, "???");
227 }
228 
229 /* Default insn printer.
230 
231    DIS_INFO is defined as `void *' so the disassembler needn't know anything
232    about disassemble_info.  */
233 
234 static void
235 print_insn_normal (CGEN_CPU_DESC cd,
236 		   void *dis_info,
237 		   const CGEN_INSN *insn,
238 		   CGEN_FIELDS *fields,
239 		   bfd_vma pc,
240 		   int length)
241 {
242   const CGEN_SYNTAX *syntax = CGEN_INSN_SYNTAX (insn);
243   disassemble_info *info = (disassemble_info *) dis_info;
244   const CGEN_SYNTAX_CHAR_TYPE *syn;
245 
246   CGEN_INIT_PRINT (cd);
247 
248   for (syn = CGEN_SYNTAX_STRING (syntax); *syn; ++syn)
249     {
250       if (CGEN_SYNTAX_MNEMONIC_P (*syn))
251 	{
252 	  (*info->fprintf_func) (info->stream, "%s", CGEN_INSN_MNEMONIC (insn));
253 	  continue;
254 	}
255       if (CGEN_SYNTAX_CHAR_P (*syn))
256 	{
257 	  (*info->fprintf_func) (info->stream, "%c", CGEN_SYNTAX_CHAR (*syn));
258 	  continue;
259 	}
260 
261       /* We have an operand.  */
262       or1k_cgen_print_operand (cd, CGEN_SYNTAX_FIELD (*syn), info,
263 				 fields, CGEN_INSN_ATTRS (insn), pc, length);
264     }
265 }
266 
267 /* Subroutine of print_insn. Reads an insn into the given buffers and updates
268    the extract info.
269    Returns 0 if all is well, non-zero otherwise.  */
270 
271 static int
272 read_insn (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
273 	   bfd_vma pc,
274 	   disassemble_info *info,
275 	   bfd_byte *buf,
276 	   int buflen,
277 	   CGEN_EXTRACT_INFO *ex_info,
278 	   unsigned long *insn_value)
279 {
280   int status = (*info->read_memory_func) (pc, buf, buflen, info);
281 
282   if (status != 0)
283     {
284       (*info->memory_error_func) (status, pc, info);
285       return -1;
286     }
287 
288   ex_info->dis_info = info;
289   ex_info->valid = (1 << buflen) - 1;
290   ex_info->insn_bytes = buf;
291 
292   *insn_value = bfd_get_bits (buf, buflen * 8, info->endian == BFD_ENDIAN_BIG);
293   return 0;
294 }
295 
296 /* Utility to print an insn.
297    BUF is the base part of the insn, target byte order, BUFLEN bytes long.
298    The result is the size of the insn in bytes or zero for an unknown insn
299    or -1 if an error occurs fetching data (memory_error_func will have
300    been called).  */
301 
302 static int
303 print_insn (CGEN_CPU_DESC cd,
304 	    bfd_vma pc,
305 	    disassemble_info *info,
306 	    bfd_byte *buf,
307 	    unsigned int buflen)
308 {
309   CGEN_INSN_INT insn_value;
310   const CGEN_INSN_LIST *insn_list;
311   CGEN_EXTRACT_INFO ex_info;
312   int basesize;
313 
314   /* Extract base part of instruction, just in case CGEN_DIS_* uses it. */
315   basesize = cd->base_insn_bitsize < buflen * 8 ?
316                                      cd->base_insn_bitsize : buflen * 8;
317   insn_value = cgen_get_insn_value (cd, buf, basesize);
318 
319 
320   /* Fill in ex_info fields like read_insn would.  Don't actually call
321      read_insn, since the incoming buffer is already read (and possibly
322      modified a la m32r).  */
323   ex_info.valid = (1 << buflen) - 1;
324   ex_info.dis_info = info;
325   ex_info.insn_bytes = buf;
326 
327   /* The instructions are stored in hash lists.
328      Pick the first one and keep trying until we find the right one.  */
329 
330   insn_list = CGEN_DIS_LOOKUP_INSN (cd, (char *) buf, insn_value);
331   while (insn_list != NULL)
332     {
333       const CGEN_INSN *insn = insn_list->insn;
334       CGEN_FIELDS fields;
335       int length;
336       unsigned long insn_value_cropped;
337 
338 #ifdef CGEN_VALIDATE_INSN_SUPPORTED
339       /* Not needed as insn shouldn't be in hash lists if not supported.  */
340       /* Supported by this cpu?  */
341       if (! or1k_cgen_insn_supported (cd, insn))
342         {
343           insn_list = CGEN_DIS_NEXT_INSN (insn_list);
344 	  continue;
345         }
346 #endif
347 
348       /* Basic bit mask must be correct.  */
349       /* ??? May wish to allow target to defer this check until the extract
350 	 handler.  */
351 
352       /* Base size may exceed this instruction's size.  Extract the
353          relevant part from the buffer. */
354       if ((unsigned) (CGEN_INSN_BITSIZE (insn) / 8) < buflen &&
355 	  (unsigned) (CGEN_INSN_BITSIZE (insn) / 8) <= sizeof (unsigned long))
356 	insn_value_cropped = bfd_get_bits (buf, CGEN_INSN_BITSIZE (insn),
357 					   info->endian == BFD_ENDIAN_BIG);
358       else
359 	insn_value_cropped = insn_value;
360 
361       if ((insn_value_cropped & CGEN_INSN_BASE_MASK (insn))
362 	  == CGEN_INSN_BASE_VALUE (insn))
363 	{
364 	  /* Printing is handled in two passes.  The first pass parses the
365 	     machine insn and extracts the fields.  The second pass prints
366 	     them.  */
367 
368 	  /* Make sure the entire insn is loaded into insn_value, if it
369 	     can fit.  */
370 	  if (((unsigned) CGEN_INSN_BITSIZE (insn) > cd->base_insn_bitsize) &&
371 	      (unsigned) (CGEN_INSN_BITSIZE (insn) / 8) <= sizeof (unsigned long))
372 	    {
373 	      unsigned long full_insn_value;
374 	      int rc = read_insn (cd, pc, info, buf,
375 				  CGEN_INSN_BITSIZE (insn) / 8,
376 				  & ex_info, & full_insn_value);
377 	      if (rc != 0)
378 		return rc;
379 	      length = CGEN_EXTRACT_FN (cd, insn)
380 		(cd, insn, &ex_info, full_insn_value, &fields, pc);
381 	    }
382 	  else
383 	    length = CGEN_EXTRACT_FN (cd, insn)
384 	      (cd, insn, &ex_info, insn_value_cropped, &fields, pc);
385 
386 	  /* Length < 0 -> error.  */
387 	  if (length < 0)
388 	    return length;
389 	  if (length > 0)
390 	    {
391 	      CGEN_PRINT_FN (cd, insn) (cd, info, insn, &fields, pc, length);
392 	      /* Length is in bits, result is in bytes.  */
393 	      return length / 8;
394 	    }
395 	}
396 
397       insn_list = CGEN_DIS_NEXT_INSN (insn_list);
398     }
399 
400   return 0;
401 }
402 
403 /* Default value for CGEN_PRINT_INSN.
404    The result is the size of the insn in bytes or zero for an unknown insn
405    or -1 if an error occured fetching bytes.  */
406 
407 #ifndef CGEN_PRINT_INSN
408 #define CGEN_PRINT_INSN default_print_insn
409 #endif
410 
411 static int
412 default_print_insn (CGEN_CPU_DESC cd, bfd_vma pc, disassemble_info *info)
413 {
414   bfd_byte buf[CGEN_MAX_INSN_SIZE];
415   int buflen;
416   int status;
417 
418   /* Attempt to read the base part of the insn.  */
419   buflen = cd->base_insn_bitsize / 8;
420   status = (*info->read_memory_func) (pc, buf, buflen, info);
421 
422   /* Try again with the minimum part, if min < base.  */
423   if (status != 0 && (cd->min_insn_bitsize < cd->base_insn_bitsize))
424     {
425       buflen = cd->min_insn_bitsize / 8;
426       status = (*info->read_memory_func) (pc, buf, buflen, info);
427     }
428 
429   if (status != 0)
430     {
431       (*info->memory_error_func) (status, pc, info);
432       return -1;
433     }
434 
435   return print_insn (cd, pc, info, buf, buflen);
436 }
437 
438 /* Main entry point.
439    Print one instruction from PC on INFO->STREAM.
440    Return the size of the instruction (in bytes).  */
441 
442 typedef struct cpu_desc_list
443 {
444   struct cpu_desc_list *next;
445   CGEN_BITSET *isa;
446   int mach;
447   int endian;
448   CGEN_CPU_DESC cd;
449 } cpu_desc_list;
450 
451 int
452 print_insn_or1k (bfd_vma pc, disassemble_info *info)
453 {
454   static cpu_desc_list *cd_list = 0;
455   cpu_desc_list *cl = 0;
456   static CGEN_CPU_DESC cd = 0;
457   static CGEN_BITSET *prev_isa;
458   static int prev_mach;
459   static int prev_endian;
460   int length;
461   CGEN_BITSET *isa;
462   int mach;
463   int endian = (info->endian == BFD_ENDIAN_BIG
464 		? CGEN_ENDIAN_BIG
465 		: CGEN_ENDIAN_LITTLE);
466   enum bfd_architecture arch;
467 
468   /* ??? gdb will set mach but leave the architecture as "unknown" */
469 #ifndef CGEN_BFD_ARCH
470 #define CGEN_BFD_ARCH bfd_arch_or1k
471 #endif
472   arch = info->arch;
473   if (arch == bfd_arch_unknown)
474     arch = CGEN_BFD_ARCH;
475 
476   /* There's no standard way to compute the machine or isa number
477      so we leave it to the target.  */
478 #ifdef CGEN_COMPUTE_MACH
479   mach = CGEN_COMPUTE_MACH (info);
480 #else
481   mach = info->mach;
482 #endif
483 
484 #ifdef CGEN_COMPUTE_ISA
485   {
486     static CGEN_BITSET *permanent_isa;
487 
488     if (!permanent_isa)
489       permanent_isa = cgen_bitset_create (MAX_ISAS);
490     isa = permanent_isa;
491     cgen_bitset_clear (isa);
492     cgen_bitset_add (isa, CGEN_COMPUTE_ISA (info));
493   }
494 #else
495   isa = info->insn_sets;
496 #endif
497 
498   /* If we've switched cpu's, try to find a handle we've used before */
499   if (cd
500       && (cgen_bitset_compare (isa, prev_isa) != 0
501 	  || mach != prev_mach
502 	  || endian != prev_endian))
503     {
504       cd = 0;
505       for (cl = cd_list; cl; cl = cl->next)
506 	{
507 	  if (cgen_bitset_compare (cl->isa, isa) == 0 &&
508 	      cl->mach == mach &&
509 	      cl->endian == endian)
510 	    {
511 	      cd = cl->cd;
512  	      prev_isa = cd->isas;
513 	      break;
514 	    }
515 	}
516     }
517 
518   /* If we haven't initialized yet, initialize the opcode table.  */
519   if (! cd)
520     {
521       const bfd_arch_info_type *arch_type = bfd_lookup_arch (arch, mach);
522       const char *mach_name;
523 
524       if (!arch_type)
525 	abort ();
526       mach_name = arch_type->printable_name;
527 
528       prev_isa = cgen_bitset_copy (isa);
529       prev_mach = mach;
530       prev_endian = endian;
531       cd = or1k_cgen_cpu_open (CGEN_CPU_OPEN_ISAS, prev_isa,
532 				 CGEN_CPU_OPEN_BFDMACH, mach_name,
533 				 CGEN_CPU_OPEN_ENDIAN, prev_endian,
534 				 CGEN_CPU_OPEN_END);
535       if (!cd)
536 	abort ();
537 
538       /* Save this away for future reference.  */
539       cl = xmalloc (sizeof (struct cpu_desc_list));
540       cl->cd = cd;
541       cl->isa = prev_isa;
542       cl->mach = mach;
543       cl->endian = endian;
544       cl->next = cd_list;
545       cd_list = cl;
546 
547       or1k_cgen_init_dis (cd);
548     }
549 
550   /* We try to have as much common code as possible.
551      But at this point some targets need to take over.  */
552   /* ??? Some targets may need a hook elsewhere.  Try to avoid this,
553      but if not possible try to move this hook elsewhere rather than
554      have two hooks.  */
555   length = CGEN_PRINT_INSN (cd, pc, info);
556   if (length > 0)
557     return length;
558   if (length < 0)
559     return -1;
560 
561   (*info->fprintf_func) (info->stream, UNKNOWN_INSN_MSG);
562   return cd->default_insn_bitsize / 8;
563 }
564