OSDN Git Service

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