00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035 #include "sysdep.h"
00036 #include <stdio.h>
00037 #include "ansidecl.h"
00038 #include "dis-asm.h"
00039 #include "bfd.h"
00040 #include "symcat.h"
00041 #include "libiberty.h"
00042 #include "iq2000-desc.h"
00043 #include "iq2000-opc.h"
00044 #include "opintl.h"
00045
00046
00047 #define UNKNOWN_INSN_MSG _("*unknown*")
00048
00049 static void print_normal
00050 (CGEN_CPU_DESC, void *, long, unsigned int, bfd_vma, int);
00051 static void print_address
00052 (CGEN_CPU_DESC, void *, bfd_vma, unsigned int, bfd_vma, int) ATTRIBUTE_UNUSED;
00053 static void print_keyword
00054 (CGEN_CPU_DESC, void *, CGEN_KEYWORD *, long, unsigned int) ATTRIBUTE_UNUSED;
00055 static void print_insn_normal
00056 (CGEN_CPU_DESC, void *, const CGEN_INSN *, CGEN_FIELDS *, bfd_vma, int);
00057 static int print_insn
00058 (CGEN_CPU_DESC, bfd_vma, disassemble_info *, bfd_byte *, unsigned);
00059 static int default_print_insn
00060 (CGEN_CPU_DESC, bfd_vma, disassemble_info *) ATTRIBUTE_UNUSED;
00061 static int read_insn
00062 (CGEN_CPU_DESC, bfd_vma, disassemble_info *, bfd_byte *, int, CGEN_EXTRACT_INFO *,
00063 unsigned long *);
00064
00065
00066
00067
00068 void iq2000_cgen_print_operand
00069 PARAMS ((CGEN_CPU_DESC, int, PTR, CGEN_FIELDS *,
00070 void const *, bfd_vma, int));
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087 void
00088 iq2000_cgen_print_operand (cd, opindex, xinfo, fields, attrs, pc, length)
00089 CGEN_CPU_DESC cd;
00090 int opindex;
00091 PTR xinfo;
00092 CGEN_FIELDS *fields;
00093 void const *attrs ATTRIBUTE_UNUSED;
00094 bfd_vma pc;
00095 int length;
00096 {
00097 disassemble_info *info = (disassemble_info *) xinfo;
00098
00099 switch (opindex)
00100 {
00101 case IQ2000_OPERAND__INDEX :
00102 print_normal (cd, info, fields->f_index, 0, pc, length);
00103 break;
00104 case IQ2000_OPERAND_BASE :
00105 print_keyword (cd, info, & iq2000_cgen_opval_gr_names, fields->f_rs, 0);
00106 break;
00107 case IQ2000_OPERAND_BASEOFF :
00108 print_address (cd, info, fields->f_imm, 0, pc, length);
00109 break;
00110 case IQ2000_OPERAND_BITNUM :
00111 print_normal (cd, info, fields->f_rt, 0, pc, length);
00112 break;
00113 case IQ2000_OPERAND_BYTECOUNT :
00114 print_normal (cd, info, fields->f_bytecount, 0, pc, length);
00115 break;
00116 case IQ2000_OPERAND_CAM_Y :
00117 print_normal (cd, info, fields->f_cam_y, 0, pc, length);
00118 break;
00119 case IQ2000_OPERAND_CAM_Z :
00120 print_normal (cd, info, fields->f_cam_z, 0, pc, length);
00121 break;
00122 case IQ2000_OPERAND_CM_3FUNC :
00123 print_normal (cd, info, fields->f_cm_3func, 0, pc, length);
00124 break;
00125 case IQ2000_OPERAND_CM_3Z :
00126 print_normal (cd, info, fields->f_cm_3z, 0, pc, length);
00127 break;
00128 case IQ2000_OPERAND_CM_4FUNC :
00129 print_normal (cd, info, fields->f_cm_4func, 0, pc, length);
00130 break;
00131 case IQ2000_OPERAND_CM_4Z :
00132 print_normal (cd, info, fields->f_cm_4z, 0, pc, length);
00133 break;
00134 case IQ2000_OPERAND_COUNT :
00135 print_normal (cd, info, fields->f_count, 0, pc, length);
00136 break;
00137 case IQ2000_OPERAND_EXECODE :
00138 print_normal (cd, info, fields->f_excode, 0, pc, length);
00139 break;
00140 case IQ2000_OPERAND_HI16 :
00141 print_normal (cd, info, fields->f_imm, 0, pc, length);
00142 break;
00143 case IQ2000_OPERAND_IMM :
00144 print_normal (cd, info, fields->f_imm, 0, pc, length);
00145 break;
00146 case IQ2000_OPERAND_JMPTARG :
00147 print_address (cd, info, fields->f_jtarg, 0|(1<<CGEN_OPERAND_ABS_ADDR), pc, length);
00148 break;
00149 case IQ2000_OPERAND_JMPTARGQ10 :
00150 print_address (cd, info, fields->f_jtargq10, 0|(1<<CGEN_OPERAND_ABS_ADDR), pc, length);
00151 break;
00152 case IQ2000_OPERAND_LO16 :
00153 print_normal (cd, info, fields->f_imm, 0, pc, length);
00154 break;
00155 case IQ2000_OPERAND_MASK :
00156 print_normal (cd, info, fields->f_mask, 0, pc, length);
00157 break;
00158 case IQ2000_OPERAND_MASKL :
00159 print_normal (cd, info, fields->f_maskl, 0, pc, length);
00160 break;
00161 case IQ2000_OPERAND_MASKQ10 :
00162 print_normal (cd, info, fields->f_maskq10, 0, pc, length);
00163 break;
00164 case IQ2000_OPERAND_MASKR :
00165 print_normal (cd, info, fields->f_rs, 0, pc, length);
00166 break;
00167 case IQ2000_OPERAND_MLO16 :
00168 print_normal (cd, info, fields->f_imm, 0, pc, length);
00169 break;
00170 case IQ2000_OPERAND_OFFSET :
00171 print_address (cd, info, fields->f_offset, 0|(1<<CGEN_OPERAND_PCREL_ADDR), pc, length);
00172 break;
00173 case IQ2000_OPERAND_RD :
00174 print_keyword (cd, info, & iq2000_cgen_opval_gr_names, fields->f_rd, 0);
00175 break;
00176 case IQ2000_OPERAND_RD_RS :
00177 print_keyword (cd, info, & iq2000_cgen_opval_gr_names, fields->f_rd_rs, 0|(1<<CGEN_OPERAND_VIRTUAL));
00178 break;
00179 case IQ2000_OPERAND_RD_RT :
00180 print_keyword (cd, info, & iq2000_cgen_opval_gr_names, fields->f_rd_rt, 0|(1<<CGEN_OPERAND_VIRTUAL));
00181 break;
00182 case IQ2000_OPERAND_RS :
00183 print_keyword (cd, info, & iq2000_cgen_opval_gr_names, fields->f_rs, 0);
00184 break;
00185 case IQ2000_OPERAND_RT :
00186 print_keyword (cd, info, & iq2000_cgen_opval_gr_names, fields->f_rt, 0);
00187 break;
00188 case IQ2000_OPERAND_RT_RS :
00189 print_keyword (cd, info, & iq2000_cgen_opval_gr_names, fields->f_rt_rs, 0|(1<<CGEN_OPERAND_VIRTUAL));
00190 break;
00191 case IQ2000_OPERAND_SHAMT :
00192 print_normal (cd, info, fields->f_shamt, 0, pc, length);
00193 break;
00194
00195 default :
00196
00197 fprintf (stderr, _("Unrecognized field %d while printing insn.\n"),
00198 opindex);
00199 abort ();
00200 }
00201 }
00202
00203 cgen_print_fn * const iq2000_cgen_print_handlers[] =
00204 {
00205 print_insn_normal,
00206 };
00207
00208
00209 void
00210 iq2000_cgen_init_dis (cd)
00211 CGEN_CPU_DESC cd;
00212 {
00213 iq2000_cgen_init_opcode_table (cd);
00214 iq2000_cgen_init_ibld_table (cd);
00215 cd->print_handlers = & iq2000_cgen_print_handlers[0];
00216 cd->print_operand = iq2000_cgen_print_operand;
00217 }
00218
00219
00220
00221
00222 static void
00223 print_normal (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
00224 void *dis_info,
00225 long value,
00226 unsigned int attrs,
00227 bfd_vma pc ATTRIBUTE_UNUSED,
00228 int length ATTRIBUTE_UNUSED)
00229 {
00230 disassemble_info *info = (disassemble_info *) dis_info;
00231
00232 #ifdef CGEN_PRINT_NORMAL
00233 CGEN_PRINT_NORMAL (cd, info, value, attrs, pc, length);
00234 #endif
00235
00236
00237 if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SEM_ONLY))
00238 ;
00239 else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SIGNED))
00240 (*info->fprintf_func) (info->stream, "%ld", value);
00241 else
00242 (*info->fprintf_func) (info->stream, "0x%lx", value);
00243 }
00244
00245
00246
00247 static void
00248 print_address (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
00249 void *dis_info,
00250 bfd_vma value,
00251 unsigned int attrs,
00252 bfd_vma pc ATTRIBUTE_UNUSED,
00253 int length ATTRIBUTE_UNUSED)
00254 {
00255 disassemble_info *info = (disassemble_info *) dis_info;
00256
00257 #ifdef CGEN_PRINT_ADDRESS
00258 CGEN_PRINT_ADDRESS (cd, info, value, attrs, pc, length);
00259 #endif
00260
00261
00262 if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SEM_ONLY))
00263 ;
00264 else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_PCREL_ADDR))
00265 (*info->print_address_func) (value, info);
00266 else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_ABS_ADDR))
00267 (*info->print_address_func) (value, info);
00268 else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SIGNED))
00269 (*info->fprintf_func) (info->stream, "%ld", (long) value);
00270 else
00271 (*info->fprintf_func) (info->stream, "0x%lx", (long) value);
00272 }
00273
00274
00275
00276 static void
00277 print_keyword (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
00278 void *dis_info,
00279 CGEN_KEYWORD *keyword_table,
00280 long value,
00281 unsigned int attrs ATTRIBUTE_UNUSED)
00282 {
00283 disassemble_info *info = (disassemble_info *) dis_info;
00284 const CGEN_KEYWORD_ENTRY *ke;
00285
00286 ke = cgen_keyword_lookup_value (keyword_table, value);
00287 if (ke != NULL)
00288 (*info->fprintf_func) (info->stream, "%s", ke->name);
00289 else
00290 (*info->fprintf_func) (info->stream, "???");
00291 }
00292
00293
00294
00295
00296
00297
00298 static void
00299 print_insn_normal (CGEN_CPU_DESC cd,
00300 void *dis_info,
00301 const CGEN_INSN *insn,
00302 CGEN_FIELDS *fields,
00303 bfd_vma pc,
00304 int length)
00305 {
00306 const CGEN_SYNTAX *syntax = CGEN_INSN_SYNTAX (insn);
00307 disassemble_info *info = (disassemble_info *) dis_info;
00308 const CGEN_SYNTAX_CHAR_TYPE *syn;
00309
00310 CGEN_INIT_PRINT (cd);
00311
00312 for (syn = CGEN_SYNTAX_STRING (syntax); *syn; ++syn)
00313 {
00314 if (CGEN_SYNTAX_MNEMONIC_P (*syn))
00315 {
00316 (*info->fprintf_func) (info->stream, "%s", CGEN_INSN_MNEMONIC (insn));
00317 continue;
00318 }
00319 if (CGEN_SYNTAX_CHAR_P (*syn))
00320 {
00321 (*info->fprintf_func) (info->stream, "%c", CGEN_SYNTAX_CHAR (*syn));
00322 continue;
00323 }
00324
00325
00326 iq2000_cgen_print_operand (cd, CGEN_SYNTAX_FIELD (*syn), info,
00327 fields, CGEN_INSN_ATTRS (insn), pc, length);
00328 }
00329 }
00330
00331
00332
00333
00334
00335 static int
00336 read_insn (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
00337 bfd_vma pc,
00338 disassemble_info *info,
00339 bfd_byte *buf,
00340 int buflen,
00341 CGEN_EXTRACT_INFO *ex_info,
00342 unsigned long *insn_value)
00343 {
00344 int status = (*info->read_memory_func) (pc, buf, buflen, info);
00345 if (status != 0)
00346 {
00347 (*info->memory_error_func) (status, pc, info);
00348 return -1;
00349 }
00350
00351 ex_info->dis_info = info;
00352 ex_info->valid = (1 << buflen) - 1;
00353 ex_info->insn_bytes = buf;
00354
00355 *insn_value = bfd_get_bits (buf, buflen * 8, info->endian == BFD_ENDIAN_BIG);
00356 return 0;
00357 }
00358
00359
00360
00361
00362
00363
00364
00365 static int
00366 print_insn (CGEN_CPU_DESC cd,
00367 bfd_vma pc,
00368 disassemble_info *info,
00369 bfd_byte *buf,
00370 unsigned int buflen)
00371 {
00372 CGEN_INSN_INT insn_value;
00373 const CGEN_INSN_LIST *insn_list;
00374 CGEN_EXTRACT_INFO ex_info;
00375 int basesize;
00376
00377
00378 basesize = cd->base_insn_bitsize < buflen * 8 ?
00379 cd->base_insn_bitsize : buflen * 8;
00380 insn_value = cgen_get_insn_value (cd, buf, basesize);
00381
00382
00383
00384
00385
00386 ex_info.valid = (1 << buflen) - 1;
00387 ex_info.dis_info = info;
00388 ex_info.insn_bytes = buf;
00389
00390
00391
00392
00393 insn_list = CGEN_DIS_LOOKUP_INSN (cd, (char *) buf, insn_value);
00394 while (insn_list != NULL)
00395 {
00396 const CGEN_INSN *insn = insn_list->insn;
00397 CGEN_FIELDS fields;
00398 int length;
00399 unsigned long insn_value_cropped;
00400
00401 #ifdef CGEN_VALIDATE_INSN_SUPPORTED
00402
00403
00404 if (! iq2000_cgen_insn_supported (cd, insn))
00405 {
00406 insn_list = CGEN_DIS_NEXT_INSN (insn_list);
00407 continue;
00408 }
00409 #endif
00410
00411
00412
00413
00414
00415
00416
00417 if ((unsigned) (CGEN_INSN_BITSIZE (insn) / 8) < buflen &&
00418 (unsigned) (CGEN_INSN_BITSIZE (insn) / 8) <= sizeof (unsigned long))
00419 insn_value_cropped = bfd_get_bits (buf, CGEN_INSN_BITSIZE (insn),
00420 info->endian == BFD_ENDIAN_BIG);
00421 else
00422 insn_value_cropped = insn_value;
00423
00424 if ((insn_value_cropped & CGEN_INSN_BASE_MASK (insn))
00425 == CGEN_INSN_BASE_VALUE (insn))
00426 {
00427
00428
00429
00430
00431
00432
00433 if (((unsigned) CGEN_INSN_BITSIZE (insn) > cd->base_insn_bitsize) &&
00434 (unsigned) (CGEN_INSN_BITSIZE (insn) / 8) <= sizeof (unsigned long))
00435 {
00436 unsigned long full_insn_value;
00437 int rc = read_insn (cd, pc, info, buf,
00438 CGEN_INSN_BITSIZE (insn) / 8,
00439 & ex_info, & full_insn_value);
00440 if (rc != 0)
00441 return rc;
00442 length = CGEN_EXTRACT_FN (cd, insn)
00443 (cd, insn, &ex_info, full_insn_value, &fields, pc);
00444 }
00445 else
00446 length = CGEN_EXTRACT_FN (cd, insn)
00447 (cd, insn, &ex_info, insn_value_cropped, &fields, pc);
00448
00449
00450 if (length < 0)
00451 return length;
00452 if (length > 0)
00453 {
00454 CGEN_PRINT_FN (cd, insn) (cd, info, insn, &fields, pc, length);
00455
00456 return length / 8;
00457 }
00458 }
00459
00460 insn_list = CGEN_DIS_NEXT_INSN (insn_list);
00461 }
00462
00463 return 0;
00464 }
00465
00466
00467
00468
00469
00470 #ifndef CGEN_PRINT_INSN
00471 #define CGEN_PRINT_INSN default_print_insn
00472 #endif
00473
00474 static int
00475 default_print_insn (CGEN_CPU_DESC cd, bfd_vma pc, disassemble_info *info)
00476 {
00477 bfd_byte buf[CGEN_MAX_INSN_SIZE];
00478 int buflen;
00479 int status;
00480
00481
00482 buflen = cd->base_insn_bitsize / 8;
00483 status = (*info->read_memory_func) (pc, buf, buflen, info);
00484
00485
00486 if (status != 0 && (cd->min_insn_bitsize < cd->base_insn_bitsize))
00487 {
00488 buflen = cd->min_insn_bitsize / 8;
00489 status = (*info->read_memory_func) (pc, buf, buflen, info);
00490 }
00491
00492 if (status != 0)
00493 {
00494 (*info->memory_error_func) (status, pc, info);
00495 return -1;
00496 }
00497
00498 return print_insn (cd, pc, info, buf, buflen);
00499 }
00500
00501
00502
00503
00504
00505 typedef struct cpu_desc_list {
00506 struct cpu_desc_list *next;
00507 int isa;
00508 int mach;
00509 int endian;
00510 CGEN_CPU_DESC cd;
00511 } cpu_desc_list;
00512
00513 int
00514 print_insn_iq2000 (bfd_vma pc, disassemble_info *info)
00515 {
00516 static cpu_desc_list *cd_list = 0;
00517 cpu_desc_list *cl = 0;
00518 static CGEN_CPU_DESC cd = 0;
00519 static int prev_isa;
00520 static int prev_mach;
00521 static int prev_endian;
00522 int length;
00523 int isa,mach;
00524 int endian = (info->endian == BFD_ENDIAN_BIG
00525 ? CGEN_ENDIAN_BIG
00526 : CGEN_ENDIAN_LITTLE);
00527 enum bfd_architecture arch;
00528
00529
00530 #ifndef CGEN_BFD_ARCH
00531 #define CGEN_BFD_ARCH bfd_arch_iq2000
00532 #endif
00533 arch = info->arch;
00534 if (arch == bfd_arch_unknown)
00535 arch = CGEN_BFD_ARCH;
00536
00537
00538
00539 #ifdef CGEN_COMPUTE_MACH
00540 mach = CGEN_COMPUTE_MACH (info);
00541 #else
00542 mach = info->mach;
00543 #endif
00544
00545 #ifdef CGEN_COMPUTE_ISA
00546 isa = CGEN_COMPUTE_ISA (info);
00547 #else
00548 isa = info->insn_sets;
00549 #endif
00550
00551
00552 if (cd
00553 && (isa != prev_isa
00554 || mach != prev_mach
00555 || endian != prev_endian))
00556 {
00557 cd = 0;
00558 for (cl = cd_list; cl; cl = cl->next)
00559 {
00560 if (cl->isa == isa &&
00561 cl->mach == mach &&
00562 cl->endian == endian)
00563 {
00564 cd = cl->cd;
00565 break;
00566 }
00567 }
00568 }
00569
00570
00571 if (! cd)
00572 {
00573 const bfd_arch_info_type *arch_type = bfd_lookup_arch (arch, mach);
00574 const char *mach_name;
00575
00576 if (!arch_type)
00577 abort ();
00578 mach_name = arch_type->printable_name;
00579
00580 prev_isa = isa;
00581 prev_mach = mach;
00582 prev_endian = endian;
00583 cd = iq2000_cgen_cpu_open (CGEN_CPU_OPEN_ISAS, prev_isa,
00584 CGEN_CPU_OPEN_BFDMACH, mach_name,
00585 CGEN_CPU_OPEN_ENDIAN, prev_endian,
00586 CGEN_CPU_OPEN_END);
00587 if (!cd)
00588 abort ();
00589
00590
00591 cl = xmalloc (sizeof (struct cpu_desc_list));
00592 cl->cd = cd;
00593 cl->isa = isa;
00594 cl->mach = mach;
00595 cl->endian = endian;
00596 cl->next = cd_list;
00597 cd_list = cl;
00598
00599 iq2000_cgen_init_dis (cd);
00600 }
00601
00602
00603
00604
00605
00606
00607 length = CGEN_PRINT_INSN (cd, pc, info);
00608 if (length > 0)
00609 return length;
00610 if (length < 0)
00611 return -1;
00612
00613 (*info->fprintf_func) (info->stream, UNKNOWN_INSN_MSG);
00614 return cd->default_insn_bitsize / 8;
00615 }