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