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