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 
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
print_dollarhex(CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,void * dis_info,long value,unsigned int attrs ATTRIBUTE_UNUSED,bfd_vma pc ATTRIBUTE_UNUSED,int length ATTRIBUTE_UNUSED)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
ms1_cgen_print_operand(CGEN_CPU_DESC cd,int opindex,void * xinfo,CGEN_FIELDS * fields,void const * attrs ATTRIBUTE_UNUSED,bfd_vma pc,int length)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
ms1_cgen_init_dis(CGEN_CPU_DESC cd)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 
280 /* Default print handler.  */
281 
282 static void
print_normal(CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,void * dis_info,long value,unsigned int attrs,bfd_vma pc ATTRIBUTE_UNUSED,int length ATTRIBUTE_UNUSED)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
print_address(CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,void * dis_info,bfd_vma value,unsigned int attrs,bfd_vma pc ATTRIBUTE_UNUSED,int length ATTRIBUTE_UNUSED)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
print_keyword(CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,void * dis_info,CGEN_KEYWORD * keyword_table,long value,unsigned int attrs ATTRIBUTE_UNUSED)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 
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
print_insn_normal(CGEN_CPU_DESC cd,void * dis_info,const CGEN_INSN * insn,CGEN_FIELDS * fields,bfd_vma pc,int length)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 
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
read_insn(CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,bfd_vma pc,disassemble_info * info,bfd_byte * buf,int buflen,CGEN_EXTRACT_INFO * ex_info,unsigned long * insn_value)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
print_insn(CGEN_CPU_DESC cd,bfd_vma pc,disassemble_info * info,bfd_byte * buf,unsigned int buflen)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
default_print_insn(CGEN_CPU_DESC cd,bfd_vma pc,disassemble_info * info)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
print_insn_ms1(bfd_vma pc,disassemble_info * info)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 }
678