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