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