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