1 /* Disassemble MSP430 instructions. 2 Copyright (C) 2002-2016 Free Software Foundation, Inc. 3 4 Contributed by Dmitry Diky <diwil (at) mail.ru> 5 6 This file is part of the GNU opcodes library. 7 8 This library is free software; you can redistribute it and/or modify 9 it under the terms of the GNU General Public License as published by 10 the Free Software Foundation; either version 3, or (at your option) 11 any later version. 12 13 It is distributed in the hope that it will be useful, but WITHOUT 14 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 15 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public 16 License for more details. 17 18 You should have received a copy of the GNU General Public License 19 along with this program; if not, write to the Free Software 20 Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, 21 MA 02110-1301, USA. */ 22 23 #include "sysdep.h" 24 #include <stdio.h> 25 #include <ctype.h> 26 #include <sys/types.h> 27 #include <errno.h> 28 29 #include "dis-asm.h" 30 #include "opintl.h" 31 #include "libiberty.h" 32 33 #define DASM_SECTION 34 #include "opcode/msp430.h" 35 #undef DASM_SECTION 36 37 38 #define PS(x) (0xffff & (x)) 39 40 static bfd_boolean 41 msp430dis_read_two_bytes (bfd_vma addr, 42 disassemble_info * info, 43 bfd_byte * buffer, 44 char * comm) 45 { 46 int status; 47 48 status = info->read_memory_func (addr, buffer, 2, info); 49 if (status == 0) 50 return TRUE; 51 52 /* PR 20150: A status of EIO means that there were no more bytes left 53 to read in the current section. This can happen when disassembling 54 interrupt vectors for example. Avoid cluttering the output with 55 unhelpful error messages in this case. */ 56 if (status == EIO) 57 { 58 if (comm) 59 sprintf (comm, _("Warning: disassembly unreliable - not enough bytes available")); 60 } 61 else 62 { 63 info->memory_error_func (status, addr, info); 64 if (comm) 65 sprintf (comm, _("Error: read from memory failed")); 66 } 67 68 return FALSE; 69 } 70 71 static bfd_boolean 72 msp430dis_opcode_unsigned (bfd_vma addr, 73 disassemble_info * info, 74 unsigned short * return_val, 75 char * comm) 76 { 77 bfd_byte buffer[2]; 78 79 if (msp430dis_read_two_bytes (addr, info, buffer, comm)) 80 { 81 * return_val = bfd_getl16 (buffer); 82 return TRUE; 83 } 84 else 85 { 86 * return_val = 0; 87 return FALSE; 88 } 89 } 90 91 static bfd_boolean 92 msp430dis_opcode_signed (bfd_vma addr, 93 disassemble_info * info, 94 signed int * return_val, 95 char * comm) 96 { 97 bfd_byte buffer[2]; 98 99 if (msp430dis_read_two_bytes (addr, info, buffer, comm)) 100 { 101 int status; 102 103 status = bfd_getl_signed_16 (buffer); 104 if (status & 0x8000) 105 status |= -1U << 16; 106 * return_val = status; 107 return TRUE; 108 } 109 else 110 { 111 * return_val = 0; 112 return FALSE; 113 } 114 } 115 116 static int 117 msp430_nooperands (struct msp430_opcode_s *opcode, 118 bfd_vma addr ATTRIBUTE_UNUSED, 119 unsigned short insn ATTRIBUTE_UNUSED, 120 char *comm, 121 int *cycles) 122 { 123 /* Pop with constant. */ 124 if (insn == 0x43b2) 125 return 0; 126 if (insn == opcode->bin_opcode) 127 return 2; 128 129 if (opcode->fmt == 0) 130 { 131 if ((insn & 0x0f00) != 0x0300 || (insn & 0x0f00) != 0x0200) 132 return 0; 133 134 strcpy (comm, "emulated..."); 135 *cycles = 1; 136 } 137 else 138 { 139 strcpy (comm, "return from interupt"); 140 *cycles = 5; 141 } 142 143 return 2; 144 } 145 146 static int 147 print_as2_reg_name (int regno, char * op1, char * comm1, 148 int c2, int c3, int cd) 149 { 150 switch (regno) 151 { 152 case 2: 153 sprintf (op1, "#4"); 154 sprintf (comm1, "r2 As==10"); 155 return c2; 156 157 case 3: 158 sprintf (op1, "#2"); 159 sprintf (comm1, "r3 As==10"); 160 return c3; 161 162 default: 163 /* Indexed register mode @Rn. */ 164 sprintf (op1, "@r%d", regno); 165 return cd; 166 } 167 } 168 169 static int 170 print_as3_reg_name (int regno, char * op1, char * comm1, 171 int c2, int c3, int cd) 172 { 173 switch (regno) 174 { 175 case 2: 176 sprintf (op1, "#8"); 177 sprintf (comm1, "r2 As==11"); 178 return c2; 179 180 case 3: 181 sprintf (op1, "#-1"); 182 sprintf (comm1, "r3 As==11"); 183 return c3; 184 185 default: 186 /* Post incremented @Rn+. */ 187 sprintf (op1, "@r%d+", regno); 188 return cd; 189 } 190 } 191 192 static int 193 msp430_singleoperand (disassemble_info *info, 194 struct msp430_opcode_s *opcode, 195 bfd_vma addr, 196 unsigned short insn, 197 char *op, 198 char *comm, 199 unsigned short extension_word, 200 int *cycles) 201 { 202 int regs = 0, regd = 0; 203 int ad = 0, as = 0; 204 int where = 0; 205 int cmd_len = 2; 206 int dst = 0; 207 int fmt; 208 int extended_dst = extension_word & 0xf; 209 210 regd = insn & 0x0f; 211 regs = (insn & 0x0f00) >> 8; 212 as = (insn & 0x0030) >> 4; 213 ad = (insn & 0x0080) >> 7; 214 215 if (opcode->fmt < 0) 216 fmt = (- opcode->fmt) - 1; 217 else 218 fmt = opcode->fmt; 219 220 switch (fmt) 221 { 222 case 0: /* Emulated work with dst register. */ 223 if (regs != 2 && regs != 3 && regs != 1) 224 return 0; 225 226 /* Check if not clr insn. */ 227 if (opcode->bin_opcode == 0x4300 && (ad || as)) 228 return 0; 229 230 /* Check if really inc, incd insns. */ 231 if ((opcode->bin_opcode & 0xff00) == 0x5300 && as == 3) 232 return 0; 233 234 if (ad == 0) 235 { 236 *cycles = 1; 237 238 /* Register. */ 239 if (regd == 0) 240 { 241 *cycles += 1; 242 sprintf (op, "r0"); 243 } 244 else if (regd == 1) 245 sprintf (op, "r1"); 246 247 else if (regd == 2) 248 sprintf (op, "r2"); 249 250 else 251 sprintf (op, "r%d", regd); 252 } 253 else /* ad == 1 msp430dis_opcode. */ 254 { 255 if (regd == 0) 256 { 257 /* PC relative. */ 258 if (msp430dis_opcode_signed (addr + 2, info, &dst, comm)) 259 { 260 cmd_len += 2; 261 *cycles = 4; 262 sprintf (op, "0x%04x", dst); 263 sprintf (comm, "PC rel. abs addr 0x%04x", 264 PS ((short) (addr + 2) + dst)); 265 if (extended_dst) 266 { 267 dst |= extended_dst << 16; 268 sprintf (op, "0x%05x", dst); 269 sprintf (comm, "PC rel. abs addr 0x%05lx", 270 (long)((addr + 2 + dst) & 0xfffff)); 271 } 272 } 273 } 274 else if (regd == 2) 275 { 276 /* Absolute. */ 277 if (msp430dis_opcode_signed (addr + 2, info, &dst, comm)) 278 { 279 cmd_len += 2; 280 *cycles = 4; 281 sprintf (op, "&0x%04x", PS (dst)); 282 if (extended_dst) 283 { 284 dst |= extended_dst << 16; 285 sprintf (op, "&0x%05x", dst & 0xfffff); 286 } 287 } 288 } 289 else 290 { 291 if (msp430dis_opcode_signed (addr + 2, info, &dst, comm)) 292 { 293 cmd_len += 2; 294 *cycles = 4; 295 if (extended_dst) 296 { 297 dst |= extended_dst << 16; 298 if (dst & 0x80000) 299 dst |= -1U << 20; 300 } 301 sprintf (op, "%d(r%d)", dst, regd); 302 } 303 } 304 } 305 break; 306 307 case 2: /* rrc, push, call, swpb, rra, sxt, push, call, reti etc... */ 308 if (as == 0) 309 { 310 if (regd == 3) 311 { 312 /* Constsnts. */ 313 sprintf (op, "#0"); 314 sprintf (comm, "r3 As==00"); 315 } 316 else 317 { 318 /* Register. */ 319 sprintf (op, "r%d", regd); 320 } 321 *cycles = 1; 322 } 323 else if (as == 2) 324 { 325 * cycles = print_as2_reg_name (regd, op, comm, 1, 1, 3); 326 } 327 else if (as == 3) 328 { 329 if (regd == 0) 330 { 331 *cycles = 3; 332 /* absolute. @pc+ */ 333 if (msp430dis_opcode_signed (addr + 2, info, &dst, comm)) 334 { 335 cmd_len += 2; 336 sprintf (op, "#%d", dst); 337 if (dst > 9 || dst < 0) 338 sprintf (comm, "#0x%04x", PS (dst)); 339 if (extended_dst) 340 { 341 dst |= extended_dst << 16; 342 if (dst & 0x80000) 343 dst |= -1U << 20; 344 sprintf (op, "#%d", dst); 345 if (dst > 9 || dst < 0) 346 sprintf (comm, "#0x%05x", dst); 347 } 348 } 349 } 350 else 351 * cycles = print_as3_reg_name (regd, op, comm, 1, 1, 3); 352 } 353 else if (as == 1) 354 { 355 *cycles = 4; 356 if (regd == 0) 357 { 358 /* PC relative. */ 359 if (msp430dis_opcode_signed (addr + 2, info, &dst, comm)) 360 { 361 cmd_len += 2; 362 sprintf (op, "0x%04x", PS (dst)); 363 sprintf (comm, "PC rel. 0x%04x", 364 PS ((short) addr + 2 + dst)); 365 if (extended_dst) 366 { 367 dst |= extended_dst << 16; 368 sprintf (op, "0x%05x", dst & 0xffff); 369 sprintf (comm, "PC rel. 0x%05lx", 370 (long)((addr + 2 + dst) & 0xfffff)); 371 } 372 } 373 } 374 else if (regd == 2) 375 { 376 /* Absolute. */ 377 if (msp430dis_opcode_signed (addr + 2, info, &dst, comm)) 378 { 379 cmd_len += 2; 380 sprintf (op, "&0x%04x", PS (dst)); 381 if (extended_dst) 382 { 383 dst |= extended_dst << 16; 384 sprintf (op, "&0x%05x", dst & 0xfffff); 385 } 386 } 387 } 388 else if (regd == 3) 389 { 390 *cycles = 1; 391 sprintf (op, "#1"); 392 sprintf (comm, "r3 As==01"); 393 } 394 else 395 { 396 /* Indexed. */ 397 if (msp430dis_opcode_signed (addr + 2, info, &dst, comm)) 398 { 399 cmd_len += 2; 400 if (extended_dst) 401 { 402 dst |= extended_dst << 16; 403 if (dst & 0x80000) 404 dst |= -1U << 20; 405 } 406 sprintf (op, "%d(r%d)", dst, regd); 407 if (dst > 9 || dst < 0) 408 sprintf (comm, "%05x", dst); 409 } 410 } 411 } 412 break; 413 414 case 3: /* Jumps. */ 415 where = insn & 0x03ff; 416 if (where & 0x200) 417 where |= ~0x03ff; 418 if (where > 512 || where < -511) 419 return 0; 420 421 where *= 2; 422 sprintf (op, "$%+-8d", where + 2); 423 sprintf (comm, "abs 0x%lx", (long) (addr + 2 + where)); 424 *cycles = 2; 425 return 2; 426 break; 427 428 default: 429 cmd_len = 0; 430 } 431 432 return cmd_len; 433 } 434 435 static int 436 msp430_doubleoperand (disassemble_info *info, 437 struct msp430_opcode_s *opcode, 438 bfd_vma addr, 439 unsigned short insn, 440 char *op1, 441 char *op2, 442 char *comm1, 443 char *comm2, 444 unsigned short extension_word, 445 int *cycles) 446 { 447 int regs = 0, regd = 0; 448 int ad = 0, as = 0; 449 int cmd_len = 2; 450 int dst = 0; 451 int fmt; 452 int extended_dst = extension_word & 0xf; 453 int extended_src = (extension_word >> 7) & 0xf; 454 455 regd = insn & 0x0f; 456 regs = (insn & 0x0f00) >> 8; 457 as = (insn & 0x0030) >> 4; 458 ad = (insn & 0x0080) >> 7; 459 460 if (opcode->fmt < 0) 461 fmt = (- opcode->fmt) - 1; 462 else 463 fmt = opcode->fmt; 464 465 if (fmt == 0) 466 { 467 /* Special case: rla and rlc are the only 2 emulated instructions that 468 fall into two operand instructions. */ 469 /* With dst, there are only: 470 Rm Register, 471 x(Rm) Indexed, 472 0xXXXX Relative, 473 &0xXXXX Absolute 474 emulated_ins dst 475 basic_ins dst, dst. */ 476 477 if (regd != regs || as != ad) 478 return 0; /* May be 'data' section. */ 479 480 if (ad == 0) 481 { 482 /* Register mode. */ 483 if (regd == 3) 484 { 485 strcpy (comm1, _("Warning: illegal as emulation instr")); 486 return -1; 487 } 488 489 sprintf (op1, "r%d", regd); 490 *cycles = 1; 491 } 492 else /* ad == 1 */ 493 { 494 if (regd == 0) 495 { 496 /* PC relative, Symbolic. */ 497 if (msp430dis_opcode_signed (addr + 2, info, &dst, comm1)) 498 { 499 cmd_len += 4; 500 *cycles = 6; 501 sprintf (op1, "0x%04x", PS (dst)); 502 sprintf (comm1, "PC rel. 0x%04x", 503 PS ((short) addr + 2 + dst)); 504 if (extension_word) 505 { 506 dst |= extended_dst << 16; 507 if (dst & 0x80000) 508 dst |= -1U << 20; 509 sprintf (op1, "0x%05x", dst & 0xfffff); 510 sprintf (comm1, "PC rel. 0x%05lx", 511 (long)((addr + 2 + dst) & 0xfffff)); 512 } 513 } 514 } 515 else if (regd == 2) 516 { 517 /* Absolute. */ 518 if (msp430dis_opcode_signed (addr + 2, info, &dst, comm1)) 519 { 520 int src; 521 522 /* If the 'src' field is not the same as the dst 523 then this is not an rla instruction. */ 524 if (msp430dis_opcode_signed (addr + 4, info, &src, comm2)) 525 { 526 if (src != dst) 527 return 0; 528 } 529 cmd_len += 4; 530 *cycles = 6; 531 sprintf (op1, "&0x%04x", PS (dst)); 532 if (extension_word) 533 { 534 dst |= extended_dst << 16; 535 sprintf (op1, "&0x%05x", dst & 0xfffff); 536 } 537 } 538 } 539 else 540 { 541 /* Indexed. */ 542 if (msp430dis_opcode_signed (addr + 2, info, &dst, comm1)) 543 { 544 if (extension_word) 545 { 546 dst |= extended_dst << 16; 547 if (dst & 0x80000) 548 dst |= -1U << 20; 549 } 550 cmd_len += 4; 551 *cycles = 6; 552 sprintf (op1, "%d(r%d)", dst, regd); 553 if (dst > 9 || dst < -9) 554 sprintf (comm1, "#0x%05x", dst); 555 } 556 } 557 } 558 559 *op2 = 0; 560 *comm2 = 0; 561 562 return cmd_len; 563 } 564 565 /* Two operands exactly. */ 566 if (ad == 0 && regd == 3) 567 { 568 /* R2/R3 are illegal as dest: may be data section. */ 569 strcpy (comm1, _("Warning: illegal as 2-op instr")); 570 return -1; 571 } 572 573 /* Source. */ 574 if (as == 0) 575 { 576 *cycles = 1; 577 if (regs == 3) 578 { 579 /* Constants. */ 580 sprintf (op1, "#0"); 581 sprintf (comm1, "r3 As==00"); 582 } 583 else 584 { 585 /* Register. */ 586 sprintf (op1, "r%d", regs); 587 } 588 } 589 else if (as == 2) 590 { 591 * cycles = print_as2_reg_name (regs, op1, comm1, 1, 1, regs == 0 ? 3 : 2); 592 } 593 else if (as == 3) 594 { 595 if (regs == 0) 596 { 597 *cycles = 3; 598 /* Absolute. @pc+. */ 599 if (msp430dis_opcode_signed (addr + 2, info, &dst, comm1)) 600 { 601 cmd_len += 2; 602 sprintf (op1, "#%d", dst); 603 if (dst > 9 || dst < 0) 604 sprintf (comm1, "#0x%04x", PS (dst)); 605 if (extension_word) 606 { 607 dst &= 0xffff; 608 dst |= extended_src << 16; 609 if (dst & 0x80000) 610 dst |= -1U << 20; 611 sprintf (op1, "#%d", dst); 612 if (dst > 9 || dst < 0) 613 sprintf (comm1, "0x%05x", dst & 0xfffff); 614 } 615 } 616 } 617 else 618 * cycles = print_as3_reg_name (regs, op1, comm1, 1, 1, 2); 619 } 620 else if (as == 1) 621 { 622 if (regs == 0) 623 { 624 *cycles = 4; 625 /* PC relative. */ 626 if (msp430dis_opcode_signed (addr + 2, info, &dst, comm1)) 627 { 628 cmd_len += 2; 629 sprintf (op1, "0x%04x", PS (dst)); 630 sprintf (comm1, "PC rel. 0x%04x", 631 PS ((short) addr + 2 + dst)); 632 if (extension_word) 633 { 634 dst &= 0xffff; 635 dst |= extended_src << 16; 636 if (dst & 0x80000) 637 dst |= -1U << 20; 638 sprintf (op1, "0x%05x", dst & 0xfffff); 639 sprintf (comm1, "PC rel. 0x%05lx", 640 (long) ((addr + 2 + dst) & 0xfffff)); 641 } 642 } 643 } 644 else if (regs == 2) 645 { 646 *cycles = 2; 647 /* Absolute. */ 648 if (msp430dis_opcode_signed (addr + 2, info, &dst, comm1)) 649 { 650 cmd_len += 2; 651 sprintf (op1, "&0x%04x", PS (dst)); 652 sprintf (comm1, "0x%04x", PS (dst)); 653 if (extension_word) 654 { 655 dst &= 0xffff; 656 dst |= extended_src << 16; 657 sprintf (op1, "&0x%05x", dst & 0xfffff); 658 * comm1 = 0; 659 } 660 } 661 } 662 else if (regs == 3) 663 { 664 *cycles = 1; 665 sprintf (op1, "#1"); 666 sprintf (comm1, "r3 As==01"); 667 } 668 else 669 { 670 *cycles = 3; 671 /* Indexed. */ 672 if (msp430dis_opcode_signed (addr + 2, info, &dst, comm1)) 673 { 674 cmd_len += 2; 675 if (extension_word) 676 { 677 dst &= 0xffff; 678 dst |= extended_src << 16; 679 if (dst & 0x80000) 680 dst |= -1U << 20; 681 } 682 sprintf (op1, "%d(r%d)", dst, regs); 683 if (dst > 9 || dst < -9) 684 sprintf (comm1, "0x%05x", dst); 685 } 686 } 687 } 688 689 /* Destination. Special care needed on addr + XXXX. */ 690 691 if (ad == 0) 692 { 693 /* Register. */ 694 if (regd == 0) 695 { 696 *cycles += 1; 697 sprintf (op2, "r0"); 698 } 699 else if (regd == 1) 700 sprintf (op2, "r1"); 701 702 else if (regd == 2) 703 sprintf (op2, "r2"); 704 705 else 706 sprintf (op2, "r%d", regd); 707 } 708 else /* ad == 1. */ 709 { 710 * cycles += 3; 711 712 if (regd == 0) 713 { 714 /* PC relative. */ 715 *cycles += 1; 716 if (msp430dis_opcode_signed (addr + cmd_len, info, &dst, comm2)) 717 { 718 sprintf (op2, "0x%04x", PS (dst)); 719 sprintf (comm2, "PC rel. 0x%04x", 720 PS ((short) addr + cmd_len + dst)); 721 if (extension_word) 722 { 723 dst |= extended_dst << 16; 724 if (dst & 0x80000) 725 dst |= -1U << 20; 726 sprintf (op2, "0x%05x", dst & 0xfffff); 727 sprintf (comm2, "PC rel. 0x%05lx", 728 (long)((addr + cmd_len + dst) & 0xfffff)); 729 } 730 } 731 cmd_len += 2; 732 } 733 else if (regd == 2) 734 { 735 /* Absolute. */ 736 if (msp430dis_opcode_signed (addr + cmd_len, info, &dst, comm2)) 737 { 738 cmd_len += 2; 739 sprintf (op2, "&0x%04x", PS (dst)); 740 if (extension_word) 741 { 742 dst |= extended_dst << 16; 743 sprintf (op2, "&0x%05x", dst & 0xfffff); 744 } 745 } 746 } 747 else 748 { 749 if (msp430dis_opcode_signed (addr + cmd_len, info, &dst, comm2)) 750 { 751 cmd_len += 2; 752 if (dst > 9 || dst < 0) 753 sprintf (comm2, "0x%04x", PS (dst)); 754 if (extension_word) 755 { 756 dst |= extended_dst << 16; 757 if (dst & 0x80000) 758 dst |= -1U << 20; 759 if (dst > 9 || dst < 0) 760 sprintf (comm2, "0x%05x", dst & 0xfffff); 761 } 762 sprintf (op2, "%d(r%d)", dst, regd); 763 } 764 } 765 } 766 767 return cmd_len; 768 } 769 770 static int 771 msp430_branchinstr (disassemble_info *info, 772 struct msp430_opcode_s *opcode ATTRIBUTE_UNUSED, 773 bfd_vma addr ATTRIBUTE_UNUSED, 774 unsigned short insn, 775 char *op1, 776 char *comm1, 777 int *cycles) 778 { 779 int regs = 0, regd = 0; 780 int as = 0; 781 int cmd_len = 2; 782 int dst = 0; 783 unsigned short udst = 0; 784 785 regd = insn & 0x0f; 786 regs = (insn & 0x0f00) >> 8; 787 as = (insn & 0x0030) >> 4; 788 789 if (regd != 0) /* Destination register is not a PC. */ 790 return 0; 791 792 /* dst is a source register. */ 793 if (as == 0) 794 { 795 /* Constants. */ 796 if (regs == 3) 797 { 798 *cycles = 1; 799 sprintf (op1, "#0"); 800 sprintf (comm1, "r3 As==00"); 801 } 802 else 803 { 804 /* Register. */ 805 *cycles = 1; 806 sprintf (op1, "r%d", regs); 807 } 808 } 809 else if (as == 2) 810 { 811 * cycles = print_as2_reg_name (regs, op1, comm1, 2, 1, 2); 812 } 813 else if (as == 3) 814 { 815 if (regs == 0) 816 { 817 /* Absolute. @pc+ */ 818 *cycles = 3; 819 if (msp430dis_opcode_unsigned (addr + 2, info, &udst, comm1)) 820 { 821 cmd_len += 2; 822 sprintf (op1, "#0x%04x", PS (udst)); 823 } 824 } 825 else 826 * cycles = print_as3_reg_name (regs, op1, comm1, 1, 1, 2); 827 } 828 else if (as == 1) 829 { 830 * cycles = 3; 831 832 if (regs == 0) 833 { 834 /* PC relative. */ 835 if (msp430dis_opcode_signed (addr + 2, info, &dst, comm1)) 836 { 837 cmd_len += 2; 838 (*cycles)++; 839 sprintf (op1, "0x%04x", PS (dst)); 840 sprintf (comm1, "PC rel. 0x%04x", 841 PS ((short) addr + 2 + dst)); 842 } 843 } 844 else if (regs == 2) 845 { 846 /* Absolute. */ 847 if (msp430dis_opcode_unsigned (addr + 2, info, &udst, comm1)) 848 { 849 cmd_len += 2; 850 sprintf (op1, "&0x%04x", PS (udst)); 851 } 852 } 853 else if (regs == 3) 854 { 855 (*cycles)--; 856 sprintf (op1, "#1"); 857 sprintf (comm1, "r3 As==01"); 858 } 859 else 860 { 861 /* Indexed. */ 862 if (msp430dis_opcode_signed (addr + 2, info, &dst, comm1)) 863 { 864 cmd_len += 2; 865 sprintf (op1, "%d(r%d)", dst, regs); 866 } 867 } 868 } 869 870 return cmd_len; 871 } 872 873 static int 874 msp430x_calla_instr (disassemble_info * info, 875 bfd_vma addr, 876 unsigned short insn, 877 char * op1, 878 char * comm1, 879 int * cycles) 880 { 881 unsigned int ureg = insn & 0xf; 882 int reg = insn & 0xf; 883 int am = (insn & 0xf0) >> 4; 884 int cmd_len = 2; 885 unsigned short udst = 0; 886 int dst = 0; 887 888 switch (am) 889 { 890 case 4: /* CALLA Rdst */ 891 *cycles = 1; 892 sprintf (op1, "r%d", reg); 893 break; 894 895 case 5: /* CALLA x(Rdst) */ 896 *cycles = 3; 897 if (msp430dis_opcode_signed (addr + 2, info, &dst, comm1)) 898 { 899 cmd_len += 2; 900 sprintf (op1, "%d(r%d)", dst, reg); 901 if (reg == 0) 902 sprintf (comm1, "PC rel. 0x%05lx", (long) (addr + 2 + dst)); 903 else 904 sprintf (comm1, "0x%05x", dst); 905 } 906 break; 907 908 case 6: /* CALLA @Rdst */ 909 *cycles = 2; 910 sprintf (op1, "@r%d", reg); 911 break; 912 913 case 7: /* CALLA @Rdst+ */ 914 *cycles = 2; 915 sprintf (op1, "@r%d+", reg); 916 break; 917 918 case 8: /* CALLA &abs20 */ 919 if (msp430dis_opcode_unsigned (addr + 2, info, &udst, comm1)) 920 { 921 cmd_len += 2; 922 *cycles = 4; 923 sprintf (op1, "&%d", (ureg << 16) + udst); 924 sprintf (comm1, "0x%05x", (ureg << 16) + udst); 925 } 926 break; 927 928 case 9: /* CALLA pcrel-sym */ 929 if (msp430dis_opcode_signed (addr + 2, info, &dst, comm1)) 930 { 931 cmd_len += 2; 932 *cycles = 4; 933 sprintf (op1, "%d(PC)", (reg << 16) + dst); 934 sprintf (comm1, "PC rel. 0x%05lx", 935 (long) (addr + 2 + dst + (reg << 16))); 936 } 937 break; 938 939 case 11: /* CALLA #imm20 */ 940 if (msp430dis_opcode_unsigned (addr + 2, info, &udst, comm1)) 941 { 942 cmd_len += 2; 943 *cycles = 4; 944 sprintf (op1, "#%d", (ureg << 16) + udst); 945 sprintf (comm1, "0x%05x", (ureg << 16) + udst); 946 } 947 break; 948 949 default: 950 strcpy (comm1, _("Warning: unrecognised CALLA addressing mode")); 951 return -1; 952 } 953 954 return cmd_len; 955 } 956 957 int 958 print_insn_msp430 (bfd_vma addr, disassemble_info *info) 959 { 960 void *stream = info->stream; 961 fprintf_ftype prin = info->fprintf_func; 962 struct msp430_opcode_s *opcode; 963 char op1[32], op2[32], comm1[64], comm2[64]; 964 int cmd_len = 0; 965 unsigned short insn; 966 int cycles = 0; 967 char *bc = ""; 968 unsigned short extension_word = 0; 969 unsigned short bits; 970 971 if (! msp430dis_opcode_unsigned (addr, info, &insn, NULL)) 972 { 973 prin (stream, ".word 0xffff; ????"); 974 return 2; 975 } 976 977 if (((int) addr & 0xffff) > 0xffdf) 978 { 979 (*prin) (stream, "interrupt service routine at 0x%04x", 0xffff & insn); 980 return 2; 981 } 982 983 *comm1 = 0; 984 *comm2 = 0; 985 986 /* Check for an extension word. */ 987 if ((insn & 0xf800) == 0x1800) 988 { 989 extension_word = insn; 990 addr += 2; 991 if (! msp430dis_opcode_unsigned (addr, info, &insn, NULL)) 992 { 993 prin (stream, ".word 0x%04x, 0xffff; ????", 994 extension_word); 995 return 4; 996 } 997 } 998 999 for (opcode = msp430_opcodes; opcode->name; opcode++) 1000 { 1001 if ((insn & opcode->bin_mask) == opcode->bin_opcode 1002 && opcode->bin_opcode != 0x9300) 1003 { 1004 *op1 = 0; 1005 *op2 = 0; 1006 *comm1 = 0; 1007 *comm2 = 0; 1008 1009 /* r0 as destination. Ad should be zero. */ 1010 if (opcode->insn_opnumb == 3 1011 && (insn & 0x000f) == 0 1012 && (insn & 0x0080) == 0) 1013 { 1014 cmd_len += 1015 msp430_branchinstr (info, opcode, addr, insn, op1, comm1, 1016 &cycles); 1017 if (cmd_len) 1018 break; 1019 } 1020 1021 switch (opcode->insn_opnumb) 1022 { 1023 int n; 1024 int reg; 1025 1026 case 4: 1027 cmd_len += msp430x_calla_instr (info, addr, insn, 1028 op1, comm1, & cycles); 1029 break; 1030 1031 case 5: /* PUSHM/POPM */ 1032 n = (insn & 0xf0) >> 4; 1033 reg = (insn & 0xf); 1034 1035 sprintf (op1, "#%d", n + 1); 1036 if (opcode->bin_opcode == 0x1400) 1037 /* PUSHM */ 1038 sprintf (op2, "r%d", reg); 1039 else 1040 /* POPM */ 1041 sprintf (op2, "r%d", reg + n); 1042 if (insn & 0x100) 1043 sprintf (comm1, "16-bit words"); 1044 else 1045 { 1046 sprintf (comm1, "20-bit words"); 1047 bc =".a"; 1048 } 1049 1050 cycles = 2; /*FIXME*/ 1051 cmd_len = 2; 1052 break; 1053 1054 case 6: /* RRAM, RRCM, RRUM, RLAM. */ 1055 n = ((insn >> 10) & 0x3) + 1; 1056 reg = (insn & 0xf); 1057 if ((insn & 0x10) == 0) 1058 bc =".a"; 1059 sprintf (op1, "#%d", n); 1060 sprintf (op2, "r%d", reg); 1061 cycles = 2; /*FIXME*/ 1062 cmd_len = 2; 1063 break; 1064 1065 case 8: /* ADDA, CMPA, SUBA. */ 1066 reg = (insn & 0xf); 1067 n = (insn >> 8) & 0xf; 1068 if (insn & 0x40) 1069 { 1070 sprintf (op1, "r%d", n); 1071 cmd_len = 2; 1072 } 1073 else 1074 { 1075 n <<= 16; 1076 if (msp430dis_opcode_unsigned (addr + 2, info, &bits, comm1)) 1077 { 1078 n |= bits; 1079 sprintf (op1, "#%d", n); 1080 if (n > 9 || n < 0) 1081 sprintf (comm1, "0x%05x", n); 1082 } 1083 cmd_len = 4; 1084 } 1085 sprintf (op2, "r%d", reg); 1086 cycles = 2; /*FIXME*/ 1087 break; 1088 1089 case 9: /* MOVA */ 1090 reg = (insn & 0xf); 1091 n = (insn >> 8) & 0xf; 1092 switch ((insn >> 4) & 0xf) 1093 { 1094 case 0: /* MOVA @Rsrc, Rdst */ 1095 cmd_len = 2; 1096 sprintf (op1, "@r%d", n); 1097 if (strcmp (opcode->name, "bra") != 0) 1098 sprintf (op2, "r%d", reg); 1099 break; 1100 1101 case 1: /* MOVA @Rsrc+, Rdst */ 1102 cmd_len = 2; 1103 if (strcmp (opcode->name, "reta") != 0) 1104 { 1105 sprintf (op1, "@r%d+", n); 1106 if (strcmp (opcode->name, "bra") != 0) 1107 sprintf (op2, "r%d", reg); 1108 } 1109 break; 1110 1111 case 2: /* MOVA &abs20, Rdst */ 1112 cmd_len = 4; 1113 n <<= 16; 1114 if (msp430dis_opcode_unsigned (addr + 2, info, &bits, comm1)) 1115 { 1116 n |= bits; 1117 sprintf (op1, "&%d", n); 1118 if (n > 9 || n < 0) 1119 sprintf (comm1, "0x%05x", n); 1120 if (strcmp (opcode->name, "bra") != 0) 1121 sprintf (op2, "r%d", reg); 1122 } 1123 break; 1124 1125 case 3: /* MOVA x(Rsrc), Rdst */ 1126 cmd_len = 4; 1127 if (strcmp (opcode->name, "bra") != 0) 1128 sprintf (op2, "r%d", reg); 1129 reg = n; 1130 if (msp430dis_opcode_signed (addr + 2, info, &n, comm1)) 1131 { 1132 sprintf (op1, "%d(r%d)", n, reg); 1133 if (n > 9 || n < 0) 1134 { 1135 if (reg == 0) 1136 sprintf (comm1, "PC rel. 0x%05lx", 1137 (long) (addr + 2 + n)); 1138 else 1139 sprintf (comm1, "0x%05x", n); 1140 } 1141 } 1142 break; 1143 1144 case 6: /* MOVA Rsrc, &abs20 */ 1145 cmd_len = 4; 1146 reg <<= 16; 1147 if (msp430dis_opcode_unsigned (addr + 2, info, &bits, comm2)) 1148 { 1149 reg |= bits; 1150 sprintf (op1, "r%d", n); 1151 sprintf (op2, "&%d", reg); 1152 if (reg > 9 || reg < 0) 1153 sprintf (comm2, "0x%05x", reg); 1154 } 1155 break; 1156 1157 case 7: /* MOVA Rsrc, x(Rdst) */ 1158 cmd_len = 4; 1159 sprintf (op1, "r%d", n); 1160 if (msp430dis_opcode_signed (addr + 2, info, &n, comm2)) 1161 { 1162 sprintf (op2, "%d(r%d)", n, reg); 1163 if (n > 9 || n < 0) 1164 { 1165 if (reg == 0) 1166 sprintf (comm2, "PC rel. 0x%05lx", 1167 (long) (addr + 2 + n)); 1168 else 1169 sprintf (comm2, "0x%05x", n); 1170 } 1171 } 1172 break; 1173 1174 case 8: /* MOVA #imm20, Rdst */ 1175 cmd_len = 4; 1176 n <<= 16; 1177 if (msp430dis_opcode_unsigned (addr + 2, info, &bits, comm1)) 1178 { 1179 n |= bits; 1180 if (n & 0x80000) 1181 n |= -1U << 20; 1182 sprintf (op1, "#%d", n); 1183 if (n > 9 || n < 0) 1184 sprintf (comm1, "0x%05x", n); 1185 if (strcmp (opcode->name, "bra") != 0) 1186 sprintf (op2, "r%d", reg); 1187 } 1188 break; 1189 1190 case 12: /* MOVA Rsrc, Rdst */ 1191 cmd_len = 2; 1192 sprintf (op1, "r%d", n); 1193 if (strcmp (opcode->name, "bra") != 0) 1194 sprintf (op2, "r%d", reg); 1195 break; 1196 1197 default: 1198 break; 1199 } 1200 cycles = 2; /* FIXME */ 1201 break; 1202 } 1203 1204 if (cmd_len) 1205 break; 1206 1207 switch (opcode->insn_opnumb) 1208 { 1209 case 0: 1210 cmd_len += msp430_nooperands (opcode, addr, insn, comm1, &cycles); 1211 break; 1212 case 2: 1213 cmd_len += 1214 msp430_doubleoperand (info, opcode, addr, insn, op1, op2, 1215 comm1, comm2, 1216 extension_word, 1217 &cycles); 1218 if (insn & BYTE_OPERATION) 1219 { 1220 if (extension_word != 0 && ((extension_word & BYTE_OPERATION) == 0)) 1221 bc = ".a"; 1222 else 1223 bc = ".b"; 1224 } 1225 else if (extension_word) 1226 { 1227 if (extension_word & BYTE_OPERATION) 1228 bc = ".w"; 1229 else 1230 { 1231 bc = ".?"; 1232 sprintf (comm2, _("Warning: reserved use of A/L and B/W bits detected")); 1233 } 1234 } 1235 1236 break; 1237 case 1: 1238 cmd_len += 1239 msp430_singleoperand (info, opcode, addr, insn, op1, comm1, 1240 extension_word, 1241 &cycles); 1242 if (extension_word 1243 && (strcmp (opcode->name, "swpb") == 0 1244 || strcmp (opcode->name, "sxt") == 0)) 1245 { 1246 if (insn & BYTE_OPERATION) 1247 { 1248 bc = ".?"; 1249 sprintf (comm2, _("Warning: reserved use of A/L and B/W bits detected")); 1250 } 1251 else if (extension_word & BYTE_OPERATION) 1252 bc = ".w"; 1253 else 1254 bc = ".a"; 1255 } 1256 else if (insn & BYTE_OPERATION && opcode->fmt != 3) 1257 { 1258 if (extension_word != 0 && ((extension_word & BYTE_OPERATION) == 0)) 1259 bc = ".a"; 1260 else 1261 bc = ".b"; 1262 } 1263 else if (extension_word) 1264 { 1265 if (extension_word & (1 << 6)) 1266 bc = ".w"; 1267 else 1268 { 1269 bc = ".?"; 1270 sprintf (comm2, _("Warning: reserved use of A/L and B/W bits detected")); 1271 } 1272 } 1273 break; 1274 default: 1275 break; 1276 } 1277 } 1278 1279 if (cmd_len) 1280 break; 1281 } 1282 1283 if (cmd_len < 1) 1284 { 1285 /* Unknown opcode, or invalid combination of operands. */ 1286 if (extension_word) 1287 { 1288 prin (stream, ".word 0x%04x, 0x%04x; ????", extension_word, PS (insn)); 1289 if (*comm1) 1290 prin (stream, "\t %s", comm1); 1291 return 4; 1292 } 1293 (*prin) (stream, ".word 0x%04x; ????", PS (insn)); 1294 return 2; 1295 } 1296 1297 /* Display the repeat count (if set) for extended register mode. */ 1298 if (cmd_len == 2 && ((extension_word & 0xf) != 0)) 1299 { 1300 if (extension_word & (1 << 7)) 1301 prin (stream, "rpt r%d { ", extension_word & 0xf); 1302 else 1303 prin (stream, "rpt #%d { ", (extension_word & 0xf) + 1); 1304 } 1305 1306 /* Special case: RRC with an extension word and the ZC bit set is actually RRU. */ 1307 if (extension_word 1308 && (extension_word & IGNORE_CARRY_BIT) 1309 && strcmp (opcode->name, "rrc") == 0) 1310 (*prin) (stream, "rrux%s", bc); 1311 else if (extension_word && opcode->name[strlen (opcode->name) - 1] != 'x') 1312 (*prin) (stream, "%sx%s", opcode->name, bc); 1313 else 1314 (*prin) (stream, "%s%s", opcode->name, bc); 1315 1316 if (*op1) 1317 (*prin) (stream, "\t%s", op1); 1318 if (*op2) 1319 (*prin) (stream, ","); 1320 1321 if (strlen (op1) < 7) 1322 (*prin) (stream, "\t"); 1323 if (!strlen (op1)) 1324 (*prin) (stream, "\t"); 1325 1326 if (*op2) 1327 (*prin) (stream, "%s", op2); 1328 if (strlen (op2) < 8) 1329 (*prin) (stream, "\t"); 1330 1331 if (*comm1 || *comm2) 1332 (*prin) (stream, ";"); 1333 else if (cycles) 1334 { 1335 if (*op2) 1336 (*prin) (stream, ";"); 1337 else 1338 { 1339 if (strlen (op1) < 7) 1340 (*prin) (stream, ";"); 1341 else 1342 (*prin) (stream, "\t;"); 1343 } 1344 } 1345 if (*comm1) 1346 (*prin) (stream, "%s", comm1); 1347 if (*comm1 && *comm2) 1348 (*prin) (stream, ","); 1349 if (*comm2) 1350 (*prin) (stream, " %s", comm2); 1351 1352 if (extension_word) 1353 cmd_len += 2; 1354 1355 return cmd_len; 1356 } 1357