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