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-2016 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 
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 
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 
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 
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 }
720