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 "frv-desc.h"
37#include "frv-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 */
62static void
63print_at (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
64	  void * dis_info,
65	  long reloc_ann ATTRIBUTE_UNUSED,
66	  long value ATTRIBUTE_UNUSED,
67	  bfd_vma pc ATTRIBUTE_UNUSED,
68	  int length ATTRIBUTE_UNUSED)
69{
70  disassemble_info *info = (disassemble_info *) dis_info;
71
72  (*info->fprintf_func) (info->stream, "@");
73}
74
75static void
76print_spr (CGEN_CPU_DESC cd,
77	   void * dis_info,
78	   CGEN_KEYWORD *names,
79	   long regno,
80	   unsigned int attrs)
81{
82  /* Use the register index format for any unnamed registers.  */
83  if (cgen_keyword_lookup_value (names, regno) == NULL)
84    {
85      disassemble_info *info = (disassemble_info *) dis_info;
86      (*info->fprintf_func) (info->stream, "spr[%ld]", regno);
87    }
88  else
89    print_keyword (cd, dis_info, names, regno, attrs);
90}
91
92static void
93print_hi (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
94	  void * dis_info,
95	  long value,
96	  unsigned int attrs ATTRIBUTE_UNUSED,
97	  bfd_vma pc ATTRIBUTE_UNUSED,
98	  int length ATTRIBUTE_UNUSED)
99{
100  disassemble_info *info = (disassemble_info *) dis_info;
101
102  (*info->fprintf_func) (info->stream, value ? "0x%lx" : "hi(0x%lx)", value);
103}
104
105static void
106print_lo (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
107	  void * dis_info,
108	  long value,
109	  unsigned int attrs ATTRIBUTE_UNUSED,
110	  bfd_vma pc ATTRIBUTE_UNUSED,
111	  int length ATTRIBUTE_UNUSED)
112{
113  disassemble_info *info = (disassemble_info *) dis_info;
114  if (value)
115    (*info->fprintf_func) (info->stream, "0x%lx", value);
116  else
117    (*info->fprintf_func) (info->stream, "lo(0x%lx)", value);
118}
119
120/* -- */
121
122void frv_cgen_print_operand
123  (CGEN_CPU_DESC, int, void *, CGEN_FIELDS *, void const *, bfd_vma, int);
124
125/* Main entry point for printing operands.
126   XINFO is a `void *' and not a `disassemble_info *' to not put a requirement
127   of dis-asm.h on cgen.h.
128
129   This function is basically just a big switch statement.  Earlier versions
130   used tables to look up the function to use, but
131   - if the table contains both assembler and disassembler functions then
132     the disassembler contains much of the assembler and vice-versa,
133   - there's a lot of inlining possibilities as things grow,
134   - using a switch statement avoids the function call overhead.
135
136   This function could be moved into `print_insn_normal', but keeping it
137   separate makes clear the interface between `print_insn_normal' and each of
138   the handlers.  */
139
140void
141frv_cgen_print_operand (CGEN_CPU_DESC cd,
142			   int opindex,
143			   void * xinfo,
144			   CGEN_FIELDS *fields,
145			   void const *attrs ATTRIBUTE_UNUSED,
146			   bfd_vma pc,
147			   int length)
148{
149  disassemble_info *info = (disassemble_info *) xinfo;
150
151  switch (opindex)
152    {
153    case FRV_OPERAND_A0 :
154      print_normal (cd, info, fields->f_A, 0, pc, length);
155      break;
156    case FRV_OPERAND_A1 :
157      print_normal (cd, info, fields->f_A, 0, pc, length);
158      break;
159    case FRV_OPERAND_ACC40SI :
160      print_keyword (cd, info, & frv_cgen_opval_acc_names, fields->f_ACC40Si, 0);
161      break;
162    case FRV_OPERAND_ACC40SK :
163      print_keyword (cd, info, & frv_cgen_opval_acc_names, fields->f_ACC40Sk, 0);
164      break;
165    case FRV_OPERAND_ACC40UI :
166      print_keyword (cd, info, & frv_cgen_opval_acc_names, fields->f_ACC40Ui, 0);
167      break;
168    case FRV_OPERAND_ACC40UK :
169      print_keyword (cd, info, & frv_cgen_opval_acc_names, fields->f_ACC40Uk, 0);
170      break;
171    case FRV_OPERAND_ACCGI :
172      print_keyword (cd, info, & frv_cgen_opval_accg_names, fields->f_ACCGi, 0);
173      break;
174    case FRV_OPERAND_ACCGK :
175      print_keyword (cd, info, & frv_cgen_opval_accg_names, fields->f_ACCGk, 0);
176      break;
177    case FRV_OPERAND_CCI :
178      print_keyword (cd, info, & frv_cgen_opval_cccr_names, fields->f_CCi, 0);
179      break;
180    case FRV_OPERAND_CPRDOUBLEK :
181      print_keyword (cd, info, & frv_cgen_opval_cpr_names, fields->f_CPRk, 0);
182      break;
183    case FRV_OPERAND_CPRI :
184      print_keyword (cd, info, & frv_cgen_opval_cpr_names, fields->f_CPRi, 0);
185      break;
186    case FRV_OPERAND_CPRJ :
187      print_keyword (cd, info, & frv_cgen_opval_cpr_names, fields->f_CPRj, 0);
188      break;
189    case FRV_OPERAND_CPRK :
190      print_keyword (cd, info, & frv_cgen_opval_cpr_names, fields->f_CPRk, 0);
191      break;
192    case FRV_OPERAND_CRI :
193      print_keyword (cd, info, & frv_cgen_opval_cccr_names, fields->f_CRi, 0);
194      break;
195    case FRV_OPERAND_CRJ :
196      print_keyword (cd, info, & frv_cgen_opval_cccr_names, fields->f_CRj, 0);
197      break;
198    case FRV_OPERAND_CRJ_FLOAT :
199      print_keyword (cd, info, & frv_cgen_opval_cccr_names, fields->f_CRj_float, 0);
200      break;
201    case FRV_OPERAND_CRJ_INT :
202      print_keyword (cd, info, & frv_cgen_opval_cccr_names, fields->f_CRj_int, 0);
203      break;
204    case FRV_OPERAND_CRK :
205      print_keyword (cd, info, & frv_cgen_opval_cccr_names, fields->f_CRk, 0);
206      break;
207    case FRV_OPERAND_FCCI_1 :
208      print_keyword (cd, info, & frv_cgen_opval_fccr_names, fields->f_FCCi_1, 0);
209      break;
210    case FRV_OPERAND_FCCI_2 :
211      print_keyword (cd, info, & frv_cgen_opval_fccr_names, fields->f_FCCi_2, 0);
212      break;
213    case FRV_OPERAND_FCCI_3 :
214      print_keyword (cd, info, & frv_cgen_opval_fccr_names, fields->f_FCCi_3, 0);
215      break;
216    case FRV_OPERAND_FCCK :
217      print_keyword (cd, info, & frv_cgen_opval_fccr_names, fields->f_FCCk, 0);
218      break;
219    case FRV_OPERAND_FRDOUBLEI :
220      print_keyword (cd, info, & frv_cgen_opval_fr_names, fields->f_FRi, 0);
221      break;
222    case FRV_OPERAND_FRDOUBLEJ :
223      print_keyword (cd, info, & frv_cgen_opval_fr_names, fields->f_FRj, 0);
224      break;
225    case FRV_OPERAND_FRDOUBLEK :
226      print_keyword (cd, info, & frv_cgen_opval_fr_names, fields->f_FRk, 0);
227      break;
228    case FRV_OPERAND_FRI :
229      print_keyword (cd, info, & frv_cgen_opval_fr_names, fields->f_FRi, 0);
230      break;
231    case FRV_OPERAND_FRINTI :
232      print_keyword (cd, info, & frv_cgen_opval_fr_names, fields->f_FRi, 0);
233      break;
234    case FRV_OPERAND_FRINTIEVEN :
235      print_keyword (cd, info, & frv_cgen_opval_fr_names, fields->f_FRi, 0);
236      break;
237    case FRV_OPERAND_FRINTJ :
238      print_keyword (cd, info, & frv_cgen_opval_fr_names, fields->f_FRj, 0);
239      break;
240    case FRV_OPERAND_FRINTJEVEN :
241      print_keyword (cd, info, & frv_cgen_opval_fr_names, fields->f_FRj, 0);
242      break;
243    case FRV_OPERAND_FRINTK :
244      print_keyword (cd, info, & frv_cgen_opval_fr_names, fields->f_FRk, 0);
245      break;
246    case FRV_OPERAND_FRINTKEVEN :
247      print_keyword (cd, info, & frv_cgen_opval_fr_names, fields->f_FRk, 0);
248      break;
249    case FRV_OPERAND_FRJ :
250      print_keyword (cd, info, & frv_cgen_opval_fr_names, fields->f_FRj, 0);
251      break;
252    case FRV_OPERAND_FRK :
253      print_keyword (cd, info, & frv_cgen_opval_fr_names, fields->f_FRk, 0);
254      break;
255    case FRV_OPERAND_FRKHI :
256      print_keyword (cd, info, & frv_cgen_opval_fr_names, fields->f_FRk, 0);
257      break;
258    case FRV_OPERAND_FRKLO :
259      print_keyword (cd, info, & frv_cgen_opval_fr_names, fields->f_FRk, 0);
260      break;
261    case FRV_OPERAND_GRDOUBLEK :
262      print_keyword (cd, info, & frv_cgen_opval_gr_names, fields->f_GRk, 0);
263      break;
264    case FRV_OPERAND_GRI :
265      print_keyword (cd, info, & frv_cgen_opval_gr_names, fields->f_GRi, 0);
266      break;
267    case FRV_OPERAND_GRJ :
268      print_keyword (cd, info, & frv_cgen_opval_gr_names, fields->f_GRj, 0);
269      break;
270    case FRV_OPERAND_GRK :
271      print_keyword (cd, info, & frv_cgen_opval_gr_names, fields->f_GRk, 0);
272      break;
273    case FRV_OPERAND_GRKHI :
274      print_keyword (cd, info, & frv_cgen_opval_gr_names, fields->f_GRk, 0);
275      break;
276    case FRV_OPERAND_GRKLO :
277      print_keyword (cd, info, & frv_cgen_opval_gr_names, fields->f_GRk, 0);
278      break;
279    case FRV_OPERAND_ICCI_1 :
280      print_keyword (cd, info, & frv_cgen_opval_iccr_names, fields->f_ICCi_1, 0);
281      break;
282    case FRV_OPERAND_ICCI_2 :
283      print_keyword (cd, info, & frv_cgen_opval_iccr_names, fields->f_ICCi_2, 0);
284      break;
285    case FRV_OPERAND_ICCI_3 :
286      print_keyword (cd, info, & frv_cgen_opval_iccr_names, fields->f_ICCi_3, 0);
287      break;
288    case FRV_OPERAND_LI :
289      print_normal (cd, info, fields->f_LI, 0, pc, length);
290      break;
291    case FRV_OPERAND_LRAD :
292      print_normal (cd, info, fields->f_LRAD, 0, pc, length);
293      break;
294    case FRV_OPERAND_LRAE :
295      print_normal (cd, info, fields->f_LRAE, 0, pc, length);
296      break;
297    case FRV_OPERAND_LRAS :
298      print_normal (cd, info, fields->f_LRAS, 0, pc, length);
299      break;
300    case FRV_OPERAND_TLBPRL :
301      print_normal (cd, info, fields->f_TLBPRL, 0, pc, length);
302      break;
303    case FRV_OPERAND_TLBPROPX :
304      print_normal (cd, info, fields->f_TLBPRopx, 0, pc, length);
305      break;
306    case FRV_OPERAND_AE :
307      print_normal (cd, info, fields->f_ae, 0|(1<<CGEN_OPERAND_HASH_PREFIX), pc, length);
308      break;
309    case FRV_OPERAND_CALLANN :
310      print_at (cd, info, fields->f_reloc_ann, 0, pc, length);
311      break;
312    case FRV_OPERAND_CCOND :
313      print_normal (cd, info, fields->f_ccond, 0|(1<<CGEN_OPERAND_HASH_PREFIX), pc, length);
314      break;
315    case FRV_OPERAND_COND :
316      print_normal (cd, info, fields->f_cond, 0|(1<<CGEN_OPERAND_HASH_PREFIX), pc, length);
317      break;
318    case FRV_OPERAND_D12 :
319      print_normal (cd, info, fields->f_d12, 0|(1<<CGEN_OPERAND_SIGNED), pc, length);
320      break;
321    case FRV_OPERAND_DEBUG :
322      print_normal (cd, info, fields->f_debug, 0|(1<<CGEN_OPERAND_HASH_PREFIX), pc, length);
323      break;
324    case FRV_OPERAND_EIR :
325      print_normal (cd, info, fields->f_eir, 0, pc, length);
326      break;
327    case FRV_OPERAND_HINT :
328      print_normal (cd, info, fields->f_hint, 0|(1<<CGEN_OPERAND_HASH_PREFIX), pc, length);
329      break;
330    case FRV_OPERAND_HINT_NOT_TAKEN :
331      print_keyword (cd, info, & frv_cgen_opval_h_hint_not_taken, fields->f_hint, 0);
332      break;
333    case FRV_OPERAND_HINT_TAKEN :
334      print_keyword (cd, info, & frv_cgen_opval_h_hint_taken, fields->f_hint, 0);
335      break;
336    case FRV_OPERAND_LABEL16 :
337      print_address (cd, info, fields->f_label16, 0|(1<<CGEN_OPERAND_PCREL_ADDR), pc, length);
338      break;
339    case FRV_OPERAND_LABEL24 :
340      print_address (cd, info, fields->f_label24, 0|(1<<CGEN_OPERAND_PCREL_ADDR)|(1<<CGEN_OPERAND_VIRTUAL), pc, length);
341      break;
342    case FRV_OPERAND_LDANN :
343      print_at (cd, info, fields->f_reloc_ann, 0, pc, length);
344      break;
345    case FRV_OPERAND_LDDANN :
346      print_at (cd, info, fields->f_reloc_ann, 0, pc, length);
347      break;
348    case FRV_OPERAND_LOCK :
349      print_normal (cd, info, fields->f_lock, 0|(1<<CGEN_OPERAND_HASH_PREFIX), pc, length);
350      break;
351    case FRV_OPERAND_PACK :
352      print_keyword (cd, info, & frv_cgen_opval_h_pack, fields->f_pack, 0);
353      break;
354    case FRV_OPERAND_S10 :
355      print_normal (cd, info, fields->f_s10, 0|(1<<CGEN_OPERAND_SIGNED)|(1<<CGEN_OPERAND_HASH_PREFIX), pc, length);
356      break;
357    case FRV_OPERAND_S12 :
358      print_normal (cd, info, fields->f_d12, 0|(1<<CGEN_OPERAND_SIGNED)|(1<<CGEN_OPERAND_HASH_PREFIX), pc, length);
359      break;
360    case FRV_OPERAND_S16 :
361      print_normal (cd, info, fields->f_s16, 0|(1<<CGEN_OPERAND_SIGNED)|(1<<CGEN_OPERAND_HASH_PREFIX), pc, length);
362      break;
363    case FRV_OPERAND_S5 :
364      print_normal (cd, info, fields->f_s5, 0|(1<<CGEN_OPERAND_SIGNED)|(1<<CGEN_OPERAND_HASH_PREFIX), pc, length);
365      break;
366    case FRV_OPERAND_S6 :
367      print_normal (cd, info, fields->f_s6, 0|(1<<CGEN_OPERAND_SIGNED)|(1<<CGEN_OPERAND_HASH_PREFIX), pc, length);
368      break;
369    case FRV_OPERAND_S6_1 :
370      print_normal (cd, info, fields->f_s6_1, 0|(1<<CGEN_OPERAND_SIGNED)|(1<<CGEN_OPERAND_HASH_PREFIX), pc, length);
371      break;
372    case FRV_OPERAND_SLO16 :
373      print_lo (cd, info, fields->f_s16, 0|(1<<CGEN_OPERAND_SIGNED), pc, length);
374      break;
375    case FRV_OPERAND_SPR :
376      print_spr (cd, info, & frv_cgen_opval_spr_names, fields->f_spr, 0|(1<<CGEN_OPERAND_VIRTUAL));
377      break;
378    case FRV_OPERAND_U12 :
379      print_normal (cd, info, fields->f_u12, 0|(1<<CGEN_OPERAND_SIGNED)|(1<<CGEN_OPERAND_HASH_PREFIX)|(1<<CGEN_OPERAND_VIRTUAL), pc, length);
380      break;
381    case FRV_OPERAND_U16 :
382      print_normal (cd, info, fields->f_u16, 0|(1<<CGEN_OPERAND_HASH_PREFIX), pc, length);
383      break;
384    case FRV_OPERAND_U6 :
385      print_normal (cd, info, fields->f_u6, 0|(1<<CGEN_OPERAND_HASH_PREFIX), pc, length);
386      break;
387    case FRV_OPERAND_UHI16 :
388      print_hi (cd, info, fields->f_u16, 0, pc, length);
389      break;
390    case FRV_OPERAND_ULO16 :
391      print_lo (cd, info, fields->f_u16, 0, pc, length);
392      break;
393
394    default :
395      /* xgettext:c-format */
396      opcodes_error_handler
397	(_("internal error: unrecognized field %d while printing insn"),
398	 opindex);
399      abort ();
400  }
401}
402
403cgen_print_fn * const frv_cgen_print_handlers[] =
404{
405  print_insn_normal,
406};
407
408
409void
410frv_cgen_init_dis (CGEN_CPU_DESC cd)
411{
412  frv_cgen_init_opcode_table (cd);
413  frv_cgen_init_ibld_table (cd);
414  cd->print_handlers = & frv_cgen_print_handlers[0];
415  cd->print_operand = frv_cgen_print_operand;
416}
417
418
419/* Default print handler.  */
420
421static void
422print_normal (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
423	      void *dis_info,
424	      long value,
425	      unsigned int attrs,
426	      bfd_vma pc ATTRIBUTE_UNUSED,
427	      int length ATTRIBUTE_UNUSED)
428{
429  disassemble_info *info = (disassemble_info *) dis_info;
430
431  /* Print the operand as directed by the attributes.  */
432  if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SEM_ONLY))
433    ; /* nothing to do */
434  else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SIGNED))
435    (*info->fprintf_func) (info->stream, "%ld", value);
436  else
437    (*info->fprintf_func) (info->stream, "0x%lx", value);
438}
439
440/* Default address handler.  */
441
442static void
443print_address (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
444	       void *dis_info,
445	       bfd_vma value,
446	       unsigned int attrs,
447	       bfd_vma pc ATTRIBUTE_UNUSED,
448	       int length ATTRIBUTE_UNUSED)
449{
450  disassemble_info *info = (disassemble_info *) dis_info;
451
452  /* Print the operand as directed by the attributes.  */
453  if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SEM_ONLY))
454    ; /* Nothing to do.  */
455  else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_PCREL_ADDR))
456    (*info->print_address_func) (value, info);
457  else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_ABS_ADDR))
458    (*info->print_address_func) (value, info);
459  else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SIGNED))
460    (*info->fprintf_func) (info->stream, "%ld", (long) value);
461  else
462    (*info->fprintf_func) (info->stream, "0x%lx", (long) value);
463}
464
465/* Keyword print handler.  */
466
467static void
468print_keyword (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
469	       void *dis_info,
470	       CGEN_KEYWORD *keyword_table,
471	       long value,
472	       unsigned int attrs ATTRIBUTE_UNUSED)
473{
474  disassemble_info *info = (disassemble_info *) dis_info;
475  const CGEN_KEYWORD_ENTRY *ke;
476
477  ke = cgen_keyword_lookup_value (keyword_table, value);
478  if (ke != NULL)
479    (*info->fprintf_func) (info->stream, "%s", ke->name);
480  else
481    (*info->fprintf_func) (info->stream, "???");
482}
483
484/* Default insn printer.
485
486   DIS_INFO is defined as `void *' so the disassembler needn't know anything
487   about disassemble_info.  */
488
489static void
490print_insn_normal (CGEN_CPU_DESC cd,
491		   void *dis_info,
492		   const CGEN_INSN *insn,
493		   CGEN_FIELDS *fields,
494		   bfd_vma pc,
495		   int length)
496{
497  const CGEN_SYNTAX *syntax = CGEN_INSN_SYNTAX (insn);
498  disassemble_info *info = (disassemble_info *) dis_info;
499  const CGEN_SYNTAX_CHAR_TYPE *syn;
500
501  CGEN_INIT_PRINT (cd);
502
503  for (syn = CGEN_SYNTAX_STRING (syntax); *syn; ++syn)
504    {
505      if (CGEN_SYNTAX_MNEMONIC_P (*syn))
506	{
507	  (*info->fprintf_func) (info->stream, "%s", CGEN_INSN_MNEMONIC (insn));
508	  continue;
509	}
510      if (CGEN_SYNTAX_CHAR_P (*syn))
511	{
512	  (*info->fprintf_func) (info->stream, "%c", CGEN_SYNTAX_CHAR (*syn));
513	  continue;
514	}
515
516      /* We have an operand.  */
517      frv_cgen_print_operand (cd, CGEN_SYNTAX_FIELD (*syn), info,
518				 fields, CGEN_INSN_ATTRS (insn), pc, length);
519    }
520}
521
522/* Subroutine of print_insn. Reads an insn into the given buffers and updates
523   the extract info.
524   Returns 0 if all is well, non-zero otherwise.  */
525
526static int
527read_insn (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
528	   bfd_vma pc,
529	   disassemble_info *info,
530	   bfd_byte *buf,
531	   int buflen,
532	   CGEN_EXTRACT_INFO *ex_info,
533	   unsigned long *insn_value)
534{
535  int status = (*info->read_memory_func) (pc, buf, buflen, info);
536
537  if (status != 0)
538    {
539      (*info->memory_error_func) (status, pc, info);
540      return -1;
541    }
542
543  ex_info->dis_info = info;
544  ex_info->valid = (1 << buflen) - 1;
545  ex_info->insn_bytes = buf;
546
547  *insn_value = bfd_get_bits (buf, buflen * 8, info->endian == BFD_ENDIAN_BIG);
548  return 0;
549}
550
551/* Utility to print an insn.
552   BUF is the base part of the insn, target byte order, BUFLEN bytes long.
553   The result is the size of the insn in bytes or zero for an unknown insn
554   or -1 if an error occurs fetching data (memory_error_func will have
555   been called).  */
556
557static int
558print_insn (CGEN_CPU_DESC cd,
559	    bfd_vma pc,
560	    disassemble_info *info,
561	    bfd_byte *buf,
562	    unsigned int buflen)
563{
564  CGEN_INSN_INT insn_value;
565  const CGEN_INSN_LIST *insn_list;
566  CGEN_EXTRACT_INFO ex_info;
567  int basesize;
568
569  /* Extract base part of instruction, just in case CGEN_DIS_* uses it. */
570  basesize = cd->base_insn_bitsize < buflen * 8 ?
571                                     cd->base_insn_bitsize : buflen * 8;
572  insn_value = cgen_get_insn_value (cd, buf, basesize, cd->insn_endian);
573
574
575  /* Fill in ex_info fields like read_insn would.  Don't actually call
576     read_insn, since the incoming buffer is already read (and possibly
577     modified a la m32r).  */
578  ex_info.valid = (1 << buflen) - 1;
579  ex_info.dis_info = info;
580  ex_info.insn_bytes = buf;
581
582  /* The instructions are stored in hash lists.
583     Pick the first one and keep trying until we find the right one.  */
584
585  insn_list = CGEN_DIS_LOOKUP_INSN (cd, (char *) buf, insn_value);
586  while (insn_list != NULL)
587    {
588      const CGEN_INSN *insn = insn_list->insn;
589      CGEN_FIELDS fields;
590      int length;
591      unsigned long insn_value_cropped;
592
593#ifdef CGEN_VALIDATE_INSN_SUPPORTED
594      /* Not needed as insn shouldn't be in hash lists if not supported.  */
595      /* Supported by this cpu?  */
596      if (! frv_cgen_insn_supported (cd, insn))
597        {
598          insn_list = CGEN_DIS_NEXT_INSN (insn_list);
599	  continue;
600        }
601#endif
602
603      /* Basic bit mask must be correct.  */
604      /* ??? May wish to allow target to defer this check until the extract
605	 handler.  */
606
607      /* Base size may exceed this instruction's size.  Extract the
608         relevant part from the buffer. */
609      if ((unsigned) (CGEN_INSN_BITSIZE (insn) / 8) < buflen &&
610	  (unsigned) (CGEN_INSN_BITSIZE (insn) / 8) <= sizeof (unsigned long))
611	insn_value_cropped = bfd_get_bits (buf, CGEN_INSN_BITSIZE (insn),
612					   info->endian == BFD_ENDIAN_BIG);
613      else
614	insn_value_cropped = insn_value;
615
616      if ((insn_value_cropped & CGEN_INSN_BASE_MASK (insn))
617	  == CGEN_INSN_BASE_VALUE (insn))
618	{
619	  /* Printing is handled in two passes.  The first pass parses the
620	     machine insn and extracts the fields.  The second pass prints
621	     them.  */
622
623	  /* Make sure the entire insn is loaded into insn_value, if it
624	     can fit.  */
625	  if (((unsigned) CGEN_INSN_BITSIZE (insn) > cd->base_insn_bitsize) &&
626	      (unsigned) (CGEN_INSN_BITSIZE (insn) / 8) <= sizeof (unsigned long))
627	    {
628	      unsigned long full_insn_value;
629	      int rc = read_insn (cd, pc, info, buf,
630				  CGEN_INSN_BITSIZE (insn) / 8,
631				  & ex_info, & full_insn_value);
632	      if (rc != 0)
633		return rc;
634	      length = CGEN_EXTRACT_FN (cd, insn)
635		(cd, insn, &ex_info, full_insn_value, &fields, pc);
636	    }
637	  else
638	    length = CGEN_EXTRACT_FN (cd, insn)
639	      (cd, insn, &ex_info, insn_value_cropped, &fields, pc);
640
641	  /* Length < 0 -> error.  */
642	  if (length < 0)
643	    return length;
644	  if (length > 0)
645	    {
646	      CGEN_PRINT_FN (cd, insn) (cd, info, insn, &fields, pc, length);
647	      /* Length is in bits, result is in bytes.  */
648	      return length / 8;
649	    }
650	}
651
652      insn_list = CGEN_DIS_NEXT_INSN (insn_list);
653    }
654
655  return 0;
656}
657
658/* Default value for CGEN_PRINT_INSN.
659   The result is the size of the insn in bytes or zero for an unknown insn
660   or -1 if an error occured fetching bytes.  */
661
662#ifndef CGEN_PRINT_INSN
663#define CGEN_PRINT_INSN default_print_insn
664#endif
665
666static int
667default_print_insn (CGEN_CPU_DESC cd, bfd_vma pc, disassemble_info *info)
668{
669  bfd_byte buf[CGEN_MAX_INSN_SIZE];
670  int buflen;
671  int status;
672
673  /* Attempt to read the base part of the insn.  */
674  buflen = cd->base_insn_bitsize / 8;
675  status = (*info->read_memory_func) (pc, buf, buflen, info);
676
677  /* Try again with the minimum part, if min < base.  */
678  if (status != 0 && (cd->min_insn_bitsize < cd->base_insn_bitsize))
679    {
680      buflen = cd->min_insn_bitsize / 8;
681      status = (*info->read_memory_func) (pc, buf, buflen, info);
682    }
683
684  if (status != 0)
685    {
686      (*info->memory_error_func) (status, pc, info);
687      return -1;
688    }
689
690  return print_insn (cd, pc, info, buf, buflen);
691}
692
693/* Main entry point.
694   Print one instruction from PC on INFO->STREAM.
695   Return the size of the instruction (in bytes).  */
696
697typedef struct cpu_desc_list
698{
699  struct cpu_desc_list *next;
700  CGEN_BITSET *isa;
701  int mach;
702  int endian;
703  int insn_endian;
704  CGEN_CPU_DESC cd;
705} cpu_desc_list;
706
707int
708print_insn_frv (bfd_vma pc, disassemble_info *info)
709{
710  static cpu_desc_list *cd_list = 0;
711  cpu_desc_list *cl = 0;
712  static CGEN_CPU_DESC cd = 0;
713  static CGEN_BITSET *prev_isa;
714  static int prev_mach;
715  static int prev_endian;
716  static int prev_insn_endian;
717  int length;
718  CGEN_BITSET *isa;
719  int mach;
720  int endian = (info->endian == BFD_ENDIAN_BIG
721		? CGEN_ENDIAN_BIG
722		: CGEN_ENDIAN_LITTLE);
723  int insn_endian = (info->endian_code == BFD_ENDIAN_BIG
724                     ? CGEN_ENDIAN_BIG
725                     : CGEN_ENDIAN_LITTLE);
726  enum bfd_architecture arch;
727
728  /* ??? gdb will set mach but leave the architecture as "unknown" */
729#ifndef CGEN_BFD_ARCH
730#define CGEN_BFD_ARCH bfd_arch_frv
731#endif
732  arch = info->arch;
733  if (arch == bfd_arch_unknown)
734    arch = CGEN_BFD_ARCH;
735
736  /* There's no standard way to compute the machine or isa number
737     so we leave it to the target.  */
738#ifdef CGEN_COMPUTE_MACH
739  mach = CGEN_COMPUTE_MACH (info);
740#else
741  mach = info->mach;
742#endif
743
744#ifdef CGEN_COMPUTE_ISA
745  {
746    static CGEN_BITSET *permanent_isa;
747
748    if (!permanent_isa)
749      permanent_isa = cgen_bitset_create (MAX_ISAS);
750    isa = permanent_isa;
751    cgen_bitset_clear (isa);
752    cgen_bitset_add (isa, CGEN_COMPUTE_ISA (info));
753  }
754#else
755  isa = info->private_data;
756#endif
757
758  /* If we've switched cpu's, try to find a handle we've used before */
759  if (cd
760      && (cgen_bitset_compare (isa, prev_isa) != 0
761	  || mach != prev_mach
762	  || endian != prev_endian))
763    {
764      cd = 0;
765      for (cl = cd_list; cl; cl = cl->next)
766	{
767	  if (cgen_bitset_compare (cl->isa, isa) == 0 &&
768	      cl->mach == mach &&
769	      cl->endian == endian)
770	    {
771	      cd = cl->cd;
772 	      prev_isa = cd->isas;
773	      break;
774	    }
775	}
776    }
777
778  /* If we haven't initialized yet, initialize the opcode table.  */
779  if (! cd)
780    {
781      const bfd_arch_info_type *arch_type = bfd_lookup_arch (arch, mach);
782      const char *mach_name;
783
784      if (!arch_type)
785	abort ();
786      mach_name = arch_type->printable_name;
787
788      prev_isa = cgen_bitset_copy (isa);
789      prev_mach = mach;
790      prev_endian = endian;
791      prev_insn_endian = insn_endian;
792      cd = frv_cgen_cpu_open (CGEN_CPU_OPEN_ISAS, prev_isa,
793				 CGEN_CPU_OPEN_BFDMACH, mach_name,
794				 CGEN_CPU_OPEN_ENDIAN, prev_endian,
795                                 CGEN_CPU_OPEN_INSN_ENDIAN, prev_insn_endian,
796				 CGEN_CPU_OPEN_END);
797      if (!cd)
798	abort ();
799
800      /* Save this away for future reference.  */
801      cl = xmalloc (sizeof (struct cpu_desc_list));
802      cl->cd = cd;
803      cl->isa = prev_isa;
804      cl->mach = mach;
805      cl->endian = endian;
806      cl->next = cd_list;
807      cd_list = cl;
808
809      frv_cgen_init_dis (cd);
810    }
811
812  /* We try to have as much common code as possible.
813     But at this point some targets need to take over.  */
814  /* ??? Some targets may need a hook elsewhere.  Try to avoid this,
815     but if not possible try to move this hook elsewhere rather than
816     have two hooks.  */
817  length = CGEN_PRINT_INSN (cd, pc, info);
818  if (length > 0)
819    return length;
820  if (length < 0)
821    return -1;
822
823  (*info->fprintf_func) (info->stream, UNKNOWN_INSN_MSG);
824  return cd->default_insn_bitsize / 8;
825}
826