frv-dis.c revision 1.1.1.1
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     PARAMS ((CGEN_CPU_DESC, PTR, long, unsigned int, bfd_vma, int));
45static void print_address
46     PARAMS ((CGEN_CPU_DESC, PTR, bfd_vma, unsigned int, bfd_vma, int));
47static void print_keyword
48     PARAMS ((CGEN_CPU_DESC, PTR, CGEN_KEYWORD *, long, unsigned int));
49static void print_insn_normal
50     PARAMS ((CGEN_CPU_DESC, PTR, const CGEN_INSN *, CGEN_FIELDS *,
51	      bfd_vma, int));
52static int print_insn
53     PARAMS ((CGEN_CPU_DESC, bfd_vma,  disassemble_info *, char *, unsigned));
54static int default_print_insn
55     PARAMS ((CGEN_CPU_DESC, bfd_vma, disassemble_info *));
56static int read_insn
57     PARAMS ((CGEN_CPU_DESC, bfd_vma, disassemble_info *, char *, int,
58	      CGEN_EXTRACT_INFO *, unsigned long *));
59
60/* -- disassembler routines inserted here */
61
62/* -- dis.c */
63static void print_spr
64  PARAMS ((CGEN_CPU_DESC, PTR, CGEN_KEYWORD *, long, unsigned));
65static void print_hi
66  PARAMS ((CGEN_CPU_DESC, PTR, long, unsigned, bfd_vma, int));
67static void print_lo
68  PARAMS ((CGEN_CPU_DESC, PTR, long, unsigned, bfd_vma, int));
69
70static void
71print_spr (cd, dis_info, names, regno, attrs)
72     CGEN_CPU_DESC cd;
73     PTR dis_info;
74     CGEN_KEYWORD *names;
75     long regno;
76     unsigned int attrs;
77{
78  /* Use the register index format for any unnamed registers.  */
79  if (cgen_keyword_lookup_value (names, regno) == NULL)
80    {
81      disassemble_info *info = (disassemble_info *) dis_info;
82      (*info->fprintf_func) (info->stream, "spr[%ld]", regno);
83    }
84  else
85    print_keyword (cd, dis_info, names, regno, attrs);
86}
87
88static void
89print_hi (cd, dis_info, value, attrs, pc, length)
90     CGEN_CPU_DESC cd ATTRIBUTE_UNUSED;
91     PTR dis_info;
92     long value;
93     unsigned int attrs ATTRIBUTE_UNUSED;
94     bfd_vma pc ATTRIBUTE_UNUSED;
95     int length ATTRIBUTE_UNUSED;
96{
97  disassemble_info *info = (disassemble_info *) dis_info;
98  if (value)
99    (*info->fprintf_func) (info->stream, "0x%lx", value);
100  else
101    (*info->fprintf_func) (info->stream, "hi(0x%lx)", value);
102}
103
104static void
105print_lo (cd, dis_info, value, attrs, pc, length)
106     CGEN_CPU_DESC cd ATTRIBUTE_UNUSED;
107     PTR 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  PARAMS ((CGEN_CPU_DESC, int, PTR, CGEN_FIELDS *,
124           void const *, bfd_vma, int));
125
126/* Main entry point for printing operands.
127   XINFO is a `void *' and not a `disassemble_info *' to not put a requirement
128   of dis-asm.h on cgen.h.
129
130   This function is basically just a big switch statement.  Earlier versions
131   used tables to look up the function to use, but
132   - if the table contains both assembler and disassembler functions then
133     the disassembler contains much of the assembler and vice-versa,
134   - there's a lot of inlining possibilities as things grow,
135   - using a switch statement avoids the function call overhead.
136
137   This function could be moved into `print_insn_normal', but keeping it
138   separate makes clear the interface between `print_insn_normal' and each of
139   the handlers.  */
140
141void
142frv_cgen_print_operand (cd, opindex, xinfo, fields, attrs, pc, length)
143     CGEN_CPU_DESC cd;
144     int opindex;
145     PTR xinfo;
146     CGEN_FIELDS *fields;
147     void const *attrs ATTRIBUTE_UNUSED;
148     bfd_vma pc;
149     int length;
150{
151 disassemble_info *info = (disassemble_info *) xinfo;
152
153  switch (opindex)
154    {
155    case FRV_OPERAND_A :
156      print_normal (cd, info, fields->f_A, 0|(1<<CGEN_OPERAND_HASH_PREFIX), 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_FRINTJ :
234      print_keyword (cd, info, & frv_cgen_opval_fr_names, fields->f_FRj, 0);
235      break;
236    case FRV_OPERAND_FRINTK :
237      print_keyword (cd, info, & frv_cgen_opval_fr_names, fields->f_FRk, 0);
238      break;
239    case FRV_OPERAND_FRJ :
240      print_keyword (cd, info, & frv_cgen_opval_fr_names, fields->f_FRj, 0);
241      break;
242    case FRV_OPERAND_FRK :
243      print_keyword (cd, info, & frv_cgen_opval_fr_names, fields->f_FRk, 0);
244      break;
245    case FRV_OPERAND_FRKHI :
246      print_keyword (cd, info, & frv_cgen_opval_fr_names, fields->f_FRk, 0);
247      break;
248    case FRV_OPERAND_FRKLO :
249      print_keyword (cd, info, & frv_cgen_opval_fr_names, fields->f_FRk, 0);
250      break;
251    case FRV_OPERAND_GRDOUBLEK :
252      print_keyword (cd, info, & frv_cgen_opval_gr_names, fields->f_GRk, 0);
253      break;
254    case FRV_OPERAND_GRI :
255      print_keyword (cd, info, & frv_cgen_opval_gr_names, fields->f_GRi, 0);
256      break;
257    case FRV_OPERAND_GRJ :
258      print_keyword (cd, info, & frv_cgen_opval_gr_names, fields->f_GRj, 0);
259      break;
260    case FRV_OPERAND_GRK :
261      print_keyword (cd, info, & frv_cgen_opval_gr_names, fields->f_GRk, 0);
262      break;
263    case FRV_OPERAND_GRKHI :
264      print_keyword (cd, info, & frv_cgen_opval_gr_names, fields->f_GRk, 0);
265      break;
266    case FRV_OPERAND_GRKLO :
267      print_keyword (cd, info, & frv_cgen_opval_gr_names, fields->f_GRk, 0);
268      break;
269    case FRV_OPERAND_ICCI_1 :
270      print_keyword (cd, info, & frv_cgen_opval_iccr_names, fields->f_ICCi_1, 0);
271      break;
272    case FRV_OPERAND_ICCI_2 :
273      print_keyword (cd, info, & frv_cgen_opval_iccr_names, fields->f_ICCi_2, 0);
274      break;
275    case FRV_OPERAND_ICCI_3 :
276      print_keyword (cd, info, & frv_cgen_opval_iccr_names, fields->f_ICCi_3, 0);
277      break;
278    case FRV_OPERAND_LI :
279      print_normal (cd, info, fields->f_LI, 0, pc, length);
280      break;
281    case FRV_OPERAND_AE :
282      print_normal (cd, info, fields->f_ae, 0|(1<<CGEN_OPERAND_HASH_PREFIX), pc, length);
283      break;
284    case FRV_OPERAND_CCOND :
285      print_normal (cd, info, fields->f_ccond, 0|(1<<CGEN_OPERAND_HASH_PREFIX), pc, length);
286      break;
287    case FRV_OPERAND_COND :
288      print_normal (cd, info, fields->f_cond, 0|(1<<CGEN_OPERAND_HASH_PREFIX), pc, length);
289      break;
290    case FRV_OPERAND_D12 :
291      print_normal (cd, info, fields->f_d12, 0|(1<<CGEN_OPERAND_SIGNED), pc, length);
292      break;
293    case FRV_OPERAND_DEBUG :
294      print_normal (cd, info, fields->f_debug, 0|(1<<CGEN_OPERAND_HASH_PREFIX), pc, length);
295      break;
296    case FRV_OPERAND_EIR :
297      print_normal (cd, info, fields->f_eir, 0, pc, length);
298      break;
299    case FRV_OPERAND_HINT :
300      print_normal (cd, info, fields->f_hint, 0|(1<<CGEN_OPERAND_HASH_PREFIX), pc, length);
301      break;
302    case FRV_OPERAND_HINT_NOT_TAKEN :
303      print_keyword (cd, info, & frv_cgen_opval_h_hint_not_taken, fields->f_hint, 0);
304      break;
305    case FRV_OPERAND_HINT_TAKEN :
306      print_keyword (cd, info, & frv_cgen_opval_h_hint_taken, fields->f_hint, 0);
307      break;
308    case FRV_OPERAND_LABEL16 :
309      print_address (cd, info, fields->f_label16, 0|(1<<CGEN_OPERAND_PCREL_ADDR), pc, length);
310      break;
311    case FRV_OPERAND_LABEL24 :
312      print_address (cd, info, fields->f_label24, 0|(1<<CGEN_OPERAND_PCREL_ADDR)|(1<<CGEN_OPERAND_VIRTUAL), pc, length);
313      break;
314    case FRV_OPERAND_LOCK :
315      print_normal (cd, info, fields->f_lock, 0|(1<<CGEN_OPERAND_HASH_PREFIX), pc, length);
316      break;
317    case FRV_OPERAND_PACK :
318      print_keyword (cd, info, & frv_cgen_opval_h_pack, fields->f_pack, 0);
319      break;
320    case FRV_OPERAND_S10 :
321      print_normal (cd, info, fields->f_s10, 0|(1<<CGEN_OPERAND_SIGNED)|(1<<CGEN_OPERAND_HASH_PREFIX), pc, length);
322      break;
323    case FRV_OPERAND_S12 :
324      print_normal (cd, info, fields->f_d12, 0|(1<<CGEN_OPERAND_SIGNED)|(1<<CGEN_OPERAND_HASH_PREFIX), pc, length);
325      break;
326    case FRV_OPERAND_S16 :
327      print_normal (cd, info, fields->f_s16, 0|(1<<CGEN_OPERAND_SIGNED)|(1<<CGEN_OPERAND_HASH_PREFIX), pc, length);
328      break;
329    case FRV_OPERAND_S5 :
330      print_normal (cd, info, fields->f_s5, 0|(1<<CGEN_OPERAND_SIGNED)|(1<<CGEN_OPERAND_HASH_PREFIX), pc, length);
331      break;
332    case FRV_OPERAND_S6 :
333      print_normal (cd, info, fields->f_s6, 0|(1<<CGEN_OPERAND_SIGNED)|(1<<CGEN_OPERAND_HASH_PREFIX), pc, length);
334      break;
335    case FRV_OPERAND_S6_1 :
336      print_normal (cd, info, fields->f_s6_1, 0|(1<<CGEN_OPERAND_SIGNED)|(1<<CGEN_OPERAND_HASH_PREFIX), pc, length);
337      break;
338    case FRV_OPERAND_SLO16 :
339      print_lo (cd, info, fields->f_s16, 0|(1<<CGEN_OPERAND_SIGNED), pc, length);
340      break;
341    case FRV_OPERAND_SPR :
342      print_spr (cd, info, & frv_cgen_opval_spr_names, fields->f_spr, 0|(1<<CGEN_OPERAND_VIRTUAL));
343      break;
344    case FRV_OPERAND_U12 :
345      print_normal (cd, info, fields->f_u12, 0|(1<<CGEN_OPERAND_SIGNED)|(1<<CGEN_OPERAND_HASH_PREFIX)|(1<<CGEN_OPERAND_VIRTUAL), pc, length);
346      break;
347    case FRV_OPERAND_U16 :
348      print_normal (cd, info, fields->f_u16, 0|(1<<CGEN_OPERAND_HASH_PREFIX), pc, length);
349      break;
350    case FRV_OPERAND_U6 :
351      print_normal (cd, info, fields->f_u6, 0|(1<<CGEN_OPERAND_HASH_PREFIX), pc, length);
352      break;
353    case FRV_OPERAND_UHI16 :
354      print_hi (cd, info, fields->f_u16, 0, pc, length);
355      break;
356    case FRV_OPERAND_ULO16 :
357      print_lo (cd, info, fields->f_u16, 0, pc, length);
358      break;
359
360    default :
361      /* xgettext:c-format */
362      fprintf (stderr, _("Unrecognized field %d while printing insn.\n"),
363	       opindex);
364    abort ();
365  }
366}
367
368cgen_print_fn * const frv_cgen_print_handlers[] =
369{
370  print_insn_normal,
371};
372
373
374void
375frv_cgen_init_dis (cd)
376     CGEN_CPU_DESC cd;
377{
378  frv_cgen_init_opcode_table (cd);
379  frv_cgen_init_ibld_table (cd);
380  cd->print_handlers = & frv_cgen_print_handlers[0];
381  cd->print_operand = frv_cgen_print_operand;
382}
383
384
385/* Default print handler.  */
386
387static void
388print_normal (cd, dis_info, value, attrs, pc, length)
389     CGEN_CPU_DESC cd ATTRIBUTE_UNUSED;
390     PTR dis_info;
391     long value;
392     unsigned int attrs;
393     bfd_vma pc ATTRIBUTE_UNUSED;
394     int length ATTRIBUTE_UNUSED;
395{
396  disassemble_info *info = (disassemble_info *) dis_info;
397
398#ifdef CGEN_PRINT_NORMAL
399  CGEN_PRINT_NORMAL (cd, info, value, attrs, pc, length);
400#endif
401
402  /* Print the operand as directed by the attributes.  */
403  if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SEM_ONLY))
404    ; /* nothing to do */
405  else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SIGNED))
406    (*info->fprintf_func) (info->stream, "%ld", value);
407  else
408    (*info->fprintf_func) (info->stream, "0x%lx", value);
409}
410
411/* Default address handler.  */
412
413static void
414print_address (cd, dis_info, value, attrs, pc, length)
415     CGEN_CPU_DESC cd ATTRIBUTE_UNUSED;
416     PTR dis_info;
417     bfd_vma value;
418     unsigned int attrs;
419     bfd_vma pc ATTRIBUTE_UNUSED;
420     int length ATTRIBUTE_UNUSED;
421{
422  disassemble_info *info = (disassemble_info *) dis_info;
423
424#ifdef CGEN_PRINT_ADDRESS
425  CGEN_PRINT_ADDRESS (cd, info, value, attrs, pc, length);
426#endif
427
428  /* Print the operand as directed by the attributes.  */
429  if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SEM_ONLY))
430    ; /* nothing to do */
431  else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_PCREL_ADDR))
432    (*info->print_address_func) (value, info);
433  else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_ABS_ADDR))
434    (*info->print_address_func) (value, info);
435  else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SIGNED))
436    (*info->fprintf_func) (info->stream, "%ld", (long) value);
437  else
438    (*info->fprintf_func) (info->stream, "0x%lx", (long) value);
439}
440
441/* Keyword print handler.  */
442
443static void
444print_keyword (cd, dis_info, keyword_table, value, attrs)
445     CGEN_CPU_DESC cd ATTRIBUTE_UNUSED;
446     PTR dis_info;
447     CGEN_KEYWORD *keyword_table;
448     long value;
449     unsigned int attrs ATTRIBUTE_UNUSED;
450{
451  disassemble_info *info = (disassemble_info *) dis_info;
452  const CGEN_KEYWORD_ENTRY *ke;
453
454  ke = cgen_keyword_lookup_value (keyword_table, value);
455  if (ke != NULL)
456    (*info->fprintf_func) (info->stream, "%s", ke->name);
457  else
458    (*info->fprintf_func) (info->stream, "???");
459}
460
461/* Default insn printer.
462
463   DIS_INFO is defined as `PTR' so the disassembler needn't know anything
464   about disassemble_info.  */
465
466static void
467print_insn_normal (cd, dis_info, insn, fields, pc, length)
468     CGEN_CPU_DESC cd;
469     PTR dis_info;
470     const CGEN_INSN *insn;
471     CGEN_FIELDS *fields;
472     bfd_vma pc;
473     int length;
474{
475  const CGEN_SYNTAX *syntax = CGEN_INSN_SYNTAX (insn);
476  disassemble_info *info = (disassemble_info *) dis_info;
477  const CGEN_SYNTAX_CHAR_TYPE *syn;
478
479  CGEN_INIT_PRINT (cd);
480
481  for (syn = CGEN_SYNTAX_STRING (syntax); *syn; ++syn)
482    {
483      if (CGEN_SYNTAX_MNEMONIC_P (*syn))
484	{
485	  (*info->fprintf_func) (info->stream, "%s", CGEN_INSN_MNEMONIC (insn));
486	  continue;
487	}
488      if (CGEN_SYNTAX_CHAR_P (*syn))
489	{
490	  (*info->fprintf_func) (info->stream, "%c", CGEN_SYNTAX_CHAR (*syn));
491	  continue;
492	}
493
494      /* We have an operand.  */
495      frv_cgen_print_operand (cd, CGEN_SYNTAX_FIELD (*syn), info,
496				 fields, CGEN_INSN_ATTRS (insn), pc, length);
497    }
498}
499
500/* Subroutine of print_insn. Reads an insn into the given buffers and updates
501   the extract info.
502   Returns 0 if all is well, non-zero otherwise.  */
503
504static int
505read_insn (cd, pc, info, buf, buflen, ex_info, insn_value)
506     CGEN_CPU_DESC cd ATTRIBUTE_UNUSED;
507     bfd_vma pc;
508     disassemble_info *info;
509     char *buf;
510     int buflen;
511     CGEN_EXTRACT_INFO *ex_info;
512     unsigned long *insn_value;
513{
514  int status = (*info->read_memory_func) (pc, buf, buflen, info);
515  if (status != 0)
516    {
517      (*info->memory_error_func) (status, pc, info);
518      return -1;
519    }
520
521  ex_info->dis_info = info;
522  ex_info->valid = (1 << buflen) - 1;
523  ex_info->insn_bytes = buf;
524
525  *insn_value = bfd_get_bits (buf, buflen * 8, info->endian == BFD_ENDIAN_BIG);
526  return 0;
527}
528
529/* Utility to print an insn.
530   BUF is the base part of the insn, target byte order, BUFLEN bytes long.
531   The result is the size of the insn in bytes or zero for an unknown insn
532   or -1 if an error occurs fetching data (memory_error_func will have
533   been called).  */
534
535static int
536print_insn (cd, pc, info, buf, buflen)
537     CGEN_CPU_DESC cd;
538     bfd_vma pc;
539     disassemble_info *info;
540     char *buf;
541     unsigned int buflen;
542{
543  CGEN_INSN_INT insn_value;
544  const CGEN_INSN_LIST *insn_list;
545  CGEN_EXTRACT_INFO ex_info;
546  int basesize;
547
548  /* Extract base part of instruction, just in case CGEN_DIS_* uses it. */
549  basesize = cd->base_insn_bitsize < buflen * 8 ?
550                                     cd->base_insn_bitsize : buflen * 8;
551  insn_value = cgen_get_insn_value (cd, buf, basesize);
552
553
554  /* Fill in ex_info fields like read_insn would.  Don't actually call
555     read_insn, since the incoming buffer is already read (and possibly
556     modified a la m32r).  */
557  ex_info.valid = (1 << buflen) - 1;
558  ex_info.dis_info = info;
559  ex_info.insn_bytes = buf;
560
561  /* The instructions are stored in hash lists.
562     Pick the first one and keep trying until we find the right one.  */
563
564  insn_list = CGEN_DIS_LOOKUP_INSN (cd, buf, insn_value);
565  while (insn_list != NULL)
566    {
567      const CGEN_INSN *insn = insn_list->insn;
568      CGEN_FIELDS fields;
569      int length;
570      unsigned long insn_value_cropped;
571
572#ifdef CGEN_VALIDATE_INSN_SUPPORTED
573      /* Not needed as insn shouldn't be in hash lists if not supported.  */
574      /* Supported by this cpu?  */
575      if (! frv_cgen_insn_supported (cd, insn))
576        {
577          insn_list = CGEN_DIS_NEXT_INSN (insn_list);
578	  continue;
579        }
580#endif
581
582      /* Basic bit mask must be correct.  */
583      /* ??? May wish to allow target to defer this check until the extract
584	 handler.  */
585
586      /* Base size may exceed this instruction's size.  Extract the
587         relevant part from the buffer. */
588      if ((unsigned) (CGEN_INSN_BITSIZE (insn) / 8) < buflen &&
589	  (unsigned) (CGEN_INSN_BITSIZE (insn) / 8) <= sizeof (unsigned long))
590	insn_value_cropped = bfd_get_bits (buf, CGEN_INSN_BITSIZE (insn),
591					   info->endian == BFD_ENDIAN_BIG);
592      else
593	insn_value_cropped = insn_value;
594
595      if ((insn_value_cropped & CGEN_INSN_BASE_MASK (insn))
596	  == CGEN_INSN_BASE_VALUE (insn))
597	{
598	  /* Printing is handled in two passes.  The first pass parses the
599	     machine insn and extracts the fields.  The second pass prints
600	     them.  */
601
602	  /* Make sure the entire insn is loaded into insn_value, if it
603	     can fit.  */
604	  if (((unsigned) CGEN_INSN_BITSIZE (insn) > cd->base_insn_bitsize) &&
605	      (unsigned) (CGEN_INSN_BITSIZE (insn) / 8) <= sizeof (unsigned long))
606	    {
607	      unsigned long full_insn_value;
608	      int rc = read_insn (cd, pc, info, buf,
609				  CGEN_INSN_BITSIZE (insn) / 8,
610				  & ex_info, & full_insn_value);
611	      if (rc != 0)
612		return rc;
613	      length = CGEN_EXTRACT_FN (cd, insn)
614		(cd, insn, &ex_info, full_insn_value, &fields, pc);
615	    }
616	  else
617	    length = CGEN_EXTRACT_FN (cd, insn)
618	      (cd, insn, &ex_info, insn_value_cropped, &fields, pc);
619
620	  /* length < 0 -> error */
621	  if (length < 0)
622	    return length;
623	  if (length > 0)
624	    {
625	      CGEN_PRINT_FN (cd, insn) (cd, info, insn, &fields, pc, length);
626	      /* length is in bits, result is in bytes */
627	      return length / 8;
628	    }
629	}
630
631      insn_list = CGEN_DIS_NEXT_INSN (insn_list);
632    }
633
634  return 0;
635}
636
637/* Default value for CGEN_PRINT_INSN.
638   The result is the size of the insn in bytes or zero for an unknown insn
639   or -1 if an error occured fetching bytes.  */
640
641#ifndef CGEN_PRINT_INSN
642#define CGEN_PRINT_INSN default_print_insn
643#endif
644
645static int
646default_print_insn (cd, pc, info)
647     CGEN_CPU_DESC cd;
648     bfd_vma pc;
649     disassemble_info *info;
650{
651  char buf[CGEN_MAX_INSN_SIZE];
652  int buflen;
653  int status;
654
655  /* Attempt to read the base part of the insn.  */
656  buflen = cd->base_insn_bitsize / 8;
657  status = (*info->read_memory_func) (pc, buf, buflen, info);
658
659  /* Try again with the minimum part, if min < base.  */
660  if (status != 0 && (cd->min_insn_bitsize < cd->base_insn_bitsize))
661    {
662      buflen = cd->min_insn_bitsize / 8;
663      status = (*info->read_memory_func) (pc, buf, buflen, info);
664    }
665
666  if (status != 0)
667    {
668      (*info->memory_error_func) (status, pc, info);
669      return -1;
670    }
671
672  return print_insn (cd, pc, info, buf, buflen);
673}
674
675/* Main entry point.
676   Print one instruction from PC on INFO->STREAM.
677   Return the size of the instruction (in bytes).  */
678
679typedef struct cpu_desc_list {
680  struct cpu_desc_list *next;
681  int isa;
682  int mach;
683  int endian;
684  CGEN_CPU_DESC cd;
685} cpu_desc_list;
686
687int
688print_insn_frv (pc, info)
689     bfd_vma pc;
690     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