OLD | NEW |
(Empty) | |
| 1 /* Disassemble Imagination Technologies Meta instructions. |
| 2 Copyright (C) 2013 Free Software Foundation, Inc. |
| 3 Contributed by Imagination Technologies Ltd. |
| 4 |
| 5 This library is free software; you can redistribute it and/or modify |
| 6 it under the terms of the GNU General Public License as published by |
| 7 the Free Software Foundation; either version 3 of the License, or |
| 8 (at your option) any later version. |
| 9 |
| 10 It is distributed in the hope that it will be useful, but WITHOUT |
| 11 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY |
| 12 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public |
| 13 License for more details. |
| 14 |
| 15 You should have received a copy of the GNU General Public License |
| 16 along with this program; if not, write to the Free Software |
| 17 Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, |
| 18 MA 02110-1301, USA. */ |
| 19 |
| 20 #include "sysdep.h" |
| 21 #include "dis-asm.h" |
| 22 #include "opintl.h" |
| 23 |
| 24 #include <stdio.h> |
| 25 #include <stdlib.h> |
| 26 #include <string.h> |
| 27 |
| 28 #include "opcode/metag.h" |
| 29 |
| 30 /* Column widths for printing. */ |
| 31 #define PREFIX_WIDTH "10" |
| 32 #define INSN_NAME_WIDTH "10" |
| 33 |
| 34 #define OPERAND_WIDTH 92 |
| 35 #define ADDR_WIDTH 20 |
| 36 #define REG_WIDTH 64 |
| 37 #define DSP_PREFIX_WIDTH 17 |
| 38 |
| 39 /* Value to print if we fail to parse a register name. */ |
| 40 const char unknown_reg[] = "?"; |
| 41 |
| 42 /* Return the size of a GET or SET instruction. */ |
| 43 unsigned int |
| 44 metag_get_set_size_bytes (unsigned int opcode) |
| 45 { |
| 46 switch (((opcode) >> 24) & 0x5) |
| 47 { |
| 48 case 0x5: |
| 49 return 8; |
| 50 case 0x4: |
| 51 return 4; |
| 52 case 0x1: |
| 53 return 2; |
| 54 case 0x0: |
| 55 return 1; |
| 56 } |
| 57 return 1; |
| 58 } |
| 59 |
| 60 /* Return the size of an extended GET or SET instruction. */ |
| 61 unsigned int |
| 62 metag_get_set_ext_size_bytes (unsigned int opcode) |
| 63 { |
| 64 switch (((opcode) >> 1) & 0x3) |
| 65 { |
| 66 case 0x3: |
| 67 return 8; |
| 68 case 0x2: |
| 69 return 4; |
| 70 case 0x1: |
| 71 return 2; |
| 72 case 0x0: |
| 73 return 1; |
| 74 } |
| 75 return 1; |
| 76 } |
| 77 |
| 78 /* Return the size of a conditional SET instruction. */ |
| 79 unsigned int |
| 80 metag_cond_set_size_bytes (unsigned int opcode) |
| 81 { |
| 82 switch (opcode & 0x201) |
| 83 { |
| 84 case 0x201: |
| 85 return 8; |
| 86 case 0x200: |
| 87 return 4; |
| 88 case 0x001: |
| 89 return 2; |
| 90 case 0x000: |
| 91 return 1; |
| 92 } |
| 93 return 1; |
| 94 } |
| 95 |
| 96 /* Return a value sign-extended. */ |
| 97 static int |
| 98 sign_extend (int n, unsigned int bits) |
| 99 { |
| 100 int mask = 1 << (bits - 1); |
| 101 return -(n & mask) | n; |
| 102 } |
| 103 |
| 104 /* Return the short interpretation of UNIT. */ |
| 105 static unsigned int |
| 106 short_unit (unsigned int unit) |
| 107 { |
| 108 if (unit == UNIT_CT) |
| 109 return UNIT_A1; |
| 110 else |
| 111 return unit; |
| 112 } |
| 113 |
| 114 /* Return the register corresponding to UNIT and NUMBER or NULL. */ |
| 115 static const metag_reg * |
| 116 lookup_reg (unsigned int unit, unsigned int number) |
| 117 { |
| 118 size_t i; |
| 119 |
| 120 for (i = 0; i < sizeof(metag_regtab)/sizeof(metag_regtab[0]); i++) |
| 121 { |
| 122 const metag_reg *reg = &metag_regtab[i]; |
| 123 |
| 124 if (reg->unit == unit && reg->no == number) |
| 125 return reg; |
| 126 } |
| 127 return NULL; |
| 128 } |
| 129 |
| 130 |
| 131 /* Return the register name corresponding to UNIT and NUMBER or NULL. */ |
| 132 static const char * |
| 133 lookup_reg_name (unsigned int unit, unsigned int number) |
| 134 { |
| 135 const metag_reg *reg; |
| 136 |
| 137 reg = lookup_reg (unit, number); |
| 138 |
| 139 if (reg) |
| 140 return reg->name; |
| 141 else |
| 142 return unknown_reg; |
| 143 } |
| 144 |
| 145 /* Return the unit that is the pair of UNIT. */ |
| 146 static unsigned int |
| 147 get_pair_unit (unsigned int unit) |
| 148 { |
| 149 switch (unit) |
| 150 { |
| 151 case UNIT_D0: |
| 152 return UNIT_D1; |
| 153 case UNIT_D1: |
| 154 return UNIT_D0; |
| 155 case UNIT_A0: |
| 156 return UNIT_A1; |
| 157 case UNIT_A1: |
| 158 return UNIT_A0; |
| 159 default: |
| 160 return unit; |
| 161 } |
| 162 } |
| 163 |
| 164 /* Return the name of the pair register for UNIT and NUMBER or NULL. */ |
| 165 static const char * |
| 166 lookup_pair_reg_name (unsigned int unit, unsigned int number) |
| 167 { |
| 168 if (unit == UNIT_FX) |
| 169 return lookup_reg_name (unit, number + 1); |
| 170 else |
| 171 return lookup_reg_name (get_pair_unit (unit), number); |
| 172 } |
| 173 |
| 174 /* Return the name of the accumulator register for PART. */ |
| 175 static const char * |
| 176 lookup_acf_name (unsigned int part) |
| 177 { |
| 178 size_t i; |
| 179 |
| 180 for (i = 0; i < sizeof(metag_acftab)/sizeof(metag_acftab[0]); i++) |
| 181 { |
| 182 const metag_acf *acf = &metag_acftab[i]; |
| 183 |
| 184 if (acf->part == part) |
| 185 return acf->name; |
| 186 } |
| 187 return "ACF.?"; |
| 188 } |
| 189 |
| 190 /* Return the register name for the O2R register for UNIT and NUMBER. */ |
| 191 static const char * |
| 192 lookup_o2r (enum metag_unit unit, unsigned int number) |
| 193 { |
| 194 unsigned int o2r_unit; |
| 195 enum metag_unit actual_unit = UNIT_A0; |
| 196 const metag_reg *reg; |
| 197 |
| 198 o2r_unit = (number & ~O2R_REG_MASK) >> 3; |
| 199 number = number & O2R_REG_MASK; |
| 200 |
| 201 if (unit == UNIT_A0) |
| 202 { |
| 203 switch (o2r_unit) |
| 204 { |
| 205 case 0: |
| 206 actual_unit = UNIT_A1; |
| 207 break; |
| 208 case 1: |
| 209 actual_unit = UNIT_D0; |
| 210 break; |
| 211 case 2: |
| 212 actual_unit = UNIT_RD; |
| 213 break; |
| 214 case 3: |
| 215 actual_unit = UNIT_D1; |
| 216 break; |
| 217 } |
| 218 } |
| 219 else if (unit == UNIT_A1) |
| 220 { |
| 221 switch (o2r_unit) |
| 222 { |
| 223 case 0: |
| 224 actual_unit = UNIT_D1; |
| 225 break; |
| 226 case 1: |
| 227 actual_unit = UNIT_D0; |
| 228 break; |
| 229 case 2: |
| 230 actual_unit = UNIT_RD; |
| 231 break; |
| 232 case 3: |
| 233 actual_unit = UNIT_A0; |
| 234 break; |
| 235 } |
| 236 } |
| 237 else if (unit == UNIT_D0) |
| 238 { |
| 239 switch (o2r_unit) |
| 240 { |
| 241 case 0: |
| 242 actual_unit = UNIT_A1; |
| 243 break; |
| 244 case 1: |
| 245 actual_unit = UNIT_D1; |
| 246 break; |
| 247 case 2: |
| 248 actual_unit = UNIT_RD; |
| 249 break; |
| 250 case 3: |
| 251 actual_unit = UNIT_A0; |
| 252 break; |
| 253 } |
| 254 } |
| 255 else if (unit == UNIT_D1) |
| 256 { |
| 257 switch (o2r_unit) |
| 258 { |
| 259 case 0: |
| 260 actual_unit = UNIT_A1; |
| 261 break; |
| 262 case 1: |
| 263 actual_unit = UNIT_D0; |
| 264 break; |
| 265 case 2: |
| 266 actual_unit = UNIT_RD; |
| 267 break; |
| 268 case 3: |
| 269 actual_unit = UNIT_A0; |
| 270 break; |
| 271 } |
| 272 } |
| 273 |
| 274 reg = lookup_reg (actual_unit, number); |
| 275 |
| 276 if (reg) |
| 277 return reg->name; |
| 278 else |
| 279 return unknown_reg; |
| 280 } |
| 281 |
| 282 /* Return the string for split condition code CODE. */ |
| 283 static const char * |
| 284 lookup_scc_flags (unsigned int code) |
| 285 { |
| 286 size_t i; |
| 287 |
| 288 for (i = 0; i < sizeof (metag_dsp_scondtab) / sizeof (metag_dsp_scondtab[0]);
i++) |
| 289 { |
| 290 if (metag_dsp_scondtab[i].code == code) |
| 291 { |
| 292 return metag_dsp_scondtab[i].name; |
| 293 } |
| 294 } |
| 295 return NULL; |
| 296 } |
| 297 |
| 298 /* Return the string for FPU split condition code CODE. */ |
| 299 static const char * |
| 300 lookup_fpu_scc_flags (unsigned int code) |
| 301 { |
| 302 size_t i; |
| 303 |
| 304 for (i = 0; i < sizeof (metag_fpu_scondtab) / sizeof (metag_fpu_scondtab[0]);
i++) |
| 305 { |
| 306 if (metag_fpu_scondtab[i].code == code) |
| 307 { |
| 308 return metag_fpu_scondtab[i].name; |
| 309 } |
| 310 } |
| 311 return NULL; |
| 312 } |
| 313 |
| 314 /* Print an instruction with PREFIX, NAME and OPERANDS. */ |
| 315 static void |
| 316 print_insn (disassemble_info *outf, const char *prefix, const char *name, |
| 317 const char *operands) |
| 318 { |
| 319 outf->fprintf_func (outf->stream, "%-" PREFIX_WIDTH "s%-" INSN_NAME_WIDTH "s%s
", prefix, name, operands); |
| 320 } |
| 321 |
| 322 /* Print an instruction with no operands. */ |
| 323 static void |
| 324 print_none (unsigned int insn_word ATTRIBUTE_UNUSED, |
| 325 bfd_vma pc ATTRIBUTE_UNUSED, |
| 326 const insn_template *template, |
| 327 disassemble_info *outf) |
| 328 { |
| 329 outf->fprintf_func (outf->stream, "%-" PREFIX_WIDTH "s%s", "", |
| 330 template->name); |
| 331 } |
| 332 |
| 333 /* Print a unit to unit MOV instruction. */ |
| 334 static void |
| 335 print_mov_u2u (unsigned int insn_word, bfd_vma pc ATTRIBUTE_UNUSED, |
| 336 const insn_template *template, |
| 337 disassemble_info *outf) |
| 338 { |
| 339 unsigned int dest_unit, dest_no, src_unit, src_no; |
| 340 unsigned int is_kick = (insn_word & 0x1) && !((insn_word >> 9) & 0x1); |
| 341 unsigned int major = MAJOR_OPCODE (insn_word); |
| 342 unsigned int minor = MINOR_OPCODE (insn_word); |
| 343 char buf[OPERAND_WIDTH]; |
| 344 const char *dest_reg; |
| 345 const char *src_reg; |
| 346 |
| 347 dest_unit = (insn_word >> 5) & UNIT_MASK; |
| 348 dest_no = (insn_word >> 14) & REG_MASK; |
| 349 |
| 350 dest_reg = lookup_reg_name (dest_unit, dest_no); |
| 351 |
| 352 if (is_kick) |
| 353 src_unit = UNIT_TR; |
| 354 else |
| 355 src_unit = (insn_word >> 10) & UNIT_MASK; |
| 356 |
| 357 /* This is really an RTI/RTH. No, really. */ |
| 358 if (major == OPC_MISC && |
| 359 minor == 0x3 && |
| 360 src_unit == 0xf) |
| 361 { |
| 362 if (insn_word & 0x800000) |
| 363 outf->fprintf_func (outf->stream, "%-" PREFIX_WIDTH "s%s", "", |
| 364 "RTI"); |
| 365 else |
| 366 outf->fprintf_func (outf->stream, "%-" PREFIX_WIDTH "s%s", "", |
| 367 "RTH"); |
| 368 |
| 369 return; |
| 370 } |
| 371 |
| 372 src_no = (insn_word >> 19) & REG_MASK; |
| 373 |
| 374 src_reg = lookup_reg_name (src_unit, src_no); |
| 375 |
| 376 snprintf (buf, OPERAND_WIDTH, "%s,%s", dest_reg, src_reg); |
| 377 |
| 378 if (dest_unit == UNIT_FX || src_unit == UNIT_FX) |
| 379 print_insn (outf, "F", template->name, buf); |
| 380 else |
| 381 print_insn (outf, "", template->name, buf); |
| 382 } |
| 383 |
| 384 /* Print a MOV to port instruction. */ |
| 385 static void |
| 386 print_mov_port (unsigned int insn_word, bfd_vma pc ATTRIBUTE_UNUSED, |
| 387 const insn_template *template, |
| 388 disassemble_info *outf) |
| 389 { |
| 390 unsigned int dest_unit, dest1_no, dest2_no, src_unit, src_no; |
| 391 unsigned int is_movl = MINOR_OPCODE (insn_word) == MOVL_MINOR; |
| 392 char buf[OPERAND_WIDTH]; |
| 393 const char *dest_reg; |
| 394 const char *pair_reg; |
| 395 const char *src_reg; |
| 396 |
| 397 if (is_movl) |
| 398 dest_unit = short_unit ((insn_word >> 5) & SHORT_UNIT_MASK); |
| 399 else |
| 400 dest_unit = (insn_word >> 5) & UNIT_MASK; |
| 401 |
| 402 dest1_no = (insn_word >> 14) & REG_MASK; |
| 403 dest2_no = (insn_word >> 9) & REG_MASK; |
| 404 |
| 405 dest_reg = lookup_reg_name (dest_unit, dest1_no); |
| 406 pair_reg = lookup_pair_reg_name (dest_unit, dest2_no); |
| 407 |
| 408 src_unit = UNIT_RD; |
| 409 src_no = 0; |
| 410 |
| 411 src_reg = lookup_reg_name (src_unit, src_no); |
| 412 |
| 413 if (is_movl) |
| 414 snprintf (buf, OPERAND_WIDTH, "%s,%s,%s", dest_reg, pair_reg, src_reg); |
| 415 else |
| 416 snprintf (buf, OPERAND_WIDTH, "%s,%s", dest_reg, src_reg); |
| 417 |
| 418 if (dest_unit == UNIT_FX) |
| 419 print_insn (outf, "F", template->name, buf); |
| 420 else |
| 421 print_insn (outf, "", template->name, buf); |
| 422 } |
| 423 |
| 424 /* Return the number of bits set in rmask. */ |
| 425 static unsigned int hweight (unsigned int rmask) |
| 426 { |
| 427 unsigned int count; |
| 428 |
| 429 for (count = 0; rmask; count++) |
| 430 { |
| 431 rmask &= rmask - 1; |
| 432 } |
| 433 |
| 434 return count; |
| 435 } |
| 436 |
| 437 /* Print a MOVL to TTREC instruction. */ |
| 438 static void |
| 439 print_movl_ttrec (unsigned int insn_word, bfd_vma pc ATTRIBUTE_UNUSED, |
| 440 const insn_template *template, |
| 441 disassemble_info *outf) |
| 442 { |
| 443 unsigned int dest_unit, dest_no, src1_no, src2_no, src_unit; |
| 444 char buf[OPERAND_WIDTH]; |
| 445 const char *dest_reg; |
| 446 const char *src_reg; |
| 447 const char *pair_reg; |
| 448 |
| 449 dest_unit = UNIT_TT; |
| 450 dest_no = 3; |
| 451 |
| 452 dest_reg = lookup_reg_name (dest_unit, dest_no); |
| 453 |
| 454 src1_no = (insn_word >> 19) & REG_MASK; |
| 455 src2_no = (insn_word >> 14) & REG_MASK; |
| 456 |
| 457 src_unit = short_unit ((insn_word >> 7) & SHORT_UNIT_MASK); |
| 458 |
| 459 src_reg = lookup_reg_name (src_unit, src1_no); |
| 460 pair_reg = lookup_pair_reg_name (src_unit, src2_no); |
| 461 |
| 462 snprintf (buf, OPERAND_WIDTH, "%s,%s,%s", dest_reg, src_reg, pair_reg); |
| 463 |
| 464 print_insn (outf, "", template->name, buf); |
| 465 } |
| 466 |
| 467 /* Format a GET or SET address mode string from INSN_WORD into BUF. */ |
| 468 static void |
| 469 get_set_addr_str (char *buf, unsigned int buf_size, unsigned int size, |
| 470 unsigned int insn_word) |
| 471 { |
| 472 const char *base_reg; |
| 473 unsigned int base_unit, base_no; |
| 474 unsigned int imm = (insn_word >> 25) & 1; |
| 475 unsigned int ua = (insn_word >> 7) & 1; |
| 476 unsigned int pp = insn_word & 1; |
| 477 |
| 478 base_unit = short_unit ((insn_word >> 5) & SHORT_UNIT_MASK); |
| 479 base_no = (insn_word >> 14) & REG_MASK; |
| 480 |
| 481 base_reg = lookup_reg_name (base_unit, base_no); |
| 482 |
| 483 if (imm) |
| 484 { |
| 485 int offset = (insn_word >> 8) & GET_SET_IMM_MASK; |
| 486 |
| 487 offset = sign_extend (offset, GET_SET_IMM_BITS); |
| 488 |
| 489 if (offset == 0) |
| 490 { |
| 491 snprintf (buf, buf_size, "[%s]", base_reg); |
| 492 return; |
| 493 } |
| 494 |
| 495 if (offset == 1 && ua) |
| 496 { |
| 497 if (pp) |
| 498 snprintf (buf, buf_size, "[%s++]", base_reg); |
| 499 else |
| 500 snprintf (buf, buf_size, "[++%s]", base_reg); |
| 501 |
| 502 return; |
| 503 } |
| 504 else if (offset == -1 && ua) |
| 505 { |
| 506 if (pp) |
| 507 snprintf (buf, buf_size, "[%s--]", base_reg); |
| 508 else |
| 509 snprintf (buf, buf_size, "[--%s]", base_reg); |
| 510 |
| 511 return; |
| 512 } |
| 513 |
| 514 offset = offset * size; |
| 515 |
| 516 if (ua) |
| 517 { |
| 518 if (pp) |
| 519 snprintf (buf, buf_size, "[%s+#%d++]", base_reg, offset); |
| 520 else |
| 521 snprintf (buf, buf_size, "[%s++#%d]", base_reg, offset); |
| 522 } |
| 523 else |
| 524 snprintf (buf, buf_size, "[%s+#%d]", base_reg, offset); |
| 525 } |
| 526 else |
| 527 { |
| 528 const char *offset_reg; |
| 529 unsigned int offset_no; |
| 530 |
| 531 offset_no = (insn_word >> 9) & REG_MASK; |
| 532 |
| 533 offset_reg = lookup_reg_name (base_unit, offset_no); |
| 534 |
| 535 if (ua) |
| 536 { |
| 537 if (pp) |
| 538 snprintf (buf, buf_size, "[%s+%s++]", base_reg, offset_reg); |
| 539 else |
| 540 snprintf (buf, buf_size, "[%s++%s]", base_reg, offset_reg); |
| 541 } |
| 542 else |
| 543 snprintf (buf, buf_size, "[%s+%s]", base_reg, offset_reg); |
| 544 } |
| 545 } |
| 546 |
| 547 /* Format an extended GET or SET address mode string from INSN_WORD into BUF. */ |
| 548 static void |
| 549 get_set_ext_addr_str (char *buf, unsigned int buf_size, unsigned int size, |
| 550 unsigned int insn_word) |
| 551 { |
| 552 const char *base_reg; |
| 553 unsigned int base_unit, base_no; |
| 554 int offset; |
| 555 |
| 556 base_unit = short_unit ((insn_word >> 5) & SHORT_UNIT_MASK); |
| 557 base_no = insn_word & EXT_BASE_REG_MASK; |
| 558 |
| 559 base_reg = lookup_reg_name (base_unit, base_no); |
| 560 |
| 561 offset = (insn_word >> 7) & GET_SET_EXT_IMM_MASK; |
| 562 |
| 563 offset = sign_extend (offset, GET_SET_EXT_IMM_BITS); |
| 564 |
| 565 offset = offset * size; |
| 566 |
| 567 if (offset == 0) |
| 568 { |
| 569 snprintf (buf, buf_size, "[%s]", base_reg); |
| 570 } |
| 571 else |
| 572 { |
| 573 snprintf (buf, buf_size, "[%s+#%d]", base_reg, offset); |
| 574 } |
| 575 } |
| 576 |
| 577 /* Format an MGET or MSET address mode string from INSN_WORD into BUF. */ |
| 578 static void |
| 579 mget_mset_addr_str (char *buf, unsigned int buf_size, |
| 580 unsigned int insn_word) |
| 581 { |
| 582 const char *base_reg; |
| 583 unsigned int base_unit, base_no; |
| 584 |
| 585 base_unit = short_unit ((insn_word >> 5) & SHORT_UNIT_MASK); |
| 586 base_no = (insn_word >> 14) & REG_MASK; |
| 587 |
| 588 base_reg = lookup_reg_name (base_unit, base_no); |
| 589 |
| 590 snprintf (buf, buf_size, "[%s++]", base_reg); |
| 591 } |
| 592 |
| 593 /* Format a conditional SET address mode string from INSN_WORD into BUF. */ |
| 594 static void |
| 595 cond_set_addr_str (char *buf, unsigned int buf_size, |
| 596 unsigned int insn_word) |
| 597 { |
| 598 const char *base_reg; |
| 599 unsigned int base_unit, base_no; |
| 600 |
| 601 base_unit = short_unit ((insn_word >> 5) & SHORT_UNIT_MASK); |
| 602 base_no = (insn_word >> 14) & REG_MASK; |
| 603 |
| 604 base_reg = lookup_reg_name (base_unit, base_no); |
| 605 |
| 606 snprintf (buf, buf_size, "[%s]", base_reg); |
| 607 } |
| 608 |
| 609 /* Format a cache instruction address mode string from INSN_WORD into BUF. */ |
| 610 static void |
| 611 cache_addr_str (char *buf, unsigned int buf_size, unsigned int insn_word, |
| 612 int width) |
| 613 { |
| 614 const char *base_reg; |
| 615 unsigned int base_unit, base_no; |
| 616 int offset; |
| 617 |
| 618 base_unit = short_unit ((insn_word >> 5) & SHORT_UNIT_MASK); |
| 619 base_no = (insn_word >> 14) & REG_MASK; |
| 620 |
| 621 base_reg = lookup_reg_name (base_unit, base_no); |
| 622 |
| 623 offset = (insn_word >> 8) & GET_SET_IMM_MASK; |
| 624 |
| 625 offset = sign_extend (offset, GET_SET_IMM_BITS); |
| 626 |
| 627 offset = offset * width; |
| 628 |
| 629 if (offset == 0) |
| 630 { |
| 631 snprintf (buf, buf_size, "[%s]", base_reg); |
| 632 } |
| 633 else |
| 634 { |
| 635 snprintf (buf, buf_size, "[%s+#%d]", base_reg, offset); |
| 636 } |
| 637 } |
| 638 |
| 639 /* Format a list of registers starting at REG_UNIT and REG_NO and conforming |
| 640 to RMASK into BUF. */ |
| 641 static void |
| 642 lookup_reg_list (char *reg_buf, size_t buf_len, unsigned int reg_unit, |
| 643 unsigned int reg_no, unsigned int rmask, |
| 644 bfd_boolean is_fpu_64bit) |
| 645 { |
| 646 const char *regs[MGET_MSET_MAX_REGS]; |
| 647 size_t used_regs = 1, i, remaining; |
| 648 |
| 649 regs[0] = lookup_reg_name (reg_unit, reg_no); |
| 650 |
| 651 for (i = 1; i < MGET_MSET_MAX_REGS; i++) |
| 652 { |
| 653 if (rmask & 1) |
| 654 { |
| 655 if (is_fpu_64bit) |
| 656 regs[used_regs] = lookup_reg_name (reg_unit, reg_no + (i * 2)); |
| 657 else |
| 658 regs[used_regs] = lookup_reg_name (reg_unit, reg_no + i); |
| 659 used_regs++; |
| 660 } |
| 661 rmask = rmask >> 1; |
| 662 } |
| 663 |
| 664 remaining = buf_len; |
| 665 |
| 666 for (i = 0; i < used_regs; i++) |
| 667 { |
| 668 size_t len; |
| 669 if (i == 0) |
| 670 len = snprintf(reg_buf, remaining, "%s", regs[i]); |
| 671 else |
| 672 len = snprintf(reg_buf, remaining, ",%s", regs[i]); |
| 673 |
| 674 reg_buf += len; |
| 675 remaining -= len; |
| 676 } |
| 677 } |
| 678 |
| 679 /* Print a GET instruction. */ |
| 680 static void |
| 681 print_get (char *buf, char *addr_buf, unsigned int size, |
| 682 const char *dest_reg, const char *pair_reg, unsigned int reg_unit, |
| 683 const insn_template *template, |
| 684 disassemble_info *outf) |
| 685 { |
| 686 if (size == 8) |
| 687 { |
| 688 snprintf (buf, OPERAND_WIDTH, "%s,%s,%s", dest_reg, pair_reg, |
| 689 addr_buf); |
| 690 } |
| 691 else |
| 692 { |
| 693 snprintf (buf, OPERAND_WIDTH, "%s,%s", dest_reg, addr_buf); |
| 694 } |
| 695 |
| 696 if (reg_unit == UNIT_FX) |
| 697 print_insn (outf, "F", template->name, buf); |
| 698 else |
| 699 print_insn (outf, "", template->name, buf); |
| 700 } |
| 701 |
| 702 /* Print a SET instruction. */ |
| 703 static void |
| 704 print_set (char *buf, char *addr_buf, unsigned int size, |
| 705 const char *src_reg, const char *pair_reg, unsigned int reg_unit, |
| 706 const insn_template *template, |
| 707 disassemble_info *outf) |
| 708 { |
| 709 if (size == 8) |
| 710 { |
| 711 snprintf (buf, OPERAND_WIDTH, "%s,%s,%s", addr_buf, src_reg, pair_reg); |
| 712 } |
| 713 else |
| 714 { |
| 715 snprintf (buf, OPERAND_WIDTH, "%s,%s", addr_buf, src_reg); |
| 716 } |
| 717 |
| 718 if (reg_unit == UNIT_FX) |
| 719 print_insn (outf, "F", template->name, buf); |
| 720 else |
| 721 print_insn (outf, "", template->name, buf); |
| 722 } |
| 723 |
| 724 /* Print a GET or SET instruction. */ |
| 725 static void |
| 726 print_get_set (unsigned int insn_word, bfd_vma pc ATTRIBUTE_UNUSED, |
| 727 const insn_template *template, |
| 728 disassemble_info *outf) |
| 729 { |
| 730 bfd_boolean is_get = MAJOR_OPCODE (template->meta_opcode) == OPC_GET; |
| 731 char buf[OPERAND_WIDTH]; |
| 732 char addr_buf[ADDR_WIDTH]; |
| 733 unsigned int reg_unit, reg_no; |
| 734 unsigned int size = metag_get_set_size_bytes (insn_word); |
| 735 const char *reg_name; |
| 736 const char *pair_reg; |
| 737 |
| 738 reg_unit = (insn_word >> 1) & UNIT_MASK; |
| 739 reg_no = (insn_word >> 19) & REG_MASK; |
| 740 |
| 741 /* SETs should always print RD. */ |
| 742 if (!is_get && reg_unit == UNIT_RD) |
| 743 reg_no = 0; |
| 744 |
| 745 reg_name = lookup_reg_name (reg_unit, reg_no); |
| 746 |
| 747 pair_reg = lookup_pair_reg_name (reg_unit, reg_no); |
| 748 |
| 749 get_set_addr_str (addr_buf, ADDR_WIDTH, size, insn_word); |
| 750 |
| 751 if (is_get) |
| 752 { |
| 753 /* RD regs are 64 bits wide so don't use the pair syntax. */ |
| 754 if (reg_unit == UNIT_RD) |
| 755 print_get (buf, addr_buf, 4, reg_name, pair_reg, reg_unit, |
| 756 template, outf); |
| 757 else |
| 758 print_get (buf, addr_buf, size, reg_name, pair_reg, reg_unit, |
| 759 template, outf); |
| 760 } |
| 761 else |
| 762 { |
| 763 /* RD regs are 64 bits wide so don't use the pair syntax. */ |
| 764 if (reg_unit == UNIT_RD) |
| 765 print_set (buf, addr_buf, 4, reg_name, pair_reg, reg_unit, |
| 766 template, outf); |
| 767 else |
| 768 print_set (buf, addr_buf, size, reg_name, pair_reg, reg_unit, |
| 769 template, outf); |
| 770 } |
| 771 } |
| 772 |
| 773 /* Print an extended GET or SET instruction. */ |
| 774 static void |
| 775 print_get_set_ext (unsigned int insn_word, bfd_vma pc ATTRIBUTE_UNUSED, |
| 776 const insn_template *template, |
| 777 disassemble_info *outf) |
| 778 { |
| 779 bfd_boolean is_get = MINOR_OPCODE (template->meta_opcode) == GET_EXT_MINOR; |
| 780 bfd_boolean is_mov = MINOR_OPCODE (template->meta_opcode) == MOV_EXT_MINOR; |
| 781 char buf[OPERAND_WIDTH]; |
| 782 char addr_buf[ADDR_WIDTH]; |
| 783 unsigned int reg_unit, reg_no; |
| 784 unsigned int size = metag_get_set_ext_size_bytes (insn_word); |
| 785 const char *reg_name; |
| 786 const char *pair_reg; |
| 787 |
| 788 if (is_mov) |
| 789 reg_unit = UNIT_RD; |
| 790 else |
| 791 reg_unit = short_unit ((insn_word >> 3) & SHORT_UNIT_MASK); |
| 792 |
| 793 reg_no = (insn_word >> 19) & REG_MASK; |
| 794 |
| 795 reg_name = lookup_reg_name (reg_unit, reg_no); |
| 796 |
| 797 pair_reg = lookup_pair_reg_name (reg_unit, reg_no); |
| 798 |
| 799 get_set_ext_addr_str (addr_buf, ADDR_WIDTH, size, insn_word); |
| 800 |
| 801 if (is_get) |
| 802 print_get (buf, addr_buf, size, reg_name, pair_reg, reg_unit, |
| 803 template, outf); |
| 804 else if (is_mov) |
| 805 print_get (buf, addr_buf, 4, reg_name, pair_reg, reg_unit, |
| 806 template, outf); |
| 807 else |
| 808 print_set (buf, addr_buf, size, reg_name, pair_reg, reg_unit, |
| 809 template, outf); |
| 810 } |
| 811 |
| 812 /* Print an MGET or MSET instruction. */ |
| 813 static void |
| 814 print_mget_mset (unsigned int insn_word, bfd_vma pc ATTRIBUTE_UNUSED, |
| 815 const insn_template *template, |
| 816 disassemble_info *outf) |
| 817 { |
| 818 bfd_boolean is_get = MAJOR_OPCODE (template->meta_opcode) == OPC_GET; |
| 819 bfd_boolean is_fpu = (MINOR_OPCODE (template->meta_opcode) & 0x6) == 0x6; |
| 820 bfd_boolean is_64bit = (MINOR_OPCODE (template->meta_opcode) & 0x1) == 0x1; |
| 821 char buf[OPERAND_WIDTH]; |
| 822 char addr_buf[ADDR_WIDTH]; |
| 823 char reg_buf[REG_WIDTH]; |
| 824 unsigned int reg_unit, reg_no, rmask; |
| 825 |
| 826 if (is_fpu) |
| 827 reg_unit = UNIT_FX; |
| 828 else |
| 829 reg_unit = short_unit ((insn_word >> 3) & SHORT_UNIT_MASK); |
| 830 |
| 831 reg_no = (insn_word >> 19) & REG_MASK; |
| 832 rmask = (insn_word >> 7) & RMASK_MASK; |
| 833 |
| 834 lookup_reg_list (reg_buf, REG_WIDTH, reg_unit, reg_no, rmask, |
| 835 is_fpu && is_64bit); |
| 836 |
| 837 mget_mset_addr_str (addr_buf, ADDR_WIDTH, insn_word); |
| 838 |
| 839 if (is_get) |
| 840 snprintf (buf, OPERAND_WIDTH, "%s,%s", reg_buf, addr_buf); |
| 841 else |
| 842 snprintf (buf, OPERAND_WIDTH, "%s,%s", addr_buf, reg_buf); |
| 843 |
| 844 if (is_fpu) |
| 845 print_insn (outf, "F", template->name, buf); |
| 846 else |
| 847 print_insn (outf, "", template->name, buf); |
| 848 } |
| 849 |
| 850 /* Print a conditional SET instruction. */ |
| 851 static void |
| 852 print_cond_set (unsigned int insn_word, bfd_vma pc ATTRIBUTE_UNUSED, |
| 853 const insn_template *template, |
| 854 disassemble_info *outf) |
| 855 { |
| 856 char buf[OPERAND_WIDTH]; |
| 857 char addr_buf[ADDR_WIDTH]; |
| 858 unsigned int src_unit, src_no; |
| 859 unsigned int size = metag_cond_set_size_bytes (insn_word); |
| 860 const char *src_reg; |
| 861 const char *pair_reg; |
| 862 |
| 863 src_unit = (insn_word >> 10) & UNIT_MASK; |
| 864 src_no = (insn_word >> 19) & REG_MASK; |
| 865 |
| 866 if (src_unit == UNIT_RD) |
| 867 src_no = 0; |
| 868 |
| 869 src_reg = lookup_reg_name (src_unit, src_no); |
| 870 |
| 871 pair_reg = lookup_pair_reg_name (src_unit, src_no); |
| 872 |
| 873 cond_set_addr_str (addr_buf, ADDR_WIDTH, insn_word); |
| 874 |
| 875 if (src_unit == UNIT_RD) |
| 876 print_set (buf, addr_buf, 4, src_reg, pair_reg, src_unit, |
| 877 template, outf); |
| 878 else |
| 879 print_set (buf, addr_buf, size, src_reg, pair_reg, src_unit, |
| 880 template, outf); |
| 881 } |
| 882 |
| 883 /* Print a MMOV instruction. */ |
| 884 static void |
| 885 print_mmov (unsigned int insn_word, bfd_vma pc ATTRIBUTE_UNUSED, |
| 886 const insn_template *template, |
| 887 disassemble_info *outf) |
| 888 { |
| 889 unsigned int is_fpu = template->insn_type == INSN_FPU; |
| 890 unsigned int is_prime = ((MINOR_OPCODE (template->meta_opcode) & 0x2) && |
| 891 !is_fpu); |
| 892 unsigned int is_64bit = MINOR_OPCODE (template->meta_opcode) & 0x1; |
| 893 unsigned int is_dsp = template->meta_opcode & 0x1; |
| 894 unsigned int dest_unit, dest_no, rmask; |
| 895 char buf[OPERAND_WIDTH]; |
| 896 char reg_buf[REG_WIDTH]; |
| 897 char addr_buf[ADDR_WIDTH]; |
| 898 |
| 899 if (is_fpu) |
| 900 dest_no = (insn_word >> 14) & REG_MASK; |
| 901 else |
| 902 dest_no = (insn_word >> 19) & REG_MASK; |
| 903 |
| 904 rmask = (insn_word >> 7) & RMASK_MASK; |
| 905 |
| 906 if (is_prime) |
| 907 { |
| 908 const char *dest_reg; |
| 909 const char *base_reg; |
| 910 unsigned int base_unit, base_no; |
| 911 int i, count = hweight (rmask); |
| 912 |
| 913 dest_reg = lookup_reg_name (UNIT_RD, dest_no); |
| 914 |
| 915 strcpy (reg_buf, dest_reg); |
| 916 |
| 917 for (i = 0; i < count; i++) |
| 918 { |
| 919 strcat (reg_buf, ","); |
| 920 strcat (reg_buf, dest_reg); |
| 921 } |
| 922 |
| 923 base_unit = short_unit ((insn_word >> 5) & SHORT_UNIT_MASK); |
| 924 base_no = (insn_word >> 14) & REG_MASK; |
| 925 |
| 926 base_reg = lookup_reg_name (base_unit, base_no); |
| 927 |
| 928 snprintf (addr_buf, ADDR_WIDTH, "[%s++]", base_reg); |
| 929 |
| 930 snprintf (buf, OPERAND_WIDTH, "%s,%s", reg_buf, addr_buf); |
| 931 } |
| 932 else |
| 933 { |
| 934 if (is_fpu) |
| 935 dest_unit = UNIT_FX; |
| 936 else |
| 937 dest_unit = short_unit ((insn_word >> 3) & SHORT_UNIT_MASK); |
| 938 |
| 939 lookup_reg_list (reg_buf, REG_WIDTH, dest_unit, dest_no, rmask, |
| 940 is_fpu && is_64bit); |
| 941 |
| 942 snprintf (buf, OPERAND_WIDTH, "%s,RD", reg_buf); |
| 943 } |
| 944 |
| 945 if (is_dsp) |
| 946 { |
| 947 char prefix_buf[10] = {0}; |
| 948 if (is_prime) |
| 949 { |
| 950 if (dest_no == 22 || dest_no == 23) |
| 951 strcpy (prefix_buf, "DB"); |
| 952 else if (dest_no == 24) |
| 953 strcpy (prefix_buf, "DBH"); |
| 954 else if (dest_no == 25) |
| 955 strcpy (prefix_buf, "DWH"); |
| 956 else if (dest_no == 31) |
| 957 strcpy (prefix_buf, "DW"); |
| 958 } |
| 959 else |
| 960 strcpy (prefix_buf, "DW"); |
| 961 print_insn (outf, prefix_buf, template->name, buf); |
| 962 } |
| 963 else if (is_fpu) |
| 964 print_insn (outf, "F", template->name, buf); |
| 965 else |
| 966 print_insn (outf, "", template->name, buf); |
| 967 } |
| 968 |
| 969 /* Print an MDRD instruction. */ |
| 970 static void |
| 971 print_mdrd (unsigned int insn_word, bfd_vma pc ATTRIBUTE_UNUSED, |
| 972 const insn_template *template, |
| 973 disassemble_info *outf) |
| 974 { |
| 975 unsigned int rmask, count; |
| 976 char buf[OPERAND_WIDTH]; |
| 977 |
| 978 rmask = (insn_word >> 7) & RMASK_MASK; |
| 979 |
| 980 count = hweight (rmask); |
| 981 |
| 982 snprintf (buf, OPERAND_WIDTH, "#%#x", count + 1); |
| 983 |
| 984 print_insn (outf, "", template->name, buf); |
| 985 } |
| 986 |
| 987 /* Print an XFR instruction. */ |
| 988 static void |
| 989 print_xfr (unsigned int insn_word, bfd_vma pc ATTRIBUTE_UNUSED, |
| 990 const insn_template *template, |
| 991 disassemble_info *outf) |
| 992 { |
| 993 char buf[OPERAND_WIDTH]; |
| 994 char dest_buf[ADDR_WIDTH]; |
| 995 char src_buf[ADDR_WIDTH]; |
| 996 unsigned int dest_unit, src_unit; |
| 997 unsigned int dest_no, src_no; |
| 998 unsigned int us, ud, pp; |
| 999 const char *dest_base_reg; |
| 1000 const char *dest_offset_reg; |
| 1001 const char *src_base_reg; |
| 1002 const char *src_offset_reg; |
| 1003 |
| 1004 src_unit = short_unit ((insn_word >> 2) & SHORT_UNIT_MASK); |
| 1005 src_no = (insn_word >> 19) & REG_MASK; |
| 1006 |
| 1007 src_base_reg = lookup_reg_name (src_unit, src_no); |
| 1008 |
| 1009 src_no = (insn_word >> 14) & REG_MASK; |
| 1010 |
| 1011 src_offset_reg = lookup_reg_name (src_unit, src_no); |
| 1012 |
| 1013 dest_unit = short_unit (insn_word & SHORT_UNIT_MASK); |
| 1014 dest_no = (insn_word >> 9) & REG_MASK; |
| 1015 |
| 1016 dest_base_reg = lookup_reg_name (dest_unit, dest_no); |
| 1017 |
| 1018 dest_no = (insn_word >> 4) & REG_MASK; |
| 1019 |
| 1020 dest_offset_reg = lookup_reg_name (dest_unit, dest_no); |
| 1021 |
| 1022 us = (insn_word >> 27) & 0x1; |
| 1023 ud = (insn_word >> 26) & 0x1; |
| 1024 pp = (insn_word >> 24) & 0x1; |
| 1025 |
| 1026 if (us) |
| 1027 if (pp) |
| 1028 snprintf (src_buf, ADDR_WIDTH, "[%s+%s++]", src_base_reg, |
| 1029 src_offset_reg); |
| 1030 else |
| 1031 snprintf (src_buf, ADDR_WIDTH, "[%s++%s]", src_base_reg, |
| 1032 src_offset_reg); |
| 1033 else |
| 1034 snprintf (src_buf, ADDR_WIDTH, "[%s+%s]", src_base_reg, |
| 1035 src_offset_reg); |
| 1036 |
| 1037 if (ud) |
| 1038 if (pp) |
| 1039 snprintf (dest_buf, ADDR_WIDTH, "[%s+%s++]", dest_base_reg, |
| 1040 dest_offset_reg); |
| 1041 else |
| 1042 snprintf (dest_buf, ADDR_WIDTH, "[%s++%s]", dest_base_reg, |
| 1043 dest_offset_reg); |
| 1044 else |
| 1045 snprintf (dest_buf, ADDR_WIDTH, "[%s+%s]", dest_base_reg, |
| 1046 dest_offset_reg); |
| 1047 |
| 1048 snprintf (buf, OPERAND_WIDTH, "%s,%s", dest_buf, src_buf); |
| 1049 |
| 1050 print_insn (outf, "", template->name, buf); |
| 1051 } |
| 1052 |
| 1053 /* Print a MOV to control unit instruction. */ |
| 1054 static void |
| 1055 print_mov_ct (unsigned int insn_word, bfd_vma pc ATTRIBUTE_UNUSED, |
| 1056 const insn_template *template, |
| 1057 disassemble_info *outf) |
| 1058 { |
| 1059 char buf[OPERAND_WIDTH]; |
| 1060 unsigned int reg_no; |
| 1061 unsigned int se = (insn_word >> 1) & 0x1; |
| 1062 unsigned int is_trace = (insn_word >> 2) & 0x1; |
| 1063 int value; |
| 1064 const char *dest_reg; |
| 1065 |
| 1066 reg_no = (insn_word >> 19) & REG_MASK; |
| 1067 |
| 1068 if (is_trace) |
| 1069 dest_reg = lookup_reg_name (UNIT_TT, reg_no); |
| 1070 else |
| 1071 dest_reg = lookup_reg_name (UNIT_CT, reg_no); |
| 1072 |
| 1073 value = (insn_word >> 3) & IMM16_MASK; |
| 1074 |
| 1075 if (se) |
| 1076 { |
| 1077 value = sign_extend (value, IMM16_BITS); |
| 1078 snprintf (buf, OPERAND_WIDTH, "%s,#%d", dest_reg, value); |
| 1079 } |
| 1080 else |
| 1081 { |
| 1082 snprintf (buf, OPERAND_WIDTH, "%s,#%#x", dest_reg, value); |
| 1083 } |
| 1084 |
| 1085 print_insn (outf, "", template->name, buf); |
| 1086 } |
| 1087 |
| 1088 /* Print a SWAP instruction. */ |
| 1089 static void |
| 1090 print_swap (unsigned int insn_word, bfd_vma pc ATTRIBUTE_UNUSED, |
| 1091 const insn_template *template, |
| 1092 disassemble_info *outf) |
| 1093 { |
| 1094 char buf[OPERAND_WIDTH]; |
| 1095 unsigned int dest_no, src_no; |
| 1096 unsigned int dest_unit, src_unit; |
| 1097 const char *dest_reg; |
| 1098 const char *src_reg; |
| 1099 |
| 1100 src_unit = (insn_word >> 10) & UNIT_MASK; |
| 1101 src_no = (insn_word >> 19) & REG_MASK; |
| 1102 |
| 1103 src_reg = lookup_reg_name (src_unit, src_no); |
| 1104 |
| 1105 dest_unit = (insn_word >> 5) & UNIT_MASK; |
| 1106 dest_no = (insn_word >> 14) & REG_MASK; |
| 1107 |
| 1108 dest_reg = lookup_reg_name (dest_unit, dest_no); |
| 1109 |
| 1110 snprintf (buf, OPERAND_WIDTH, "%s,%s", dest_reg, src_reg); |
| 1111 |
| 1112 if (dest_unit == UNIT_FX || src_unit == UNIT_FX) |
| 1113 print_insn (outf, "F", template->name, buf); |
| 1114 else |
| 1115 print_insn (outf, "", template->name, buf); |
| 1116 } |
| 1117 |
| 1118 /* Print a SWAP instruction. */ |
| 1119 static void |
| 1120 print_jump (unsigned int insn_word, bfd_vma pc ATTRIBUTE_UNUSED, |
| 1121 const insn_template *template, |
| 1122 disassemble_info *outf) |
| 1123 { |
| 1124 char buf[OPERAND_WIDTH]; |
| 1125 unsigned int reg_no, reg_unit; |
| 1126 const char *reg_name; |
| 1127 int value; |
| 1128 |
| 1129 reg_unit = short_unit (insn_word & SHORT_UNIT_MASK); |
| 1130 reg_no = (insn_word >> 19) & REG_MASK; |
| 1131 |
| 1132 reg_name = lookup_reg_name (reg_unit, reg_no); |
| 1133 |
| 1134 value = (insn_word >> 3) & IMM16_MASK; |
| 1135 |
| 1136 snprintf (buf, OPERAND_WIDTH, "%s,#%#x", reg_name, value); |
| 1137 |
| 1138 print_insn (outf, "", template->name, buf); |
| 1139 } |
| 1140 |
| 1141 /* Print a CALLR instruction. */ |
| 1142 static void |
| 1143 print_callr (unsigned int insn_word, bfd_vma pc, const insn_template *template, |
| 1144 disassemble_info *outf) |
| 1145 { |
| 1146 char buf[OPERAND_WIDTH]; |
| 1147 unsigned int reg_no, reg_unit; |
| 1148 const char *reg_name; |
| 1149 int value; |
| 1150 |
| 1151 reg_unit = short_unit ((insn_word >> 3) & SHORT_UNIT_MASK); |
| 1152 reg_no = insn_word & CALLR_REG_MASK; |
| 1153 |
| 1154 reg_name = lookup_reg_name (reg_unit, reg_no); |
| 1155 |
| 1156 value = (insn_word >> 5) & IMM19_MASK; |
| 1157 |
| 1158 value = sign_extend (value, IMM19_BITS); |
| 1159 |
| 1160 value = value * 4; |
| 1161 |
| 1162 value += pc; |
| 1163 |
| 1164 snprintf (buf, OPERAND_WIDTH, "%s,", reg_name); |
| 1165 |
| 1166 print_insn (outf, "", template->name, buf); |
| 1167 |
| 1168 outf->print_address_func (value, outf); |
| 1169 } |
| 1170 |
| 1171 /* Print a GP ALU instruction. */ |
| 1172 static void |
| 1173 print_alu (unsigned int insn_word, bfd_vma pc ATTRIBUTE_UNUSED, |
| 1174 const insn_template *template, |
| 1175 disassemble_info *outf) |
| 1176 { |
| 1177 char buf[OPERAND_WIDTH]; |
| 1178 unsigned int is_addr_op = MAJOR_OPCODE (template->meta_opcode) == OPC_ADDR; |
| 1179 unsigned int is_mul = MAJOR_OPCODE (template->meta_opcode) == OPC_MUL; |
| 1180 unsigned int dest_no, src1_no, src2_no; |
| 1181 unsigned int imm = (insn_word >> 25) & 0x1; |
| 1182 unsigned int cond = (insn_word >> 26) & 0x1; |
| 1183 unsigned int o1z = 0; |
| 1184 unsigned int o2r = insn_word & 0x1; |
| 1185 unsigned int unit_bit = (insn_word >> 24) & 0x1; |
| 1186 unsigned int ca = (insn_word >> 5) & 0x1; |
| 1187 unsigned int se = (insn_word >> 1) & 0x1; |
| 1188 bfd_boolean is_quickrot = template->arg_type & GP_ARGS_QR; |
| 1189 enum metag_unit base_unit; |
| 1190 enum metag_unit dest_unit; |
| 1191 const char *dest_reg; |
| 1192 const char *src1_reg; |
| 1193 const char *src2_reg; |
| 1194 int value; |
| 1195 |
| 1196 if ((MAJOR_OPCODE (template->meta_opcode) == OPC_ADDR || |
| 1197 MAJOR_OPCODE (template->meta_opcode) == OPC_ADD || |
| 1198 MAJOR_OPCODE (template->meta_opcode) == OPC_SUB) && |
| 1199 ((insn_word >> 2) & 0x1)) |
| 1200 o1z = 1; |
| 1201 |
| 1202 if (is_addr_op) |
| 1203 { |
| 1204 if (unit_bit) |
| 1205 base_unit = UNIT_A1; |
| 1206 else |
| 1207 base_unit = UNIT_A0; |
| 1208 } |
| 1209 else |
| 1210 { |
| 1211 if (unit_bit) |
| 1212 base_unit = UNIT_D1; |
| 1213 else |
| 1214 base_unit = UNIT_D0; |
| 1215 } |
| 1216 |
| 1217 dest_no = (insn_word >> 19) & REG_MASK; |
| 1218 src1_no = (insn_word >> 14) & REG_MASK; |
| 1219 src2_no = (insn_word >> 9) & REG_MASK; |
| 1220 |
| 1221 dest_unit = base_unit; |
| 1222 |
| 1223 if (imm) |
| 1224 { |
| 1225 if (cond) |
| 1226 { |
| 1227 if (ca) |
| 1228 { |
| 1229 dest_unit = (insn_word >> 1) & UNIT_MASK; |
| 1230 dest_reg = lookup_reg_name (dest_unit, dest_no); |
| 1231 } |
| 1232 else |
| 1233 dest_reg = lookup_reg_name (dest_unit, dest_no); |
| 1234 |
| 1235 src1_reg = lookup_reg_name (base_unit, src1_no); |
| 1236 |
| 1237 value = (insn_word >> 6) & IMM8_MASK; |
| 1238 |
| 1239 if (is_quickrot) |
| 1240 { |
| 1241 unsigned int qr_unit = unit_bit ? UNIT_A1 : UNIT_A0; |
| 1242 unsigned int qr_no = 2; |
| 1243 const char *qr_reg = lookup_reg_name (qr_unit, qr_no); |
| 1244 |
| 1245 snprintf (buf, OPERAND_WIDTH, "%s,%s,#%#x,%s", dest_reg, |
| 1246 src1_reg, value, qr_reg); |
| 1247 } |
| 1248 else |
| 1249 snprintf (buf, OPERAND_WIDTH, "%s,%s,#%#x", dest_reg, |
| 1250 src1_reg, value); |
| 1251 } |
| 1252 else |
| 1253 { |
| 1254 if (is_addr_op && (dest_no & ~CPC_REG_MASK)) |
| 1255 { |
| 1256 dest_reg = lookup_reg_name (dest_unit, dest_no & CPC_REG_MASK); |
| 1257 src1_reg = lookup_reg_name (base_unit, 0x10); |
| 1258 } |
| 1259 else |
| 1260 { |
| 1261 dest_reg = lookup_reg_name (dest_unit, dest_no); |
| 1262 src1_reg = lookup_reg_name (base_unit, dest_no); |
| 1263 } |
| 1264 |
| 1265 value = (insn_word >> 3) & IMM16_MASK; |
| 1266 |
| 1267 if (se) |
| 1268 { |
| 1269 value = sign_extend (value, IMM16_BITS); |
| 1270 if (o1z) |
| 1271 { |
| 1272 snprintf (buf, OPERAND_WIDTH, "%s,#%d", dest_reg, value); |
| 1273 } |
| 1274 else |
| 1275 { |
| 1276 snprintf (buf, OPERAND_WIDTH, "%s,%s,#%d", dest_reg, |
| 1277 src1_reg, value); |
| 1278 } |
| 1279 } |
| 1280 else |
| 1281 { |
| 1282 if (o1z) |
| 1283 { |
| 1284 snprintf (buf, OPERAND_WIDTH, "%s,#%#x", dest_reg, value); |
| 1285 } |
| 1286 else |
| 1287 { |
| 1288 snprintf (buf, OPERAND_WIDTH, "%s,%s,#%#x", dest_reg, |
| 1289 src1_reg, value); |
| 1290 } |
| 1291 } |
| 1292 } |
| 1293 } |
| 1294 else |
| 1295 { |
| 1296 src1_reg = lookup_reg_name (base_unit, src1_no); |
| 1297 |
| 1298 if (o2r) |
| 1299 src2_reg = lookup_o2r (base_unit, src2_no); |
| 1300 else |
| 1301 src2_reg = lookup_reg_name (base_unit, src2_no); |
| 1302 |
| 1303 if (cond) |
| 1304 { |
| 1305 dest_unit = (insn_word >> 5) & UNIT_MASK; |
| 1306 |
| 1307 if (is_mul) |
| 1308 { |
| 1309 if (ca) |
| 1310 dest_unit = (insn_word >> 1) & UNIT_MASK; |
| 1311 else |
| 1312 dest_unit = base_unit; |
| 1313 } |
| 1314 |
| 1315 dest_reg = lookup_reg_name (dest_unit, dest_no); |
| 1316 |
| 1317 snprintf (buf, OPERAND_WIDTH, "%s,%s,%s", dest_reg, |
| 1318 src1_reg, src2_reg); |
| 1319 } |
| 1320 else |
| 1321 { |
| 1322 dest_reg = lookup_reg_name (dest_unit, dest_no); |
| 1323 |
| 1324 if (is_quickrot) |
| 1325 { |
| 1326 unsigned int qr_unit = unit_bit ? UNIT_A1 : UNIT_A0; |
| 1327 unsigned int qr_no = 2 + ((insn_word >> 7) & 0x1); |
| 1328 const char *qr_reg = lookup_reg_name (qr_unit, qr_no); |
| 1329 |
| 1330 snprintf (buf, OPERAND_WIDTH, "%s,%s,%s,%s", dest_reg, |
| 1331 src1_reg, src2_reg, qr_reg); |
| 1332 } |
| 1333 else if (o1z) |
| 1334 { |
| 1335 snprintf (buf, OPERAND_WIDTH, "%s,%s", dest_reg, src2_reg); |
| 1336 } |
| 1337 else |
| 1338 { |
| 1339 snprintf (buf, OPERAND_WIDTH, "%s,%s,%s", dest_reg, |
| 1340 src1_reg, src2_reg); |
| 1341 } |
| 1342 } |
| 1343 } |
| 1344 |
| 1345 if (dest_unit == UNIT_FX) |
| 1346 print_insn (outf, "F", template->name, buf); |
| 1347 else |
| 1348 print_insn (outf, "", template->name, buf); |
| 1349 } |
| 1350 |
| 1351 /* Print a B instruction. */ |
| 1352 static void |
| 1353 print_branch (unsigned int insn_word, bfd_vma pc, |
| 1354 const insn_template *template, |
| 1355 disassemble_info *outf) |
| 1356 { |
| 1357 int value; |
| 1358 |
| 1359 value = (insn_word >> 5) & IMM19_MASK; |
| 1360 |
| 1361 value = sign_extend (value, IMM19_BITS); |
| 1362 |
| 1363 value = value * 4; |
| 1364 |
| 1365 value += pc; |
| 1366 |
| 1367 print_insn (outf, "", template->name, ""); |
| 1368 |
| 1369 outf->print_address_func (value, outf); |
| 1370 } |
| 1371 |
| 1372 /* Print a SWITCH instruction. */ |
| 1373 static void |
| 1374 print_switch (unsigned int insn_word, bfd_vma pc ATTRIBUTE_UNUSED, |
| 1375 const insn_template *template, |
| 1376 disassemble_info *outf) |
| 1377 { |
| 1378 char buf[OPERAND_WIDTH]; |
| 1379 unsigned int value; |
| 1380 |
| 1381 value = insn_word & IMM24_MASK; |
| 1382 |
| 1383 snprintf (buf, OPERAND_WIDTH, "#%#x", value); |
| 1384 |
| 1385 print_insn (outf, "", template->name, buf); |
| 1386 } |
| 1387 |
| 1388 /* Print a shift instruction. */ |
| 1389 static void |
| 1390 print_shift (unsigned int insn_word, bfd_vma pc ATTRIBUTE_UNUSED, |
| 1391 const insn_template *template, |
| 1392 disassemble_info *outf) |
| 1393 { |
| 1394 char buf[OPERAND_WIDTH]; |
| 1395 unsigned int dest_no, src1_no, src2_no; |
| 1396 unsigned int imm = (insn_word >> 25) & 0x1; |
| 1397 unsigned int cond = (insn_word >> 26) & 0x1; |
| 1398 unsigned int unit_bit = (insn_word >> 24) & 0x1; |
| 1399 unsigned int ca = (insn_word >> 5) & 0x1; |
| 1400 enum metag_unit base_unit; |
| 1401 unsigned int dest_unit; |
| 1402 const char *dest_reg; |
| 1403 const char *src1_reg; |
| 1404 const char *src2_reg; |
| 1405 int value; |
| 1406 |
| 1407 if (unit_bit) |
| 1408 base_unit = UNIT_D1; |
| 1409 else |
| 1410 base_unit = UNIT_D0; |
| 1411 |
| 1412 dest_no = (insn_word >> 19) & REG_MASK; |
| 1413 src1_no = (insn_word >> 14) & REG_MASK; |
| 1414 src2_no = (insn_word >> 9) & REG_MASK; |
| 1415 |
| 1416 dest_unit = base_unit; |
| 1417 |
| 1418 if (imm) |
| 1419 { |
| 1420 if (cond && ca) |
| 1421 dest_unit = (insn_word >> 1) & UNIT_MASK; |
| 1422 |
| 1423 dest_reg = lookup_reg_name (dest_unit, dest_no); |
| 1424 |
| 1425 src1_reg = lookup_reg_name (base_unit, src1_no); |
| 1426 |
| 1427 value = (insn_word >> 9) & IMM5_MASK; |
| 1428 |
| 1429 snprintf (buf, OPERAND_WIDTH, "%s,%s,#%#x", dest_reg, |
| 1430 src1_reg, value); |
| 1431 } |
| 1432 else |
| 1433 { |
| 1434 if (cond && ca) |
| 1435 dest_unit = (insn_word >> 1) & UNIT_MASK; |
| 1436 |
| 1437 dest_reg = lookup_reg_name (dest_unit, dest_no); |
| 1438 |
| 1439 src1_reg = lookup_reg_name (base_unit, src1_no); |
| 1440 src2_reg = lookup_reg_name (base_unit, src2_no); |
| 1441 |
| 1442 snprintf (buf, OPERAND_WIDTH, "%s,%s,%s", dest_reg, |
| 1443 src1_reg, src2_reg); |
| 1444 } |
| 1445 |
| 1446 if (dest_unit == UNIT_FX) |
| 1447 print_insn (outf, "F", template->name, buf); |
| 1448 else |
| 1449 print_insn (outf, "", template->name, buf); |
| 1450 } |
| 1451 |
| 1452 /* Print a MIN or MAX instruction. */ |
| 1453 static void |
| 1454 print_min_max (unsigned int insn_word, bfd_vma pc ATTRIBUTE_UNUSED, |
| 1455 const insn_template *template, |
| 1456 disassemble_info *outf) |
| 1457 { |
| 1458 unsigned int base_unit, dest_no, src1_no, src2_no; |
| 1459 char buf[OPERAND_WIDTH]; |
| 1460 const char *dest_reg; |
| 1461 const char *src1_reg; |
| 1462 const char *src2_reg; |
| 1463 |
| 1464 if ((insn_word >> 24) & UNIT_MASK) |
| 1465 base_unit = UNIT_D1; |
| 1466 else |
| 1467 base_unit = UNIT_D0; |
| 1468 |
| 1469 dest_no = (insn_word >> 19) & REG_MASK; |
| 1470 src1_no = (insn_word >> 14) & REG_MASK; |
| 1471 src2_no = (insn_word >> 9) & REG_MASK; |
| 1472 |
| 1473 dest_reg = lookup_reg_name (base_unit, dest_no); |
| 1474 |
| 1475 src1_reg = lookup_reg_name (base_unit, src1_no); |
| 1476 src2_reg = lookup_reg_name (base_unit, src2_no); |
| 1477 |
| 1478 snprintf (buf, OPERAND_WIDTH, "%s,%s,%s", dest_reg, src1_reg, src2_reg); |
| 1479 |
| 1480 print_insn (outf, "", template->name, buf); |
| 1481 } |
| 1482 |
| 1483 /* Print a bit operation instruction. */ |
| 1484 static void |
| 1485 print_bitop (unsigned int insn_word, bfd_vma pc ATTRIBUTE_UNUSED, |
| 1486 const insn_template *template, |
| 1487 disassemble_info *outf) |
| 1488 { |
| 1489 unsigned int swap_inst = MAJOR_OPCODE (template->meta_opcode) == OPC_MISC; |
| 1490 unsigned int base_unit, src_unit, dest_no, src_no; |
| 1491 unsigned int is_bexl = 0; |
| 1492 char buf[OPERAND_WIDTH]; |
| 1493 const char *dest_reg; |
| 1494 const char *src_reg; |
| 1495 |
| 1496 if (swap_inst && |
| 1497 ((insn_word >> 1) & 0xb) == 0xa) |
| 1498 is_bexl = 1; |
| 1499 |
| 1500 if (swap_inst) |
| 1501 { |
| 1502 if (insn_word & 0x1) |
| 1503 base_unit = UNIT_D1; |
| 1504 else |
| 1505 base_unit = UNIT_D0; |
| 1506 } |
| 1507 else |
| 1508 { |
| 1509 if ((insn_word >> 24) & 0x1) |
| 1510 base_unit = UNIT_D1; |
| 1511 else |
| 1512 base_unit = UNIT_D0; |
| 1513 } |
| 1514 |
| 1515 src_unit = base_unit; |
| 1516 |
| 1517 if (is_bexl) |
| 1518 base_unit = get_pair_unit (base_unit); |
| 1519 |
| 1520 dest_no = (insn_word >> 19) & REG_MASK; |
| 1521 |
| 1522 dest_reg = lookup_reg_name (base_unit, dest_no); |
| 1523 |
| 1524 src_no = (insn_word >> 14) & REG_MASK; |
| 1525 |
| 1526 src_reg = lookup_reg_name (src_unit, src_no); |
| 1527 |
| 1528 snprintf (buf, OPERAND_WIDTH, "%s,%s", dest_reg, src_reg); |
| 1529 |
| 1530 print_insn (outf, "", template->name, buf); |
| 1531 } |
| 1532 |
| 1533 /* Print a CMP or TST instruction. */ |
| 1534 static void |
| 1535 print_cmp (unsigned int insn_word, bfd_vma pc ATTRIBUTE_UNUSED, |
| 1536 const insn_template *template, |
| 1537 disassemble_info *outf) |
| 1538 { |
| 1539 char buf[OPERAND_WIDTH]; |
| 1540 unsigned int dest_no, src_no; |
| 1541 unsigned int imm = (insn_word >> 25) & 0x1; |
| 1542 unsigned int cond = (insn_word >> 26) & 0x1; |
| 1543 unsigned int o2r = insn_word & 0x1; |
| 1544 unsigned int unit_bit = (insn_word >> 24) & 0x1; |
| 1545 unsigned int se = (insn_word >> 1) & 0x1; |
| 1546 enum metag_unit base_unit; |
| 1547 const char *dest_reg; |
| 1548 const char *src_reg; |
| 1549 int value; |
| 1550 |
| 1551 if (unit_bit) |
| 1552 base_unit = UNIT_D1; |
| 1553 else |
| 1554 base_unit = UNIT_D0; |
| 1555 |
| 1556 dest_no = (insn_word >> 14) & REG_MASK; |
| 1557 src_no = (insn_word >> 9) & REG_MASK; |
| 1558 |
| 1559 dest_reg = lookup_reg_name (base_unit, dest_no); |
| 1560 |
| 1561 if (imm) |
| 1562 { |
| 1563 if (cond) |
| 1564 { |
| 1565 value = (insn_word >> 6) & IMM8_MASK; |
| 1566 |
| 1567 snprintf (buf, OPERAND_WIDTH, "%s,#%#x", dest_reg, value); |
| 1568 } |
| 1569 else |
| 1570 { |
| 1571 dest_no = (insn_word >> 19) & REG_MASK; |
| 1572 |
| 1573 dest_reg = lookup_reg_name (base_unit, dest_no); |
| 1574 |
| 1575 value = (insn_word >> 3) & IMM16_MASK; |
| 1576 |
| 1577 if (se) |
| 1578 { |
| 1579 value = sign_extend (value, IMM16_BITS); |
| 1580 snprintf (buf, OPERAND_WIDTH, "%s,#%d", dest_reg, value); |
| 1581 } |
| 1582 else |
| 1583 { |
| 1584 snprintf (buf, OPERAND_WIDTH, "%s,#%#x", dest_reg, value); |
| 1585 } |
| 1586 } |
| 1587 } |
| 1588 else |
| 1589 { |
| 1590 if (o2r) |
| 1591 src_reg = lookup_o2r (base_unit, src_no); |
| 1592 else |
| 1593 src_reg = lookup_reg_name (base_unit, src_no); |
| 1594 |
| 1595 snprintf (buf, OPERAND_WIDTH, "%s,%s", dest_reg, src_reg); |
| 1596 } |
| 1597 |
| 1598 print_insn (outf, "", template->name, buf); |
| 1599 } |
| 1600 |
| 1601 /* Print a CACHER instruction. */ |
| 1602 static void |
| 1603 print_cacher (unsigned int insn_word, bfd_vma pc ATTRIBUTE_UNUSED, |
| 1604 const insn_template *template, |
| 1605 disassemble_info *outf) |
| 1606 { |
| 1607 char buf[OPERAND_WIDTH]; |
| 1608 char addr_buf[ADDR_WIDTH]; |
| 1609 unsigned int reg_unit, reg_no; |
| 1610 unsigned int size = ((insn_word >> 1) & 0x1) ? 8 : 4; |
| 1611 const char *reg_name; |
| 1612 const char *pair_name; |
| 1613 |
| 1614 reg_unit = short_unit ((insn_word >> 3) & SHORT_UNIT_MASK); |
| 1615 reg_no = (insn_word >> 19) & REG_MASK; |
| 1616 |
| 1617 reg_name = lookup_reg_name (reg_unit, reg_no); |
| 1618 pair_name = lookup_pair_reg_name (reg_unit, reg_no); |
| 1619 |
| 1620 cache_addr_str (addr_buf, ADDR_WIDTH, insn_word, size); |
| 1621 |
| 1622 if (size == 8) |
| 1623 snprintf (buf, OPERAND_WIDTH, "%s,%s,%s", reg_name, pair_name, addr_buf); |
| 1624 else |
| 1625 snprintf (buf, OPERAND_WIDTH, "%s,%s", reg_name, addr_buf); |
| 1626 |
| 1627 print_insn (outf, "", template->name, buf); |
| 1628 } |
| 1629 |
| 1630 /* Print a CACHEW instruction. */ |
| 1631 static void |
| 1632 print_cachew (unsigned int insn_word, bfd_vma pc ATTRIBUTE_UNUSED, |
| 1633 const insn_template *template, |
| 1634 disassemble_info *outf) |
| 1635 { |
| 1636 char buf[OPERAND_WIDTH]; |
| 1637 char addr_buf[ADDR_WIDTH]; |
| 1638 unsigned int reg_unit, reg_no; |
| 1639 unsigned int size = ((insn_word >> 1) & 0x1) ? 8 : 4; |
| 1640 const char *reg_name; |
| 1641 const char *pair_name; |
| 1642 |
| 1643 reg_unit = short_unit ((insn_word >> 3) & SHORT_UNIT_MASK); |
| 1644 reg_no = (insn_word >> 19) & REG_MASK; |
| 1645 |
| 1646 reg_name = lookup_reg_name (reg_unit, reg_no); |
| 1647 pair_name = lookup_pair_reg_name (reg_unit, reg_no); |
| 1648 |
| 1649 cache_addr_str (addr_buf, ADDR_WIDTH, insn_word, 64); |
| 1650 |
| 1651 if (size == 8) |
| 1652 snprintf (buf, OPERAND_WIDTH, "%s,%s,%s", addr_buf, reg_name, pair_name); |
| 1653 else |
| 1654 snprintf (buf, OPERAND_WIDTH, "%s,%s", addr_buf, reg_name); |
| 1655 |
| 1656 print_insn (outf, "", template->name, buf); |
| 1657 } |
| 1658 |
| 1659 /* Print an ICACHE instruction. */ |
| 1660 static void |
| 1661 print_icache (unsigned int insn_word, bfd_vma pc ATTRIBUTE_UNUSED, |
| 1662 const insn_template *template, |
| 1663 disassemble_info *outf) |
| 1664 { |
| 1665 char buf[OPERAND_WIDTH]; |
| 1666 int offset; |
| 1667 int pfcount; |
| 1668 |
| 1669 offset = ((insn_word >> 9) & IMM15_MASK); |
| 1670 pfcount = ((insn_word >> 1) & IMM4_MASK); |
| 1671 |
| 1672 offset = sign_extend (offset, IMM15_BITS); |
| 1673 |
| 1674 if (pfcount) |
| 1675 snprintf (buf, OPERAND_WIDTH, "#%d,#0x%x", offset, pfcount); |
| 1676 else |
| 1677 snprintf (buf, OPERAND_WIDTH, "#%d,#0", offset); |
| 1678 print_insn (outf, "", template->name, buf); |
| 1679 } |
| 1680 |
| 1681 /* Print a LNKGET instruction. */ |
| 1682 static void |
| 1683 print_lnkget (unsigned int insn_word, bfd_vma pc ATTRIBUTE_UNUSED, |
| 1684 const insn_template *template, |
| 1685 disassemble_info *outf) |
| 1686 { |
| 1687 char buf[OPERAND_WIDTH]; |
| 1688 char addr_buf[ADDR_WIDTH]; |
| 1689 unsigned int reg_unit, reg_no; |
| 1690 unsigned int size = metag_get_set_ext_size_bytes (insn_word); |
| 1691 const char *reg_name; |
| 1692 const char *pair_name; |
| 1693 |
| 1694 reg_unit = short_unit ((insn_word >> 3) & SHORT_UNIT_MASK); |
| 1695 reg_no = (insn_word >> 19) & REG_MASK; |
| 1696 |
| 1697 reg_name = lookup_reg_name (reg_unit, reg_no); |
| 1698 pair_name = lookup_pair_reg_name (reg_unit, reg_no); |
| 1699 |
| 1700 cache_addr_str (addr_buf, ADDR_WIDTH, insn_word, size); |
| 1701 |
| 1702 if (size == 8) |
| 1703 snprintf (buf, OPERAND_WIDTH, "%s,%s,%s", reg_name, pair_name, addr_buf); |
| 1704 else |
| 1705 snprintf (buf, OPERAND_WIDTH, "%s,%s", reg_name, addr_buf); |
| 1706 |
| 1707 print_insn (outf, "", template->name, buf); |
| 1708 } |
| 1709 |
| 1710 /* Print an FPU MOV instruction. */ |
| 1711 static void |
| 1712 print_fmov (unsigned int insn_word, bfd_vma pc ATTRIBUTE_UNUSED, |
| 1713 const insn_template *template, |
| 1714 disassemble_info *outf) |
| 1715 { |
| 1716 char buf[OPERAND_WIDTH]; |
| 1717 char prefix_buf[10]; |
| 1718 unsigned int src_no, dest_no; |
| 1719 unsigned int p = (insn_word >> 6) & 0x1; |
| 1720 unsigned int d = (insn_word >> 5) & 0x1; |
| 1721 unsigned int cc = (insn_word >> 1) & CC_MASK; |
| 1722 bfd_boolean show_cond = cc != COND_A && cc != COND_NV; |
| 1723 const char *dest_reg; |
| 1724 const char *src_reg; |
| 1725 const char *cc_flags; |
| 1726 |
| 1727 dest_no = (insn_word >> 19) & REG_MASK; |
| 1728 src_no = (insn_word >> 14) & REG_MASK; |
| 1729 |
| 1730 dest_reg = lookup_reg_name (UNIT_FX, dest_no); |
| 1731 src_reg = lookup_reg_name (UNIT_FX, src_no); |
| 1732 |
| 1733 cc_flags = lookup_fpu_scc_flags (cc); |
| 1734 |
| 1735 snprintf (buf, OPERAND_WIDTH, "%s,%s", dest_reg, src_reg); |
| 1736 |
| 1737 snprintf (prefix_buf, 10, "F%s%s%s", p ? "L" : "", |
| 1738 d ? "D" : "", show_cond ? cc_flags : ""); |
| 1739 |
| 1740 print_insn (outf, prefix_buf, template->name, buf); |
| 1741 } |
| 1742 |
| 1743 /* Convert an FPU rmask into a compatible form. */ |
| 1744 static unsigned int |
| 1745 convert_fx_rmask (unsigned int rmask) |
| 1746 { |
| 1747 int num_bits = hweight (rmask), i; |
| 1748 unsigned int ret = 0; |
| 1749 |
| 1750 for (i = 0; i < num_bits; i++) |
| 1751 { |
| 1752 ret <<= 1; |
| 1753 ret |= 0x1; |
| 1754 } |
| 1755 |
| 1756 return ret; |
| 1757 } |
| 1758 |
| 1759 /* Print an FPU MMOV instruction. */ |
| 1760 static void |
| 1761 print_fmmov (unsigned int insn_word, bfd_vma pc ATTRIBUTE_UNUSED, |
| 1762 const insn_template *template, |
| 1763 disassemble_info *outf) |
| 1764 { |
| 1765 char buf[OPERAND_WIDTH]; |
| 1766 char data_buf[REG_WIDTH]; |
| 1767 char fpu_buf[REG_WIDTH]; |
| 1768 bfd_boolean to_fpu = MAJOR_OPCODE (insn_word) == OPC_GET; |
| 1769 bfd_boolean is_mmovl = MINOR_OPCODE (insn_word) & 0x1; |
| 1770 unsigned int rmask = (insn_word >> 7) & RMASK_MASK; |
| 1771 unsigned int fpu_no, data_no, data_unit; |
| 1772 |
| 1773 data_no = (insn_word >> 19) & REG_MASK; |
| 1774 fpu_no = (insn_word >> 14) & REG_MASK; |
| 1775 |
| 1776 if (insn_word & 0x1) |
| 1777 data_unit = UNIT_D1; |
| 1778 else |
| 1779 data_unit = UNIT_D0; |
| 1780 |
| 1781 lookup_reg_list (data_buf, REG_WIDTH, data_unit, data_no, rmask, FALSE); |
| 1782 lookup_reg_list (fpu_buf, REG_WIDTH, UNIT_FX, fpu_no, |
| 1783 convert_fx_rmask (rmask), is_mmovl); |
| 1784 |
| 1785 if (to_fpu) |
| 1786 snprintf (buf, OPERAND_WIDTH, "%s,%s", fpu_buf, data_buf); |
| 1787 else |
| 1788 snprintf (buf, OPERAND_WIDTH, "%s,%s", data_buf, fpu_buf); |
| 1789 |
| 1790 print_insn (outf, "F", template->name, buf); |
| 1791 } |
| 1792 |
| 1793 /* Print an FPU data unit MOV instruction. */ |
| 1794 static void |
| 1795 print_fmov_data (unsigned int insn_word, bfd_vma pc ATTRIBUTE_UNUSED, |
| 1796 const insn_template *template, |
| 1797 disassemble_info *outf) |
| 1798 { |
| 1799 char buf[OPERAND_WIDTH]; |
| 1800 unsigned int src_no, dest_no; |
| 1801 unsigned int to_fpu = ((insn_word >> 7) & 0x1); |
| 1802 unsigned int unit_bit = (insn_word >> 24) & 0x1; |
| 1803 enum metag_unit base_unit; |
| 1804 const char *dest_reg; |
| 1805 const char *src_reg; |
| 1806 |
| 1807 dest_no = (insn_word >> 19) & REG_MASK; |
| 1808 src_no = (insn_word >> 9) & REG_MASK; |
| 1809 |
| 1810 if (unit_bit) |
| 1811 base_unit = UNIT_D1; |
| 1812 else |
| 1813 base_unit = UNIT_D0; |
| 1814 |
| 1815 if (to_fpu) |
| 1816 { |
| 1817 dest_reg = lookup_reg_name (UNIT_FX, dest_no); |
| 1818 src_reg = lookup_reg_name (base_unit, src_no); |
| 1819 } |
| 1820 else |
| 1821 { |
| 1822 dest_reg = lookup_reg_name (base_unit, dest_no); |
| 1823 src_reg = lookup_reg_name (UNIT_FX, src_no); |
| 1824 } |
| 1825 |
| 1826 snprintf (buf, OPERAND_WIDTH, "%s,%s", dest_reg, src_reg); |
| 1827 |
| 1828 print_insn (outf, "F", template->name, buf); |
| 1829 } |
| 1830 |
| 1831 /* Print an FPU MOV immediate instruction. */ |
| 1832 static void |
| 1833 print_fmov_i (unsigned int insn_word, bfd_vma pc ATTRIBUTE_UNUSED, |
| 1834 const insn_template *template, |
| 1835 disassemble_info *outf) |
| 1836 { |
| 1837 char buf[OPERAND_WIDTH]; |
| 1838 unsigned int dest_no; |
| 1839 unsigned int p = (insn_word >> 2) & 0x1; |
| 1840 unsigned int d = (insn_word >> 1) & 0x1; |
| 1841 const char *dest_reg; |
| 1842 unsigned int value = (insn_word >> 3) & IMM16_MASK; |
| 1843 |
| 1844 dest_no = (insn_word >> 19) & REG_MASK; |
| 1845 |
| 1846 dest_reg = lookup_reg_name (UNIT_FX, dest_no); |
| 1847 |
| 1848 snprintf (buf, OPERAND_WIDTH, "%s,#%#x", dest_reg, value); |
| 1849 |
| 1850 if (p) |
| 1851 print_insn (outf, "FL", template->name, buf); |
| 1852 else if (d) |
| 1853 print_insn (outf, "FD", template->name, buf); |
| 1854 else |
| 1855 print_insn (outf, "F", template->name, buf); |
| 1856 } |
| 1857 |
| 1858 /* Print an FPU PACK instruction. */ |
| 1859 static void |
| 1860 print_fpack (unsigned int insn_word, bfd_vma pc ATTRIBUTE_UNUSED, |
| 1861 const insn_template *template, |
| 1862 disassemble_info *outf) |
| 1863 { |
| 1864 char buf[OPERAND_WIDTH]; |
| 1865 unsigned int src1_no, src2_no, dest_no; |
| 1866 const char *dest_reg; |
| 1867 const char *src1_reg; |
| 1868 const char *src2_reg; |
| 1869 |
| 1870 dest_no = (insn_word >> 19) & REG_MASK; |
| 1871 src1_no = (insn_word >> 14) & REG_MASK; |
| 1872 src2_no = (insn_word >> 9) & REG_MASK; |
| 1873 |
| 1874 dest_reg = lookup_reg_name (UNIT_FX, dest_no); |
| 1875 src1_reg = lookup_reg_name (UNIT_FX, src1_no); |
| 1876 src2_reg = lookup_reg_name (UNIT_FX, src2_no); |
| 1877 |
| 1878 snprintf (buf, OPERAND_WIDTH, "%s,%s,%s", dest_reg, src1_reg, src2_reg); |
| 1879 |
| 1880 print_insn (outf, "F", template->name, buf); |
| 1881 } |
| 1882 |
| 1883 /* Print an FPU SWAP instruction. */ |
| 1884 static void |
| 1885 print_fswap (unsigned int insn_word, bfd_vma pc ATTRIBUTE_UNUSED, |
| 1886 const insn_template *template, |
| 1887 disassemble_info *outf) |
| 1888 { |
| 1889 char buf[OPERAND_WIDTH]; |
| 1890 unsigned int src_no, dest_no; |
| 1891 const char *dest_reg; |
| 1892 const char *src_reg; |
| 1893 |
| 1894 dest_no = (insn_word >> 19) & REG_MASK; |
| 1895 src_no = (insn_word >> 14) & REG_MASK; |
| 1896 |
| 1897 dest_reg = lookup_reg_name (UNIT_FX, dest_no); |
| 1898 src_reg = lookup_reg_name (UNIT_FX, src_no); |
| 1899 |
| 1900 snprintf (buf, OPERAND_WIDTH, "%s,%s", dest_reg, src_reg); |
| 1901 |
| 1902 print_insn (outf, "FL", template->name, buf); |
| 1903 } |
| 1904 |
| 1905 /* Print an FPU CMP instruction. */ |
| 1906 static void |
| 1907 print_fcmp (unsigned int insn_word, bfd_vma pc ATTRIBUTE_UNUSED, |
| 1908 const insn_template *template, |
| 1909 disassemble_info *outf) |
| 1910 { |
| 1911 char buf[OPERAND_WIDTH]; |
| 1912 char prefix_buf[10]; |
| 1913 unsigned int src_no, dest_no; |
| 1914 unsigned int a = (insn_word >> 19) & 0x1; |
| 1915 unsigned int z = (insn_word >> 8) & 0x1; |
| 1916 unsigned int p = (insn_word >> 6) & 0x1; |
| 1917 unsigned int d = (insn_word >> 5) & 0x1; |
| 1918 unsigned int q = (insn_word >> 7) & 0x1; |
| 1919 unsigned int cc = (insn_word >> 1) & CC_MASK; |
| 1920 bfd_boolean show_cond = cc != COND_A && cc != COND_NV; |
| 1921 const char *dest_reg; |
| 1922 const char *src_reg; |
| 1923 const char *cc_flags; |
| 1924 |
| 1925 dest_no = (insn_word >> 14) & REG_MASK; |
| 1926 src_no = (insn_word >> 9) & REG_MASK; |
| 1927 |
| 1928 dest_reg = lookup_reg_name (UNIT_FX, dest_no); |
| 1929 src_reg = lookup_reg_name (UNIT_FX, src_no); |
| 1930 |
| 1931 cc_flags = lookup_fpu_scc_flags (cc); |
| 1932 |
| 1933 if (z) |
| 1934 snprintf (buf, OPERAND_WIDTH, "%s,#0", dest_reg); |
| 1935 else |
| 1936 snprintf (buf, OPERAND_WIDTH, "%s,%s", dest_reg, src_reg); |
| 1937 |
| 1938 snprintf (prefix_buf, 10, "F%s%s%s%s%s", p ? "L" : "", |
| 1939 d ? "D" : "", a ? "A" : "", q ? "Q" : "", |
| 1940 show_cond ? cc_flags : ""); |
| 1941 |
| 1942 print_insn (outf, prefix_buf, template->name, buf); |
| 1943 } |
| 1944 |
| 1945 /* Print an FPU MIN or MAX instruction. */ |
| 1946 static void |
| 1947 print_fminmax (unsigned int insn_word, bfd_vma pc ATTRIBUTE_UNUSED, |
| 1948 const insn_template *template, |
| 1949 disassemble_info *outf) |
| 1950 { |
| 1951 char buf[OPERAND_WIDTH]; |
| 1952 char prefix_buf[10]; |
| 1953 unsigned int p = (insn_word >> 6) & 0x1; |
| 1954 unsigned int d = (insn_word >> 5) & 0x1; |
| 1955 unsigned int src1_no, src2_no, dest_no; |
| 1956 unsigned int cc = (insn_word >> 1) & CC_MASK; |
| 1957 bfd_boolean show_cond = cc != COND_A && cc != COND_NV; |
| 1958 const char *dest_reg; |
| 1959 const char *src1_reg; |
| 1960 const char *src2_reg; |
| 1961 const char *cc_flags; |
| 1962 |
| 1963 dest_no = (insn_word >> 19) & REG_MASK; |
| 1964 src1_no = (insn_word >> 14) & REG_MASK; |
| 1965 src2_no = (insn_word >> 9) & REG_MASK; |
| 1966 |
| 1967 dest_reg = lookup_reg_name (UNIT_FX, dest_no); |
| 1968 src1_reg = lookup_reg_name (UNIT_FX, src1_no); |
| 1969 src2_reg = lookup_reg_name (UNIT_FX, src2_no); |
| 1970 |
| 1971 cc_flags = lookup_fpu_scc_flags (cc); |
| 1972 |
| 1973 snprintf (buf, OPERAND_WIDTH, "%s,%s,%s", dest_reg, src1_reg, src2_reg); |
| 1974 |
| 1975 snprintf (prefix_buf, 10, "F%s%s%s", p ? "L" : "", |
| 1976 d ? "D" : "", show_cond ? cc_flags : ""); |
| 1977 |
| 1978 print_insn (outf, prefix_buf, template->name, buf); |
| 1979 } |
| 1980 |
| 1981 /* Print an FPU data conversion instruction. */ |
| 1982 static void |
| 1983 print_fconv (unsigned int insn_word, bfd_vma pc ATTRIBUTE_UNUSED, |
| 1984 const insn_template *template, |
| 1985 disassemble_info *outf) |
| 1986 { |
| 1987 char buf[OPERAND_WIDTH]; |
| 1988 char prefix_buf[10]; |
| 1989 unsigned int p = (insn_word >> 6) & 0x1; |
| 1990 unsigned int z = (insn_word >> 12) & 0x1; |
| 1991 unsigned int src_no, dest_no; |
| 1992 unsigned int cc = (insn_word >> 1) & CC_MASK; |
| 1993 bfd_boolean show_cond = cc != COND_A && cc != COND_NV; |
| 1994 const char *dest_reg; |
| 1995 const char *src_reg; |
| 1996 const char *cc_flags; |
| 1997 |
| 1998 dest_no = (insn_word >> 19) & REG_MASK; |
| 1999 src_no = (insn_word >> 14) & REG_MASK; |
| 2000 |
| 2001 dest_reg = lookup_reg_name (UNIT_FX, dest_no); |
| 2002 src_reg = lookup_reg_name (UNIT_FX, src_no); |
| 2003 |
| 2004 cc_flags = lookup_fpu_scc_flags (cc); |
| 2005 |
| 2006 snprintf (buf, OPERAND_WIDTH, "%s,%s", dest_reg, src_reg); |
| 2007 |
| 2008 snprintf (prefix_buf, 10, "F%s%s%s", p ? "L" : "", |
| 2009 z ? "Z" : "", show_cond ? cc_flags : ""); |
| 2010 |
| 2011 print_insn (outf, prefix_buf, template->name, buf); |
| 2012 } |
| 2013 |
| 2014 /* Print an FPU extended data conversion instruction. */ |
| 2015 static void |
| 2016 print_fconvx (unsigned int insn_word, bfd_vma pc ATTRIBUTE_UNUSED, |
| 2017 const insn_template *template, |
| 2018 disassemble_info *outf) |
| 2019 { |
| 2020 char buf[OPERAND_WIDTH]; |
| 2021 char prefix_buf[10]; |
| 2022 unsigned int p = (insn_word >> 6) & 0x1; |
| 2023 unsigned int xl = (insn_word >> 7) & 0x1; |
| 2024 unsigned int src_no, dest_no, fraction_bits; |
| 2025 unsigned int cc = (insn_word >> 1) & CC_MASK; |
| 2026 bfd_boolean show_cond = cc != COND_A && cc != COND_NV; |
| 2027 const char *dest_reg; |
| 2028 const char *src_reg; |
| 2029 const char *cc_flags; |
| 2030 |
| 2031 dest_no = (insn_word >> 19) & REG_MASK; |
| 2032 src_no = (insn_word >> 14) & REG_MASK; |
| 2033 |
| 2034 dest_reg = lookup_reg_name (UNIT_FX, dest_no); |
| 2035 src_reg = lookup_reg_name (UNIT_FX, src_no); |
| 2036 |
| 2037 cc_flags = lookup_fpu_scc_flags (cc); |
| 2038 |
| 2039 if (xl) |
| 2040 fraction_bits = (insn_word >> 8) & IMM6_MASK; |
| 2041 else |
| 2042 fraction_bits = (insn_word >> 9) & IMM5_MASK; |
| 2043 |
| 2044 snprintf (buf, OPERAND_WIDTH, "%s,%s,#%#x", dest_reg, src_reg, |
| 2045 fraction_bits); |
| 2046 |
| 2047 snprintf (prefix_buf, 10, "F%s%s", p ? "L" : "", |
| 2048 show_cond ? cc_flags : ""); |
| 2049 |
| 2050 print_insn (outf, prefix_buf, template->name, buf); |
| 2051 } |
| 2052 |
| 2053 /* Print an FPU basic arithmetic instruction. */ |
| 2054 static void |
| 2055 print_fbarith (unsigned int insn_word, bfd_vma pc ATTRIBUTE_UNUSED, |
| 2056 const insn_template *template, |
| 2057 disassemble_info *outf) |
| 2058 { |
| 2059 char buf[OPERAND_WIDTH]; |
| 2060 char prefix_buf[10]; |
| 2061 unsigned int n = (insn_word >> 7) & 0x1; |
| 2062 unsigned int p = (insn_word >> 6) & 0x1; |
| 2063 unsigned int d = (insn_word >> 5) & 0x1; |
| 2064 unsigned int src1_no, src2_no, dest_no; |
| 2065 unsigned int cc = (insn_word >> 1) & CC_MASK; |
| 2066 bfd_boolean show_cond = cc != COND_A && cc != COND_NV; |
| 2067 const char *dest_reg; |
| 2068 const char *src1_reg; |
| 2069 const char *src2_reg; |
| 2070 const char *cc_flags; |
| 2071 |
| 2072 dest_no = (insn_word >> 19) & REG_MASK; |
| 2073 src1_no = (insn_word >> 14) & REG_MASK; |
| 2074 src2_no = (insn_word >> 9) & REG_MASK; |
| 2075 |
| 2076 dest_reg = lookup_reg_name (UNIT_FX, dest_no); |
| 2077 src1_reg = lookup_reg_name (UNIT_FX, src1_no); |
| 2078 src2_reg = lookup_reg_name (UNIT_FX, src2_no); |
| 2079 |
| 2080 cc_flags = lookup_fpu_scc_flags (cc); |
| 2081 |
| 2082 snprintf (buf, OPERAND_WIDTH, "%s,%s,%s", dest_reg, src1_reg, src2_reg); |
| 2083 |
| 2084 snprintf (prefix_buf, 10, "F%s%s%s%s", p ? "L" : "", |
| 2085 d ? "D" : "", n ? "I" : "", show_cond ? cc_flags : ""); |
| 2086 |
| 2087 print_insn (outf, prefix_buf, template->name, buf); |
| 2088 } |
| 2089 |
| 2090 /* Print an FPU extended arithmetic instruction. */ |
| 2091 static void |
| 2092 print_fearith (unsigned int insn_word, bfd_vma pc ATTRIBUTE_UNUSED, |
| 2093 const insn_template *template, |
| 2094 disassemble_info *outf) |
| 2095 { |
| 2096 char buf[OPERAND_WIDTH]; |
| 2097 char prefix_buf[10]; |
| 2098 bfd_boolean is_muz = (MINOR_OPCODE (insn_word) == 0x6 && |
| 2099 ((insn_word >> 4) & 0x1)); |
| 2100 bfd_boolean is_mac = (MINOR_OPCODE (insn_word) == 0x6 && |
| 2101 (insn_word & 0x1f) == 0); |
| 2102 bfd_boolean is_maw = (MINOR_OPCODE (insn_word) == 0x6 && |
| 2103 ((insn_word >> 3) & 0x1)); |
| 2104 unsigned int o3o = insn_word & 0x1; |
| 2105 unsigned int q = is_muz && ((insn_word >> 1) & 0x1); |
| 2106 unsigned int n = (insn_word >> 7) & 0x1; |
| 2107 unsigned int p = (insn_word >> 6) & 0x1; |
| 2108 unsigned int d = (insn_word >> 5) & 0x1; |
| 2109 unsigned int cc = (insn_word >> 1) & CC_MASK; |
| 2110 bfd_boolean show_cond = (MINOR_OPCODE (insn_word) == 0x5 && cc != COND_A && |
| 2111 cc != COND_NV); |
| 2112 unsigned int src1_no, src2_no, dest_no; |
| 2113 const char *dest_reg; |
| 2114 const char *src1_reg; |
| 2115 const char *src2_reg; |
| 2116 const char *cc_flags; |
| 2117 |
| 2118 dest_no = (insn_word >> 19) & REG_MASK; |
| 2119 src1_no = (insn_word >> 14) & REG_MASK; |
| 2120 src2_no = (insn_word >> 9) & REG_MASK; |
| 2121 |
| 2122 dest_reg = lookup_reg_name (UNIT_FX, dest_no); |
| 2123 src1_reg = lookup_reg_name (UNIT_FX, src1_no); |
| 2124 src2_reg = lookup_reg_name (UNIT_FX, src2_no); |
| 2125 |
| 2126 cc_flags = lookup_fpu_scc_flags (cc); |
| 2127 |
| 2128 if (is_mac) |
| 2129 snprintf (buf, OPERAND_WIDTH, "ACF.0,%s,%s", src1_reg, src2_reg); |
| 2130 else if (o3o && is_maw) |
| 2131 snprintf (buf, OPERAND_WIDTH, "%s,%s", src1_reg, src2_reg); |
| 2132 else |
| 2133 snprintf (buf, OPERAND_WIDTH, "%s,%s,%s", dest_reg, src1_reg, src2_reg); |
| 2134 |
| 2135 snprintf (prefix_buf, 10, "F%s%s%s%s%s", p ? "L" : "", |
| 2136 d ? "D" : "", n ? "I" : "", q ? "Q" : "", |
| 2137 show_cond ? cc_flags : ""); |
| 2138 |
| 2139 print_insn (outf, prefix_buf, template->name, buf); |
| 2140 } |
| 2141 |
| 2142 /* Print an FPU RCP or RSQ instruction. */ |
| 2143 static void |
| 2144 print_frec (unsigned int insn_word, bfd_vma pc ATTRIBUTE_UNUSED, |
| 2145 const insn_template *template, |
| 2146 disassemble_info *outf) |
| 2147 { |
| 2148 char buf[OPERAND_WIDTH]; |
| 2149 char prefix_buf[10]; |
| 2150 unsigned int z = (insn_word >> 10) & 0x1; |
| 2151 unsigned int q = (insn_word >> 9) & 0x1; |
| 2152 unsigned int n = (insn_word >> 7) & 0x1; |
| 2153 unsigned int p = (insn_word >> 6) & 0x1; |
| 2154 unsigned int d = (insn_word >> 5) & 0x1; |
| 2155 unsigned int src_no, dest_no; |
| 2156 const char *dest_reg; |
| 2157 const char *src_reg; |
| 2158 |
| 2159 dest_no = (insn_word >> 19) & REG_MASK; |
| 2160 src_no = (insn_word >> 14) & REG_MASK; |
| 2161 |
| 2162 dest_reg = lookup_reg_name (UNIT_FX, dest_no); |
| 2163 src_reg = lookup_reg_name (UNIT_FX, src_no); |
| 2164 |
| 2165 snprintf (buf, OPERAND_WIDTH, "%s,%s", dest_reg, src_reg); |
| 2166 |
| 2167 snprintf (prefix_buf, 10, "F%s%s%s%s%s", p ? "L" : "", |
| 2168 d ? "D" : "", n ? "I" : "", q ? "Q" : "", z ? "Z" : ""); |
| 2169 |
| 2170 print_insn (outf, prefix_buf, template->name, buf); |
| 2171 } |
| 2172 |
| 2173 static void |
| 2174 print_fsimd (unsigned int insn_word, bfd_vma pc ATTRIBUTE_UNUSED, |
| 2175 const insn_template *template, |
| 2176 disassemble_info *outf) |
| 2177 { |
| 2178 char buf[OPERAND_WIDTH]; |
| 2179 unsigned int n = (insn_word >> 7) & 0x1; |
| 2180 unsigned int src1_no, src2_no, dest_no; |
| 2181 const char *dest_reg; |
| 2182 const char *src1_reg; |
| 2183 const char *src2_reg; |
| 2184 |
| 2185 dest_no = (insn_word >> 19) & REG_MASK; |
| 2186 src1_no = (insn_word >> 14) & REG_MASK; |
| 2187 src2_no = (insn_word >> 9) & REG_MASK; |
| 2188 |
| 2189 dest_reg = lookup_reg_name (UNIT_FX, dest_no); |
| 2190 src1_reg = lookup_reg_name (UNIT_FX, src1_no); |
| 2191 src2_reg = lookup_reg_name (UNIT_FX, src2_no); |
| 2192 |
| 2193 snprintf (buf, OPERAND_WIDTH, "%s,%s,%s", dest_reg, src1_reg, src2_reg); |
| 2194 |
| 2195 if (n) |
| 2196 print_insn (outf, "FLI", template->name, buf); |
| 2197 else |
| 2198 print_insn (outf, "FL", template->name, buf); |
| 2199 } |
| 2200 |
| 2201 /* Print an FPU accumulator GET or SET instruction. */ |
| 2202 static void |
| 2203 print_fget_set_acf (unsigned int insn_word, bfd_vma pc ATTRIBUTE_UNUSED, |
| 2204 const insn_template *template, |
| 2205 disassemble_info *outf) |
| 2206 { |
| 2207 bfd_boolean is_get = MAJOR_OPCODE (template->meta_opcode) == OPC_GET; |
| 2208 char buf[OPERAND_WIDTH]; |
| 2209 char addr_buf[ADDR_WIDTH]; |
| 2210 unsigned int part; |
| 2211 const char *reg_name; |
| 2212 |
| 2213 part = (insn_word >> 19) & ACF_PART_MASK; |
| 2214 |
| 2215 reg_name = lookup_acf_name (part); |
| 2216 |
| 2217 mget_mset_addr_str (addr_buf, ADDR_WIDTH, insn_word); |
| 2218 |
| 2219 if (is_get) |
| 2220 { |
| 2221 snprintf (buf, OPERAND_WIDTH, "%s,%s", reg_name, addr_buf); |
| 2222 } |
| 2223 else |
| 2224 { |
| 2225 snprintf (buf, OPERAND_WIDTH, "%s,%s", addr_buf, reg_name); |
| 2226 } |
| 2227 print_insn (outf, "F", template->name, buf); |
| 2228 } |
| 2229 |
| 2230 /* Return the name of the DSP register or accumulator for NUM and UNIT. */ |
| 2231 static const char * |
| 2232 __lookup_dsp_name (unsigned int num, unsigned int unit) |
| 2233 { |
| 2234 size_t i; |
| 2235 |
| 2236 for (i = 0; i < sizeof(metag_dsp_regtab)/sizeof(metag_dsp_regtab[0]); i++) |
| 2237 { |
| 2238 const metag_reg *reg = &metag_dsp_regtab[i]; |
| 2239 |
| 2240 if (reg->no == num) |
| 2241 { |
| 2242 if ((reg->unit == UNIT_RAM_D0 || reg->unit == UNIT_ACC_D0) && |
| 2243 unit == UNIT_D0) |
| 2244 return reg->name; |
| 2245 |
| 2246 if ((reg->unit == UNIT_RAM_D1 || reg->unit == UNIT_ACC_D1) && |
| 2247 unit == UNIT_D1) |
| 2248 return reg->name; |
| 2249 } |
| 2250 } |
| 2251 return "?.?"; |
| 2252 } |
| 2253 |
| 2254 /* Return the name of the DSP register for NUM and UNIT. */ |
| 2255 static const char * |
| 2256 lookup_dsp_name (unsigned int num, unsigned int unit) |
| 2257 { |
| 2258 size_t i; |
| 2259 |
| 2260 for (i = 0; i < sizeof(metag_dsp_regtab)/sizeof(metag_dsp_regtab[0]); i++) |
| 2261 { |
| 2262 const metag_reg *reg = &metag_dsp_regtab[i]; |
| 2263 |
| 2264 if (reg->no == num && reg->unit == unit) |
| 2265 return reg->name; |
| 2266 } |
| 2267 return "?.?"; |
| 2268 } |
| 2269 |
| 2270 /* Return the name of the DSP RAM register for NUM and UNIT. */ |
| 2271 static const char * |
| 2272 lookup_dspram_name (unsigned int num, unsigned int unit, bfd_boolean load) |
| 2273 { |
| 2274 size_t i, nentries; |
| 2275 |
| 2276 nentries = sizeof(metag_dsp_tmpl_regtab[load])/sizeof(metag_dsp_tmpl_regtab[lo
ad][0]); |
| 2277 |
| 2278 for (i = 0; i < nentries; i++) |
| 2279 { |
| 2280 const metag_reg *reg = &metag_dsp_tmpl_regtab[load][i]; |
| 2281 |
| 2282 if (reg->no == num && reg->unit == unit) |
| 2283 return reg->name; |
| 2284 } |
| 2285 return "?.?"; |
| 2286 } |
| 2287 |
| 2288 /* This lookup function looks up the corresponding name for a register |
| 2289 number in a DSP instruction. SOURCE indicates whether this |
| 2290 register is a source or destination operand. */ |
| 2291 static const char * |
| 2292 lookup_any_reg_name (unsigned int unit, unsigned int num, bfd_boolean source) |
| 2293 { |
| 2294 /* A register with the top bit set (5th bit) indicates a DSPRAM |
| 2295 register. */ |
| 2296 if (num > 15) |
| 2297 { |
| 2298 unsigned int dunit = (unit == UNIT_D0) ? UNIT_RAM_D0 : UNIT_RAM_D1; |
| 2299 return lookup_dspram_name (num, dunit, source); |
| 2300 } |
| 2301 else |
| 2302 return lookup_reg_name (unit, num); |
| 2303 } |
| 2304 |
| 2305 /* Return the DSP data unit for UNIT. */ |
| 2306 static inline enum metag_unit |
| 2307 dsp_data_unit_to_sym (unsigned int unit) |
| 2308 { |
| 2309 if (unit == 0) |
| 2310 return UNIT_D0; |
| 2311 else |
| 2312 return UNIT_D1; |
| 2313 } |
| 2314 |
| 2315 /* Print a DSP GET or SET instruction. */ |
| 2316 static void |
| 2317 print_dget_set (unsigned int insn_word, bfd_vma pc ATTRIBUTE_UNUSED, |
| 2318 const insn_template *template, |
| 2319 disassemble_info *outf) |
| 2320 { |
| 2321 bfd_boolean is_get = (template->meta_opcode & 0x100); |
| 2322 char buf[OPERAND_WIDTH]; |
| 2323 char addr_buf[ADDR_WIDTH]; |
| 2324 char prefix[DSP_PREFIX_WIDTH]; |
| 2325 unsigned int part; |
| 2326 const char *reg_name[2]; |
| 2327 bfd_boolean is_high = FALSE; |
| 2328 bfd_boolean is_dual = (insn_word & 0x4); |
| 2329 bfd_boolean is_template = (insn_word & 0x2); |
| 2330 const char *base_reg = "?"; |
| 2331 unsigned int addr_unit, base_no, unit; |
| 2332 |
| 2333 unit = dsp_data_unit_to_sym (insn_word & 0x1); |
| 2334 |
| 2335 /* Is this a load/store to a template table? */ |
| 2336 if (is_template) |
| 2337 { |
| 2338 part = (insn_word >> 19) & 0x1f; |
| 2339 reg_name[0] = lookup_dsp_name (part, UNIT_DT); |
| 2340 } |
| 2341 else |
| 2342 { |
| 2343 part = (insn_word >> 19) & REG_MASK; |
| 2344 is_high = ((part & 0x18) == 0x18); |
| 2345 |
| 2346 /* Strip bit high indicator. */ |
| 2347 if (is_high) |
| 2348 part &= 0x17; |
| 2349 |
| 2350 reg_name[0] = __lookup_dsp_name (part, unit); |
| 2351 |
| 2352 } |
| 2353 |
| 2354 /* Is this a dual unit DSP operation? The modulo operator below |
| 2355 makes sure that we print the Rd register in the correct order, |
| 2356 e.g. because there's only one bit in the instruction for the Data |
| 2357 Unit we have to work out what the other data unit number is. |
| 2358 (there's only 2). */ |
| 2359 if (is_dual) |
| 2360 { |
| 2361 unsigned int _unit = insn_word & 0x1; |
| 2362 |
| 2363 _unit = ((_unit + 1) % 2); |
| 2364 reg_name[1] = __lookup_dsp_name(part, dsp_data_unit_to_sym (_unit)); |
| 2365 } |
| 2366 else |
| 2367 reg_name[1] = NULL; |
| 2368 |
| 2369 addr_unit = ((insn_word >> 18) & 0x1); |
| 2370 if (addr_unit == 0) |
| 2371 addr_unit = UNIT_A0; |
| 2372 else |
| 2373 addr_unit = UNIT_A1; |
| 2374 |
| 2375 base_no = (insn_word >> 14) & DSP_REG_MASK; |
| 2376 |
| 2377 base_reg = lookup_reg_name (addr_unit, base_no); |
| 2378 |
| 2379 /* Check if it's a post-increment/post-decrement. */ |
| 2380 if (insn_word & 0x2000) |
| 2381 { |
| 2382 unsigned int imm = (insn_word >> 9) & DGET_SET_IMM_MASK; |
| 2383 const char *post_op; |
| 2384 |
| 2385 switch (imm) |
| 2386 { |
| 2387 case 0x1: |
| 2388 post_op = "++"; |
| 2389 break; |
| 2390 case 0x3: |
| 2391 post_op = "--"; |
| 2392 break; |
| 2393 default: |
| 2394 post_op = ""; |
| 2395 } |
| 2396 |
| 2397 snprintf (addr_buf, ADDR_WIDTH, "[%s%s]", base_reg, post_op); |
| 2398 } |
| 2399 else |
| 2400 { |
| 2401 unsigned int offset_part = (insn_word >> 9) & DSP_REG_MASK; |
| 2402 const char *offset_reg = lookup_reg_name (addr_unit, offset_part); |
| 2403 |
| 2404 snprintf (addr_buf, ADDR_WIDTH, "[%s+%s++]", base_reg, offset_reg); |
| 2405 } |
| 2406 |
| 2407 if (is_get) |
| 2408 { |
| 2409 if (is_dual && !is_template) |
| 2410 snprintf (buf, OPERAND_WIDTH, "%s,%s,%s", reg_name[0], |
| 2411 reg_name[1], addr_buf); |
| 2412 else |
| 2413 snprintf (buf, OPERAND_WIDTH, "%s,%s", reg_name[0], addr_buf); |
| 2414 } |
| 2415 else |
| 2416 { |
| 2417 if (is_dual && !is_template) |
| 2418 snprintf (buf, OPERAND_WIDTH, "%s,%s,%s", addr_buf, |
| 2419 reg_name[0], reg_name[1]); |
| 2420 else |
| 2421 snprintf (buf, OPERAND_WIDTH, "%s,%s", addr_buf, reg_name[0]); |
| 2422 } |
| 2423 |
| 2424 snprintf (prefix, DSP_PREFIX_WIDTH, "D%s", is_high ? "H" : ""); |
| 2425 print_insn (outf, prefix, template->name, buf); |
| 2426 } |
| 2427 |
| 2428 /* Print a DSP template instruction. */ |
| 2429 static void |
| 2430 print_dtemplate (unsigned int insn_word, bfd_vma pc ATTRIBUTE_UNUSED, |
| 2431 const insn_template *template, |
| 2432 disassemble_info *outf) |
| 2433 { |
| 2434 char buf[OPERAND_WIDTH]; |
| 2435 char prefix[DSP_PREFIX_WIDTH]; |
| 2436 unsigned int offset[4]; |
| 2437 bfd_boolean is_half = (MINOR_OPCODE (insn_word) == 0x5); |
| 2438 bfd_boolean daop_only = (MINOR_OPCODE (insn_word) == 0x3); |
| 2439 |
| 2440 offset[0] = ((insn_word >> 19) & REG_MASK); |
| 2441 offset[1] = ((insn_word >> 14) & REG_MASK); |
| 2442 offset[2] = ((insn_word >> 9) & REG_MASK); |
| 2443 offset[3] = ((insn_word >> 4) & REG_MASK); |
| 2444 |
| 2445 if (daop_only) |
| 2446 snprintf (buf, OPERAND_WIDTH, "#0x%x,#0x%x,#0x%x", offset[0], |
| 2447 offset[1], offset[2]); |
| 2448 else |
| 2449 { |
| 2450 snprintf (buf, OPERAND_WIDTH, "#0x%x,#0x%x,#0x%x,#0x%x", offset[0], |
| 2451 offset[1], offset[2], offset[3]); |
| 2452 } |
| 2453 |
| 2454 snprintf (prefix, DSP_PREFIX_WIDTH, "D%s", is_half ? "H" : ""); |
| 2455 print_insn (outf, prefix, template->name, buf); |
| 2456 } |
| 2457 |
| 2458 /* Format template definition from INSN_WORD into BUF. */ |
| 2459 static void |
| 2460 decode_template_definition(unsigned int insn_word, char *buf, size_t len) |
| 2461 { |
| 2462 bfd_boolean load = ((insn_word >> 13) & 0x1); |
| 2463 bfd_boolean dspram = (((insn_word >> 17) & 0x3) == 0x3); |
| 2464 const char *template[1]; |
| 2465 unsigned int tidx = ((insn_word >> 9) & TEMPLATE_REGS_MASK); |
| 2466 enum metag_unit au, ram_unit; |
| 2467 unsigned int addr_reg_nums[2]; |
| 2468 const char *addr_reg_names[2]; |
| 2469 const char *post_op = ""; |
| 2470 const char *join_op = ""; |
| 2471 enum metag_unit data_unit = ((insn_word >> 24) & 0x1) ? UNIT_D1 : UNIT_D0; |
| 2472 |
| 2473 template[0] = lookup_dsp_name (tidx, UNIT_DT); |
| 2474 |
| 2475 addr_reg_names[1] = ""; |
| 2476 |
| 2477 if (dspram) |
| 2478 { |
| 2479 ram_unit = (data_unit == UNIT_D0) ? UNIT_RAM_D0 : UNIT_RAM_D1; |
| 2480 addr_reg_nums[0] = ((insn_word >> 19) & REG_MASK); |
| 2481 addr_reg_names[0] = lookup_dspram_name (addr_reg_nums[0], |
| 2482 ram_unit, load); |
| 2483 } |
| 2484 else |
| 2485 { |
| 2486 bfd_boolean im = (((insn_word >> 18) & 0x1) != 0); |
| 2487 |
| 2488 au = (((insn_word >> 23) & 0x1) == 0) ? UNIT_A0 : UNIT_A1; |
| 2489 addr_reg_nums[0] = ((insn_word >> 19) & DSP_REG_MASK); |
| 2490 |
| 2491 addr_reg_names[0] = lookup_reg_name (au, addr_reg_nums[0]); |
| 2492 |
| 2493 if (im) |
| 2494 { |
| 2495 unsigned int im_value = ((insn_word >> 14) & 0x3); |
| 2496 |
| 2497 switch (im_value) |
| 2498 { |
| 2499 case 0x1: |
| 2500 post_op = "++"; |
| 2501 break; |
| 2502 case 0x3: |
| 2503 post_op = "--"; |
| 2504 break; |
| 2505 } |
| 2506 } |
| 2507 else |
| 2508 { |
| 2509 addr_reg_nums[1] = ((insn_word >> 14) & DSP_REG_MASK); |
| 2510 addr_reg_names[1] = lookup_reg_name (au, addr_reg_nums[1]); |
| 2511 join_op = "+"; |
| 2512 post_op = "++"; |
| 2513 } |
| 2514 } |
| 2515 |
| 2516 if (load) |
| 2517 { |
| 2518 len = snprintf (buf, len, " %s,[%s%s%s%s]", template[0], addr_reg_names[0]
, |
| 2519 join_op, addr_reg_names[1], post_op); |
| 2520 } |
| 2521 else |
| 2522 { |
| 2523 len = snprintf (buf, len, " [%s%s%s%s],%s", addr_reg_names[0], join_op, |
| 2524 addr_reg_names[1], post_op, template[0]); |
| 2525 } |
| 2526 } |
| 2527 |
| 2528 /* Print a DSP ALU instruction. */ |
| 2529 static void |
| 2530 print_dalu (unsigned int insn_word, bfd_vma pc ATTRIBUTE_UNUSED, |
| 2531 const insn_template *template, |
| 2532 disassemble_info *outf) |
| 2533 { |
| 2534 bfd_boolean is_dual = FALSE; |
| 2535 unsigned int data_unit = (((insn_word >> 24) & 0x1) ? UNIT_D1 : UNIT_D0); |
| 2536 const char *reg_names[3]; |
| 2537 unsigned int reg_nums[3]; |
| 2538 bfd_boolean ac = ((insn_word >> 7) & 0x1); |
| 2539 char buf[OPERAND_WIDTH]; |
| 2540 char prefix[DSP_PREFIX_WIDTH]; |
| 2541 size_t len; |
| 2542 bfd_boolean is_mod = FALSE; |
| 2543 bfd_boolean is_overflow = FALSE; |
| 2544 unsigned int reg_brackets[3]; |
| 2545 bfd_boolean is_w_mx = FALSE; |
| 2546 bfd_boolean is_b_mx = FALSE; |
| 2547 bfd_boolean imm = FALSE; |
| 2548 bfd_boolean is_quickrot64 = FALSE; |
| 2549 bfd_boolean conditional = FALSE; |
| 2550 const char *cc_flags = NULL; |
| 2551 bfd_boolean is_unsigned = FALSE; |
| 2552 |
| 2553 memset (reg_brackets, 0, sizeof (reg_brackets)); |
| 2554 |
| 2555 if (template->arg_type & DSP_ARGS_1) |
| 2556 { |
| 2557 bfd_boolean is_template = FALSE; |
| 2558 const char *addr_reg = NULL; |
| 2559 bfd_boolean qr = FALSE; |
| 2560 bfd_boolean is_acc_add = FALSE; |
| 2561 bfd_boolean is_acc_sub = FALSE; |
| 2562 bfd_boolean is_acc_zero = FALSE; |
| 2563 bfd_boolean is_split8 = (template->arg_type & DSP_ARGS_SPLIT8); |
| 2564 |
| 2565 /* Read DU bit. */ |
| 2566 data_unit = ((insn_word >> 24) & 0x1) ? UNIT_D1 : UNIT_D0; |
| 2567 |
| 2568 conditional = ((insn_word >> 24) & 0x4); |
| 2569 |
| 2570 /* Templates can't be conditional. */ |
| 2571 is_template = (((insn_word & 0x02000002) == 0x2) && !conditional); |
| 2572 |
| 2573 if (is_split8) |
| 2574 is_mod = (insn_word & 0x80); |
| 2575 |
| 2576 if (template->arg_type & DSP_ARGS_QR) |
| 2577 { |
| 2578 if (!conditional) |
| 2579 is_quickrot64 = ((insn_word >> 5) & 0x1); |
| 2580 } |
| 2581 |
| 2582 if (template->arg_type & DSP_ARGS_DACC) |
| 2583 { |
| 2584 is_mod = (insn_word & 0x8); |
| 2585 is_unsigned = (insn_word & 0x40); |
| 2586 } |
| 2587 |
| 2588 if (is_template) |
| 2589 { |
| 2590 is_w_mx = (insn_word & 0x1); |
| 2591 is_dual = ((insn_word >> 0x4) & 0x1); |
| 2592 |
| 2593 /* De.r,Dx.r,De.r|ACe.r */ |
| 2594 if (template->arg_type & DSP_ARGS_ACC2) |
| 2595 { |
| 2596 is_mod = (insn_word & 0x8); |
| 2597 is_overflow = (insn_word & 0x20); |
| 2598 } |
| 2599 |
| 2600 /* ACe.e,ACx.r,ACo.e? */ |
| 2601 if ((template->arg_type & DSP_ARGS_XACC) && |
| 2602 (((insn_word >> 6) & 0x5) == 0x5)) |
| 2603 { |
| 2604 enum metag_unit ac_unit, ao_unit; |
| 2605 |
| 2606 ac_unit = (data_unit == UNIT_D0) ? UNIT_ACC_D0 : UNIT_ACC_D1; |
| 2607 |
| 2608 if (ac_unit == UNIT_ACC_D0) |
| 2609 ao_unit = UNIT_ACC_D1; |
| 2610 else |
| 2611 ao_unit = UNIT_ACC_D0; |
| 2612 |
| 2613 reg_nums[1] = ((insn_word >> 19) & REG_MASK); |
| 2614 |
| 2615 /* These are dummy arguments anyway so the register |
| 2616 number does not matter. */ |
| 2617 reg_names[0] = lookup_dsp_name (16, ac_unit); /* ACe.0 */ |
| 2618 reg_names[1] = lookup_dsp_name (16, ac_unit); /* ACx.0 */ |
| 2619 reg_names[2] = lookup_dsp_name (16, ao_unit); /* ACo.0 */ |
| 2620 } |
| 2621 else |
| 2622 { |
| 2623 /* De.r|ACe.r,Dx.r,De.r */ |
| 2624 if (template->arg_type & DSP_ARGS_DACC && |
| 2625 ((insn_word & 0x84) != 0)) |
| 2626 { |
| 2627 enum metag_unit ac_unit; |
| 2628 |
| 2629 ac_unit = (data_unit == UNIT_D0) ? UNIT_ACC_D0 : UNIT_ACC_D1; |
| 2630 reg_names[0] = lookup_dsp_name (16, ac_unit); |
| 2631 |
| 2632 is_acc_zero = ((insn_word & 0x84) == 0x04); |
| 2633 is_acc_add = ((insn_word & 0x84) == 0x80); |
| 2634 is_acc_sub = ((insn_word & 0x84) == 0x84); |
| 2635 } |
| 2636 else |
| 2637 reg_names[0] = lookup_any_reg_name (data_unit, 0, FALSE); |
| 2638 |
| 2639 /* These are dummy arguments anyway so the register |
| 2640 number does not matter. */ |
| 2641 reg_names[1] = lookup_any_reg_name (data_unit, 0, TRUE); |
| 2642 |
| 2643 /* De.r,Dx.r,De.r|ACe.r */ |
| 2644 if ((template->arg_type & DSP_ARGS_ACC2) && |
| 2645 ((insn_word & 0x80) == 0x80)) |
| 2646 { |
| 2647 enum metag_unit ac_unit; |
| 2648 |
| 2649 ac_unit = (data_unit == UNIT_D0) ? UNIT_ACC_D0 : UNIT_ACC_D1; |
| 2650 reg_names[2] = lookup_dsp_name (16, ac_unit); |
| 2651 } |
| 2652 /* Detection of QUICKRoT and accumulator usage uses the |
| 2653 same bits. They are mutually exclusive. */ |
| 2654 else if (ac && (template->arg_type & DSP_ARGS_ACC2)) |
| 2655 { |
| 2656 reg_nums[2] = ((insn_word >> 9) & REG_MASK); |
| 2657 |
| 2658 if (data_unit == UNIT_D0) |
| 2659 reg_names[2] = lookup_dsp_name (reg_nums[2], UNIT_ACC_D0); |
| 2660 else |
| 2661 reg_names[2] = lookup_dsp_name (reg_nums[2], UNIT_ACC_D1); |
| 2662 } |
| 2663 else |
| 2664 { |
| 2665 if ((template->arg_type & DSP_ARGS_QR) && |
| 2666 ((insn_word & 0x40) == 0x40)) |
| 2667 { |
| 2668 enum metag_unit aunit; |
| 2669 int reg_no; |
| 2670 |
| 2671 if (conditional) |
| 2672 reg_no = ((insn_word >> 5) & 0x1); |
| 2673 else |
| 2674 reg_no = ((insn_word >> 7) & 0x1); |
| 2675 |
| 2676 aunit = (data_unit == UNIT_D0) ? UNIT_A0 : UNIT_A1; |
| 2677 addr_reg = lookup_reg_name (aunit, reg_no + 2); |
| 2678 |
| 2679 qr = TRUE; |
| 2680 } |
| 2681 |
| 2682 reg_names[2] = lookup_any_reg_name (data_unit, 0, TRUE); |
| 2683 } |
| 2684 } |
| 2685 |
| 2686 if (qr) |
| 2687 { |
| 2688 len = snprintf (buf, OPERAND_WIDTH, "%s,%s,%s,%s", |
| 2689 reg_names[0], reg_names[1], reg_names[2], |
| 2690 addr_reg); |
| 2691 } |
| 2692 else |
| 2693 { |
| 2694 len = snprintf (buf, OPERAND_WIDTH, "%s,%s,%s%s%s", |
| 2695 reg_names[0], reg_names[1], |
| 2696 reg_brackets[2] ? "[" : "", |
| 2697 reg_names[2], reg_brackets[2] ? "]" : ""); |
| 2698 } |
| 2699 |
| 2700 decode_template_definition (insn_word, buf + len, |
| 2701 OPERAND_WIDTH - len); |
| 2702 } |
| 2703 else /* Not a template definiton. */ |
| 2704 { |
| 2705 reg_nums[0] = ((insn_word >> 19) & REG_MASK); |
| 2706 reg_nums[1] = ((insn_word >> 14) & REG_MASK); |
| 2707 reg_nums[2] = ((insn_word >> 9) & REG_MASK); |
| 2708 |
| 2709 imm = (((insn_word >> 24) & 0x2) && (template->arg_type & DSP_ARGS_IMM
)); |
| 2710 |
| 2711 if (imm) |
| 2712 is_dual = (insn_word & 0x4); |
| 2713 else if (!conditional) |
| 2714 is_dual = (insn_word & 0x10); |
| 2715 else |
| 2716 cc_flags = lookup_scc_flags ((insn_word >> 1) & CC_MASK); |
| 2717 |
| 2718 /* De.r,Dx.r,De.r|ACe.r */ |
| 2719 if (template->arg_type & DSP_ARGS_ACC2) |
| 2720 { |
| 2721 is_mod = (insn_word & 0x8); |
| 2722 is_overflow = (insn_word & 0x20); |
| 2723 } |
| 2724 |
| 2725 if (template->arg_type & DSP_ARGS_SPLIT8) |
| 2726 { |
| 2727 is_overflow = (insn_word & 0x20); |
| 2728 } |
| 2729 |
| 2730 /* ACe.e,ACx.r,ACo.e? */ |
| 2731 if ((template->arg_type & DSP_ARGS_XACC) && |
| 2732 (((insn_word >> 6) & 0x5) == 0x5)) |
| 2733 { |
| 2734 enum metag_unit ac_unit, ao_unit; |
| 2735 |
| 2736 ac_unit = (data_unit == UNIT_D0) ? UNIT_ACC_D0 : UNIT_ACC_D1; |
| 2737 |
| 2738 if (ac_unit == UNIT_ACC_D0) |
| 2739 ao_unit = UNIT_ACC_D1; |
| 2740 else |
| 2741 ao_unit = UNIT_ACC_D0; |
| 2742 |
| 2743 reg_nums[1] = ((insn_word >> 19) & REG_MASK); |
| 2744 reg_names[0] = lookup_dsp_name (reg_nums[1], ac_unit); |
| 2745 reg_names[1] = lookup_dsp_name (reg_nums[1], ac_unit); |
| 2746 reg_names[2] = lookup_dsp_name (reg_nums[1], ao_unit); |
| 2747 } |
| 2748 else |
| 2749 { |
| 2750 bfd_boolean o2r = (insn_word & 0x1); |
| 2751 |
| 2752 /* De.r|ACe.r,Dx.r,De.r */ |
| 2753 if ((template->arg_type & DSP_ARGS_DACC) && |
| 2754 ((insn_word & 0x84) != 0)) |
| 2755 { |
| 2756 enum metag_unit ac_unit; |
| 2757 |
| 2758 ac_unit = (data_unit == UNIT_D0) ? UNIT_ACC_D0 : UNIT_ACC_D1; |
| 2759 reg_names[0] = lookup_dsp_name (reg_nums[0], ac_unit); |
| 2760 |
| 2761 is_acc_zero = ((insn_word & 0x84) == 0x04); |
| 2762 is_acc_add = ((insn_word & 0x84) == 0x80); |
| 2763 is_acc_sub = ((insn_word & 0x84) == 0x84); |
| 2764 } |
| 2765 else if (conditional) |
| 2766 { |
| 2767 reg_names[0] = lookup_reg_name (data_unit, reg_nums[0]); |
| 2768 } |
| 2769 else |
| 2770 { |
| 2771 reg_names[0] = lookup_any_reg_name (data_unit, |
| 2772 reg_nums[0], FALSE); |
| 2773 if (reg_nums[0] > 15) |
| 2774 reg_brackets[0] = 1; |
| 2775 } |
| 2776 |
| 2777 if (imm) |
| 2778 { |
| 2779 reg_names[1] = lookup_any_reg_name (data_unit, reg_nums[0], TR
UE); |
| 2780 |
| 2781 if (reg_brackets[0]) |
| 2782 reg_brackets[1] = 1; |
| 2783 } |
| 2784 else |
| 2785 { |
| 2786 if (is_split8 && is_mod) |
| 2787 { |
| 2788 reg_names[1] = lookup_reg_name (data_unit, reg_nums[1]); |
| 2789 } |
| 2790 else |
| 2791 { |
| 2792 reg_names[1] = lookup_any_reg_name (data_unit, reg_nums[1],
TRUE); |
| 2793 |
| 2794 if (reg_nums[1] > 15) |
| 2795 reg_brackets[1] = 1; |
| 2796 } |
| 2797 } |
| 2798 |
| 2799 /* Detection of QUICKRoT and accumulator usage uses the |
| 2800 same bits. They are mutually exclusive. */ |
| 2801 if (ac && (template->arg_type & DSP_ARGS_ACC2)) |
| 2802 { |
| 2803 if (data_unit == UNIT_D0) |
| 2804 reg_names[2] = lookup_dsp_name (reg_nums[2], UNIT_ACC_D0); |
| 2805 else |
| 2806 reg_names[2] = lookup_dsp_name (reg_nums[2], UNIT_ACC_D1); |
| 2807 } |
| 2808 |
| 2809 else |
| 2810 { |
| 2811 if ((template->arg_type & DSP_ARGS_QR) && |
| 2812 ((insn_word & 0x40) == 0x40)) |
| 2813 { |
| 2814 enum metag_unit aunit; |
| 2815 int reg_no; |
| 2816 |
| 2817 if (conditional) |
| 2818 reg_no = ((insn_word >> 5) & 0x1); |
| 2819 else |
| 2820 reg_no = ((insn_word >> 7) & 0x1); |
| 2821 |
| 2822 aunit = (data_unit == UNIT_D0) ? UNIT_A0 : UNIT_A1; |
| 2823 addr_reg = lookup_reg_name (aunit, reg_no + 2); |
| 2824 |
| 2825 qr = TRUE; |
| 2826 } |
| 2827 |
| 2828 if (o2r) |
| 2829 reg_names[2] = lookup_o2r (data_unit, reg_nums[2]); |
| 2830 else |
| 2831 { |
| 2832 /* Can't use a DSPRAM reg if both QD and L1 are |
| 2833 set on a QUICKRoT instruction or if we're a |
| 2834 split 8. */ |
| 2835 if (((template->arg_type & DSP_ARGS_QR) |
| 2836 && ((insn_word & 0x30) == 0x30 && !conditional)) || |
| 2837 (is_split8 && is_mod)) |
| 2838 reg_names[2] = lookup_reg_name (data_unit, reg_nums[2]); |
| 2839 else |
| 2840 { |
| 2841 reg_names[2] = lookup_any_reg_name (data_unit, |
| 2842 reg_nums[2], TRUE)
; |
| 2843 if (reg_nums[2] > 15) |
| 2844 reg_brackets[2] = 1; |
| 2845 } |
| 2846 } |
| 2847 } |
| 2848 } |
| 2849 |
| 2850 if (qr) |
| 2851 { |
| 2852 len = snprintf (buf, OPERAND_WIDTH, "%s%s%s,%s%s%s,%s%s%s,%s", |
| 2853 reg_brackets[0] ? "[" : "", |
| 2854 reg_names[0], reg_brackets[0] ? "]" : "", |
| 2855 reg_brackets[1] ? "[" : "", |
| 2856 reg_names[1], reg_brackets[1] ? "]" : "", |
| 2857 reg_brackets[2] ? "[" : "", |
| 2858 reg_names[2], reg_brackets[2] ? "]" : "", |
| 2859 addr_reg); |
| 2860 } |
| 2861 else |
| 2862 { |
| 2863 if (imm) |
| 2864 { |
| 2865 /* Conform to the embedded assembler's policy of |
| 2866 printing negative numbers as decimal and positive |
| 2867 as hex. */ |
| 2868 int value = ((insn_word >> 3) & IMM16_MASK); |
| 2869 |
| 2870 if ((value & 0x8000) || value == 0) |
| 2871 { |
| 2872 value = sign_extend (value, IMM16_BITS); |
| 2873 len = snprintf (buf, OPERAND_WIDTH, "%s%s%s,%s%s%s,#%d", |
| 2874 reg_brackets[0] ? "[" : "", |
| 2875 reg_names[0], reg_brackets[0] ? "]" : "", |
| 2876 reg_brackets[1] ? "[" : "", |
| 2877 reg_names[1], reg_brackets[1] ? "]" : "", |
| 2878 value); |
| 2879 } |
| 2880 else |
| 2881 { |
| 2882 len = snprintf (buf, OPERAND_WIDTH, "%s%s%s,%s%s%s,#%#x", |
| 2883 reg_brackets[0] ? "[" : "", |
| 2884 reg_names[0], reg_brackets[0] ? "]" : "", |
| 2885 reg_brackets[1] ? "[" : "", |
| 2886 reg_names[1], reg_brackets[1] ? "]" : "", |
| 2887 value); |
| 2888 } |
| 2889 } |
| 2890 else |
| 2891 { |
| 2892 len = snprintf (buf, OPERAND_WIDTH, "%s%s%s,%s%s%s,%s%s%s", |
| 2893 reg_brackets[0] ? "[" : "", |
| 2894 reg_names[0], reg_brackets[0] ? "]" : "", |
| 2895 reg_brackets[1] ? "[" : "", reg_names[1], |
| 2896 reg_brackets[1] ? "]" : "", |
| 2897 reg_brackets[2] ? "[" : "", |
| 2898 reg_names[2], reg_brackets[2] ? "]" : ""); |
| 2899 } |
| 2900 } |
| 2901 } |
| 2902 |
| 2903 snprintf (prefix, DSP_PREFIX_WIDTH, "D%s%s%s%s%s%s%s%s%s%s%s%s", |
| 2904 cc_flags ? cc_flags : "", |
| 2905 is_dual ? "L" : "", |
| 2906 is_quickrot64 ? "Q" : "", |
| 2907 is_unsigned ? "U" : "", |
| 2908 is_mod ? "M" : "", |
| 2909 is_acc_zero ? "Z" : "", |
| 2910 is_acc_add ? "P" : "", is_acc_sub ? "N" : "", |
| 2911 is_overflow ? "O" : "", |
| 2912 is_w_mx ? "W" : "", |
| 2913 is_b_mx ? "B" : "", |
| 2914 is_template ? "T" : ""); |
| 2915 } |
| 2916 else if (template->arg_type & DSP_ARGS_2) /* Group 2. */ |
| 2917 { |
| 2918 bfd_boolean is_template; |
| 2919 bfd_boolean o2r = FALSE; |
| 2920 int major = MAJOR_OPCODE (template->meta_opcode); |
| 2921 bfd_boolean is_neg_or_mov = (major == OPC_ADD || major == OPC_SUB); |
| 2922 bfd_boolean is_cmp_tst = ((major == OPC_CMP) && |
| 2923 ((insn_word & 0x0000002c) == 0)); |
| 2924 bfd_boolean is_fpu_mov = template->insn_type == INSN_DSP_FPU; |
| 2925 bfd_boolean to_fpu = (template->meta_opcode >> 7) & 0x1; |
| 2926 |
| 2927 if (major == OPC_9) |
| 2928 imm = (insn_word & 0x2); |
| 2929 else if (template->arg_type & DSP_ARGS_IMM) |
| 2930 imm = ((insn_word >> 25) & 0x1); |
| 2931 |
| 2932 is_template = (((insn_word & 0x02000002) == 0x2) && |
| 2933 major != OPC_9); |
| 2934 |
| 2935 if (imm) |
| 2936 is_dual = ((insn_word >> 0x2) & 0x1); |
| 2937 else |
| 2938 is_dual = ((insn_word >> 0x4) & 0x1); |
| 2939 |
| 2940 /* MOV and XSD[BW] do not have o2r. */ |
| 2941 if (major != OPC_9 && major != OPC_MISC) |
| 2942 o2r = (insn_word & 0x1); |
| 2943 |
| 2944 if (is_neg_or_mov) |
| 2945 { |
| 2946 is_mod = (insn_word & 0x8); |
| 2947 is_overflow = (insn_word & 0x20); |
| 2948 } |
| 2949 |
| 2950 /* XSD */ |
| 2951 if (major == OPC_MISC) |
| 2952 data_unit = (insn_word & 0x1) ? UNIT_D1 : UNIT_D0; |
| 2953 else |
| 2954 data_unit = ((insn_word >> 24) & 0x1) ? UNIT_D1 : UNIT_D0; |
| 2955 |
| 2956 /* Check for NEG,MOV,ABS,FFB, etc. */ |
| 2957 if (is_neg_or_mov || !is_cmp_tst || imm || |
| 2958 MAJOR_OPCODE (insn_word) == OPC_9 || |
| 2959 MAJOR_OPCODE (insn_word) == OPC_MISC) |
| 2960 reg_nums[0] = ((insn_word >> 19) & REG_MASK); |
| 2961 else |
| 2962 reg_nums[0] = ((insn_word >> 14) & REG_MASK); |
| 2963 |
| 2964 if (is_template) |
| 2965 { |
| 2966 is_w_mx = (insn_word & 0x1); |
| 2967 |
| 2968 /* These are dummy arguments anyway so the register number |
| 2969 does not matter. */ |
| 2970 if (is_fpu_mov) |
| 2971 { |
| 2972 if (to_fpu) |
| 2973 { |
| 2974 reg_names[0] = lookup_reg_name (UNIT_FX, 0); |
| 2975 reg_names[1] = lookup_reg_name (data_unit, 0); |
| 2976 } |
| 2977 else |
| 2978 { |
| 2979 reg_names[0] = lookup_reg_name (data_unit, 0); |
| 2980 reg_names[1] = lookup_reg_name (UNIT_FX, 0); |
| 2981 } |
| 2982 } |
| 2983 else |
| 2984 { |
| 2985 reg_names[0] = lookup_reg_name (data_unit, 0); |
| 2986 reg_names[1] = lookup_reg_name (data_unit, 0); |
| 2987 } |
| 2988 |
| 2989 len = snprintf (buf, OPERAND_WIDTH, "%s,%s", |
| 2990 reg_names[0], reg_names[1]); |
| 2991 |
| 2992 decode_template_definition (insn_word, buf + len, |
| 2993 OPERAND_WIDTH - len); |
| 2994 } |
| 2995 else |
| 2996 { |
| 2997 if (imm) |
| 2998 { |
| 2999 /* Conform to the embedded assembler's policy of |
| 3000 printing negative numbers as decimal and positive as |
| 3001 hex. */ |
| 3002 unsigned int value = ((insn_word >> 3) & IMM16_MASK); |
| 3003 |
| 3004 if (major == OPC_9) |
| 3005 { |
| 3006 data_unit = (insn_word & 0x1) ? UNIT_D1 : UNIT_D0; |
| 3007 is_dual = (insn_word & 0x4); |
| 3008 |
| 3009 reg_names[0] = __lookup_dsp_name (reg_nums[0], data_unit); |
| 3010 } |
| 3011 else |
| 3012 { |
| 3013 reg_names[0] = lookup_any_reg_name (data_unit, reg_nums[0], TR
UE); |
| 3014 if (reg_nums[0] > 15) |
| 3015 reg_brackets[0] = 1; |
| 3016 } |
| 3017 |
| 3018 if ((value & 0x8000) || value == 0) |
| 3019 { |
| 3020 value = sign_extend (value, IMM16_BITS); |
| 3021 snprintf (buf, OPERAND_WIDTH, "%s%s%s,#%d", |
| 3022 reg_brackets[0] ? "[" : "", |
| 3023 reg_names[0], reg_brackets[0] ? "]" : "", |
| 3024 value); |
| 3025 } |
| 3026 else |
| 3027 { |
| 3028 snprintf (buf, OPERAND_WIDTH, "%s%s%s,#0x%x", |
| 3029 reg_brackets[0] ? "[" : "", |
| 3030 reg_names[0], reg_brackets[0] ? "]" : "", |
| 3031 value); |
| 3032 } |
| 3033 } |
| 3034 else |
| 3035 { |
| 3036 if (is_neg_or_mov || is_cmp_tst) |
| 3037 reg_nums[1] = ((insn_word >> 9) & REG_MASK); |
| 3038 else |
| 3039 reg_nums[1] = ((insn_word >> 14) & REG_MASK); |
| 3040 |
| 3041 if (major == OPC_9) |
| 3042 { |
| 3043 is_dual = (insn_word & 0x4); |
| 3044 data_unit = (insn_word & 0x1) ? UNIT_D1 : UNIT_D0; |
| 3045 |
| 3046 if (MINOR_OPCODE (template->meta_opcode) == 0x1) |
| 3047 reg_names[0] = __lookup_dsp_name (reg_nums[0], data_unit); |
| 3048 else |
| 3049 reg_names[0] = lookup_reg_name (data_unit, reg_nums[0]); |
| 3050 } |
| 3051 else |
| 3052 { |
| 3053 unsigned int reg0_unit = data_unit; |
| 3054 |
| 3055 if (is_fpu_mov && to_fpu) |
| 3056 reg0_unit = UNIT_FX; |
| 3057 |
| 3058 reg_names[0] = lookup_any_reg_name (reg0_unit, reg_nums[0], |
| 3059 (!is_neg_or_mov && is_cmp_
tst)); |
| 3060 if (reg_nums[0] > 15) |
| 3061 reg_brackets[0] = 1; |
| 3062 } |
| 3063 |
| 3064 if (o2r) |
| 3065 reg_names[1] = lookup_o2r (data_unit, reg_nums[1]); |
| 3066 else |
| 3067 { |
| 3068 /* Check for accumulator argument. */ |
| 3069 if (is_neg_or_mov && ((insn_word & 0x80) == 0x80)) |
| 3070 { |
| 3071 if (data_unit == UNIT_D0) |
| 3072 reg_names[1] = lookup_dsp_name (reg_nums[1], UNIT_ACC_D0
); |
| 3073 else |
| 3074 reg_names[1] = lookup_dsp_name (reg_nums[1], UNIT_ACC_D1
); |
| 3075 } |
| 3076 else |
| 3077 { |
| 3078 if (major == OPC_9) |
| 3079 { |
| 3080 if (MINOR_OPCODE (template->meta_opcode) == 0x1) |
| 3081 { |
| 3082 reg_names[1] = lookup_reg_name (data_unit, reg_num
s[1]); |
| 3083 } |
| 3084 else |
| 3085 { |
| 3086 enum metag_unit u; |
| 3087 |
| 3088 u = (insn_word & 0x1) ? UNIT_RAM_D1 : UNIT_RAM_D0; |
| 3089 reg_names[1] = lookup_dsp_name (reg_nums[1], u); |
| 3090 } |
| 3091 } |
| 3092 else |
| 3093 { |
| 3094 reg_names[1] = lookup_any_reg_name (data_unit, |
| 3095 reg_nums[1], TRUE)
; |
| 3096 if (reg_nums[1] > 15) |
| 3097 reg_brackets[1] = 1; |
| 3098 } |
| 3099 } |
| 3100 } |
| 3101 |
| 3102 snprintf (buf, OPERAND_WIDTH, "%s%s%s,%s%s%s", |
| 3103 reg_brackets[0] ? "[" : "", reg_names[0], |
| 3104 reg_brackets[0] ? "]" : "", |
| 3105 reg_brackets[1] ? "[" : "", reg_names[1], |
| 3106 reg_brackets[1] ? "]" : ""); |
| 3107 } |
| 3108 } |
| 3109 |
| 3110 snprintf (prefix, DSP_PREFIX_WIDTH, "D%s%s%s%s%s%s", |
| 3111 is_fpu_mov ? "F" : "", |
| 3112 is_dual ? "L" : "", |
| 3113 is_mod ? "M" : "", is_overflow ? "O" : "", |
| 3114 is_w_mx ? "W" : "", |
| 3115 is_template ? "T" : ""); |
| 3116 } |
| 3117 else /* Group 3. */ |
| 3118 { |
| 3119 /* If both the C and CA bits are set, then the Rd register can |
| 3120 be in any unit. Figure out which unit from the Ud field. */ |
| 3121 bfd_boolean all_units = (((insn_word) & 0x04000020) == 0x04000020); |
| 3122 enum metag_unit ud_unit = ((insn_word >> 1) & UNIT_MASK); |
| 3123 enum metag_unit ram_unit, acc_unit; |
| 3124 bfd_boolean round = FALSE; |
| 3125 bfd_boolean clamp9 = FALSE; |
| 3126 bfd_boolean clamp8 = FALSE; |
| 3127 bfd_boolean is_template = ((insn_word & 0x04000002) == 0x2); |
| 3128 |
| 3129 imm = ((insn_word >> 25) & 0x1); |
| 3130 ac = (insn_word & 0x1); |
| 3131 |
| 3132 conditional = (MINOR_OPCODE (insn_word) & 0x4); |
| 3133 |
| 3134 /* Check for conditional and not Condition Always. */ |
| 3135 if (conditional && !(insn_word & 0x20)) |
| 3136 cc_flags = lookup_scc_flags ((insn_word >> 1) & CC_MASK); |
| 3137 else if (!(conditional && (insn_word & 0x20))) |
| 3138 is_dual = ((insn_word >> 0x4) & 0x1); |
| 3139 |
| 3140 /* Conditional instructions don't have the L1 or RSPP fields. */ |
| 3141 if ((insn_word & 0x04000000) == 0) |
| 3142 { |
| 3143 round = (((insn_word >> 2) & 0x3) == 0x1); |
| 3144 clamp9 = (((insn_word >> 2) & 0x3) == 0x2); |
| 3145 clamp8 = (((insn_word >> 2) & 0x3) == 0x3); |
| 3146 } |
| 3147 |
| 3148 /* Read DU bit. */ |
| 3149 data_unit = ((insn_word >> 24) & 0x1) ? UNIT_D1 : UNIT_D0; |
| 3150 reg_nums[0] = ((insn_word >> 19) & REG_MASK); |
| 3151 reg_nums[1] = ((insn_word >> 14) & REG_MASK); |
| 3152 |
| 3153 ram_unit = (data_unit == UNIT_D0) ? UNIT_RAM_D0 : UNIT_RAM_D1; |
| 3154 acc_unit = (data_unit == UNIT_D0) ? UNIT_ACC_D0 : UNIT_ACC_D1; |
| 3155 |
| 3156 if (all_units) |
| 3157 reg_names[0] = lookup_reg_name (ud_unit, reg_nums[0]); |
| 3158 else |
| 3159 { |
| 3160 if (conditional) |
| 3161 reg_names[0] = lookup_reg_name (data_unit, reg_nums[0]); |
| 3162 else |
| 3163 { |
| 3164 reg_names[0] = lookup_any_reg_name (data_unit, reg_nums[0], FALSE)
; |
| 3165 if (reg_nums[0] > 15) |
| 3166 reg_brackets[0] = 1; |
| 3167 } |
| 3168 } |
| 3169 |
| 3170 if (ac) |
| 3171 { |
| 3172 reg_names[1] = lookup_dsp_name (reg_nums[1], acc_unit); |
| 3173 } |
| 3174 else |
| 3175 { |
| 3176 reg_names[1] = lookup_any_reg_name (data_unit, reg_nums[1], TRUE); |
| 3177 if (reg_nums[1] > 15) |
| 3178 reg_brackets[1] = 1; |
| 3179 } |
| 3180 |
| 3181 if (imm) |
| 3182 { |
| 3183 snprintf (buf, OPERAND_WIDTH, "%s%s%s,%s%s%s,#%#x", |
| 3184 reg_brackets[0] ? "[" : "", |
| 3185 reg_names[0], reg_brackets[0] ? "]" : "", |
| 3186 reg_brackets[1] ? "[" : "", |
| 3187 reg_names[1], reg_brackets[1] ? "]" : "", |
| 3188 ((insn_word >> 9) & IMM5_MASK)); |
| 3189 } |
| 3190 else |
| 3191 { |
| 3192 reg_nums[2] = ((insn_word >> 9) & REG_MASK); |
| 3193 |
| 3194 reg_names[2] = lookup_any_reg_name (data_unit, reg_nums[2], TRUE); |
| 3195 |
| 3196 if (reg_nums[2] > 15) |
| 3197 reg_brackets[2] = 1; |
| 3198 |
| 3199 if (is_template) |
| 3200 { |
| 3201 bfd_boolean load = ((insn_word >> 13) & 0x1); |
| 3202 bfd_boolean dspram = (((insn_word >> 17) & 0x3) == 0x3); |
| 3203 const char *tname[1]; |
| 3204 unsigned int tidx = ((insn_word >> 9) & TEMPLATE_REGS_MASK); |
| 3205 enum metag_unit au; |
| 3206 unsigned int addr_reg_nums[2]; |
| 3207 const char *addr_reg_names[2]; |
| 3208 const char *post_op = ""; |
| 3209 const char *join_op = ""; |
| 3210 |
| 3211 is_w_mx = ((insn_word >> 5) & 0x1); |
| 3212 |
| 3213 tname[0] = lookup_dsp_name (tidx, UNIT_DT); |
| 3214 |
| 3215 /* These are dummy arguments anyway */ |
| 3216 reg_names[0] = lookup_reg_name (data_unit, 0); |
| 3217 if (ac) |
| 3218 reg_names[1] = lookup_dsp_name (16, acc_unit); |
| 3219 else |
| 3220 reg_names[1] = lookup_reg_name (data_unit, 0); |
| 3221 reg_names[2] = lookup_reg_name (data_unit, 0); |
| 3222 |
| 3223 addr_reg_names[1] = ""; |
| 3224 |
| 3225 if (dspram) |
| 3226 { |
| 3227 ram_unit = (data_unit == UNIT_D0) ? UNIT_RAM_D0 : UNIT_RAM_D1; |
| 3228 addr_reg_nums[0] = ((insn_word >> 19) & REG_MASK); |
| 3229 addr_reg_names[0] = lookup_dspram_name (addr_reg_nums[0], |
| 3230 ram_unit, load); |
| 3231 } |
| 3232 else |
| 3233 { |
| 3234 bfd_boolean im = (((insn_word >> 18) & 0x1) != 0); |
| 3235 |
| 3236 au = (((insn_word >> 23) & 0x1) == 0) ? UNIT_A0 : UNIT_A1; |
| 3237 addr_reg_nums[0] = ((insn_word >> 19) & DSP_REG_MASK); |
| 3238 |
| 3239 addr_reg_names[0] = lookup_reg_name (au, addr_reg_nums[0]); |
| 3240 |
| 3241 if (im) |
| 3242 { |
| 3243 unsigned int im_value = ((insn_word >> 14) & 0x3); |
| 3244 |
| 3245 switch (im_value) |
| 3246 { |
| 3247 case 0x1: |
| 3248 post_op = "++"; |
| 3249 break; |
| 3250 case 0x3: |
| 3251 post_op = "--"; |
| 3252 break; |
| 3253 } |
| 3254 } |
| 3255 else |
| 3256 { |
| 3257 addr_reg_nums[1] = ((insn_word >> 14) & DSP_REG_MASK); |
| 3258 addr_reg_names[1] = lookup_reg_name (au, addr_reg_nums[1])
; |
| 3259 join_op = "+"; |
| 3260 post_op = "++"; |
| 3261 } |
| 3262 } |
| 3263 |
| 3264 if (load) |
| 3265 { |
| 3266 snprintf (buf, OPERAND_WIDTH, "%s,%s,%s %s,[%s%s%s%s]", |
| 3267 reg_names[0], reg_names[1], reg_names[2], |
| 3268 tname[0], addr_reg_names[0], join_op, |
| 3269 addr_reg_names[1], post_op); |
| 3270 } |
| 3271 else |
| 3272 { |
| 3273 snprintf (buf, OPERAND_WIDTH, "%s,%s,%s [%s%s%s%s],%s", |
| 3274 reg_names[0], reg_names[1], reg_names[2], |
| 3275 addr_reg_names[0], join_op, addr_reg_names[1], |
| 3276 post_op, tname[0]); |
| 3277 } |
| 3278 } |
| 3279 else |
| 3280 { |
| 3281 snprintf (buf, OPERAND_WIDTH, "%s%s%s,%s%s%s,%s%s%s", |
| 3282 reg_brackets[0] ? "[" : "", |
| 3283 reg_names[0], reg_brackets[0] ? "]" : "", |
| 3284 reg_brackets[1] ? "[" : "", |
| 3285 reg_names[1], reg_brackets[1] ? "]" : "", |
| 3286 reg_brackets[2] ? "[" : "", |
| 3287 reg_names[2], reg_brackets[2] ? "]" : ""); |
| 3288 } |
| 3289 } |
| 3290 |
| 3291 snprintf (prefix, DSP_PREFIX_WIDTH, "D%s%s%s%s%s%s%s", |
| 3292 cc_flags ? cc_flags : "", |
| 3293 is_dual ? "L" : "", clamp9 ? "G" : "", |
| 3294 clamp8 ? "B" : "", round ? "R" : "", |
| 3295 is_w_mx ? "W" : "", |
| 3296 is_template ? "T" : ""); |
| 3297 } |
| 3298 |
| 3299 print_insn (outf, prefix, template->name, buf); |
| 3300 |
| 3301 } |
| 3302 |
| 3303 typedef void (*insn_printer)(unsigned int, bfd_vma, const insn_template *, |
| 3304 disassemble_info *); |
| 3305 |
| 3306 /* Printer table. */ |
| 3307 static const insn_printer insn_printers[ENC_MAX] = |
| 3308 { |
| 3309 [ENC_NONE] = print_none, |
| 3310 [ENC_MOV_U2U] = print_mov_u2u, |
| 3311 [ENC_MOV_PORT] = print_mov_port, |
| 3312 [ENC_MMOV] = print_mmov, |
| 3313 [ENC_MDRD] = print_mdrd, |
| 3314 [ENC_MOVL_TTREC] = print_movl_ttrec, |
| 3315 [ENC_GET_SET] = print_get_set, |
| 3316 [ENC_GET_SET_EXT] = print_get_set_ext, |
| 3317 [ENC_MGET_MSET] = print_mget_mset, |
| 3318 [ENC_COND_SET] = print_cond_set, |
| 3319 [ENC_XFR] = print_xfr, |
| 3320 [ENC_MOV_CT] = print_mov_ct, |
| 3321 [ENC_SWAP] = print_swap, |
| 3322 [ENC_JUMP] = print_jump, |
| 3323 [ENC_CALLR] = print_callr, |
| 3324 [ENC_ALU] = print_alu, |
| 3325 [ENC_SHIFT] = print_shift, |
| 3326 [ENC_MIN_MAX] = print_min_max, |
| 3327 [ENC_BITOP] = print_bitop, |
| 3328 [ENC_CMP] = print_cmp, |
| 3329 [ENC_BRANCH] = print_branch, |
| 3330 [ENC_KICK] = print_mov_u2u, |
| 3331 [ENC_SWITCH] = print_switch, |
| 3332 [ENC_CACHER] = print_cacher, |
| 3333 [ENC_CACHEW] = print_cachew, |
| 3334 [ENC_ICACHE] = print_icache, |
| 3335 [ENC_LNKGET] = print_lnkget, |
| 3336 [ENC_FMOV] = print_fmov, |
| 3337 [ENC_FMMOV] = print_fmmov, |
| 3338 [ENC_FMOV_DATA] = print_fmov_data, |
| 3339 [ENC_FMOV_I] = print_fmov_i, |
| 3340 [ENC_FPACK] = print_fpack, |
| 3341 [ENC_FSWAP] = print_fswap, |
| 3342 [ENC_FCMP] = print_fcmp, |
| 3343 [ENC_FMINMAX] = print_fminmax, |
| 3344 [ENC_FCONV] = print_fconv, |
| 3345 [ENC_FCONVX] = print_fconvx, |
| 3346 [ENC_FBARITH] = print_fbarith, |
| 3347 [ENC_FEARITH] = print_fearith, |
| 3348 [ENC_FREC] = print_frec, |
| 3349 [ENC_FSIMD] = print_fsimd, |
| 3350 [ENC_FGET_SET_ACF] = print_fget_set_acf, |
| 3351 [ENC_DGET_SET] = print_dget_set, |
| 3352 [ENC_DTEMPLATE] = print_dtemplate, |
| 3353 [ENC_DALU] = print_dalu, |
| 3354 }; |
| 3355 |
| 3356 /* Entry point for instruction printing. */ |
| 3357 int |
| 3358 print_insn_metag (bfd_vma pc, disassemble_info *outf) |
| 3359 { |
| 3360 bfd_byte buf[4]; |
| 3361 unsigned int insn_word; |
| 3362 size_t i; |
| 3363 outf->bytes_per_chunk = 4; |
| 3364 |
| 3365 (*outf->read_memory_func) (pc & ~0x03, buf, 4, outf); |
| 3366 insn_word = bfd_getl32 (buf); |
| 3367 |
| 3368 for (i = 0; i < sizeof(metag_optab)/sizeof(metag_optab[0]); i++) |
| 3369 { |
| 3370 const insn_template *template = &metag_optab[i]; |
| 3371 |
| 3372 if ((insn_word & template->meta_mask) == template->meta_opcode) |
| 3373 { |
| 3374 enum insn_encoding encoding = template->encoding; |
| 3375 insn_printer printer = insn_printers[encoding]; |
| 3376 |
| 3377 if (printer) |
| 3378 printer (insn_word, pc, template, outf); |
| 3379 |
| 3380 return 4; |
| 3381 } |
| 3382 } |
| 3383 |
| 3384 return 4; |
| 3385 } |
OLD | NEW |