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