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