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