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