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 "openrisc-desc.h"
00043 #include "openrisc-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 openrisc_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 openrisc_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 OPENRISC_OPERAND_ABS_26 :
00102 print_address (cd, info, fields->f_abs26, 0|(1<<CGEN_OPERAND_ABS_ADDR), pc, length);
00103 break;
00104 case OPENRISC_OPERAND_DISP_26 :
00105 print_address (cd, info, fields->f_disp26, 0|(1<<CGEN_OPERAND_PCREL_ADDR), pc, length);
00106 break;
00107 case OPENRISC_OPERAND_HI16 :
00108 print_normal (cd, info, fields->f_simm16, 0|(1<<CGEN_OPERAND_SIGNED)|(1<<CGEN_OPERAND_SIGN_OPT), pc, length);
00109 break;
00110 case OPENRISC_OPERAND_LO16 :
00111 print_normal (cd, info, fields->f_lo16, 0|(1<<CGEN_OPERAND_SIGNED)|(1<<CGEN_OPERAND_SIGN_OPT), pc, length);
00112 break;
00113 case OPENRISC_OPERAND_OP_F_23 :
00114 print_normal (cd, info, fields->f_op4, 0, pc, length);
00115 break;
00116 case OPENRISC_OPERAND_OP_F_3 :
00117 print_normal (cd, info, fields->f_op5, 0, pc, length);
00118 break;
00119 case OPENRISC_OPERAND_RA :
00120 print_keyword (cd, info, & openrisc_cgen_opval_h_gr, fields->f_r2, 0);
00121 break;
00122 case OPENRISC_OPERAND_RB :
00123 print_keyword (cd, info, & openrisc_cgen_opval_h_gr, fields->f_r3, 0);
00124 break;
00125 case OPENRISC_OPERAND_RD :
00126 print_keyword (cd, info, & openrisc_cgen_opval_h_gr, fields->f_r1, 0);
00127 break;
00128 case OPENRISC_OPERAND_SIMM_16 :
00129 print_normal (cd, info, fields->f_simm16, 0|(1<<CGEN_OPERAND_SIGNED), pc, length);
00130 break;
00131 case OPENRISC_OPERAND_UI16NC :
00132 print_normal (cd, info, fields->f_i16nc, 0|(1<<CGEN_OPERAND_SIGNED)|(1<<CGEN_OPERAND_SIGN_OPT)|(1<<CGEN_OPERAND_VIRTUAL), pc, length);
00133 break;
00134 case OPENRISC_OPERAND_UIMM_16 :
00135 print_normal (cd, info, fields->f_uimm16, 0, pc, length);
00136 break;
00137 case OPENRISC_OPERAND_UIMM_5 :
00138 print_normal (cd, info, fields->f_uimm5, 0, pc, length);
00139 break;
00140
00141 default :
00142
00143 fprintf (stderr, _("Unrecognized field %d while printing insn.\n"),
00144 opindex);
00145 abort ();
00146 }
00147 }
00148
00149 cgen_print_fn * const openrisc_cgen_print_handlers[] =
00150 {
00151 print_insn_normal,
00152 };
00153
00154
00155 void
00156 openrisc_cgen_init_dis (cd)
00157 CGEN_CPU_DESC cd;
00158 {
00159 openrisc_cgen_init_opcode_table (cd);
00160 openrisc_cgen_init_ibld_table (cd);
00161 cd->print_handlers = & openrisc_cgen_print_handlers[0];
00162 cd->print_operand = openrisc_cgen_print_operand;
00163 }
00164
00165
00166
00167
00168 static void
00169 print_normal (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
00170 void *dis_info,
00171 long value,
00172 unsigned int attrs,
00173 bfd_vma pc ATTRIBUTE_UNUSED,
00174 int length ATTRIBUTE_UNUSED)
00175 {
00176 disassemble_info *info = (disassemble_info *) dis_info;
00177
00178 #ifdef CGEN_PRINT_NORMAL
00179 CGEN_PRINT_NORMAL (cd, info, value, attrs, pc, length);
00180 #endif
00181
00182
00183 if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SEM_ONLY))
00184 ;
00185 else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SIGNED))
00186 (*info->fprintf_func) (info->stream, "%ld", value);
00187 else
00188 (*info->fprintf_func) (info->stream, "0x%lx", value);
00189 }
00190
00191
00192
00193 static void
00194 print_address (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
00195 void *dis_info,
00196 bfd_vma value,
00197 unsigned int attrs,
00198 bfd_vma pc ATTRIBUTE_UNUSED,
00199 int length ATTRIBUTE_UNUSED)
00200 {
00201 disassemble_info *info = (disassemble_info *) dis_info;
00202
00203 #ifdef CGEN_PRINT_ADDRESS
00204 CGEN_PRINT_ADDRESS (cd, info, value, attrs, pc, length);
00205 #endif
00206
00207
00208 if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SEM_ONLY))
00209 ;
00210 else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_PCREL_ADDR))
00211 (*info->print_address_func) (value, info);
00212 else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_ABS_ADDR))
00213 (*info->print_address_func) (value, info);
00214 else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SIGNED))
00215 (*info->fprintf_func) (info->stream, "%ld", (long) value);
00216 else
00217 (*info->fprintf_func) (info->stream, "0x%lx", (long) value);
00218 }
00219
00220
00221
00222 static void
00223 print_keyword (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
00224 void *dis_info,
00225 CGEN_KEYWORD *keyword_table,
00226 long value,
00227 unsigned int attrs ATTRIBUTE_UNUSED)
00228 {
00229 disassemble_info *info = (disassemble_info *) dis_info;
00230 const CGEN_KEYWORD_ENTRY *ke;
00231
00232 ke = cgen_keyword_lookup_value (keyword_table, value);
00233 if (ke != NULL)
00234 (*info->fprintf_func) (info->stream, "%s", ke->name);
00235 else
00236 (*info->fprintf_func) (info->stream, "???");
00237 }
00238
00239
00240
00241
00242
00243
00244 static void
00245 print_insn_normal (CGEN_CPU_DESC cd,
00246 void *dis_info,
00247 const CGEN_INSN *insn,
00248 CGEN_FIELDS *fields,
00249 bfd_vma pc,
00250 int length)
00251 {
00252 const CGEN_SYNTAX *syntax = CGEN_INSN_SYNTAX (insn);
00253 disassemble_info *info = (disassemble_info *) dis_info;
00254 const CGEN_SYNTAX_CHAR_TYPE *syn;
00255
00256 CGEN_INIT_PRINT (cd);
00257
00258 for (syn = CGEN_SYNTAX_STRING (syntax); *syn; ++syn)
00259 {
00260 if (CGEN_SYNTAX_MNEMONIC_P (*syn))
00261 {
00262 (*info->fprintf_func) (info->stream, "%s", CGEN_INSN_MNEMONIC (insn));
00263 continue;
00264 }
00265 if (CGEN_SYNTAX_CHAR_P (*syn))
00266 {
00267 (*info->fprintf_func) (info->stream, "%c", CGEN_SYNTAX_CHAR (*syn));
00268 continue;
00269 }
00270
00271
00272 openrisc_cgen_print_operand (cd, CGEN_SYNTAX_FIELD (*syn), info,
00273 fields, CGEN_INSN_ATTRS (insn), pc, length);
00274 }
00275 }
00276
00277
00278
00279
00280
00281 static int
00282 read_insn (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
00283 bfd_vma pc,
00284 disassemble_info *info,
00285 bfd_byte *buf,
00286 int buflen,
00287 CGEN_EXTRACT_INFO *ex_info,
00288 unsigned long *insn_value)
00289 {
00290 int status = (*info->read_memory_func) (pc, buf, buflen, info);
00291 if (status != 0)
00292 {
00293 (*info->memory_error_func) (status, pc, info);
00294 return -1;
00295 }
00296
00297 ex_info->dis_info = info;
00298 ex_info->valid = (1 << buflen) - 1;
00299 ex_info->insn_bytes = buf;
00300
00301 *insn_value = bfd_get_bits (buf, buflen * 8, info->endian == BFD_ENDIAN_BIG);
00302 return 0;
00303 }
00304
00305
00306
00307
00308
00309
00310
00311 static int
00312 print_insn (CGEN_CPU_DESC cd,
00313 bfd_vma pc,
00314 disassemble_info *info,
00315 bfd_byte *buf,
00316 unsigned int buflen)
00317 {
00318 CGEN_INSN_INT insn_value;
00319 const CGEN_INSN_LIST *insn_list;
00320 CGEN_EXTRACT_INFO ex_info;
00321 int basesize;
00322
00323
00324 basesize = cd->base_insn_bitsize < buflen * 8 ?
00325 cd->base_insn_bitsize : buflen * 8;
00326 insn_value = cgen_get_insn_value (cd, buf, basesize);
00327
00328
00329
00330
00331
00332 ex_info.valid = (1 << buflen) - 1;
00333 ex_info.dis_info = info;
00334 ex_info.insn_bytes = buf;
00335
00336
00337
00338
00339 insn_list = CGEN_DIS_LOOKUP_INSN (cd, (char *) buf, insn_value);
00340 while (insn_list != NULL)
00341 {
00342 const CGEN_INSN *insn = insn_list->insn;
00343 CGEN_FIELDS fields;
00344 int length;
00345 unsigned long insn_value_cropped;
00346
00347 #ifdef CGEN_VALIDATE_INSN_SUPPORTED
00348
00349
00350 if (! openrisc_cgen_insn_supported (cd, insn))
00351 {
00352 insn_list = CGEN_DIS_NEXT_INSN (insn_list);
00353 continue;
00354 }
00355 #endif
00356
00357
00358
00359
00360
00361
00362
00363 if ((unsigned) (CGEN_INSN_BITSIZE (insn) / 8) < buflen &&
00364 (unsigned) (CGEN_INSN_BITSIZE (insn) / 8) <= sizeof (unsigned long))
00365 insn_value_cropped = bfd_get_bits (buf, CGEN_INSN_BITSIZE (insn),
00366 info->endian == BFD_ENDIAN_BIG);
00367 else
00368 insn_value_cropped = insn_value;
00369
00370 if ((insn_value_cropped & CGEN_INSN_BASE_MASK (insn))
00371 == CGEN_INSN_BASE_VALUE (insn))
00372 {
00373
00374
00375
00376
00377
00378
00379 if (((unsigned) CGEN_INSN_BITSIZE (insn) > cd->base_insn_bitsize) &&
00380 (unsigned) (CGEN_INSN_BITSIZE (insn) / 8) <= sizeof (unsigned long))
00381 {
00382 unsigned long full_insn_value;
00383 int rc = read_insn (cd, pc, info, buf,
00384 CGEN_INSN_BITSIZE (insn) / 8,
00385 & ex_info, & full_insn_value);
00386 if (rc != 0)
00387 return rc;
00388 length = CGEN_EXTRACT_FN (cd, insn)
00389 (cd, insn, &ex_info, full_insn_value, &fields, pc);
00390 }
00391 else
00392 length = CGEN_EXTRACT_FN (cd, insn)
00393 (cd, insn, &ex_info, insn_value_cropped, &fields, pc);
00394
00395
00396 if (length < 0)
00397 return length;
00398 if (length > 0)
00399 {
00400 CGEN_PRINT_FN (cd, insn) (cd, info, insn, &fields, pc, length);
00401
00402 return length / 8;
00403 }
00404 }
00405
00406 insn_list = CGEN_DIS_NEXT_INSN (insn_list);
00407 }
00408
00409 return 0;
00410 }
00411
00412
00413
00414
00415
00416 #ifndef CGEN_PRINT_INSN
00417 #define CGEN_PRINT_INSN default_print_insn
00418 #endif
00419
00420 static int
00421 default_print_insn (CGEN_CPU_DESC cd, bfd_vma pc, disassemble_info *info)
00422 {
00423 bfd_byte buf[CGEN_MAX_INSN_SIZE];
00424 int buflen;
00425 int status;
00426
00427
00428 buflen = cd->base_insn_bitsize / 8;
00429 status = (*info->read_memory_func) (pc, buf, buflen, info);
00430
00431
00432 if (status != 0 && (cd->min_insn_bitsize < cd->base_insn_bitsize))
00433 {
00434 buflen = cd->min_insn_bitsize / 8;
00435 status = (*info->read_memory_func) (pc, buf, buflen, info);
00436 }
00437
00438 if (status != 0)
00439 {
00440 (*info->memory_error_func) (status, pc, info);
00441 return -1;
00442 }
00443
00444 return print_insn (cd, pc, info, buf, buflen);
00445 }
00446
00447
00448
00449
00450
00451 typedef struct cpu_desc_list {
00452 struct cpu_desc_list *next;
00453 int isa;
00454 int mach;
00455 int endian;
00456 CGEN_CPU_DESC cd;
00457 } cpu_desc_list;
00458
00459 int
00460 print_insn_openrisc (bfd_vma pc, disassemble_info *info)
00461 {
00462 static cpu_desc_list *cd_list = 0;
00463 cpu_desc_list *cl = 0;
00464 static CGEN_CPU_DESC cd = 0;
00465 static int prev_isa;
00466 static int prev_mach;
00467 static int prev_endian;
00468 int length;
00469 int isa,mach;
00470 int endian = (info->endian == BFD_ENDIAN_BIG
00471 ? CGEN_ENDIAN_BIG
00472 : CGEN_ENDIAN_LITTLE);
00473 enum bfd_architecture arch;
00474
00475
00476 #ifndef CGEN_BFD_ARCH
00477 #define CGEN_BFD_ARCH bfd_arch_openrisc
00478 #endif
00479 arch = info->arch;
00480 if (arch == bfd_arch_unknown)
00481 arch = CGEN_BFD_ARCH;
00482
00483
00484
00485 #ifdef CGEN_COMPUTE_MACH
00486 mach = CGEN_COMPUTE_MACH (info);
00487 #else
00488 mach = info->mach;
00489 #endif
00490
00491 #ifdef CGEN_COMPUTE_ISA
00492 isa = CGEN_COMPUTE_ISA (info);
00493 #else
00494 isa = info->insn_sets;
00495 #endif
00496
00497
00498 if (cd
00499 && (isa != prev_isa
00500 || mach != prev_mach
00501 || endian != prev_endian))
00502 {
00503 cd = 0;
00504 for (cl = cd_list; cl; cl = cl->next)
00505 {
00506 if (cl->isa == isa &&
00507 cl->mach == mach &&
00508 cl->endian == endian)
00509 {
00510 cd = cl->cd;
00511 break;
00512 }
00513 }
00514 }
00515
00516
00517 if (! cd)
00518 {
00519 const bfd_arch_info_type *arch_type = bfd_lookup_arch (arch, mach);
00520 const char *mach_name;
00521
00522 if (!arch_type)
00523 abort ();
00524 mach_name = arch_type->printable_name;
00525
00526 prev_isa = isa;
00527 prev_mach = mach;
00528 prev_endian = endian;
00529 cd = openrisc_cgen_cpu_open (CGEN_CPU_OPEN_ISAS, prev_isa,
00530 CGEN_CPU_OPEN_BFDMACH, mach_name,
00531 CGEN_CPU_OPEN_ENDIAN, prev_endian,
00532 CGEN_CPU_OPEN_END);
00533 if (!cd)
00534 abort ();
00535
00536
00537 cl = xmalloc (sizeof (struct cpu_desc_list));
00538 cl->cd = cd;
00539 cl->isa = isa;
00540 cl->mach = mach;
00541 cl->endian = endian;
00542 cl->next = cd_list;
00543 cd_list = cl;
00544
00545 openrisc_cgen_init_dis (cd);
00546 }
00547
00548
00549
00550
00551
00552
00553 length = CGEN_PRINT_INSN (cd, pc, info);
00554 if (length > 0)
00555 return length;
00556 if (length < 0)
00557 return -1;
00558
00559 (*info->fprintf_func) (info->stream, UNKNOWN_INSN_MSG);
00560 return cd->default_insn_bitsize / 8;
00561 }