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