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 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2005
8   Free Software Foundation, Inc.
9
10   This file is part of the GNU Binutils and GDB, the GNU debugger.
11
12   This program 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 2, or (at your option)
15   any later version.
16
17   This program is distributed in the hope that it will be useful,
18   but WITHOUT ANY WARRANTY; without even the implied warranty of
19   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20   GNU General Public 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 "dis-asm.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, PTR, 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      fprintf (stderr, _("Unrecognized field %d while printing insn.\n"),
397	       opindex);
398    abort ();
399  }
400}
401
402cgen_print_fn * const frv_cgen_print_handlers[] =
403{
404  print_insn_normal,
405};
406
407
408void
409frv_cgen_init_dis (CGEN_CPU_DESC cd)
410{
411  frv_cgen_init_opcode_table (cd);
412  frv_cgen_init_ibld_table (cd);
413  cd->print_handlers = & frv_cgen_print_handlers[0];
414  cd->print_operand = frv_cgen_print_operand;
415}
416
417
418/* Default print handler.  */
419
420static void
421print_normal (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
422	      void *dis_info,
423	      long value,
424	      unsigned int attrs,
425	      bfd_vma pc ATTRIBUTE_UNUSED,
426	      int length ATTRIBUTE_UNUSED)
427{
428  disassemble_info *info = (disassemble_info *) dis_info;
429
430#ifdef CGEN_PRINT_NORMAL
431  CGEN_PRINT_NORMAL (cd, info, value, attrs, pc, length);
432#endif
433
434  /* Print the operand as directed by the attributes.  */
435  if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SEM_ONLY))
436    ; /* nothing to do */
437  else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SIGNED))
438    (*info->fprintf_func) (info->stream, "%ld", value);
439  else
440    (*info->fprintf_func) (info->stream, "0x%lx", value);
441}
442
443/* Default address handler.  */
444
445static void
446print_address (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
447	       void *dis_info,
448	       bfd_vma value,
449	       unsigned int attrs,
450	       bfd_vma pc ATTRIBUTE_UNUSED,
451	       int length ATTRIBUTE_UNUSED)
452{
453  disassemble_info *info = (disassemble_info *) dis_info;
454
455#ifdef CGEN_PRINT_ADDRESS
456  CGEN_PRINT_ADDRESS (cd, info, value, attrs, pc, length);
457#endif
458
459  /* Print the operand as directed by the attributes.  */
460  if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SEM_ONLY))
461    ; /* Nothing to do.  */
462  else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_PCREL_ADDR))
463    (*info->print_address_func) (value, info);
464  else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_ABS_ADDR))
465    (*info->print_address_func) (value, info);
466  else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SIGNED))
467    (*info->fprintf_func) (info->stream, "%ld", (long) value);
468  else
469    (*info->fprintf_func) (info->stream, "0x%lx", (long) value);
470}
471
472/* Keyword print handler.  */
473
474static void
475print_keyword (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
476	       void *dis_info,
477	       CGEN_KEYWORD *keyword_table,
478	       long value,
479	       unsigned int attrs ATTRIBUTE_UNUSED)
480{
481  disassemble_info *info = (disassemble_info *) dis_info;
482  const CGEN_KEYWORD_ENTRY *ke;
483
484  ke = cgen_keyword_lookup_value (keyword_table, value);
485  if (ke != NULL)
486    (*info->fprintf_func) (info->stream, "%s", ke->name);
487  else
488    (*info->fprintf_func) (info->stream, "???");
489}
490
491/* Default insn printer.
492
493   DIS_INFO is defined as `void *' so the disassembler needn't know anything
494   about disassemble_info.  */
495
496static void
497print_insn_normal (CGEN_CPU_DESC cd,
498		   void *dis_info,
499		   const CGEN_INSN *insn,
500		   CGEN_FIELDS *fields,
501		   bfd_vma pc,
502		   int length)
503{
504  const CGEN_SYNTAX *syntax = CGEN_INSN_SYNTAX (insn);
505  disassemble_info *info = (disassemble_info *) dis_info;
506  const CGEN_SYNTAX_CHAR_TYPE *syn;
507
508  CGEN_INIT_PRINT (cd);
509
510  for (syn = CGEN_SYNTAX_STRING (syntax); *syn; ++syn)
511    {
512      if (CGEN_SYNTAX_MNEMONIC_P (*syn))
513	{
514	  (*info->fprintf_func) (info->stream, "%s", CGEN_INSN_MNEMONIC (insn));
515	  continue;
516	}
517      if (CGEN_SYNTAX_CHAR_P (*syn))
518	{
519	  (*info->fprintf_func) (info->stream, "%c", CGEN_SYNTAX_CHAR (*syn));
520	  continue;
521	}
522
523      /* We have an operand.  */
524      frv_cgen_print_operand (cd, CGEN_SYNTAX_FIELD (*syn), info,
525				 fields, CGEN_INSN_ATTRS (insn), pc, length);
526    }
527}
528
529/* Subroutine of print_insn. Reads an insn into the given buffers and updates
530   the extract info.
531   Returns 0 if all is well, non-zero otherwise.  */
532
533static int
534read_insn (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
535	   bfd_vma pc,
536	   disassemble_info *info,
537	   bfd_byte *buf,
538	   int buflen,
539	   CGEN_EXTRACT_INFO *ex_info,
540	   unsigned long *insn_value)
541{
542  int status = (*info->read_memory_func) (pc, buf, buflen, info);
543
544  if (status != 0)
545    {
546      (*info->memory_error_func) (status, pc, info);
547      return -1;
548    }
549
550  ex_info->dis_info = info;
551  ex_info->valid = (1 << buflen) - 1;
552  ex_info->insn_bytes = buf;
553
554  *insn_value = bfd_get_bits (buf, buflen * 8, info->endian == BFD_ENDIAN_BIG);
555  return 0;
556}
557
558/* Utility to print an insn.
559   BUF is the base part of the insn, target byte order, BUFLEN bytes long.
560   The result is the size of the insn in bytes or zero for an unknown insn
561   or -1 if an error occurs fetching data (memory_error_func will have
562   been called).  */
563
564static int
565print_insn (CGEN_CPU_DESC cd,
566	    bfd_vma pc,
567	    disassemble_info *info,
568	    bfd_byte *buf,
569	    unsigned int buflen)
570{
571  CGEN_INSN_INT insn_value;
572  const CGEN_INSN_LIST *insn_list;
573  CGEN_EXTRACT_INFO ex_info;
574  int basesize;
575
576  /* Extract base part of instruction, just in case CGEN_DIS_* uses it. */
577  basesize = cd->base_insn_bitsize < buflen * 8 ?
578                                     cd->base_insn_bitsize : buflen * 8;
579  insn_value = cgen_get_insn_value (cd, buf, basesize);
580
581
582  /* Fill in ex_info fields like read_insn would.  Don't actually call
583     read_insn, since the incoming buffer is already read (and possibly
584     modified a la m32r).  */
585  ex_info.valid = (1 << buflen) - 1;
586  ex_info.dis_info = info;
587  ex_info.insn_bytes = buf;
588
589  /* The instructions are stored in hash lists.
590     Pick the first one and keep trying until we find the right one.  */
591
592  insn_list = CGEN_DIS_LOOKUP_INSN (cd, (char *) buf, insn_value);
593  while (insn_list != NULL)
594    {
595      const CGEN_INSN *insn = insn_list->insn;
596      CGEN_FIELDS fields;
597      int length;
598      unsigned long insn_value_cropped;
599
600#ifdef CGEN_VALIDATE_INSN_SUPPORTED
601      /* Not needed as insn shouldn't be in hash lists if not supported.  */
602      /* Supported by this cpu?  */
603      if (! frv_cgen_insn_supported (cd, insn))
604        {
605          insn_list = CGEN_DIS_NEXT_INSN (insn_list);
606	  continue;
607        }
608#endif
609
610      /* Basic bit mask must be correct.  */
611      /* ??? May wish to allow target to defer this check until the extract
612	 handler.  */
613
614      /* Base size may exceed this instruction's size.  Extract the
615         relevant part from the buffer. */
616      if ((unsigned) (CGEN_INSN_BITSIZE (insn) / 8) < buflen &&
617	  (unsigned) (CGEN_INSN_BITSIZE (insn) / 8) <= sizeof (unsigned long))
618	insn_value_cropped = bfd_get_bits (buf, CGEN_INSN_BITSIZE (insn),
619					   info->endian == BFD_ENDIAN_BIG);
620      else
621	insn_value_cropped = insn_value;
622
623      if ((insn_value_cropped & CGEN_INSN_BASE_MASK (insn))
624	  == CGEN_INSN_BASE_VALUE (insn))
625	{
626	  /* Printing is handled in two passes.  The first pass parses the
627	     machine insn and extracts the fields.  The second pass prints
628	     them.  */
629
630	  /* Make sure the entire insn is loaded into insn_value, if it
631	     can fit.  */
632	  if (((unsigned) CGEN_INSN_BITSIZE (insn) > cd->base_insn_bitsize) &&
633	      (unsigned) (CGEN_INSN_BITSIZE (insn) / 8) <= sizeof (unsigned long))
634	    {
635	      unsigned long full_insn_value;
636	      int rc = read_insn (cd, pc, info, buf,
637				  CGEN_INSN_BITSIZE (insn) / 8,
638				  & ex_info, & full_insn_value);
639	      if (rc != 0)
640		return rc;
641	      length = CGEN_EXTRACT_FN (cd, insn)
642		(cd, insn, &ex_info, full_insn_value, &fields, pc);
643	    }
644	  else
645	    length = CGEN_EXTRACT_FN (cd, insn)
646	      (cd, insn, &ex_info, insn_value_cropped, &fields, pc);
647
648	  /* Length < 0 -> error.  */
649	  if (length < 0)
650	    return length;
651	  if (length > 0)
652	    {
653	      CGEN_PRINT_FN (cd, insn) (cd, info, insn, &fields, pc, length);
654	      /* Length is in bits, result is in bytes.  */
655	      return length / 8;
656	    }
657	}
658
659      insn_list = CGEN_DIS_NEXT_INSN (insn_list);
660    }
661
662  return 0;
663}
664
665/* Default value for CGEN_PRINT_INSN.
666   The result is the size of the insn in bytes or zero for an unknown insn
667   or -1 if an error occured fetching bytes.  */
668
669#ifndef CGEN_PRINT_INSN
670#define CGEN_PRINT_INSN default_print_insn
671#endif
672
673static int
674default_print_insn (CGEN_CPU_DESC cd, bfd_vma pc, disassemble_info *info)
675{
676  bfd_byte buf[CGEN_MAX_INSN_SIZE];
677  int buflen;
678  int status;
679
680  /* Attempt to read the base part of the insn.  */
681  buflen = cd->base_insn_bitsize / 8;
682  status = (*info->read_memory_func) (pc, buf, buflen, info);
683
684  /* Try again with the minimum part, if min < base.  */
685  if (status != 0 && (cd->min_insn_bitsize < cd->base_insn_bitsize))
686    {
687      buflen = cd->min_insn_bitsize / 8;
688      status = (*info->read_memory_func) (pc, buf, buflen, info);
689    }
690
691  if (status != 0)
692    {
693      (*info->memory_error_func) (status, pc, info);
694      return -1;
695    }
696
697  return print_insn (cd, pc, info, buf, buflen);
698}
699
700/* Main entry point.
701   Print one instruction from PC on INFO->STREAM.
702   Return the size of the instruction (in bytes).  */
703
704typedef struct cpu_desc_list
705{
706  struct cpu_desc_list *next;
707  CGEN_BITSET *isa;
708  int mach;
709  int endian;
710  CGEN_CPU_DESC cd;
711} cpu_desc_list;
712
713int
714print_insn_frv (bfd_vma pc, disassemble_info *info)
715{
716  static cpu_desc_list *cd_list = 0;
717  cpu_desc_list *cl = 0;
718  static CGEN_CPU_DESC cd = 0;
719  static CGEN_BITSET *prev_isa;
720  static int prev_mach;
721  static int prev_endian;
722  int length;
723  CGEN_BITSET *isa;
724  int mach;
725  int endian = (info->endian == BFD_ENDIAN_BIG
726		? CGEN_ENDIAN_BIG
727		: CGEN_ENDIAN_LITTLE);
728  enum bfd_architecture arch;
729
730  /* ??? gdb will set mach but leave the architecture as "unknown" */
731#ifndef CGEN_BFD_ARCH
732#define CGEN_BFD_ARCH bfd_arch_frv
733#endif
734  arch = info->arch;
735  if (arch == bfd_arch_unknown)
736    arch = CGEN_BFD_ARCH;
737
738  /* There's no standard way to compute the machine or isa number
739     so we leave it to the target.  */
740#ifdef CGEN_COMPUTE_MACH
741  mach = CGEN_COMPUTE_MACH (info);
742#else
743  mach = info->mach;
744#endif
745
746#ifdef CGEN_COMPUTE_ISA
747  {
748    static CGEN_BITSET *permanent_isa;
749
750    if (!permanent_isa)
751      permanent_isa = cgen_bitset_create (MAX_ISAS);
752    isa = permanent_isa;
753    cgen_bitset_clear (isa);
754    cgen_bitset_add (isa, CGEN_COMPUTE_ISA (info));
755  }
756#else
757  isa = info->insn_sets;
758#endif
759
760  /* If we've switched cpu's, try to find a handle we've used before */
761  if (cd
762      && (cgen_bitset_compare (isa, prev_isa) != 0
763	  || mach != prev_mach
764	  || endian != prev_endian))
765    {
766      cd = 0;
767      for (cl = cd_list; cl; cl = cl->next)
768	{
769	  if (cgen_bitset_compare (cl->isa, isa) == 0 &&
770	      cl->mach == mach &&
771	      cl->endian == endian)
772	    {
773	      cd = cl->cd;
774 	      prev_isa = cd->isas;
775	      break;
776	    }
777	}
778    }
779
780  /* If we haven't initialized yet, initialize the opcode table.  */
781  if (! cd)
782    {
783      const bfd_arch_info_type *arch_type = bfd_lookup_arch (arch, mach);
784      const char *mach_name;
785
786      if (!arch_type)
787	abort ();
788      mach_name = arch_type->printable_name;
789
790      prev_isa = cgen_bitset_copy (isa);
791      prev_mach = mach;
792      prev_endian = endian;
793      cd = frv_cgen_cpu_open (CGEN_CPU_OPEN_ISAS, prev_isa,
794				 CGEN_CPU_OPEN_BFDMACH, mach_name,
795				 CGEN_CPU_OPEN_ENDIAN, prev_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