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