1143880Spjd/* Disassemble Imagination Technologies Meta instructions. 2143880Spjd Copyright (C) 2013-2020 Free Software Foundation, Inc. 3143880Spjd Contributed by Imagination Technologies Ltd. 4143880Spjd 5143880Spjd This library is free software; you can redistribute it and/or modify 6143880Spjd it under the terms of the GNU General Public License as published by 7143880Spjd the Free Software Foundation; either version 3 of the License, or 8143880Spjd (at your option) any later version. 9143880Spjd 10263351Sjmmv It is distributed in the hope that it will be useful, but WITHOUT 11143880Spjd ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 12143880Spjd or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public 13143880Spjd License for more details. 14143880Spjd 15143880Spjd You should have received a copy of the GNU General Public License 16143880Spjd along with this program; if not, write to the Free Software 17143880Spjd Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, 18143880Spjd MA 02110-1301, USA. */ 19143880Spjd 20143880Spjd#include "sysdep.h" 21143880Spjd#include "disassemble.h" 22143880Spjd#include "opintl.h" 23143880Spjd 24143880Spjd#include <stdio.h> 25143880Spjd#include <stdlib.h> 26143880Spjd#include <string.h> 27143880Spjd 28263351Sjmmv#include "opcode/metag.h" 29143880Spjd 30143880Spjd/* Column widths for printing. */ 31143880Spjd#define PREFIX_WIDTH "10" 32143880Spjd#define INSN_NAME_WIDTH "10" 33143880Spjd 34143880Spjd#define OPERAND_WIDTH 92 35143880Spjd#define ADDR_WIDTH 20 36143880Spjd#define REG_WIDTH 64 37143880Spjd#define DSP_PREFIX_WIDTH 17 38143880Spjd 39143880Spjd/* Value to print if we fail to parse a register name. */ 40143880Spjdconst char unknown_reg[] = "?"; 41143880Spjd 42143880Spjd/* Return the size of a GET or SET instruction. */ 43unsigned int 44metag_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. */ 61unsigned int 62metag_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. */ 79unsigned int 80metag_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. */ 97static int 98sign_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. */ 105static unsigned int 106short_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. */ 115static const metag_reg * 116lookup_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. */ 132static const char * 133lookup_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. */ 146static unsigned int 147get_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. */ 165static const char * 166lookup_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. */ 175static const char * 176lookup_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. */ 191static const char * 192lookup_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. */ 283static const char * 284lookup_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. */ 299static const char * 300lookup_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. */ 315static void 316print_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. */ 323static void 324print_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. */ 334static void 335print_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. */ 385static void 386print_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. */ 425static 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. */ 438static void 439print_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. */ 468static void 469get_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. */ 548static void 549get_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. */ 578static void 579mget_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. */ 594static void 595cond_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. */ 610static void 611cache_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. */ 641static void 642lookup_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. */ 680static void 681print_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. */ 703static void 704print_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. */ 725static void 726print_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. */ 774static void 775print_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. */ 813static void 814print_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. */ 851static void 852print_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. */ 884static void 885print_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. */ 970static void 971print_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. */ 988static void 989print_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. */ 1054static void 1055print_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. */ 1089static void 1090print_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. */ 1119static void 1120print_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. */ 1142static void 1143print_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. */ 1172static void 1173print_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. */ 1352static void 1353print_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. */ 1373static void 1374print_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. */ 1389static void 1390print_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. */ 1453static void 1454print_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. */ 1484static void 1485print_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. */ 1534static void 1535print_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. */ 1602static void 1603print_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. */ 1631static void 1632print_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. */ 1660static void 1661print_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. */ 1682static void 1683print_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. */ 1711static void 1712print_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. */ 1744static unsigned int 1745convert_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. */ 1760static void 1761print_fmmov (unsigned int insn_word, bfd_vma pc ATTRIBUTE_UNUSED, 1762 const insn_template *template, 1763 disassemble_info *outf) 1764{ 1765 /* We used to have buf[OPERAND_WIDTH] here, but gcc v8 complains 1766 about the snprintf()s below possibly truncating the output. 1767 (There is no way to tell gcc that this truncation is intentional). 1768 So now we use an extra wide buffer. */ 1769 char buf[OPERAND_WIDTH * 2]; 1770 char data_buf[REG_WIDTH]; 1771 char fpu_buf[REG_WIDTH]; 1772 bfd_boolean to_fpu = MAJOR_OPCODE (insn_word) == OPC_GET; 1773 bfd_boolean is_mmovl = MINOR_OPCODE (insn_word) & 0x1; 1774 unsigned int rmask = (insn_word >> 7) & RMASK_MASK; 1775 unsigned int fpu_no, data_no, data_unit; 1776 1777 data_no = (insn_word >> 19) & REG_MASK; 1778 fpu_no = (insn_word >> 14) & REG_MASK; 1779 1780 if (insn_word & 0x1) 1781 data_unit = UNIT_D1; 1782 else 1783 data_unit = UNIT_D0; 1784 1785 lookup_reg_list (data_buf, REG_WIDTH, data_unit, data_no, rmask, FALSE); 1786 lookup_reg_list (fpu_buf, REG_WIDTH, UNIT_FX, fpu_no, 1787 convert_fx_rmask (rmask), is_mmovl); 1788 1789 if (to_fpu) 1790 snprintf (buf, sizeof buf, "%s,%s", fpu_buf, data_buf); 1791 else 1792 snprintf (buf, sizeof buf, "%s,%s", data_buf, fpu_buf); 1793 1794 print_insn (outf, "F", template->name, buf); 1795} 1796 1797/* Print an FPU data unit MOV instruction. */ 1798static void 1799print_fmov_data (unsigned int insn_word, bfd_vma pc ATTRIBUTE_UNUSED, 1800 const insn_template *template, 1801 disassemble_info *outf) 1802{ 1803 char buf[OPERAND_WIDTH]; 1804 unsigned int src_no, dest_no; 1805 unsigned int to_fpu = ((insn_word >> 7) & 0x1); 1806 unsigned int unit_bit = (insn_word >> 24) & 0x1; 1807 enum metag_unit base_unit; 1808 const char *dest_reg; 1809 const char *src_reg; 1810 1811 dest_no = (insn_word >> 19) & REG_MASK; 1812 src_no = (insn_word >> 9) & REG_MASK; 1813 1814 if (unit_bit) 1815 base_unit = UNIT_D1; 1816 else 1817 base_unit = UNIT_D0; 1818 1819 if (to_fpu) 1820 { 1821 dest_reg = lookup_reg_name (UNIT_FX, dest_no); 1822 src_reg = lookup_reg_name (base_unit, src_no); 1823 } 1824 else 1825 { 1826 dest_reg = lookup_reg_name (base_unit, dest_no); 1827 src_reg = lookup_reg_name (UNIT_FX, src_no); 1828 } 1829 1830 snprintf (buf, OPERAND_WIDTH, "%s,%s", dest_reg, src_reg); 1831 1832 print_insn (outf, "F", template->name, buf); 1833} 1834 1835/* Print an FPU MOV immediate instruction. */ 1836static void 1837print_fmov_i (unsigned int insn_word, bfd_vma pc ATTRIBUTE_UNUSED, 1838 const insn_template *template, 1839 disassemble_info *outf) 1840{ 1841 char buf[OPERAND_WIDTH]; 1842 unsigned int dest_no; 1843 unsigned int p = (insn_word >> 2) & 0x1; 1844 unsigned int d = (insn_word >> 1) & 0x1; 1845 const char *dest_reg; 1846 unsigned int value = (insn_word >> 3) & IMM16_MASK; 1847 1848 dest_no = (insn_word >> 19) & REG_MASK; 1849 1850 dest_reg = lookup_reg_name (UNIT_FX, dest_no); 1851 1852 snprintf (buf, OPERAND_WIDTH, "%s,#%#x", dest_reg, value); 1853 1854 if (p) 1855 print_insn (outf, "FL", template->name, buf); 1856 else if (d) 1857 print_insn (outf, "FD", template->name, buf); 1858 else 1859 print_insn (outf, "F", template->name, buf); 1860} 1861 1862/* Print an FPU PACK instruction. */ 1863static void 1864print_fpack (unsigned int insn_word, bfd_vma pc ATTRIBUTE_UNUSED, 1865 const insn_template *template, 1866 disassemble_info *outf) 1867{ 1868 char buf[OPERAND_WIDTH]; 1869 unsigned int src1_no, src2_no, dest_no; 1870 const char *dest_reg; 1871 const char *src1_reg; 1872 const char *src2_reg; 1873 1874 dest_no = (insn_word >> 19) & REG_MASK; 1875 src1_no = (insn_word >> 14) & REG_MASK; 1876 src2_no = (insn_word >> 9) & REG_MASK; 1877 1878 dest_reg = lookup_reg_name (UNIT_FX, dest_no); 1879 src1_reg = lookup_reg_name (UNIT_FX, src1_no); 1880 src2_reg = lookup_reg_name (UNIT_FX, src2_no); 1881 1882 snprintf (buf, OPERAND_WIDTH, "%s,%s,%s", dest_reg, src1_reg, src2_reg); 1883 1884 print_insn (outf, "F", template->name, buf); 1885} 1886 1887/* Print an FPU SWAP instruction. */ 1888static void 1889print_fswap (unsigned int insn_word, bfd_vma pc ATTRIBUTE_UNUSED, 1890 const insn_template *template, 1891 disassemble_info *outf) 1892{ 1893 char buf[OPERAND_WIDTH]; 1894 unsigned int src_no, dest_no; 1895 const char *dest_reg; 1896 const char *src_reg; 1897 1898 dest_no = (insn_word >> 19) & REG_MASK; 1899 src_no = (insn_word >> 14) & REG_MASK; 1900 1901 dest_reg = lookup_reg_name (UNIT_FX, dest_no); 1902 src_reg = lookup_reg_name (UNIT_FX, src_no); 1903 1904 snprintf (buf, OPERAND_WIDTH, "%s,%s", dest_reg, src_reg); 1905 1906 print_insn (outf, "FL", template->name, buf); 1907} 1908 1909/* Print an FPU CMP instruction. */ 1910static void 1911print_fcmp (unsigned int insn_word, bfd_vma pc ATTRIBUTE_UNUSED, 1912 const insn_template *template, 1913 disassemble_info *outf) 1914{ 1915 char buf[OPERAND_WIDTH]; 1916 char prefix_buf[10]; 1917 unsigned int src_no, dest_no; 1918 unsigned int a = (insn_word >> 19) & 0x1; 1919 unsigned int z = (insn_word >> 8) & 0x1; 1920 unsigned int p = (insn_word >> 6) & 0x1; 1921 unsigned int d = (insn_word >> 5) & 0x1; 1922 unsigned int q = (insn_word >> 7) & 0x1; 1923 unsigned int cc = (insn_word >> 1) & CC_MASK; 1924 bfd_boolean show_cond = cc != COND_A && cc != COND_NV; 1925 const char *dest_reg; 1926 const char *src_reg; 1927 const char *cc_flags; 1928 1929 dest_no = (insn_word >> 14) & REG_MASK; 1930 src_no = (insn_word >> 9) & REG_MASK; 1931 1932 dest_reg = lookup_reg_name (UNIT_FX, dest_no); 1933 src_reg = lookup_reg_name (UNIT_FX, src_no); 1934 1935 cc_flags = lookup_fpu_scc_flags (cc); 1936 1937 if (z) 1938 snprintf (buf, OPERAND_WIDTH, "%s,#0", dest_reg); 1939 else 1940 snprintf (buf, OPERAND_WIDTH, "%s,%s", dest_reg, src_reg); 1941 1942 snprintf (prefix_buf, 10, "F%s%s%s%s%s", p ? "L" : "", 1943 d ? "D" : "", a ? "A" : "", q ? "Q" : "", 1944 show_cond ? cc_flags : ""); 1945 1946 print_insn (outf, prefix_buf, template->name, buf); 1947} 1948 1949/* Print an FPU MIN or MAX instruction. */ 1950static void 1951print_fminmax (unsigned int insn_word, bfd_vma pc ATTRIBUTE_UNUSED, 1952 const insn_template *template, 1953 disassemble_info *outf) 1954{ 1955 char buf[OPERAND_WIDTH]; 1956 char prefix_buf[10]; 1957 unsigned int p = (insn_word >> 6) & 0x1; 1958 unsigned int d = (insn_word >> 5) & 0x1; 1959 unsigned int src1_no, src2_no, dest_no; 1960 unsigned int cc = (insn_word >> 1) & CC_MASK; 1961 bfd_boolean show_cond = cc != COND_A && cc != COND_NV; 1962 const char *dest_reg; 1963 const char *src1_reg; 1964 const char *src2_reg; 1965 const char *cc_flags; 1966 1967 dest_no = (insn_word >> 19) & REG_MASK; 1968 src1_no = (insn_word >> 14) & REG_MASK; 1969 src2_no = (insn_word >> 9) & REG_MASK; 1970 1971 dest_reg = lookup_reg_name (UNIT_FX, dest_no); 1972 src1_reg = lookup_reg_name (UNIT_FX, src1_no); 1973 src2_reg = lookup_reg_name (UNIT_FX, src2_no); 1974 1975 cc_flags = lookup_fpu_scc_flags (cc); 1976 1977 snprintf (buf, OPERAND_WIDTH, "%s,%s,%s", dest_reg, src1_reg, src2_reg); 1978 1979 snprintf (prefix_buf, 10, "F%s%s%s", p ? "L" : "", 1980 d ? "D" : "", show_cond ? cc_flags : ""); 1981 1982 print_insn (outf, prefix_buf, template->name, buf); 1983} 1984 1985/* Print an FPU data conversion instruction. */ 1986static void 1987print_fconv (unsigned int insn_word, bfd_vma pc ATTRIBUTE_UNUSED, 1988 const insn_template *template, 1989 disassemble_info *outf) 1990{ 1991 char buf[OPERAND_WIDTH]; 1992 char prefix_buf[10]; 1993 unsigned int p = (insn_word >> 6) & 0x1; 1994 unsigned int z = (insn_word >> 12) & 0x1; 1995 unsigned int src_no, dest_no; 1996 unsigned int cc = (insn_word >> 1) & CC_MASK; 1997 bfd_boolean show_cond = cc != COND_A && cc != COND_NV; 1998 const char *dest_reg; 1999 const char *src_reg; 2000 const char *cc_flags; 2001 2002 dest_no = (insn_word >> 19) & REG_MASK; 2003 src_no = (insn_word >> 14) & REG_MASK; 2004 2005 dest_reg = lookup_reg_name (UNIT_FX, dest_no); 2006 src_reg = lookup_reg_name (UNIT_FX, src_no); 2007 2008 cc_flags = lookup_fpu_scc_flags (cc); 2009 2010 snprintf (buf, OPERAND_WIDTH, "%s,%s", dest_reg, src_reg); 2011 2012 snprintf (prefix_buf, 10, "F%s%s%s", p ? "L" : "", 2013 z ? "Z" : "", show_cond ? cc_flags : ""); 2014 2015 print_insn (outf, prefix_buf, template->name, buf); 2016} 2017 2018/* Print an FPU extended data conversion instruction. */ 2019static void 2020print_fconvx (unsigned int insn_word, bfd_vma pc ATTRIBUTE_UNUSED, 2021 const insn_template *template, 2022 disassemble_info *outf) 2023{ 2024 char buf[OPERAND_WIDTH]; 2025 char prefix_buf[10]; 2026 unsigned int p = (insn_word >> 6) & 0x1; 2027 unsigned int xl = (insn_word >> 7) & 0x1; 2028 unsigned int src_no, dest_no, fraction_bits; 2029 unsigned int cc = (insn_word >> 1) & CC_MASK; 2030 bfd_boolean show_cond = cc != COND_A && cc != COND_NV; 2031 const char *dest_reg; 2032 const char *src_reg; 2033 const char *cc_flags; 2034 2035 dest_no = (insn_word >> 19) & REG_MASK; 2036 src_no = (insn_word >> 14) & REG_MASK; 2037 2038 dest_reg = lookup_reg_name (UNIT_FX, dest_no); 2039 src_reg = lookup_reg_name (UNIT_FX, src_no); 2040 2041 cc_flags = lookup_fpu_scc_flags (cc); 2042 2043 if (xl) 2044 fraction_bits = (insn_word >> 8) & IMM6_MASK; 2045 else 2046 fraction_bits = (insn_word >> 9) & IMM5_MASK; 2047 2048 snprintf (buf, OPERAND_WIDTH, "%s,%s,#%#x", dest_reg, src_reg, 2049 fraction_bits); 2050 2051 snprintf (prefix_buf, 10, "F%s%s", p ? "L" : "", 2052 show_cond ? cc_flags : ""); 2053 2054 print_insn (outf, prefix_buf, template->name, buf); 2055} 2056 2057/* Print an FPU basic arithmetic instruction. */ 2058static void 2059print_fbarith (unsigned int insn_word, bfd_vma pc ATTRIBUTE_UNUSED, 2060 const insn_template *template, 2061 disassemble_info *outf) 2062{ 2063 char buf[OPERAND_WIDTH]; 2064 char prefix_buf[10]; 2065 unsigned int n = (insn_word >> 7) & 0x1; 2066 unsigned int p = (insn_word >> 6) & 0x1; 2067 unsigned int d = (insn_word >> 5) & 0x1; 2068 unsigned int src1_no, src2_no, dest_no; 2069 unsigned int cc = (insn_word >> 1) & CC_MASK; 2070 bfd_boolean show_cond = cc != COND_A && cc != COND_NV; 2071 const char *dest_reg; 2072 const char *src1_reg; 2073 const char *src2_reg; 2074 const char *cc_flags; 2075 2076 dest_no = (insn_word >> 19) & REG_MASK; 2077 src1_no = (insn_word >> 14) & REG_MASK; 2078 src2_no = (insn_word >> 9) & REG_MASK; 2079 2080 dest_reg = lookup_reg_name (UNIT_FX, dest_no); 2081 src1_reg = lookup_reg_name (UNIT_FX, src1_no); 2082 src2_reg = lookup_reg_name (UNIT_FX, src2_no); 2083 2084 cc_flags = lookup_fpu_scc_flags (cc); 2085 2086 snprintf (buf, OPERAND_WIDTH, "%s,%s,%s", dest_reg, src1_reg, src2_reg); 2087 2088 snprintf (prefix_buf, 10, "F%s%s%s%s", p ? "L" : "", 2089 d ? "D" : "", n ? "I" : "", show_cond ? cc_flags : ""); 2090 2091 print_insn (outf, prefix_buf, template->name, buf); 2092} 2093 2094/* Print an FPU extended arithmetic instruction. */ 2095static void 2096print_fearith (unsigned int insn_word, bfd_vma pc ATTRIBUTE_UNUSED, 2097 const insn_template *template, 2098 disassemble_info *outf) 2099{ 2100 char buf[OPERAND_WIDTH]; 2101 char prefix_buf[10]; 2102 bfd_boolean is_muz = (MINOR_OPCODE (insn_word) == 0x6 && 2103 ((insn_word >> 4) & 0x1)); 2104 bfd_boolean is_mac = (MINOR_OPCODE (insn_word) == 0x6 && 2105 (insn_word & 0x1f) == 0); 2106 bfd_boolean is_maw = (MINOR_OPCODE (insn_word) == 0x6 && 2107 ((insn_word >> 3) & 0x1)); 2108 unsigned int o3o = insn_word & 0x1; 2109 unsigned int q = is_muz && ((insn_word >> 1) & 0x1); 2110 unsigned int n = (insn_word >> 7) & 0x1; 2111 unsigned int p = (insn_word >> 6) & 0x1; 2112 unsigned int d = (insn_word >> 5) & 0x1; 2113 unsigned int cc = (insn_word >> 1) & CC_MASK; 2114 bfd_boolean show_cond = (MINOR_OPCODE (insn_word) == 0x5 && cc != COND_A && 2115 cc != COND_NV); 2116 unsigned int src1_no, src2_no, dest_no; 2117 const char *dest_reg; 2118 const char *src1_reg; 2119 const char *src2_reg; 2120 const char *cc_flags; 2121 2122 dest_no = (insn_word >> 19) & REG_MASK; 2123 src1_no = (insn_word >> 14) & REG_MASK; 2124 src2_no = (insn_word >> 9) & REG_MASK; 2125 2126 dest_reg = lookup_reg_name (UNIT_FX, dest_no); 2127 src1_reg = lookup_reg_name (UNIT_FX, src1_no); 2128 src2_reg = lookup_reg_name (UNIT_FX, src2_no); 2129 2130 cc_flags = lookup_fpu_scc_flags (cc); 2131 2132 if (is_mac) 2133 snprintf (buf, OPERAND_WIDTH, "ACF.0,%s,%s", src1_reg, src2_reg); 2134 else if (o3o && is_maw) 2135 snprintf (buf, OPERAND_WIDTH, "%s,%s", src1_reg, src2_reg); 2136 else 2137 snprintf (buf, OPERAND_WIDTH, "%s,%s,%s", dest_reg, src1_reg, src2_reg); 2138 2139 snprintf (prefix_buf, 10, "F%s%s%s%s%s", p ? "L" : "", 2140 d ? "D" : "", n ? "I" : "", q ? "Q" : "", 2141 show_cond ? cc_flags : ""); 2142 2143 print_insn (outf, prefix_buf, template->name, buf); 2144} 2145 2146/* Print an FPU RCP or RSQ instruction. */ 2147static void 2148print_frec (unsigned int insn_word, bfd_vma pc ATTRIBUTE_UNUSED, 2149 const insn_template *template, 2150 disassemble_info *outf) 2151{ 2152 char buf[OPERAND_WIDTH]; 2153 char prefix_buf[10]; 2154 unsigned int z = (insn_word >> 10) & 0x1; 2155 unsigned int q = (insn_word >> 9) & 0x1; 2156 unsigned int n = (insn_word >> 7) & 0x1; 2157 unsigned int p = (insn_word >> 6) & 0x1; 2158 unsigned int d = (insn_word >> 5) & 0x1; 2159 unsigned int src_no, dest_no; 2160 const char *dest_reg; 2161 const char *src_reg; 2162 2163 dest_no = (insn_word >> 19) & REG_MASK; 2164 src_no = (insn_word >> 14) & REG_MASK; 2165 2166 dest_reg = lookup_reg_name (UNIT_FX, dest_no); 2167 src_reg = lookup_reg_name (UNIT_FX, src_no); 2168 2169 snprintf (buf, OPERAND_WIDTH, "%s,%s", dest_reg, src_reg); 2170 2171 snprintf (prefix_buf, 10, "F%s%s%s%s%s", p ? "L" : "", 2172 d ? "D" : "", n ? "I" : "", q ? "Q" : "", z ? "Z" : ""); 2173 2174 print_insn (outf, prefix_buf, template->name, buf); 2175} 2176 2177static void 2178print_fsimd (unsigned int insn_word, bfd_vma pc ATTRIBUTE_UNUSED, 2179 const insn_template *template, 2180 disassemble_info *outf) 2181{ 2182 char buf[OPERAND_WIDTH]; 2183 unsigned int n = (insn_word >> 7) & 0x1; 2184 unsigned int src1_no, src2_no, dest_no; 2185 const char *dest_reg; 2186 const char *src1_reg; 2187 const char *src2_reg; 2188 2189 dest_no = (insn_word >> 19) & REG_MASK; 2190 src1_no = (insn_word >> 14) & REG_MASK; 2191 src2_no = (insn_word >> 9) & REG_MASK; 2192 2193 dest_reg = lookup_reg_name (UNIT_FX, dest_no); 2194 src1_reg = lookup_reg_name (UNIT_FX, src1_no); 2195 src2_reg = lookup_reg_name (UNIT_FX, src2_no); 2196 2197 snprintf (buf, OPERAND_WIDTH, "%s,%s,%s", dest_reg, src1_reg, src2_reg); 2198 2199 if (n) 2200 print_insn (outf, "FLI", template->name, buf); 2201 else 2202 print_insn (outf, "FL", template->name, buf); 2203} 2204 2205/* Print an FPU accumulator GET or SET instruction. */ 2206static void 2207print_fget_set_acf (unsigned int insn_word, bfd_vma pc ATTRIBUTE_UNUSED, 2208 const insn_template *template, 2209 disassemble_info *outf) 2210{ 2211 bfd_boolean is_get = MAJOR_OPCODE (template->meta_opcode) == OPC_GET; 2212 char buf[OPERAND_WIDTH]; 2213 char addr_buf[ADDR_WIDTH]; 2214 unsigned int part; 2215 const char *reg_name; 2216 2217 part = (insn_word >> 19) & ACF_PART_MASK; 2218 2219 reg_name = lookup_acf_name (part); 2220 2221 mget_mset_addr_str (addr_buf, ADDR_WIDTH, insn_word); 2222 2223 if (is_get) 2224 { 2225 snprintf (buf, OPERAND_WIDTH, "%s,%s", reg_name, addr_buf); 2226 } 2227 else 2228 { 2229 snprintf (buf, OPERAND_WIDTH, "%s,%s", addr_buf, reg_name); 2230 } 2231 print_insn (outf, "F", template->name, buf); 2232} 2233 2234/* Return the name of the DSP register or accumulator for NUM and UNIT. */ 2235static const char * 2236__lookup_dsp_name (unsigned int num, unsigned int unit) 2237{ 2238 size_t i; 2239 2240 for (i = 0; i < sizeof(metag_dsp_regtab)/sizeof(metag_dsp_regtab[0]); i++) 2241 { 2242 const metag_reg *reg = &metag_dsp_regtab[i]; 2243 2244 if (reg->no == num) 2245 { 2246 if ((reg->unit == UNIT_RAM_D0 || reg->unit == UNIT_ACC_D0) && 2247 unit == UNIT_D0) 2248 return reg->name; 2249 2250 if ((reg->unit == UNIT_RAM_D1 || reg->unit == UNIT_ACC_D1) && 2251 unit == UNIT_D1) 2252 return reg->name; 2253 } 2254 } 2255 return "?.?"; 2256} 2257 2258/* Return the name of the DSP register for NUM and UNIT. */ 2259static const char * 2260lookup_dsp_name (unsigned int num, unsigned int unit) 2261{ 2262 size_t i; 2263 2264 for (i = 0; i < sizeof(metag_dsp_regtab)/sizeof(metag_dsp_regtab[0]); i++) 2265 { 2266 const metag_reg *reg = &metag_dsp_regtab[i]; 2267 2268 if (reg->no == num && reg->unit == unit) 2269 return reg->name; 2270 } 2271 return "?.?"; 2272} 2273 2274/* Return the name of the DSP RAM register for NUM and UNIT. */ 2275static const char * 2276lookup_dspram_name (unsigned int num, unsigned int unit, bfd_boolean load) 2277{ 2278 size_t i, nentries; 2279 2280 nentries = sizeof(metag_dsp_tmpl_regtab[load])/sizeof(metag_dsp_tmpl_regtab[load][0]); 2281 2282 for (i = 0; i < nentries; i++) 2283 { 2284 const metag_reg *reg = &metag_dsp_tmpl_regtab[load][i]; 2285 2286 if (reg->no == num && reg->unit == unit) 2287 return reg->name; 2288 } 2289 return "?.?"; 2290} 2291 2292/* This lookup function looks up the corresponding name for a register 2293 number in a DSP instruction. SOURCE indicates whether this 2294 register is a source or destination operand. */ 2295static const char * 2296lookup_any_reg_name (unsigned int unit, unsigned int num, bfd_boolean source) 2297{ 2298 /* A register with the top bit set (5th bit) indicates a DSPRAM 2299 register. */ 2300 if (num > 15) 2301 { 2302 unsigned int dunit = (unit == UNIT_D0) ? UNIT_RAM_D0 : UNIT_RAM_D1; 2303 return lookup_dspram_name (num, dunit, source); 2304 } 2305 else 2306 return lookup_reg_name (unit, num); 2307} 2308 2309/* Return the DSP data unit for UNIT. */ 2310static inline enum metag_unit 2311dsp_data_unit_to_sym (unsigned int unit) 2312{ 2313 if (unit == 0) 2314 return UNIT_D0; 2315 else 2316 return UNIT_D1; 2317} 2318 2319/* Print a DSP GET or SET instruction. */ 2320static void 2321print_dget_set (unsigned int insn_word, bfd_vma pc ATTRIBUTE_UNUSED, 2322 const insn_template *template, 2323 disassemble_info *outf) 2324{ 2325 bfd_boolean is_get = (template->meta_opcode & 0x100); 2326 char buf[OPERAND_WIDTH]; 2327 char addr_buf[ADDR_WIDTH]; 2328 char prefix[DSP_PREFIX_WIDTH]; 2329 unsigned int part; 2330 const char *reg_name[2]; 2331 bfd_boolean is_high = FALSE; 2332 bfd_boolean is_dual = (insn_word & 0x4); 2333 bfd_boolean is_template = (insn_word & 0x2); 2334 const char *base_reg = "?"; 2335 unsigned int addr_unit, base_no, unit; 2336 2337 unit = dsp_data_unit_to_sym (insn_word & 0x1); 2338 2339 /* Is this a load/store to a template table? */ 2340 if (is_template) 2341 { 2342 part = (insn_word >> 19) & 0x1f; 2343 reg_name[0] = lookup_dsp_name (part, UNIT_DT); 2344 } 2345 else 2346 { 2347 part = (insn_word >> 19) & REG_MASK; 2348 is_high = ((part & 0x18) == 0x18); 2349 2350 /* Strip bit high indicator. */ 2351 if (is_high) 2352 part &= 0x17; 2353 2354 reg_name[0] = __lookup_dsp_name (part, unit); 2355 2356 } 2357 2358 /* Is this a dual unit DSP operation? The modulo operator below 2359 makes sure that we print the Rd register in the correct order, 2360 e.g. because there's only one bit in the instruction for the Data 2361 Unit we have to work out what the other data unit number is. 2362 (there's only 2). */ 2363 if (is_dual) 2364 { 2365 unsigned int _unit = insn_word & 0x1; 2366 2367 _unit = ((_unit + 1) % 2); 2368 reg_name[1] = __lookup_dsp_name(part, dsp_data_unit_to_sym (_unit)); 2369 } 2370 else 2371 reg_name[1] = NULL; 2372 2373 addr_unit = ((insn_word >> 18) & 0x1); 2374 if (addr_unit == 0) 2375 addr_unit = UNIT_A0; 2376 else 2377 addr_unit = UNIT_A1; 2378 2379 base_no = (insn_word >> 14) & DSP_REG_MASK; 2380 2381 base_reg = lookup_reg_name (addr_unit, base_no); 2382 2383 /* Check if it's a post-increment/post-decrement. */ 2384 if (insn_word & 0x2000) 2385 { 2386 unsigned int imm = (insn_word >> 9) & DGET_SET_IMM_MASK; 2387 const char *post_op; 2388 2389 switch (imm) 2390 { 2391 case 0x1: 2392 post_op = "++"; 2393 break; 2394 case 0x3: 2395 post_op = "--"; 2396 break; 2397 default: 2398 post_op = ""; 2399 } 2400 2401 snprintf (addr_buf, ADDR_WIDTH, "[%s%s]", base_reg, post_op); 2402 } 2403 else 2404 { 2405 unsigned int offset_part = (insn_word >> 9) & DSP_REG_MASK; 2406 const char *offset_reg = lookup_reg_name (addr_unit, offset_part); 2407 2408 snprintf (addr_buf, ADDR_WIDTH, "[%s+%s++]", base_reg, offset_reg); 2409 } 2410 2411 if (is_get) 2412 { 2413 if (is_dual && !is_template) 2414 snprintf (buf, OPERAND_WIDTH, "%s,%s,%s", reg_name[0], 2415 reg_name[1], addr_buf); 2416 else 2417 snprintf (buf, OPERAND_WIDTH, "%s,%s", reg_name[0], addr_buf); 2418 } 2419 else 2420 { 2421 if (is_dual && !is_template) 2422 snprintf (buf, OPERAND_WIDTH, "%s,%s,%s", addr_buf, 2423 reg_name[0], reg_name[1]); 2424 else 2425 snprintf (buf, OPERAND_WIDTH, "%s,%s", addr_buf, reg_name[0]); 2426 } 2427 2428 snprintf (prefix, DSP_PREFIX_WIDTH, "D%s", is_high ? "H" : ""); 2429 print_insn (outf, prefix, template->name, buf); 2430} 2431 2432/* Print a DSP template instruction. */ 2433static void 2434print_dtemplate (unsigned int insn_word, bfd_vma pc ATTRIBUTE_UNUSED, 2435 const insn_template *template, 2436 disassemble_info *outf) 2437{ 2438 char buf[OPERAND_WIDTH]; 2439 char prefix[DSP_PREFIX_WIDTH]; 2440 unsigned int offset[4]; 2441 bfd_boolean is_half = (MINOR_OPCODE (insn_word) == 0x5); 2442 bfd_boolean daop_only = (MINOR_OPCODE (insn_word) == 0x3); 2443 2444 offset[0] = ((insn_word >> 19) & REG_MASK); 2445 offset[1] = ((insn_word >> 14) & REG_MASK); 2446 offset[2] = ((insn_word >> 9) & REG_MASK); 2447 offset[3] = ((insn_word >> 4) & REG_MASK); 2448 2449 if (daop_only) 2450 snprintf (buf, OPERAND_WIDTH, "#0x%x,#0x%x,#0x%x", offset[0], 2451 offset[1], offset[2]); 2452 else 2453 { 2454 snprintf (buf, OPERAND_WIDTH, "#0x%x,#0x%x,#0x%x,#0x%x", offset[0], 2455 offset[1], offset[2], offset[3]); 2456 } 2457 2458 snprintf (prefix, DSP_PREFIX_WIDTH, "D%s", is_half ? "H" : ""); 2459 print_insn (outf, prefix, template->name, buf); 2460} 2461 2462/* Format template definition from INSN_WORD into BUF. */ 2463static void 2464decode_template_definition(unsigned int insn_word, char *buf, size_t len) 2465{ 2466 bfd_boolean load = ((insn_word >> 13) & 0x1); 2467 bfd_boolean dspram = (((insn_word >> 17) & 0x3) == 0x3); 2468 const char *template[1]; 2469 unsigned int tidx = ((insn_word >> 9) & TEMPLATE_REGS_MASK); 2470 enum metag_unit au, ram_unit; 2471 unsigned int addr_reg_nums[2]; 2472 const char *addr_reg_names[2]; 2473 const char *post_op = ""; 2474 const char *join_op = ""; 2475 enum metag_unit data_unit = ((insn_word >> 24) & 0x1) ? UNIT_D1 : UNIT_D0; 2476 2477 template[0] = lookup_dsp_name (tidx, UNIT_DT); 2478 2479 addr_reg_names[1] = ""; 2480 2481 if (dspram) 2482 { 2483 ram_unit = (data_unit == UNIT_D0) ? UNIT_RAM_D0 : UNIT_RAM_D1; 2484 addr_reg_nums[0] = ((insn_word >> 19) & REG_MASK); 2485 addr_reg_names[0] = lookup_dspram_name (addr_reg_nums[0], 2486 ram_unit, load); 2487 } 2488 else 2489 { 2490 bfd_boolean im = (((insn_word >> 18) & 0x1) != 0); 2491 2492 au = (((insn_word >> 23) & 0x1) == 0) ? UNIT_A0 : UNIT_A1; 2493 addr_reg_nums[0] = ((insn_word >> 19) & DSP_REG_MASK); 2494 2495 addr_reg_names[0] = lookup_reg_name (au, addr_reg_nums[0]); 2496 2497 if (im) 2498 { 2499 unsigned int im_value = ((insn_word >> 14) & 0x3); 2500 2501 switch (im_value) 2502 { 2503 case 0x1: 2504 post_op = "++"; 2505 break; 2506 case 0x3: 2507 post_op = "--"; 2508 break; 2509 } 2510 } 2511 else 2512 { 2513 addr_reg_nums[1] = ((insn_word >> 14) & DSP_REG_MASK); 2514 addr_reg_names[1] = lookup_reg_name (au, addr_reg_nums[1]); 2515 join_op = "+"; 2516 post_op = "++"; 2517 } 2518 } 2519 2520 if (load) 2521 { 2522 len = snprintf (buf, len, " %s,[%s%s%s%s]", template[0], addr_reg_names[0], 2523 join_op, addr_reg_names[1], post_op); 2524 } 2525 else 2526 { 2527 len = snprintf (buf, len, " [%s%s%s%s],%s", addr_reg_names[0], join_op, 2528 addr_reg_names[1], post_op, template[0]); 2529 } 2530} 2531 2532/* Print a DSP ALU instruction. */ 2533static void 2534print_dalu (unsigned int insn_word, bfd_vma pc ATTRIBUTE_UNUSED, 2535 const insn_template *template, 2536 disassemble_info *outf) 2537{ 2538 bfd_boolean is_dual = FALSE; 2539 unsigned int data_unit = (((insn_word >> 24) & 0x1) ? UNIT_D1 : UNIT_D0); 2540 const char *reg_names[3]; 2541 unsigned int reg_nums[3]; 2542 bfd_boolean ac = ((insn_word >> 7) & 0x1); 2543 char buf[OPERAND_WIDTH]; 2544 char prefix[DSP_PREFIX_WIDTH]; 2545 size_t len; 2546 bfd_boolean is_mod = FALSE; 2547 bfd_boolean is_overflow = FALSE; 2548 unsigned int reg_brackets[3]; 2549 bfd_boolean is_w_mx = FALSE; 2550 bfd_boolean is_b_mx = FALSE; 2551 bfd_boolean imm = FALSE; 2552 bfd_boolean is_quickrot64 = FALSE; 2553 bfd_boolean conditional = FALSE; 2554 const char *cc_flags = NULL; 2555 bfd_boolean is_unsigned = FALSE; 2556 2557 memset (reg_brackets, 0, sizeof (reg_brackets)); 2558 2559 if (template->arg_type & DSP_ARGS_1) 2560 { 2561 bfd_boolean is_template = FALSE; 2562 const char *addr_reg = NULL; 2563 bfd_boolean qr = FALSE; 2564 bfd_boolean is_acc_add = FALSE; 2565 bfd_boolean is_acc_sub = FALSE; 2566 bfd_boolean is_acc_zero = FALSE; 2567 bfd_boolean is_split8 = (template->arg_type & DSP_ARGS_SPLIT8); 2568 2569 /* Read DU bit. */ 2570 data_unit = ((insn_word >> 24) & 0x1) ? UNIT_D1 : UNIT_D0; 2571 2572 conditional = ((insn_word >> 24) & 0x4); 2573 2574 /* Templates can't be conditional. */ 2575 is_template = (((insn_word & 0x02000002) == 0x2) && !conditional); 2576 2577 if (is_split8) 2578 is_mod = (insn_word & 0x80); 2579 2580 if (template->arg_type & DSP_ARGS_QR) 2581 { 2582 if (!conditional) 2583 is_quickrot64 = ((insn_word >> 5) & 0x1); 2584 } 2585 2586 if (template->arg_type & DSP_ARGS_DACC) 2587 { 2588 is_mod = (insn_word & 0x8); 2589 is_unsigned = (insn_word & 0x40); 2590 } 2591 2592 if (is_template) 2593 { 2594 is_w_mx = (insn_word & 0x1); 2595 is_dual = ((insn_word >> 0x4) & 0x1); 2596 2597 /* De.r,Dx.r,De.r|ACe.r */ 2598 if (template->arg_type & DSP_ARGS_ACC2) 2599 { 2600 is_mod = (insn_word & 0x8); 2601 is_overflow = (insn_word & 0x20); 2602 } 2603 2604 /* ACe.e,ACx.r,ACo.e? */ 2605 if ((template->arg_type & DSP_ARGS_XACC) && 2606 (((insn_word >> 6) & 0x5) == 0x5)) 2607 { 2608 enum metag_unit ac_unit, ao_unit; 2609 2610 ac_unit = (data_unit == UNIT_D0) ? UNIT_ACC_D0 : UNIT_ACC_D1; 2611 2612 if (ac_unit == UNIT_ACC_D0) 2613 ao_unit = UNIT_ACC_D1; 2614 else 2615 ao_unit = UNIT_ACC_D0; 2616 2617 reg_nums[1] = ((insn_word >> 19) & REG_MASK); 2618 2619 /* These are dummy arguments anyway so the register 2620 number does not matter. */ 2621 reg_names[0] = lookup_dsp_name (16, ac_unit); /* ACe.0 */ 2622 reg_names[1] = lookup_dsp_name (16, ac_unit); /* ACx.0 */ 2623 reg_names[2] = lookup_dsp_name (16, ao_unit); /* ACo.0 */ 2624 } 2625 else 2626 { 2627 /* De.r|ACe.r,Dx.r,De.r */ 2628 if (template->arg_type & DSP_ARGS_DACC && 2629 ((insn_word & 0x84) != 0)) 2630 { 2631 enum metag_unit ac_unit; 2632 2633 ac_unit = (data_unit == UNIT_D0) ? UNIT_ACC_D0 : UNIT_ACC_D1; 2634 reg_names[0] = lookup_dsp_name (16, ac_unit); 2635 2636 is_acc_zero = ((insn_word & 0x84) == 0x04); 2637 is_acc_add = ((insn_word & 0x84) == 0x80); 2638 is_acc_sub = ((insn_word & 0x84) == 0x84); 2639 } 2640 else 2641 reg_names[0] = lookup_any_reg_name (data_unit, 0, FALSE); 2642 2643 /* These are dummy arguments anyway so the register 2644 number does not matter. */ 2645 reg_names[1] = lookup_any_reg_name (data_unit, 0, TRUE); 2646 2647 /* De.r,Dx.r,De.r|ACe.r */ 2648 if ((template->arg_type & DSP_ARGS_ACC2) && 2649 ((insn_word & 0x80) == 0x80)) 2650 { 2651 enum metag_unit ac_unit; 2652 2653 ac_unit = (data_unit == UNIT_D0) ? UNIT_ACC_D0 : UNIT_ACC_D1; 2654 reg_names[2] = lookup_dsp_name (16, ac_unit); 2655 } 2656 /* Detection of QUICKRoT and accumulator usage uses the 2657 same bits. They are mutually exclusive. */ 2658 else if (ac && (template->arg_type & DSP_ARGS_ACC2)) 2659 { 2660 reg_nums[2] = ((insn_word >> 9) & REG_MASK); 2661 2662 if (data_unit == UNIT_D0) 2663 reg_names[2] = lookup_dsp_name (reg_nums[2], UNIT_ACC_D0); 2664 else 2665 reg_names[2] = lookup_dsp_name (reg_nums[2], UNIT_ACC_D1); 2666 } 2667 else 2668 { 2669 if ((template->arg_type & DSP_ARGS_QR) && 2670 ((insn_word & 0x40) == 0x40)) 2671 { 2672 enum metag_unit aunit; 2673 int reg_no; 2674 2675 if (conditional) 2676 reg_no = ((insn_word >> 5) & 0x1); 2677 else 2678 reg_no = ((insn_word >> 7) & 0x1); 2679 2680 aunit = (data_unit == UNIT_D0) ? UNIT_A0 : UNIT_A1; 2681 addr_reg = lookup_reg_name (aunit, reg_no + 2); 2682 2683 qr = TRUE; 2684 } 2685 2686 reg_names[2] = lookup_any_reg_name (data_unit, 0, TRUE); 2687 } 2688 } 2689 2690 if (qr) 2691 { 2692 len = snprintf (buf, OPERAND_WIDTH, "%s,%s,%s,%s", 2693 reg_names[0], reg_names[1], reg_names[2], 2694 addr_reg); 2695 } 2696 else 2697 { 2698 len = snprintf (buf, OPERAND_WIDTH, "%s,%s,%s%s%s", 2699 reg_names[0], reg_names[1], 2700 reg_brackets[2] ? "[" : "", 2701 reg_names[2], reg_brackets[2] ? "]" : ""); 2702 } 2703 2704 decode_template_definition (insn_word, buf + len, 2705 OPERAND_WIDTH - len); 2706 } 2707 else /* Not a template definiton. */ 2708 { 2709 reg_nums[0] = ((insn_word >> 19) & REG_MASK); 2710 reg_nums[1] = ((insn_word >> 14) & REG_MASK); 2711 reg_nums[2] = ((insn_word >> 9) & REG_MASK); 2712 2713 imm = (((insn_word >> 24) & 0x2) && (template->arg_type & DSP_ARGS_IMM)); 2714 2715 if (imm) 2716 is_dual = (insn_word & 0x4); 2717 else if (!conditional) 2718 is_dual = (insn_word & 0x10); 2719 else 2720 cc_flags = lookup_scc_flags ((insn_word >> 1) & CC_MASK); 2721 2722 /* De.r,Dx.r,De.r|ACe.r */ 2723 if (template->arg_type & DSP_ARGS_ACC2) 2724 { 2725 is_mod = (insn_word & 0x8); 2726 is_overflow = (insn_word & 0x20); 2727 } 2728 2729 if (template->arg_type & DSP_ARGS_SPLIT8) 2730 { 2731 is_overflow = (insn_word & 0x20); 2732 } 2733 2734 /* ACe.e,ACx.r,ACo.e? */ 2735 if ((template->arg_type & DSP_ARGS_XACC) && 2736 (((insn_word >> 6) & 0x5) == 0x5)) 2737 { 2738 enum metag_unit ac_unit, ao_unit; 2739 2740 ac_unit = (data_unit == UNIT_D0) ? UNIT_ACC_D0 : UNIT_ACC_D1; 2741 2742 if (ac_unit == UNIT_ACC_D0) 2743 ao_unit = UNIT_ACC_D1; 2744 else 2745 ao_unit = UNIT_ACC_D0; 2746 2747 reg_nums[1] = ((insn_word >> 19) & REG_MASK); 2748 reg_names[0] = lookup_dsp_name (reg_nums[1], ac_unit); 2749 reg_names[1] = lookup_dsp_name (reg_nums[1], ac_unit); 2750 reg_names[2] = lookup_dsp_name (reg_nums[1], ao_unit); 2751 } 2752 else 2753 { 2754 bfd_boolean o2r = (insn_word & 0x1); 2755 2756 /* De.r|ACe.r,Dx.r,De.r */ 2757 if ((template->arg_type & DSP_ARGS_DACC) && 2758 ((insn_word & 0x84) != 0)) 2759 { 2760 enum metag_unit ac_unit; 2761 2762 ac_unit = (data_unit == UNIT_D0) ? UNIT_ACC_D0 : UNIT_ACC_D1; 2763 reg_names[0] = lookup_dsp_name (reg_nums[0], ac_unit); 2764 2765 is_acc_zero = ((insn_word & 0x84) == 0x04); 2766 is_acc_add = ((insn_word & 0x84) == 0x80); 2767 is_acc_sub = ((insn_word & 0x84) == 0x84); 2768 } 2769 else if (conditional) 2770 { 2771 reg_names[0] = lookup_reg_name (data_unit, reg_nums[0]); 2772 } 2773 else 2774 { 2775 reg_names[0] = lookup_any_reg_name (data_unit, 2776 reg_nums[0], FALSE); 2777 if (reg_nums[0] > 15) 2778 reg_brackets[0] = 1; 2779 } 2780 2781 if (imm) 2782 { 2783 reg_names[1] = lookup_any_reg_name (data_unit, reg_nums[0], TRUE); 2784 2785 if (reg_brackets[0]) 2786 reg_brackets[1] = 1; 2787 } 2788 else 2789 { 2790 if (is_split8 && is_mod) 2791 { 2792 reg_names[1] = lookup_reg_name (data_unit, reg_nums[1]); 2793 } 2794 else 2795 { 2796 reg_names[1] = lookup_any_reg_name (data_unit, reg_nums[1], TRUE); 2797 2798 if (reg_nums[1] > 15) 2799 reg_brackets[1] = 1; 2800 } 2801 } 2802 2803 /* Detection of QUICKRoT and accumulator usage uses the 2804 same bits. They are mutually exclusive. */ 2805 if (ac && (template->arg_type & DSP_ARGS_ACC2)) 2806 { 2807 if (data_unit == UNIT_D0) 2808 reg_names[2] = lookup_dsp_name (reg_nums[2], UNIT_ACC_D0); 2809 else 2810 reg_names[2] = lookup_dsp_name (reg_nums[2], UNIT_ACC_D1); 2811 } 2812 2813 else 2814 { 2815 if ((template->arg_type & DSP_ARGS_QR) && 2816 ((insn_word & 0x40) == 0x40)) 2817 { 2818 enum metag_unit aunit; 2819 int reg_no; 2820 2821 if (conditional) 2822 reg_no = ((insn_word >> 5) & 0x1); 2823 else 2824 reg_no = ((insn_word >> 7) & 0x1); 2825 2826 aunit = (data_unit == UNIT_D0) ? UNIT_A0 : UNIT_A1; 2827 addr_reg = lookup_reg_name (aunit, reg_no + 2); 2828 2829 qr = TRUE; 2830 } 2831 2832 if (o2r) 2833 reg_names[2] = lookup_o2r (data_unit, reg_nums[2]); 2834 else 2835 { 2836 /* Can't use a DSPRAM reg if both QD and L1 are 2837 set on a QUICKRoT instruction or if we're a 2838 split 8. */ 2839 if (((template->arg_type & DSP_ARGS_QR) 2840 && ((insn_word & 0x30) == 0x30 && !conditional)) || 2841 (is_split8 && is_mod)) 2842 reg_names[2] = lookup_reg_name (data_unit, reg_nums[2]); 2843 else 2844 { 2845 reg_names[2] = lookup_any_reg_name (data_unit, 2846 reg_nums[2], TRUE); 2847 if (reg_nums[2] > 15) 2848 reg_brackets[2] = 1; 2849 } 2850 } 2851 } 2852 } 2853 2854 if (qr) 2855 { 2856 len = snprintf (buf, OPERAND_WIDTH, "%s%s%s,%s%s%s,%s%s%s,%s", 2857 reg_brackets[0] ? "[" : "", 2858 reg_names[0], reg_brackets[0] ? "]" : "", 2859 reg_brackets[1] ? "[" : "", 2860 reg_names[1], reg_brackets[1] ? "]" : "", 2861 reg_brackets[2] ? "[" : "", 2862 reg_names[2], reg_brackets[2] ? "]" : "", 2863 addr_reg); 2864 } 2865 else 2866 { 2867 if (imm) 2868 { 2869 /* Conform to the embedded assembler's policy of 2870 printing negative numbers as decimal and positive 2871 as hex. */ 2872 int value = ((insn_word >> 3) & IMM16_MASK); 2873 2874 if ((value & 0x8000) || value == 0) 2875 { 2876 value = sign_extend (value, IMM16_BITS); 2877 len = snprintf (buf, OPERAND_WIDTH, "%s%s%s,%s%s%s,#%d", 2878 reg_brackets[0] ? "[" : "", 2879 reg_names[0], reg_brackets[0] ? "]" : "", 2880 reg_brackets[1] ? "[" : "", 2881 reg_names[1], reg_brackets[1] ? "]" : "", 2882 value); 2883 } 2884 else 2885 { 2886 len = snprintf (buf, OPERAND_WIDTH, "%s%s%s,%s%s%s,#%#x", 2887 reg_brackets[0] ? "[" : "", 2888 reg_names[0], reg_brackets[0] ? "]" : "", 2889 reg_brackets[1] ? "[" : "", 2890 reg_names[1], reg_brackets[1] ? "]" : "", 2891 value); 2892 } 2893 } 2894 else 2895 { 2896 len = snprintf (buf, OPERAND_WIDTH, "%s%s%s,%s%s%s,%s%s%s", 2897 reg_brackets[0] ? "[" : "", 2898 reg_names[0], reg_brackets[0] ? "]" : "", 2899 reg_brackets[1] ? "[" : "", reg_names[1], 2900 reg_brackets[1] ? "]" : "", 2901 reg_brackets[2] ? "[" : "", 2902 reg_names[2], reg_brackets[2] ? "]" : ""); 2903 } 2904 } 2905 } 2906 2907 snprintf (prefix, DSP_PREFIX_WIDTH, "D%s%s%s%s%s%s%s%s%s%s%s%s", 2908 cc_flags ? cc_flags : "", 2909 is_dual ? "L" : "", 2910 is_quickrot64 ? "Q" : "", 2911 is_unsigned ? "U" : "", 2912 is_mod ? "M" : "", 2913 is_acc_zero ? "Z" : "", 2914 is_acc_add ? "P" : "", is_acc_sub ? "N" : "", 2915 is_overflow ? "O" : "", 2916 is_w_mx ? "W" : "", 2917 is_b_mx ? "B" : "", 2918 is_template ? "T" : ""); 2919 } 2920 else if (template->arg_type & DSP_ARGS_2) /* Group 2. */ 2921 { 2922 bfd_boolean is_template; 2923 bfd_boolean o2r = FALSE; 2924 int major = MAJOR_OPCODE (template->meta_opcode); 2925 bfd_boolean is_neg_or_mov = (major == OPC_ADD || major == OPC_SUB); 2926 bfd_boolean is_cmp_tst = ((major == OPC_CMP) && 2927 ((insn_word & 0x0000002c) == 0)); 2928 bfd_boolean is_fpu_mov = template->insn_type == INSN_DSP_FPU; 2929 bfd_boolean to_fpu = (template->meta_opcode >> 7) & 0x1; 2930 2931 if (major == OPC_9) 2932 imm = (insn_word & 0x2); 2933 else if (template->arg_type & DSP_ARGS_IMM) 2934 imm = ((insn_word >> 25) & 0x1); 2935 2936 is_template = (((insn_word & 0x02000002) == 0x2) && 2937 major != OPC_9); 2938 2939 if (imm) 2940 is_dual = ((insn_word >> 0x2) & 0x1); 2941 else 2942 is_dual = ((insn_word >> 0x4) & 0x1); 2943 2944 /* MOV and XSD[BW] do not have o2r. */ 2945 if (major != OPC_9 && major != OPC_MISC) 2946 o2r = (insn_word & 0x1); 2947 2948 if (is_neg_or_mov) 2949 { 2950 is_mod = (insn_word & 0x8); 2951 is_overflow = (insn_word & 0x20); 2952 } 2953 2954 /* XSD */ 2955 if (major == OPC_MISC) 2956 data_unit = (insn_word & 0x1) ? UNIT_D1 : UNIT_D0; 2957 else 2958 data_unit = ((insn_word >> 24) & 0x1) ? UNIT_D1 : UNIT_D0; 2959 2960 /* Check for NEG,MOV,ABS,FFB, etc. */ 2961 if (is_neg_or_mov || !is_cmp_tst || imm || 2962 MAJOR_OPCODE (insn_word) == OPC_9 || 2963 MAJOR_OPCODE (insn_word) == OPC_MISC) 2964 reg_nums[0] = ((insn_word >> 19) & REG_MASK); 2965 else 2966 reg_nums[0] = ((insn_word >> 14) & REG_MASK); 2967 2968 if (is_template) 2969 { 2970 is_w_mx = (insn_word & 0x1); 2971 2972 /* These are dummy arguments anyway so the register number 2973 does not matter. */ 2974 if (is_fpu_mov) 2975 { 2976 if (to_fpu) 2977 { 2978 reg_names[0] = lookup_reg_name (UNIT_FX, 0); 2979 reg_names[1] = lookup_reg_name (data_unit, 0); 2980 } 2981 else 2982 { 2983 reg_names[0] = lookup_reg_name (data_unit, 0); 2984 reg_names[1] = lookup_reg_name (UNIT_FX, 0); 2985 } 2986 } 2987 else 2988 { 2989 reg_names[0] = lookup_reg_name (data_unit, 0); 2990 reg_names[1] = lookup_reg_name (data_unit, 0); 2991 } 2992 2993 len = snprintf (buf, OPERAND_WIDTH, "%s,%s", 2994 reg_names[0], reg_names[1]); 2995 2996 decode_template_definition (insn_word, buf + len, 2997 OPERAND_WIDTH - len); 2998 } 2999 else 3000 { 3001 if (imm) 3002 { 3003 /* Conform to the embedded assembler's policy of 3004 printing negative numbers as decimal and positive as 3005 hex. */ 3006 unsigned int value = ((insn_word >> 3) & IMM16_MASK); 3007 3008 if (major == OPC_9) 3009 { 3010 data_unit = (insn_word & 0x1) ? UNIT_D1 : UNIT_D0; 3011 is_dual = (insn_word & 0x4); 3012 3013 reg_names[0] = __lookup_dsp_name (reg_nums[0], data_unit); 3014 } 3015 else 3016 { 3017 reg_names[0] = lookup_any_reg_name (data_unit, reg_nums[0], TRUE); 3018 if (reg_nums[0] > 15) 3019 reg_brackets[0] = 1; 3020 } 3021 3022 if ((value & 0x8000) || value == 0) 3023 { 3024 value = sign_extend (value, IMM16_BITS); 3025 snprintf (buf, OPERAND_WIDTH, "%s%s%s,#%d", 3026 reg_brackets[0] ? "[" : "", 3027 reg_names[0], reg_brackets[0] ? "]" : "", 3028 value); 3029 } 3030 else 3031 { 3032 snprintf (buf, OPERAND_WIDTH, "%s%s%s,#0x%x", 3033 reg_brackets[0] ? "[" : "", 3034 reg_names[0], reg_brackets[0] ? "]" : "", 3035 value); 3036 } 3037 } 3038 else 3039 { 3040 if (is_neg_or_mov || is_cmp_tst) 3041 reg_nums[1] = ((insn_word >> 9) & REG_MASK); 3042 else 3043 reg_nums[1] = ((insn_word >> 14) & REG_MASK); 3044 3045 if (major == OPC_9) 3046 { 3047 is_dual = (insn_word & 0x4); 3048 data_unit = (insn_word & 0x1) ? UNIT_D1 : UNIT_D0; 3049 3050 if (MINOR_OPCODE (template->meta_opcode) == 0x1) 3051 reg_names[0] = __lookup_dsp_name (reg_nums[0], data_unit); 3052 else 3053 reg_names[0] = lookup_reg_name (data_unit, reg_nums[0]); 3054 } 3055 else 3056 { 3057 unsigned int reg0_unit = data_unit; 3058 3059 if (is_fpu_mov && to_fpu) 3060 reg0_unit = UNIT_FX; 3061 3062 reg_names[0] = lookup_any_reg_name (reg0_unit, reg_nums[0], 3063 (!is_neg_or_mov && is_cmp_tst)); 3064 if (reg_nums[0] > 15) 3065 reg_brackets[0] = 1; 3066 } 3067 3068 if (o2r) 3069 reg_names[1] = lookup_o2r (data_unit, reg_nums[1]); 3070 else 3071 { 3072 /* Check for accumulator argument. */ 3073 if (is_neg_or_mov && ((insn_word & 0x80) == 0x80)) 3074 { 3075 if (data_unit == UNIT_D0) 3076 reg_names[1] = lookup_dsp_name (reg_nums[1], UNIT_ACC_D0); 3077 else 3078 reg_names[1] = lookup_dsp_name (reg_nums[1], UNIT_ACC_D1); 3079 } 3080 else 3081 { 3082 if (major == OPC_9) 3083 { 3084 if (MINOR_OPCODE (template->meta_opcode) == 0x1) 3085 { 3086 reg_names[1] = lookup_reg_name (data_unit, reg_nums[1]); 3087 } 3088 else 3089 { 3090 enum metag_unit u; 3091 3092 u = (insn_word & 0x1) ? UNIT_RAM_D1 : UNIT_RAM_D0; 3093 reg_names[1] = lookup_dsp_name (reg_nums[1], u); 3094 } 3095 } 3096 else 3097 { 3098 reg_names[1] = lookup_any_reg_name (data_unit, 3099 reg_nums[1], TRUE); 3100 if (reg_nums[1] > 15) 3101 reg_brackets[1] = 1; 3102 } 3103 } 3104 } 3105 3106 snprintf (buf, OPERAND_WIDTH, "%s%s%s,%s%s%s", 3107 reg_brackets[0] ? "[" : "", reg_names[0], 3108 reg_brackets[0] ? "]" : "", 3109 reg_brackets[1] ? "[" : "", reg_names[1], 3110 reg_brackets[1] ? "]" : ""); 3111 } 3112 } 3113 3114 snprintf (prefix, DSP_PREFIX_WIDTH, "D%s%s%s%s%s%s", 3115 is_fpu_mov ? "F" : "", 3116 is_dual ? "L" : "", 3117 is_mod ? "M" : "", is_overflow ? "O" : "", 3118 is_w_mx ? "W" : "", 3119 is_template ? "T" : ""); 3120 } 3121 else /* Group 3. */ 3122 { 3123 /* If both the C and CA bits are set, then the Rd register can 3124 be in any unit. Figure out which unit from the Ud field. */ 3125 bfd_boolean all_units = (((insn_word) & 0x04000020) == 0x04000020); 3126 enum metag_unit ud_unit = ((insn_word >> 1) & UNIT_MASK); 3127 enum metag_unit ram_unit, acc_unit; 3128 bfd_boolean round = FALSE; 3129 bfd_boolean clamp9 = FALSE; 3130 bfd_boolean clamp8 = FALSE; 3131 bfd_boolean is_template = ((insn_word & 0x04000002) == 0x2); 3132 3133 imm = ((insn_word >> 25) & 0x1); 3134 ac = (insn_word & 0x1); 3135 3136 conditional = (MINOR_OPCODE (insn_word) & 0x4); 3137 3138 /* Check for conditional and not Condition Always. */ 3139 if (conditional && !(insn_word & 0x20)) 3140 cc_flags = lookup_scc_flags ((insn_word >> 1) & CC_MASK); 3141 else if (!(conditional && (insn_word & 0x20))) 3142 is_dual = ((insn_word >> 0x4) & 0x1); 3143 3144 /* Conditional instructions don't have the L1 or RSPP fields. */ 3145 if ((insn_word & 0x04000000) == 0) 3146 { 3147 round = (((insn_word >> 2) & 0x3) == 0x1); 3148 clamp9 = (((insn_word >> 2) & 0x3) == 0x2); 3149 clamp8 = (((insn_word >> 2) & 0x3) == 0x3); 3150 } 3151 3152 /* Read DU bit. */ 3153 data_unit = ((insn_word >> 24) & 0x1) ? UNIT_D1 : UNIT_D0; 3154 reg_nums[0] = ((insn_word >> 19) & REG_MASK); 3155 reg_nums[1] = ((insn_word >> 14) & REG_MASK); 3156 3157 ram_unit = (data_unit == UNIT_D0) ? UNIT_RAM_D0 : UNIT_RAM_D1; 3158 acc_unit = (data_unit == UNIT_D0) ? UNIT_ACC_D0 : UNIT_ACC_D1; 3159 3160 if (all_units) 3161 reg_names[0] = lookup_reg_name (ud_unit, reg_nums[0]); 3162 else 3163 { 3164 if (conditional) 3165 reg_names[0] = lookup_reg_name (data_unit, reg_nums[0]); 3166 else 3167 { 3168 reg_names[0] = lookup_any_reg_name (data_unit, reg_nums[0], FALSE); 3169 if (reg_nums[0] > 15) 3170 reg_brackets[0] = 1; 3171 } 3172 } 3173 3174 if (ac) 3175 { 3176 reg_names[1] = lookup_dsp_name (reg_nums[1], acc_unit); 3177 } 3178 else 3179 { 3180 reg_names[1] = lookup_any_reg_name (data_unit, reg_nums[1], TRUE); 3181 if (reg_nums[1] > 15) 3182 reg_brackets[1] = 1; 3183 } 3184 3185 if (imm) 3186 { 3187 snprintf (buf, OPERAND_WIDTH, "%s%s%s,%s%s%s,#%#x", 3188 reg_brackets[0] ? "[" : "", 3189 reg_names[0], reg_brackets[0] ? "]" : "", 3190 reg_brackets[1] ? "[" : "", 3191 reg_names[1], reg_brackets[1] ? "]" : "", 3192 ((insn_word >> 9) & IMM5_MASK)); 3193 } 3194 else 3195 { 3196 reg_nums[2] = ((insn_word >> 9) & REG_MASK); 3197 3198 reg_names[2] = lookup_any_reg_name (data_unit, reg_nums[2], TRUE); 3199 3200 if (reg_nums[2] > 15) 3201 reg_brackets[2] = 1; 3202 3203 if (is_template) 3204 { 3205 bfd_boolean load = ((insn_word >> 13) & 0x1); 3206 bfd_boolean dspram = (((insn_word >> 17) & 0x3) == 0x3); 3207 const char *tname[1]; 3208 unsigned int tidx = ((insn_word >> 9) & TEMPLATE_REGS_MASK); 3209 enum metag_unit au; 3210 unsigned int addr_reg_nums[2]; 3211 const char *addr_reg_names[2]; 3212 const char *post_op = ""; 3213 const char *join_op = ""; 3214 3215 is_w_mx = ((insn_word >> 5) & 0x1); 3216 3217 tname[0] = lookup_dsp_name (tidx, UNIT_DT); 3218 3219 /* These are dummy arguments anyway */ 3220 reg_names[0] = lookup_reg_name (data_unit, 0); 3221 if (ac) 3222 reg_names[1] = lookup_dsp_name (16, acc_unit); 3223 else 3224 reg_names[1] = lookup_reg_name (data_unit, 0); 3225 reg_names[2] = lookup_reg_name (data_unit, 0); 3226 3227 addr_reg_names[1] = ""; 3228 3229 if (dspram) 3230 { 3231 ram_unit = (data_unit == UNIT_D0) ? UNIT_RAM_D0 : UNIT_RAM_D1; 3232 addr_reg_nums[0] = ((insn_word >> 19) & REG_MASK); 3233 addr_reg_names[0] = lookup_dspram_name (addr_reg_nums[0], 3234 ram_unit, load); 3235 } 3236 else 3237 { 3238 bfd_boolean im = (((insn_word >> 18) & 0x1) != 0); 3239 3240 au = (((insn_word >> 23) & 0x1) == 0) ? UNIT_A0 : UNIT_A1; 3241 addr_reg_nums[0] = ((insn_word >> 19) & DSP_REG_MASK); 3242 3243 addr_reg_names[0] = lookup_reg_name (au, addr_reg_nums[0]); 3244 3245 if (im) 3246 { 3247 unsigned int im_value = ((insn_word >> 14) & 0x3); 3248 3249 switch (im_value) 3250 { 3251 case 0x1: 3252 post_op = "++"; 3253 break; 3254 case 0x3: 3255 post_op = "--"; 3256 break; 3257 } 3258 } 3259 else 3260 { 3261 addr_reg_nums[1] = ((insn_word >> 14) & DSP_REG_MASK); 3262 addr_reg_names[1] = lookup_reg_name (au, addr_reg_nums[1]); 3263 join_op = "+"; 3264 post_op = "++"; 3265 } 3266 } 3267 3268 if (load) 3269 { 3270 snprintf (buf, OPERAND_WIDTH, "%s,%s,%s %s,[%s%s%s%s]", 3271 reg_names[0], reg_names[1], reg_names[2], 3272 tname[0], addr_reg_names[0], join_op, 3273 addr_reg_names[1], post_op); 3274 } 3275 else 3276 { 3277 snprintf (buf, OPERAND_WIDTH, "%s,%s,%s [%s%s%s%s],%s", 3278 reg_names[0], reg_names[1], reg_names[2], 3279 addr_reg_names[0], join_op, addr_reg_names[1], 3280 post_op, tname[0]); 3281 } 3282 } 3283 else 3284 { 3285 snprintf (buf, OPERAND_WIDTH, "%s%s%s,%s%s%s,%s%s%s", 3286 reg_brackets[0] ? "[" : "", 3287 reg_names[0], reg_brackets[0] ? "]" : "", 3288 reg_brackets[1] ? "[" : "", 3289 reg_names[1], reg_brackets[1] ? "]" : "", 3290 reg_brackets[2] ? "[" : "", 3291 reg_names[2], reg_brackets[2] ? "]" : ""); 3292 } 3293 } 3294 3295 snprintf (prefix, DSP_PREFIX_WIDTH, "D%s%s%s%s%s%s%s", 3296 cc_flags ? cc_flags : "", 3297 is_dual ? "L" : "", clamp9 ? "G" : "", 3298 clamp8 ? "B" : "", round ? "R" : "", 3299 is_w_mx ? "W" : "", 3300 is_template ? "T" : ""); 3301 } 3302 3303 print_insn (outf, prefix, template->name, buf); 3304 3305} 3306 3307typedef void (*insn_printer)(unsigned int, bfd_vma, const insn_template *, 3308 disassemble_info *); 3309 3310/* Printer table. */ 3311static const insn_printer insn_printers[ENC_MAX] = 3312 { 3313 [ENC_NONE] = print_none, 3314 [ENC_MOV_U2U] = print_mov_u2u, 3315 [ENC_MOV_PORT] = print_mov_port, 3316 [ENC_MMOV] = print_mmov, 3317 [ENC_MDRD] = print_mdrd, 3318 [ENC_MOVL_TTREC] = print_movl_ttrec, 3319 [ENC_GET_SET] = print_get_set, 3320 [ENC_GET_SET_EXT] = print_get_set_ext, 3321 [ENC_MGET_MSET] = print_mget_mset, 3322 [ENC_COND_SET] = print_cond_set, 3323 [ENC_XFR] = print_xfr, 3324 [ENC_MOV_CT] = print_mov_ct, 3325 [ENC_SWAP] = print_swap, 3326 [ENC_JUMP] = print_jump, 3327 [ENC_CALLR] = print_callr, 3328 [ENC_ALU] = print_alu, 3329 [ENC_SHIFT] = print_shift, 3330 [ENC_MIN_MAX] = print_min_max, 3331 [ENC_BITOP] = print_bitop, 3332 [ENC_CMP] = print_cmp, 3333 [ENC_BRANCH] = print_branch, 3334 [ENC_KICK] = print_mov_u2u, 3335 [ENC_SWITCH] = print_switch, 3336 [ENC_CACHER] = print_cacher, 3337 [ENC_CACHEW] = print_cachew, 3338 [ENC_ICACHE] = print_icache, 3339 [ENC_LNKGET] = print_lnkget, 3340 [ENC_FMOV] = print_fmov, 3341 [ENC_FMMOV] = print_fmmov, 3342 [ENC_FMOV_DATA] = print_fmov_data, 3343 [ENC_FMOV_I] = print_fmov_i, 3344 [ENC_FPACK] = print_fpack, 3345 [ENC_FSWAP] = print_fswap, 3346 [ENC_FCMP] = print_fcmp, 3347 [ENC_FMINMAX] = print_fminmax, 3348 [ENC_FCONV] = print_fconv, 3349 [ENC_FCONVX] = print_fconvx, 3350 [ENC_FBARITH] = print_fbarith, 3351 [ENC_FEARITH] = print_fearith, 3352 [ENC_FREC] = print_frec, 3353 [ENC_FSIMD] = print_fsimd, 3354 [ENC_FGET_SET_ACF] = print_fget_set_acf, 3355 [ENC_DGET_SET] = print_dget_set, 3356 [ENC_DTEMPLATE] = print_dtemplate, 3357 [ENC_DALU] = print_dalu, 3358 }; 3359 3360/* Entry point for instruction printing. */ 3361int 3362print_insn_metag (bfd_vma pc, disassemble_info *outf) 3363{ 3364 bfd_byte buf[4]; 3365 unsigned int insn_word; 3366 size_t i; 3367 int status; 3368 3369 outf->bytes_per_chunk = 4; 3370 status = (*outf->read_memory_func) (pc & ~0x03, buf, 4, outf); 3371 if (status) 3372 { 3373 (*outf->memory_error_func) (status, pc, outf); 3374 return -1; 3375 } 3376 insn_word = bfd_getl32 (buf); 3377 3378 for (i = 0; i < sizeof(metag_optab)/sizeof(metag_optab[0]); i++) 3379 { 3380 const insn_template *template = &metag_optab[i]; 3381 3382 if ((insn_word & template->meta_mask) == template->meta_opcode) 3383 { 3384 enum insn_encoding encoding = template->encoding; 3385 insn_printer printer = insn_printers[encoding]; 3386 3387 if (printer) 3388 printer (insn_word, pc, template, outf); 3389 3390 return 4; 3391 } 3392 } 3393 3394 return 4; 3395} 3396