[ gas/ChangeLog ]
[platform/upstream/binutils.git] / opcodes / fr30-dis.c
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
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 59 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 "fr30-desc.h"
37 #include "fr30-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
43 static void print_normal
44      PARAMS ((CGEN_CPU_DESC, PTR, long, unsigned int, bfd_vma, int));
45 static void print_address
46      PARAMS ((CGEN_CPU_DESC, PTR, bfd_vma, unsigned int, bfd_vma, int));
47 static void print_keyword
48      PARAMS ((CGEN_CPU_DESC, PTR, CGEN_KEYWORD *, long, unsigned int));
49 static void print_insn_normal
50      PARAMS ((CGEN_CPU_DESC, PTR, const CGEN_INSN *, CGEN_FIELDS *,
51               bfd_vma, int));
52 static int print_insn
53      PARAMS ((CGEN_CPU_DESC, bfd_vma,  disassemble_info *, char *, unsigned));
54 static int default_print_insn
55      PARAMS ((CGEN_CPU_DESC, bfd_vma, disassemble_info *));
56 static int read_insn
57      PARAMS ((CGEN_CPU_DESC, bfd_vma, disassemble_info *, char *, int,
58               CGEN_EXTRACT_INFO *, unsigned long *));
59 \f
60 /* -- disassembler routines inserted here */
61
62 /* -- dis.c */
63 static void print_register_list
64   PARAMS ((PTR, long, long, int));
65 static void print_hi_register_list_ld
66   PARAMS ((CGEN_CPU_DESC, PTR, long, unsigned, bfd_vma, int));
67 static void print_low_register_list_ld
68   PARAMS ((CGEN_CPU_DESC, PTR, long, unsigned, bfd_vma, int));
69 static void print_hi_register_list_st
70   PARAMS ((CGEN_CPU_DESC, PTR, long, unsigned, bfd_vma, int));
71 static void print_low_register_list_st
72   PARAMS ((CGEN_CPU_DESC, PTR, long, unsigned, bfd_vma, int));
73 static void print_m4
74   PARAMS ((CGEN_CPU_DESC, PTR, long, unsigned, bfd_vma, int));
75
76 static void
77 print_register_list (dis_info, value, offset, load_store)
78      PTR dis_info;
79      long value;
80      long offset;
81      int load_store; /* 0 == load, 1 == store */
82 {
83   disassemble_info *info = dis_info;
84   int mask;
85   int index = 0;
86   char* comma = "";
87
88   if (load_store)
89     mask = 0x80;
90   else
91     mask = 1;
92
93   if (value & mask)
94     {
95       (*info->fprintf_func) (info->stream, "r%i", index + offset);
96       comma = ",";
97     }
98     
99   for (index = 1; index <= 7; ++index)
100     {
101       if (load_store)
102         mask >>= 1;
103       else
104         mask <<= 1;
105
106       if (value & mask)
107         {
108           (*info->fprintf_func) (info->stream, "%sr%i", comma, index + offset);
109           comma = ",";
110         }
111     }
112 }
113
114 static void
115 print_hi_register_list_ld (cd, dis_info, value, attrs, pc, length)
116      CGEN_CPU_DESC cd ATTRIBUTE_UNUSED;
117      PTR dis_info;
118      long value;
119      unsigned int attrs ATTRIBUTE_UNUSED;
120      bfd_vma pc ATTRIBUTE_UNUSED;
121      int length ATTRIBUTE_UNUSED;
122 {
123   print_register_list (dis_info, value, 8, 0/*load*/);
124 }
125
126 static void
127 print_low_register_list_ld (cd, dis_info, value, attrs, pc, length)
128      CGEN_CPU_DESC cd ATTRIBUTE_UNUSED;
129      PTR dis_info;
130      long value;
131      unsigned int attrs ATTRIBUTE_UNUSED;
132      bfd_vma pc ATTRIBUTE_UNUSED;
133      int length ATTRIBUTE_UNUSED;
134 {
135   print_register_list (dis_info, value, 0, 0/*load*/);
136 }
137
138 static void
139 print_hi_register_list_st (cd, dis_info, value, attrs, pc, length)
140      CGEN_CPU_DESC cd ATTRIBUTE_UNUSED;
141      PTR dis_info;
142      long value;
143      unsigned int attrs ATTRIBUTE_UNUSED;
144      bfd_vma pc ATTRIBUTE_UNUSED;
145      int length ATTRIBUTE_UNUSED;
146 {
147   print_register_list (dis_info, value, 8, 1/*store*/);
148 }
149
150 static void
151 print_low_register_list_st (cd, dis_info, value, attrs, pc, length)
152      CGEN_CPU_DESC cd ATTRIBUTE_UNUSED;
153      PTR dis_info;
154      long value;
155      unsigned int attrs ATTRIBUTE_UNUSED;
156      bfd_vma pc ATTRIBUTE_UNUSED;
157      int length ATTRIBUTE_UNUSED;
158 {
159   print_register_list (dis_info, value, 0, 1/*store*/);
160 }
161
162 static void
163 print_m4 (cd, dis_info, value, attrs, pc, length)
164      CGEN_CPU_DESC cd ATTRIBUTE_UNUSED;
165      PTR dis_info;
166      long value;
167      unsigned int attrs ATTRIBUTE_UNUSED;
168      bfd_vma pc ATTRIBUTE_UNUSED;
169      int length ATTRIBUTE_UNUSED;
170 {
171   disassemble_info *info = (disassemble_info *) dis_info;
172   (*info->fprintf_func) (info->stream, "%ld", value);
173 }
174 /* -- */
175
176 void fr30_cgen_print_operand
177   PARAMS ((CGEN_CPU_DESC, int, PTR, CGEN_FIELDS *,
178            void const *, bfd_vma, int));
179
180 /* Main entry point for printing operands.
181    XINFO is a `void *' and not a `disassemble_info *' to not put a requirement
182    of dis-asm.h on cgen.h.
183
184    This function is basically just a big switch statement.  Earlier versions
185    used tables to look up the function to use, but
186    - if the table contains both assembler and disassembler functions then
187      the disassembler contains much of the assembler and vice-versa,
188    - there's a lot of inlining possibilities as things grow,
189    - using a switch statement avoids the function call overhead.
190
191    This function could be moved into `print_insn_normal', but keeping it
192    separate makes clear the interface between `print_insn_normal' and each of
193    the handlers.  */
194
195 void
196 fr30_cgen_print_operand (cd, opindex, xinfo, fields, attrs, pc, length)
197      CGEN_CPU_DESC cd;
198      int opindex;
199      PTR xinfo;
200      CGEN_FIELDS *fields;
201      void const *attrs ATTRIBUTE_UNUSED;
202      bfd_vma pc;
203      int length;
204 {
205  disassemble_info *info = (disassemble_info *) xinfo;
206
207   switch (opindex)
208     {
209     case FR30_OPERAND_CRI :
210       print_keyword (cd, info, & fr30_cgen_opval_cr_names, fields->f_CRi, 0);
211       break;
212     case FR30_OPERAND_CRJ :
213       print_keyword (cd, info, & fr30_cgen_opval_cr_names, fields->f_CRj, 0);
214       break;
215     case FR30_OPERAND_R13 :
216       print_keyword (cd, info, & fr30_cgen_opval_h_r13, 0, 0);
217       break;
218     case FR30_OPERAND_R14 :
219       print_keyword (cd, info, & fr30_cgen_opval_h_r14, 0, 0);
220       break;
221     case FR30_OPERAND_R15 :
222       print_keyword (cd, info, & fr30_cgen_opval_h_r15, 0, 0);
223       break;
224     case FR30_OPERAND_RI :
225       print_keyword (cd, info, & fr30_cgen_opval_gr_names, fields->f_Ri, 0);
226       break;
227     case FR30_OPERAND_RIC :
228       print_keyword (cd, info, & fr30_cgen_opval_gr_names, fields->f_Ric, 0);
229       break;
230     case FR30_OPERAND_RJ :
231       print_keyword (cd, info, & fr30_cgen_opval_gr_names, fields->f_Rj, 0);
232       break;
233     case FR30_OPERAND_RJC :
234       print_keyword (cd, info, & fr30_cgen_opval_gr_names, fields->f_Rjc, 0);
235       break;
236     case FR30_OPERAND_RS1 :
237       print_keyword (cd, info, & fr30_cgen_opval_dr_names, fields->f_Rs1, 0);
238       break;
239     case FR30_OPERAND_RS2 :
240       print_keyword (cd, info, & fr30_cgen_opval_dr_names, fields->f_Rs2, 0);
241       break;
242     case FR30_OPERAND_CC :
243       print_normal (cd, info, fields->f_cc, 0, pc, length);
244       break;
245     case FR30_OPERAND_CCC :
246       print_normal (cd, info, fields->f_ccc, 0|(1<<CGEN_OPERAND_HASH_PREFIX), pc, length);
247       break;
248     case FR30_OPERAND_DIR10 :
249       print_normal (cd, info, fields->f_dir10, 0, pc, length);
250       break;
251     case FR30_OPERAND_DIR8 :
252       print_normal (cd, info, fields->f_dir8, 0, pc, length);
253       break;
254     case FR30_OPERAND_DIR9 :
255       print_normal (cd, info, fields->f_dir9, 0, pc, length);
256       break;
257     case FR30_OPERAND_DISP10 :
258       print_normal (cd, info, fields->f_disp10, 0|(1<<CGEN_OPERAND_SIGNED)|(1<<CGEN_OPERAND_HASH_PREFIX), pc, length);
259       break;
260     case FR30_OPERAND_DISP8 :
261       print_normal (cd, info, fields->f_disp8, 0|(1<<CGEN_OPERAND_SIGNED)|(1<<CGEN_OPERAND_HASH_PREFIX), pc, length);
262       break;
263     case FR30_OPERAND_DISP9 :
264       print_normal (cd, info, fields->f_disp9, 0|(1<<CGEN_OPERAND_SIGNED)|(1<<CGEN_OPERAND_HASH_PREFIX), pc, length);
265       break;
266     case FR30_OPERAND_I20 :
267       print_normal (cd, info, fields->f_i20, 0|(1<<CGEN_OPERAND_HASH_PREFIX)|(1<<CGEN_OPERAND_VIRTUAL), pc, length);
268       break;
269     case FR30_OPERAND_I32 :
270       print_normal (cd, info, fields->f_i32, 0|(1<<CGEN_OPERAND_HASH_PREFIX)|(1<<CGEN_OPERAND_SIGN_OPT), pc, length);
271       break;
272     case FR30_OPERAND_I8 :
273       print_normal (cd, info, fields->f_i8, 0|(1<<CGEN_OPERAND_HASH_PREFIX), pc, length);
274       break;
275     case FR30_OPERAND_LABEL12 :
276       print_address (cd, info, fields->f_rel12, 0|(1<<CGEN_OPERAND_PCREL_ADDR), pc, length);
277       break;
278     case FR30_OPERAND_LABEL9 :
279       print_address (cd, info, fields->f_rel9, 0|(1<<CGEN_OPERAND_PCREL_ADDR), pc, length);
280       break;
281     case FR30_OPERAND_M4 :
282       print_m4 (cd, info, fields->f_m4, 0|(1<<CGEN_OPERAND_SIGNED)|(1<<CGEN_OPERAND_HASH_PREFIX), pc, length);
283       break;
284     case FR30_OPERAND_PS :
285       print_keyword (cd, info, & fr30_cgen_opval_h_ps, 0, 0);
286       break;
287     case FR30_OPERAND_REGLIST_HI_LD :
288       print_hi_register_list_ld (cd, info, fields->f_reglist_hi_ld, 0, pc, length);
289       break;
290     case FR30_OPERAND_REGLIST_HI_ST :
291       print_hi_register_list_st (cd, info, fields->f_reglist_hi_st, 0, pc, length);
292       break;
293     case FR30_OPERAND_REGLIST_LOW_LD :
294       print_low_register_list_ld (cd, info, fields->f_reglist_low_ld, 0, pc, length);
295       break;
296     case FR30_OPERAND_REGLIST_LOW_ST :
297       print_low_register_list_st (cd, info, fields->f_reglist_low_st, 0, pc, length);
298       break;
299     case FR30_OPERAND_S10 :
300       print_normal (cd, info, fields->f_s10, 0|(1<<CGEN_OPERAND_SIGNED)|(1<<CGEN_OPERAND_HASH_PREFIX), pc, length);
301       break;
302     case FR30_OPERAND_U10 :
303       print_normal (cd, info, fields->f_u10, 0|(1<<CGEN_OPERAND_HASH_PREFIX), pc, length);
304       break;
305     case FR30_OPERAND_U4 :
306       print_normal (cd, info, fields->f_u4, 0|(1<<CGEN_OPERAND_HASH_PREFIX), pc, length);
307       break;
308     case FR30_OPERAND_U4C :
309       print_normal (cd, info, fields->f_u4c, 0|(1<<CGEN_OPERAND_HASH_PREFIX), pc, length);
310       break;
311     case FR30_OPERAND_U8 :
312       print_normal (cd, info, fields->f_u8, 0|(1<<CGEN_OPERAND_HASH_PREFIX), pc, length);
313       break;
314     case FR30_OPERAND_UDISP6 :
315       print_normal (cd, info, fields->f_udisp6, 0|(1<<CGEN_OPERAND_HASH_PREFIX), pc, length);
316       break;
317
318     default :
319       /* xgettext:c-format */
320       fprintf (stderr, _("Unrecognized field %d while printing insn.\n"),
321                opindex);
322     abort ();
323   }
324 }
325
326 cgen_print_fn * const fr30_cgen_print_handlers[] = 
327 {
328   print_insn_normal,
329 };
330
331
332 void
333 fr30_cgen_init_dis (cd)
334      CGEN_CPU_DESC cd;
335 {
336   fr30_cgen_init_opcode_table (cd);
337   fr30_cgen_init_ibld_table (cd);
338   cd->print_handlers = & fr30_cgen_print_handlers[0];
339   cd->print_operand = fr30_cgen_print_operand;
340 }
341
342 \f
343 /* Default print handler.  */
344
345 static void
346 print_normal (cd, dis_info, value, attrs, pc, length)
347      CGEN_CPU_DESC cd ATTRIBUTE_UNUSED;
348      PTR dis_info;
349      long value;
350      unsigned int attrs;
351      bfd_vma pc ATTRIBUTE_UNUSED;
352      int length ATTRIBUTE_UNUSED;
353 {
354   disassemble_info *info = (disassemble_info *) dis_info;
355
356 #ifdef CGEN_PRINT_NORMAL
357   CGEN_PRINT_NORMAL (cd, info, value, attrs, pc, length);
358 #endif
359
360   /* Print the operand as directed by the attributes.  */
361   if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SEM_ONLY))
362     ; /* nothing to do */
363   else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SIGNED))
364     (*info->fprintf_func) (info->stream, "%ld", value);
365   else
366     (*info->fprintf_func) (info->stream, "0x%lx", value);
367 }
368
369 /* Default address handler.  */
370
371 static void
372 print_address (cd, dis_info, value, attrs, pc, length)
373      CGEN_CPU_DESC cd ATTRIBUTE_UNUSED;
374      PTR dis_info;
375      bfd_vma value;
376      unsigned int attrs;
377      bfd_vma pc ATTRIBUTE_UNUSED;
378      int length ATTRIBUTE_UNUSED;
379 {
380   disassemble_info *info = (disassemble_info *) dis_info;
381
382 #ifdef CGEN_PRINT_ADDRESS
383   CGEN_PRINT_ADDRESS (cd, info, value, attrs, pc, length);
384 #endif
385
386   /* Print the operand as directed by the attributes.  */
387   if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SEM_ONLY))
388     ; /* nothing to do */
389   else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_PCREL_ADDR))
390     (*info->print_address_func) (value, info);
391   else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_ABS_ADDR))
392     (*info->print_address_func) (value, info);
393   else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SIGNED))
394     (*info->fprintf_func) (info->stream, "%ld", (long) value);
395   else
396     (*info->fprintf_func) (info->stream, "0x%lx", (long) value);
397 }
398
399 /* Keyword print handler.  */
400
401 static void
402 print_keyword (cd, dis_info, keyword_table, value, attrs)
403      CGEN_CPU_DESC cd ATTRIBUTE_UNUSED;
404      PTR dis_info;
405      CGEN_KEYWORD *keyword_table;
406      long value;
407      unsigned int attrs ATTRIBUTE_UNUSED;
408 {
409   disassemble_info *info = (disassemble_info *) dis_info;
410   const CGEN_KEYWORD_ENTRY *ke;
411
412   ke = cgen_keyword_lookup_value (keyword_table, value);
413   if (ke != NULL)
414     (*info->fprintf_func) (info->stream, "%s", ke->name);
415   else
416     (*info->fprintf_func) (info->stream, "???");
417 }
418 \f
419 /* Default insn printer.
420
421    DIS_INFO is defined as `PTR' so the disassembler needn't know anything
422    about disassemble_info.  */
423
424 static void
425 print_insn_normal (cd, dis_info, insn, fields, pc, length)
426      CGEN_CPU_DESC cd;
427      PTR dis_info;
428      const CGEN_INSN *insn;
429      CGEN_FIELDS *fields;
430      bfd_vma pc;
431      int length;
432 {
433   const CGEN_SYNTAX *syntax = CGEN_INSN_SYNTAX (insn);
434   disassemble_info *info = (disassemble_info *) dis_info;
435   const CGEN_SYNTAX_CHAR_TYPE *syn;
436
437   CGEN_INIT_PRINT (cd);
438
439   for (syn = CGEN_SYNTAX_STRING (syntax); *syn; ++syn)
440     {
441       if (CGEN_SYNTAX_MNEMONIC_P (*syn))
442         {
443           (*info->fprintf_func) (info->stream, "%s", CGEN_INSN_MNEMONIC (insn));
444           continue;
445         }
446       if (CGEN_SYNTAX_CHAR_P (*syn))
447         {
448           (*info->fprintf_func) (info->stream, "%c", CGEN_SYNTAX_CHAR (*syn));
449           continue;
450         }
451
452       /* We have an operand.  */
453       fr30_cgen_print_operand (cd, CGEN_SYNTAX_FIELD (*syn), info,
454                                  fields, CGEN_INSN_ATTRS (insn), pc, length);
455     }
456 }
457 \f
458 /* Subroutine of print_insn. Reads an insn into the given buffers and updates
459    the extract info.
460    Returns 0 if all is well, non-zero otherwise.  */
461
462 static int
463 read_insn (cd, pc, info, buf, buflen, ex_info, insn_value)
464      CGEN_CPU_DESC cd ATTRIBUTE_UNUSED;
465      bfd_vma pc;
466      disassemble_info *info;
467      char *buf;
468      int buflen;
469      CGEN_EXTRACT_INFO *ex_info;
470      unsigned long *insn_value;
471 {
472   int status = (*info->read_memory_func) (pc, buf, buflen, info);
473   if (status != 0)
474     {
475       (*info->memory_error_func) (status, pc, info);
476       return -1;
477     }
478
479   ex_info->dis_info = info;
480   ex_info->valid = (1 << buflen) - 1;
481   ex_info->insn_bytes = buf;
482
483   *insn_value = bfd_get_bits (buf, buflen * 8, info->endian == BFD_ENDIAN_BIG);
484   return 0;
485 }
486
487 /* Utility to print an insn.
488    BUF is the base part of the insn, target byte order, BUFLEN bytes long.
489    The result is the size of the insn in bytes or zero for an unknown insn
490    or -1 if an error occurs fetching data (memory_error_func will have
491    been called).  */
492
493 static int
494 print_insn (cd, pc, info, buf, buflen)
495      CGEN_CPU_DESC cd;
496      bfd_vma pc;
497      disassemble_info *info;
498      char *buf;
499      unsigned int buflen;
500 {
501   CGEN_INSN_INT insn_value;
502   const CGEN_INSN_LIST *insn_list;
503   CGEN_EXTRACT_INFO ex_info;
504   int basesize;
505
506   /* Extract base part of instruction, just in case CGEN_DIS_* uses it. */
507   basesize = cd->base_insn_bitsize < buflen * 8 ?
508                                      cd->base_insn_bitsize : buflen * 8;
509   insn_value = cgen_get_insn_value (cd, buf, basesize);
510
511
512   /* Fill in ex_info fields like read_insn would.  Don't actually call
513      read_insn, since the incoming buffer is already read (and possibly
514      modified a la m32r).  */
515   ex_info.valid = (1 << buflen) - 1;
516   ex_info.dis_info = info;
517   ex_info.insn_bytes = buf;
518
519   /* The instructions are stored in hash lists.
520      Pick the first one and keep trying until we find the right one.  */
521
522   insn_list = CGEN_DIS_LOOKUP_INSN (cd, buf, insn_value);
523   while (insn_list != NULL)
524     {
525       const CGEN_INSN *insn = insn_list->insn;
526       CGEN_FIELDS fields;
527       int length;
528       unsigned long insn_value_cropped;
529
530 #ifdef CGEN_VALIDATE_INSN_SUPPORTED 
531       /* Not needed as insn shouldn't be in hash lists if not supported.  */
532       /* Supported by this cpu?  */
533       if (! fr30_cgen_insn_supported (cd, insn))
534         {
535           insn_list = CGEN_DIS_NEXT_INSN (insn_list);
536           continue;
537         }
538 #endif
539
540       /* Basic bit mask must be correct.  */
541       /* ??? May wish to allow target to defer this check until the extract
542          handler.  */
543
544       /* Base size may exceed this instruction's size.  Extract the
545          relevant part from the buffer. */
546       if ((unsigned) (CGEN_INSN_BITSIZE (insn) / 8) < buflen &&
547           (unsigned) (CGEN_INSN_BITSIZE (insn) / 8) <= sizeof (unsigned long))
548         insn_value_cropped = bfd_get_bits (buf, CGEN_INSN_BITSIZE (insn), 
549                                            info->endian == BFD_ENDIAN_BIG);
550       else
551         insn_value_cropped = insn_value;
552
553       if ((insn_value_cropped & CGEN_INSN_BASE_MASK (insn))
554           == CGEN_INSN_BASE_VALUE (insn))
555         {
556           /* Printing is handled in two passes.  The first pass parses the
557              machine insn and extracts the fields.  The second pass prints
558              them.  */
559
560           /* Make sure the entire insn is loaded into insn_value, if it
561              can fit.  */
562           if (((unsigned) CGEN_INSN_BITSIZE (insn) > cd->base_insn_bitsize) &&
563               (unsigned) (CGEN_INSN_BITSIZE (insn) / 8) <= sizeof (unsigned long))
564             {
565               unsigned long full_insn_value;
566               int rc = read_insn (cd, pc, info, buf,
567                                   CGEN_INSN_BITSIZE (insn) / 8,
568                                   & ex_info, & full_insn_value);
569               if (rc != 0)
570                 return rc;
571               length = CGEN_EXTRACT_FN (cd, insn)
572                 (cd, insn, &ex_info, full_insn_value, &fields, pc);
573             }
574           else
575             length = CGEN_EXTRACT_FN (cd, insn)
576               (cd, insn, &ex_info, insn_value_cropped, &fields, pc);
577
578           /* length < 0 -> error */
579           if (length < 0)
580             return length;
581           if (length > 0)
582             {
583               CGEN_PRINT_FN (cd, insn) (cd, info, insn, &fields, pc, length);
584               /* length is in bits, result is in bytes */
585               return length / 8;
586             }
587         }
588
589       insn_list = CGEN_DIS_NEXT_INSN (insn_list);
590     }
591
592   return 0;
593 }
594
595 /* Default value for CGEN_PRINT_INSN.
596    The result is the size of the insn in bytes or zero for an unknown insn
597    or -1 if an error occured fetching bytes.  */
598
599 #ifndef CGEN_PRINT_INSN
600 #define CGEN_PRINT_INSN default_print_insn
601 #endif
602
603 static int
604 default_print_insn (cd, pc, info)
605      CGEN_CPU_DESC cd;
606      bfd_vma pc;
607      disassemble_info *info;
608 {
609   char buf[CGEN_MAX_INSN_SIZE];
610   int buflen;
611   int status;
612
613   /* Attempt to read the base part of the insn.  */
614   buflen = cd->base_insn_bitsize / 8;
615   status = (*info->read_memory_func) (pc, buf, buflen, info);
616
617   /* Try again with the minimum part, if min < base.  */
618   if (status != 0 && (cd->min_insn_bitsize < cd->base_insn_bitsize))
619     {
620       buflen = cd->min_insn_bitsize / 8;
621       status = (*info->read_memory_func) (pc, buf, buflen, info);
622     }
623
624   if (status != 0)
625     {
626       (*info->memory_error_func) (status, pc, info);
627       return -1;
628     }
629
630   return print_insn (cd, pc, info, buf, buflen);
631 }
632
633 /* Main entry point.
634    Print one instruction from PC on INFO->STREAM.
635    Return the size of the instruction (in bytes).  */
636
637 typedef struct cpu_desc_list {
638   struct cpu_desc_list *next;
639   int isa;
640   int mach;
641   int endian;
642   CGEN_CPU_DESC cd;
643 } cpu_desc_list;
644
645 int
646 print_insn_fr30 (pc, info)
647      bfd_vma pc;
648      disassemble_info *info;
649 {
650   static cpu_desc_list *cd_list = 0;
651   cpu_desc_list *cl = 0;
652   static CGEN_CPU_DESC cd = 0;
653   static int prev_isa;
654   static int prev_mach;
655   static int prev_endian;
656   int length;
657   int isa,mach;
658   int endian = (info->endian == BFD_ENDIAN_BIG
659                 ? CGEN_ENDIAN_BIG
660                 : CGEN_ENDIAN_LITTLE);
661   enum bfd_architecture arch;
662
663   /* ??? gdb will set mach but leave the architecture as "unknown" */
664 #ifndef CGEN_BFD_ARCH
665 #define CGEN_BFD_ARCH bfd_arch_fr30
666 #endif
667   arch = info->arch;
668   if (arch == bfd_arch_unknown)
669     arch = CGEN_BFD_ARCH;
670    
671   /* There's no standard way to compute the machine or isa number
672      so we leave it to the target.  */
673 #ifdef CGEN_COMPUTE_MACH
674   mach = CGEN_COMPUTE_MACH (info);
675 #else
676   mach = info->mach;
677 #endif
678
679 #ifdef CGEN_COMPUTE_ISA
680   isa = CGEN_COMPUTE_ISA (info);
681 #else
682   isa = info->insn_sets;
683 #endif
684
685   /* If we've switched cpu's, try to find a handle we've used before */
686   if (cd
687       && (isa != prev_isa
688           || mach != prev_mach
689           || endian != prev_endian))
690     {
691       cd = 0;
692       for (cl = cd_list; cl; cl = cl->next)
693         {
694           if (cl->isa == isa &&
695               cl->mach == mach &&
696               cl->endian == endian)
697             {
698               cd = cl->cd;
699               break;
700             }
701         }
702     } 
703
704   /* If we haven't initialized yet, initialize the opcode table.  */
705   if (! cd)
706     {
707       const bfd_arch_info_type *arch_type = bfd_lookup_arch (arch, mach);
708       const char *mach_name;
709
710       if (!arch_type)
711         abort ();
712       mach_name = arch_type->printable_name;
713
714       prev_isa = isa;
715       prev_mach = mach;
716       prev_endian = endian;
717       cd = fr30_cgen_cpu_open (CGEN_CPU_OPEN_ISAS, prev_isa,
718                                  CGEN_CPU_OPEN_BFDMACH, mach_name,
719                                  CGEN_CPU_OPEN_ENDIAN, prev_endian,
720                                  CGEN_CPU_OPEN_END);
721       if (!cd)
722         abort ();
723
724       /* save this away for future reference */
725       cl = xmalloc (sizeof (struct cpu_desc_list));
726       cl->cd = cd;
727       cl->isa = isa;
728       cl->mach = mach;
729       cl->endian = endian;
730       cl->next = cd_list;
731       cd_list = cl;
732
733       fr30_cgen_init_dis (cd);
734     }
735
736   /* We try to have as much common code as possible.
737      But at this point some targets need to take over.  */
738   /* ??? Some targets may need a hook elsewhere.  Try to avoid this,
739      but if not possible try to move this hook elsewhere rather than
740      have two hooks.  */
741   length = CGEN_PRINT_INSN (cd, pc, info);
742   if (length > 0)
743     return length;
744   if (length < 0)
745     return -1;
746
747   (*info->fprintf_func) (info->stream, UNKNOWN_INSN_MSG);
748   return cd->default_insn_bitsize / 8;
749 }