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