msp430-dis.c revision 1.1.1.9
1/* Disassemble MSP430 instructions. 2 Copyright (C) 2002-2024 Free Software Foundation, Inc. 3 4 Contributed by Dmitry Diky <diwil@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 "disassemble.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 40static bool 41msp430dis_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 71static bool 72msp430dis_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 91static bool 92msp430dis_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 116static int 117msp430_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 146static int 147print_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 169static int 170print_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 192static int 193msp430_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 else 274 return -1; 275 } 276 else if (regd == 2) 277 { 278 /* Absolute. */ 279 if (msp430dis_opcode_signed (addr + 2, info, &dst, comm)) 280 { 281 cmd_len += 2; 282 *cycles = 4; 283 sprintf (op, "&0x%04x", PS (dst)); 284 if (extended_dst) 285 { 286 dst |= extended_dst << 16; 287 sprintf (op, "&0x%05x", dst & 0xfffff); 288 } 289 } 290 else 291 return -1; 292 } 293 else 294 { 295 if (msp430dis_opcode_signed (addr + 2, info, &dst, comm)) 296 { 297 cmd_len += 2; 298 *cycles = 4; 299 if (extended_dst) 300 { 301 dst |= extended_dst << 16; 302 if (dst & 0x80000) 303 dst |= -1U << 20; 304 } 305 sprintf (op, "%d(r%d)", dst, regd); 306 } 307 else 308 return -1; 309 } 310 } 311 break; 312 313 case 2: /* rrc, push, call, swpb, rra, sxt, push, call, reti etc... */ 314 if (as == 0) 315 { 316 if (regd == 3) 317 { 318 /* Constsnts. */ 319 sprintf (op, "#0"); 320 sprintf (comm, "r3 As==00"); 321 } 322 else 323 { 324 /* Register. */ 325 sprintf (op, "r%d", regd); 326 } 327 *cycles = 1; 328 } 329 else if (as == 2) 330 { 331 * cycles = print_as2_reg_name (regd, op, comm, 1, 1, 3); 332 } 333 else if (as == 3) 334 { 335 if (regd == 0) 336 { 337 *cycles = 3; 338 /* absolute. @pc+ */ 339 if (msp430dis_opcode_signed (addr + 2, info, &dst, comm)) 340 { 341 cmd_len += 2; 342 sprintf (op, "#%d", dst); 343 if (dst > 9 || dst < 0) 344 sprintf (comm, "#0x%04x", PS (dst)); 345 if (extended_dst) 346 { 347 dst |= extended_dst << 16; 348 if (dst & 0x80000) 349 dst |= -1U << 20; 350 sprintf (op, "#%d", dst); 351 if (dst > 9 || dst < 0) 352 sprintf (comm, "#0x%05x", dst); 353 } 354 } 355 else 356 return -1; 357 } 358 else 359 * cycles = print_as3_reg_name (regd, op, comm, 1, 1, 3); 360 } 361 else if (as == 1) 362 { 363 *cycles = 4; 364 if (regd == 0) 365 { 366 /* PC relative. */ 367 if (msp430dis_opcode_signed (addr + 2, info, &dst, comm)) 368 { 369 cmd_len += 2; 370 sprintf (op, "0x%04x", PS (dst)); 371 sprintf (comm, "PC rel. 0x%04x", 372 PS ((short) addr + 2 + dst)); 373 if (extended_dst) 374 { 375 dst |= extended_dst << 16; 376 sprintf (op, "0x%05x", dst & 0xffff); 377 sprintf (comm, "PC rel. 0x%05lx", 378 (long)((addr + 2 + dst) & 0xfffff)); 379 } 380 } 381 else 382 return -1; 383 } 384 else if (regd == 2) 385 { 386 /* Absolute. */ 387 if (msp430dis_opcode_signed (addr + 2, info, &dst, comm)) 388 { 389 cmd_len += 2; 390 sprintf (op, "&0x%04x", PS (dst)); 391 if (extended_dst) 392 { 393 dst |= extended_dst << 16; 394 sprintf (op, "&0x%05x", dst & 0xfffff); 395 } 396 } 397 else 398 return -1; 399 } 400 else if (regd == 3) 401 { 402 *cycles = 1; 403 sprintf (op, "#1"); 404 sprintf (comm, "r3 As==01"); 405 } 406 else 407 { 408 /* Indexed. */ 409 if (msp430dis_opcode_signed (addr + 2, info, &dst, comm)) 410 { 411 cmd_len += 2; 412 if (extended_dst) 413 { 414 dst |= extended_dst << 16; 415 if (dst & 0x80000) 416 dst |= -1U << 20; 417 } 418 sprintf (op, "%d(r%d)", dst, regd); 419 if (dst > 9 || dst < 0) 420 sprintf (comm, "%05x", dst); 421 } 422 else 423 return -1; 424 } 425 } 426 break; 427 428 case 3: /* Jumps. */ 429 where = insn & 0x03ff; 430 if (where & 0x200) 431 where |= ~0x03ff; 432 if (where > 512 || where < -511) 433 return 0; 434 435 where *= 2; 436 sprintf (op, "$%+-8d", where + 2); 437 sprintf (comm, "abs 0x%lx", (long) (addr + 2 + where)); 438 *cycles = 2; 439 return 2; 440 break; 441 442 default: 443 cmd_len = 0; 444 } 445 446 return cmd_len; 447} 448 449static int 450msp430_doubleoperand (disassemble_info *info, 451 struct msp430_opcode_s *opcode, 452 bfd_vma addr, 453 unsigned short insn, 454 char *op1, 455 char *op2, 456 char *comm1, 457 char *comm2, 458 unsigned short extension_word, 459 int *cycles) 460{ 461 int regs = 0, regd = 0; 462 int ad = 0, as = 0; 463 int cmd_len = 2; 464 int dst = 0; 465 int fmt; 466 int extended_dst = extension_word & 0xf; 467 int extended_src = (extension_word >> 7) & 0xf; 468 469 regd = insn & 0x0f; 470 regs = (insn & 0x0f00) >> 8; 471 as = (insn & 0x0030) >> 4; 472 ad = (insn & 0x0080) >> 7; 473 474 if (opcode->fmt < 0) 475 fmt = (- opcode->fmt) - 1; 476 else 477 fmt = opcode->fmt; 478 479 if (fmt == 0) 480 { 481 /* Special case: rla and rlc are the only 2 emulated instructions that 482 fall into two operand instructions. */ 483 /* With dst, there are only: 484 Rm Register, 485 x(Rm) Indexed, 486 0xXXXX Relative, 487 &0xXXXX Absolute 488 emulated_ins dst 489 basic_ins dst, dst. */ 490 491 if (regd != regs || as != ad) 492 return 0; /* May be 'data' section. */ 493 494 if (ad == 0) 495 { 496 /* Register mode. */ 497 if (regd == 3) 498 { 499 strcpy (comm1, _("Warning: illegal as emulation instr")); 500 return -1; 501 } 502 503 sprintf (op1, "r%d", regd); 504 *cycles = 1; 505 } 506 else /* ad == 1 */ 507 { 508 if (regd == 0) 509 { 510 /* PC relative, Symbolic. */ 511 if (msp430dis_opcode_signed (addr + 2, info, &dst, comm1)) 512 { 513 cmd_len += 4; 514 *cycles = 6; 515 sprintf (op1, "0x%04x", PS (dst)); 516 sprintf (comm1, "PC rel. 0x%04x", 517 PS ((short) addr + 2 + dst)); 518 if (extension_word) 519 { 520 dst |= extended_dst << 16; 521 if (dst & 0x80000) 522 dst |= -1U << 20; 523 sprintf (op1, "0x%05x", dst & 0xfffff); 524 sprintf (comm1, "PC rel. 0x%05lx", 525 (long)((addr + 2 + dst) & 0xfffff)); 526 } 527 } 528 else 529 return -1; 530 } 531 else if (regd == 2) 532 { 533 /* Absolute. */ 534 if (msp430dis_opcode_signed (addr + 2, info, &dst, comm1)) 535 { 536 int src; 537 538 /* If the 'src' field is not the same as the dst 539 then this is not an rla instruction. */ 540 if (msp430dis_opcode_signed (addr + 4, info, &src, comm2)) 541 { 542 if (src != dst) 543 return 0; 544 } 545 else 546 return -1; 547 cmd_len += 4; 548 *cycles = 6; 549 sprintf (op1, "&0x%04x", PS (dst)); 550 if (extension_word) 551 { 552 dst |= extended_dst << 16; 553 sprintf (op1, "&0x%05x", dst & 0xfffff); 554 } 555 } 556 else 557 return -1; 558 } 559 else 560 { 561 /* Indexed. */ 562 if (msp430dis_opcode_signed (addr + 2, info, &dst, comm1)) 563 { 564 if (extension_word) 565 { 566 dst |= extended_dst << 16; 567 if (dst & 0x80000) 568 dst |= -1U << 20; 569 } 570 cmd_len += 4; 571 *cycles = 6; 572 sprintf (op1, "%d(r%d)", dst, regd); 573 if (dst > 9 || dst < -9) 574 sprintf (comm1, "#0x%05x", dst); 575 } 576 else 577 return -1; 578 } 579 } 580 581 *op2 = 0; 582 *comm2 = 0; 583 584 return cmd_len; 585 } 586 587 /* Two operands exactly. */ 588 if (ad == 0 && regd == 3) 589 { 590 /* R2/R3 are illegal as dest: may be data section. */ 591 strcpy (comm1, _("Warning: illegal as 2-op instr")); 592 return -1; 593 } 594 595 /* Source. */ 596 if (as == 0) 597 { 598 *cycles = 1; 599 if (regs == 3) 600 { 601 /* Constants. */ 602 sprintf (op1, "#0"); 603 sprintf (comm1, "r3 As==00"); 604 } 605 else 606 { 607 /* Register. */ 608 sprintf (op1, "r%d", regs); 609 } 610 } 611 else if (as == 2) 612 { 613 * cycles = print_as2_reg_name (regs, op1, comm1, 1, 1, regs == 0 ? 3 : 2); 614 } 615 else if (as == 3) 616 { 617 if (regs == 0) 618 { 619 *cycles = 3; 620 /* Absolute. @pc+. */ 621 if (msp430dis_opcode_signed (addr + 2, info, &dst, comm1)) 622 { 623 cmd_len += 2; 624 sprintf (op1, "#%d", dst); 625 if (dst > 9 || dst < 0) 626 sprintf (comm1, "#0x%04x", PS (dst)); 627 if (extension_word) 628 { 629 dst &= 0xffff; 630 dst |= extended_src << 16; 631 if (dst & 0x80000) 632 dst |= -1U << 20; 633 sprintf (op1, "#%d", dst); 634 if (dst > 9 || dst < 0) 635 sprintf (comm1, "0x%05x", dst & 0xfffff); 636 } 637 } 638 else 639 return -1; 640 } 641 else 642 * cycles = print_as3_reg_name (regs, op1, comm1, 1, 1, 2); 643 } 644 else if (as == 1) 645 { 646 if (regs == 0) 647 { 648 *cycles = 4; 649 /* PC relative. */ 650 if (msp430dis_opcode_signed (addr + 2, info, &dst, comm1)) 651 { 652 cmd_len += 2; 653 sprintf (op1, "0x%04x", PS (dst)); 654 sprintf (comm1, "PC rel. 0x%04x", 655 PS ((short) addr + 2 + dst)); 656 if (extension_word) 657 { 658 dst &= 0xffff; 659 dst |= extended_src << 16; 660 if (dst & 0x80000) 661 dst |= -1U << 20; 662 sprintf (op1, "0x%05x", dst & 0xfffff); 663 sprintf (comm1, "PC rel. 0x%05lx", 664 (long) ((addr + 2 + dst) & 0xfffff)); 665 } 666 } 667 else 668 return -1; 669 } 670 else if (regs == 2) 671 { 672 *cycles = 2; 673 /* Absolute. */ 674 if (msp430dis_opcode_signed (addr + 2, info, &dst, comm1)) 675 { 676 cmd_len += 2; 677 sprintf (op1, "&0x%04x", PS (dst)); 678 sprintf (comm1, "0x%04x", PS (dst)); 679 if (extension_word) 680 { 681 dst &= 0xffff; 682 dst |= extended_src << 16; 683 sprintf (op1, "&0x%05x", dst & 0xfffff); 684 * comm1 = 0; 685 } 686 } 687 else 688 return -1; 689 } 690 else if (regs == 3) 691 { 692 *cycles = 1; 693 sprintf (op1, "#1"); 694 sprintf (comm1, "r3 As==01"); 695 } 696 else 697 { 698 *cycles = 3; 699 /* Indexed. */ 700 if (msp430dis_opcode_signed (addr + 2, info, &dst, comm1)) 701 { 702 cmd_len += 2; 703 if (extension_word) 704 { 705 dst &= 0xffff; 706 dst |= extended_src << 16; 707 if (dst & 0x80000) 708 dst |= -1U << 20; 709 } 710 sprintf (op1, "%d(r%d)", dst, regs); 711 if (dst > 9 || dst < -9) 712 sprintf (comm1, "0x%05x", dst); 713 } 714 else 715 return -1; 716 } 717 } 718 719 /* Destination. Special care needed on addr + XXXX. */ 720 721 if (ad == 0) 722 { 723 /* Register. */ 724 if (regd == 0) 725 { 726 *cycles += 1; 727 sprintf (op2, "r0"); 728 } 729 else if (regd == 1) 730 sprintf (op2, "r1"); 731 732 else if (regd == 2) 733 sprintf (op2, "r2"); 734 735 else 736 sprintf (op2, "r%d", regd); 737 } 738 else /* ad == 1. */ 739 { 740 * cycles += 3; 741 742 if (regd == 0) 743 { 744 /* PC relative. */ 745 *cycles += 1; 746 if (msp430dis_opcode_signed (addr + cmd_len, info, &dst, comm2)) 747 { 748 sprintf (op2, "0x%04x", PS (dst)); 749 sprintf (comm2, "PC rel. 0x%04x", 750 PS ((short) addr + cmd_len + dst)); 751 if (extension_word) 752 { 753 dst |= extended_dst << 16; 754 if (dst & 0x80000) 755 dst |= -1U << 20; 756 sprintf (op2, "0x%05x", dst & 0xfffff); 757 sprintf (comm2, "PC rel. 0x%05lx", 758 (long)((addr + cmd_len + dst) & 0xfffff)); 759 } 760 } 761 else 762 return -1; 763 cmd_len += 2; 764 } 765 else if (regd == 2) 766 { 767 /* Absolute. */ 768 if (msp430dis_opcode_signed (addr + cmd_len, info, &dst, comm2)) 769 { 770 cmd_len += 2; 771 sprintf (op2, "&0x%04x", PS (dst)); 772 if (extension_word) 773 { 774 dst |= extended_dst << 16; 775 sprintf (op2, "&0x%05x", dst & 0xfffff); 776 } 777 } 778 else 779 return -1; 780 } 781 else 782 { 783 if (msp430dis_opcode_signed (addr + cmd_len, info, &dst, comm2)) 784 { 785 cmd_len += 2; 786 if (dst > 9 || dst < 0) 787 sprintf (comm2, "0x%04x", PS (dst)); 788 if (extension_word) 789 { 790 dst |= extended_dst << 16; 791 if (dst & 0x80000) 792 dst |= -1U << 20; 793 if (dst > 9 || dst < 0) 794 sprintf (comm2, "0x%05x", dst & 0xfffff); 795 } 796 sprintf (op2, "%d(r%d)", dst, regd); 797 } 798 else 799 return -1; 800 } 801 } 802 803 return cmd_len; 804} 805 806static int 807msp430_branchinstr (disassemble_info *info, 808 struct msp430_opcode_s *opcode ATTRIBUTE_UNUSED, 809 bfd_vma addr ATTRIBUTE_UNUSED, 810 unsigned short insn, 811 char *op1, 812 char *comm1, 813 int *cycles) 814{ 815 int regs = 0, regd = 0; 816 int as = 0; 817 int cmd_len = 2; 818 int dst = 0; 819 unsigned short udst = 0; 820 821 regd = insn & 0x0f; 822 regs = (insn & 0x0f00) >> 8; 823 as = (insn & 0x0030) >> 4; 824 825 if (regd != 0) /* Destination register is not a PC. */ 826 return 0; 827 828 /* dst is a source register. */ 829 if (as == 0) 830 { 831 /* Constants. */ 832 if (regs == 3) 833 { 834 *cycles = 1; 835 sprintf (op1, "#0"); 836 sprintf (comm1, "r3 As==00"); 837 } 838 else 839 { 840 /* Register. */ 841 *cycles = 1; 842 sprintf (op1, "r%d", regs); 843 } 844 } 845 else if (as == 2) 846 { 847 * cycles = print_as2_reg_name (regs, op1, comm1, 2, 1, 2); 848 } 849 else if (as == 3) 850 { 851 if (regs == 0) 852 { 853 /* Absolute. @pc+ */ 854 *cycles = 3; 855 if (msp430dis_opcode_unsigned (addr + 2, info, &udst, comm1)) 856 { 857 cmd_len += 2; 858 sprintf (op1, "#0x%04x", PS (udst)); 859 } 860 else 861 return -1; 862 } 863 else 864 * cycles = print_as3_reg_name (regs, op1, comm1, 1, 1, 2); 865 } 866 else if (as == 1) 867 { 868 * cycles = 3; 869 870 if (regs == 0) 871 { 872 /* PC relative. */ 873 if (msp430dis_opcode_signed (addr + 2, info, &dst, comm1)) 874 { 875 cmd_len += 2; 876 (*cycles)++; 877 sprintf (op1, "0x%04x", PS (dst)); 878 sprintf (comm1, "PC rel. 0x%04x", 879 PS ((short) addr + 2 + dst)); 880 } 881 else 882 return -1; 883 } 884 else if (regs == 2) 885 { 886 /* Absolute. */ 887 if (msp430dis_opcode_unsigned (addr + 2, info, &udst, comm1)) 888 { 889 cmd_len += 2; 890 sprintf (op1, "&0x%04x", PS (udst)); 891 } 892 else 893 return -1; 894 } 895 else if (regs == 3) 896 { 897 (*cycles)--; 898 sprintf (op1, "#1"); 899 sprintf (comm1, "r3 As==01"); 900 } 901 else 902 { 903 /* Indexed. */ 904 if (msp430dis_opcode_signed (addr + 2, info, &dst, comm1)) 905 { 906 cmd_len += 2; 907 sprintf (op1, "%d(r%d)", dst, regs); 908 } 909 else 910 return -1; 911 } 912 } 913 914 return cmd_len; 915} 916 917static int 918msp430x_calla_instr (disassemble_info * info, 919 bfd_vma addr, 920 unsigned short insn, 921 char * op1, 922 char * comm1, 923 int * cycles) 924{ 925 unsigned int ureg = insn & 0xf; 926 int reg = insn & 0xf; 927 int am = (insn & 0xf0) >> 4; 928 int cmd_len = 2; 929 unsigned short udst = 0; 930 int dst = 0; 931 932 switch (am) 933 { 934 case 4: /* CALLA Rdst */ 935 *cycles = 1; 936 sprintf (op1, "r%d", reg); 937 break; 938 939 case 5: /* CALLA x(Rdst) */ 940 *cycles = 3; 941 if (msp430dis_opcode_signed (addr + 2, info, &dst, comm1)) 942 { 943 cmd_len += 2; 944 sprintf (op1, "%d(r%d)", dst, reg); 945 if (reg == 0) 946 sprintf (comm1, "PC rel. 0x%05lx", (long) (addr + 2 + dst)); 947 else 948 sprintf (comm1, "0x%05x", dst); 949 } 950 else 951 return -1; 952 break; 953 954 case 6: /* CALLA @Rdst */ 955 *cycles = 2; 956 sprintf (op1, "@r%d", reg); 957 break; 958 959 case 7: /* CALLA @Rdst+ */ 960 *cycles = 2; 961 sprintf (op1, "@r%d+", reg); 962 break; 963 964 case 8: /* CALLA &abs20 */ 965 if (msp430dis_opcode_unsigned (addr + 2, info, &udst, comm1)) 966 { 967 cmd_len += 2; 968 *cycles = 4; 969 sprintf (op1, "&%d", (ureg << 16) + udst); 970 sprintf (comm1, "0x%05x", (ureg << 16) + udst); 971 } 972 else 973 return -1; 974 break; 975 976 case 9: /* CALLA pcrel-sym */ 977 if (msp430dis_opcode_signed (addr + 2, info, &dst, comm1)) 978 { 979 cmd_len += 2; 980 *cycles = 4; 981 sprintf (op1, "%d(PC)", (reg << 16) + dst); 982 sprintf (comm1, "PC rel. 0x%05lx", 983 (long) (addr + 2 + dst + (reg << 16))); 984 } 985 else 986 return -1; 987 break; 988 989 case 11: /* CALLA #imm20 */ 990 if (msp430dis_opcode_unsigned (addr + 2, info, &udst, comm1)) 991 { 992 cmd_len += 2; 993 *cycles = 4; 994 sprintf (op1, "#%d", (ureg << 16) + udst); 995 sprintf (comm1, "0x%05x", (ureg << 16) + udst); 996 } 997 else 998 return -1; 999 break; 1000 1001 default: 1002 strcpy (comm1, _("Warning: unrecognised CALLA addressing mode")); 1003 return -1; 1004 } 1005 1006 return cmd_len; 1007} 1008 1009int 1010print_insn_msp430 (bfd_vma addr, disassemble_info *info) 1011{ 1012 void *stream = info->stream; 1013 fprintf_ftype prin = info->fprintf_func; 1014 struct msp430_opcode_s *opcode; 1015 char op1[32], op2[32], comm1[64], comm2[64]; 1016 int cmd_len = 0; 1017 unsigned short insn; 1018 int cycles = 0; 1019 char *bc = ""; 1020 unsigned short extension_word = 0; 1021 unsigned short bits; 1022 1023 if (! msp430dis_opcode_unsigned (addr, info, &insn, NULL)) 1024 return -1; 1025 1026 if (((int) addr & 0xffff) > 0xffdf) 1027 { 1028 (*prin) (stream, "interrupt service routine at 0x%04x", 0xffff & insn); 1029 return 2; 1030 } 1031 1032 *comm1 = 0; 1033 *comm2 = 0; 1034 1035 /* Check for an extension word. */ 1036 if ((insn & 0xf800) == 0x1800) 1037 { 1038 extension_word = insn; 1039 addr += 2; 1040 if (! msp430dis_opcode_unsigned (addr, info, &insn, NULL)) 1041 return -1; 1042 } 1043 1044 for (opcode = msp430_opcodes; opcode->name; opcode++) 1045 { 1046 if ((insn & opcode->bin_mask) == opcode->bin_opcode 1047 && opcode->bin_opcode != 0x9300) 1048 { 1049 *op1 = 0; 1050 *op2 = 0; 1051 *comm1 = 0; 1052 *comm2 = 0; 1053 1054 /* r0 as destination. Ad should be zero. */ 1055 if (opcode->insn_opnumb == 3 1056 && (insn & 0x000f) == 0 1057 && (insn & 0x0080) == 0) 1058 { 1059 int ret = 1060 msp430_branchinstr (info, opcode, addr, insn, op1, comm1, 1061 &cycles); 1062 1063 if (ret == -1) 1064 return -1; 1065 cmd_len += ret; 1066 if (cmd_len) 1067 break; 1068 } 1069 1070 switch (opcode->insn_opnumb) 1071 { 1072 int n; 1073 int reg; 1074 int ret; 1075 1076 case 4: 1077 ret = msp430x_calla_instr (info, addr, insn, 1078 op1, comm1, & cycles); 1079 if (ret == -1) 1080 return -1; 1081 cmd_len += ret; 1082 break; 1083 1084 case 5: /* PUSHM/POPM */ 1085 n = (insn & 0xf0) >> 4; 1086 reg = (insn & 0xf); 1087 1088 sprintf (op1, "#%d", n + 1); 1089 if (opcode->bin_opcode == 0x1400) 1090 /* PUSHM */ 1091 sprintf (op2, "r%d", reg); 1092 else 1093 /* POPM */ 1094 sprintf (op2, "r%d", reg + n); 1095 if (insn & 0x100) 1096 sprintf (comm1, "16-bit words"); 1097 else 1098 { 1099 sprintf (comm1, "20-bit words"); 1100 bc =".a"; 1101 } 1102 1103 cycles = 2; /*FIXME*/ 1104 cmd_len = 2; 1105 break; 1106 1107 case 6: /* RRAM, RRCM, RRUM, RLAM. */ 1108 n = ((insn >> 10) & 0x3) + 1; 1109 reg = (insn & 0xf); 1110 if ((insn & 0x10) == 0) 1111 bc =".a"; 1112 sprintf (op1, "#%d", n); 1113 sprintf (op2, "r%d", reg); 1114 cycles = 2; /*FIXME*/ 1115 cmd_len = 2; 1116 break; 1117 1118 case 8: /* ADDA, CMPA, SUBA. */ 1119 reg = (insn & 0xf); 1120 n = (insn >> 8) & 0xf; 1121 if (insn & 0x40) 1122 { 1123 sprintf (op1, "r%d", n); 1124 cmd_len = 2; 1125 } 1126 else 1127 { 1128 n <<= 16; 1129 if (msp430dis_opcode_unsigned (addr + 2, info, &bits, comm1)) 1130 { 1131 n |= bits; 1132 sprintf (op1, "#%d", n); 1133 if (n > 9 || n < 0) 1134 sprintf (comm1, "0x%05x", n); 1135 } 1136 else 1137 return -1; 1138 cmd_len = 4; 1139 } 1140 sprintf (op2, "r%d", reg); 1141 cycles = 2; /*FIXME*/ 1142 break; 1143 1144 case 9: /* MOVA */ 1145 reg = (insn & 0xf); 1146 n = (insn >> 8) & 0xf; 1147 switch ((insn >> 4) & 0xf) 1148 { 1149 case 0: /* MOVA @Rsrc, Rdst */ 1150 cmd_len = 2; 1151 sprintf (op1, "@r%d", n); 1152 if (strcmp (opcode->name, "bra") != 0) 1153 sprintf (op2, "r%d", reg); 1154 break; 1155 1156 case 1: /* MOVA @Rsrc+, Rdst */ 1157 cmd_len = 2; 1158 if (strcmp (opcode->name, "reta") != 0) 1159 { 1160 sprintf (op1, "@r%d+", n); 1161 if (strcmp (opcode->name, "bra") != 0) 1162 sprintf (op2, "r%d", reg); 1163 } 1164 break; 1165 1166 case 2: /* MOVA &abs20, Rdst */ 1167 cmd_len = 4; 1168 n <<= 16; 1169 if (msp430dis_opcode_unsigned (addr + 2, info, &bits, comm1)) 1170 { 1171 n |= bits; 1172 sprintf (op1, "&%d", n); 1173 if (n > 9 || n < 0) 1174 sprintf (comm1, "0x%05x", n); 1175 if (strcmp (opcode->name, "bra") != 0) 1176 sprintf (op2, "r%d", reg); 1177 } 1178 else 1179 return -1; 1180 break; 1181 1182 case 3: /* MOVA x(Rsrc), Rdst */ 1183 cmd_len = 4; 1184 if (strcmp (opcode->name, "bra") != 0) 1185 sprintf (op2, "r%d", reg); 1186 reg = n; 1187 if (msp430dis_opcode_signed (addr + 2, info, &n, comm1)) 1188 { 1189 sprintf (op1, "%d(r%d)", n, reg); 1190 if (n > 9 || n < 0) 1191 { 1192 if (reg == 0) 1193 sprintf (comm1, "PC rel. 0x%05lx", 1194 (long) (addr + 2 + n)); 1195 else 1196 sprintf (comm1, "0x%05x", n); 1197 } 1198 } 1199 else 1200 return -1; 1201 break; 1202 1203 case 6: /* MOVA Rsrc, &abs20 */ 1204 cmd_len = 4; 1205 reg <<= 16; 1206 if (msp430dis_opcode_unsigned (addr + 2, info, &bits, comm2)) 1207 { 1208 reg |= bits; 1209 sprintf (op1, "r%d", n); 1210 sprintf (op2, "&%d", reg); 1211 if (reg > 9 || reg < 0) 1212 sprintf (comm2, "0x%05x", reg); 1213 } 1214 else 1215 return -1; 1216 break; 1217 1218 case 7: /* MOVA Rsrc, x(Rdst) */ 1219 cmd_len = 4; 1220 sprintf (op1, "r%d", n); 1221 if (msp430dis_opcode_signed (addr + 2, info, &n, comm2)) 1222 { 1223 sprintf (op2, "%d(r%d)", n, reg); 1224 if (n > 9 || n < 0) 1225 { 1226 if (reg == 0) 1227 sprintf (comm2, "PC rel. 0x%05lx", 1228 (long) (addr + 2 + n)); 1229 else 1230 sprintf (comm2, "0x%05x", n); 1231 } 1232 } 1233 else 1234 return -1; 1235 break; 1236 1237 case 8: /* MOVA #imm20, Rdst */ 1238 cmd_len = 4; 1239 n <<= 16; 1240 if (msp430dis_opcode_unsigned (addr + 2, info, &bits, comm1)) 1241 { 1242 n |= bits; 1243 if (n & 0x80000) 1244 n |= -1U << 20; 1245 sprintf (op1, "#%d", n); 1246 if (n > 9 || n < 0) 1247 sprintf (comm1, "0x%05x", n); 1248 if (strcmp (opcode->name, "bra") != 0) 1249 sprintf (op2, "r%d", reg); 1250 } 1251 else 1252 return -1; 1253 break; 1254 1255 case 12: /* MOVA Rsrc, Rdst */ 1256 cmd_len = 2; 1257 sprintf (op1, "r%d", n); 1258 if (strcmp (opcode->name, "bra") != 0) 1259 sprintf (op2, "r%d", reg); 1260 break; 1261 1262 default: 1263 break; 1264 } 1265 cycles = 2; /* FIXME */ 1266 break; 1267 } 1268 1269 if (cmd_len) 1270 break; 1271 1272 switch (opcode->insn_opnumb) 1273 { 1274 int ret; 1275 1276 case 0: 1277 cmd_len += msp430_nooperands (opcode, addr, insn, comm1, &cycles); 1278 break; 1279 case 2: 1280 ret = 1281 msp430_doubleoperand (info, opcode, addr, insn, op1, op2, 1282 comm1, comm2, 1283 extension_word, 1284 &cycles); 1285 1286 if (ret == -1) 1287 return -1; 1288 cmd_len += ret; 1289 if (insn & BYTE_OPERATION) 1290 { 1291 if (extension_word != 0 && ((extension_word & BYTE_OPERATION) == 0)) 1292 bc = ".a"; 1293 else 1294 bc = ".b"; 1295 } 1296 else if (extension_word) 1297 { 1298 if (extension_word & BYTE_OPERATION) 1299 bc = ".w"; 1300 else 1301 { 1302 bc = ".?"; 1303 sprintf (comm2, _("Warning: reserved use of A/L and B/W bits detected")); 1304 } 1305 } 1306 1307 break; 1308 case 1: 1309 ret = 1310 msp430_singleoperand (info, opcode, addr, insn, op1, comm1, 1311 extension_word, 1312 &cycles); 1313 1314 if (ret == -1) 1315 return -1; 1316 cmd_len += ret; 1317 if (extension_word 1318 && (strcmp (opcode->name, "swpb") == 0 1319 || strcmp (opcode->name, "sxt") == 0)) 1320 { 1321 if (insn & BYTE_OPERATION) 1322 { 1323 bc = ".?"; 1324 sprintf (comm2, _("Warning: reserved use of A/L and B/W bits detected")); 1325 } 1326 else if (extension_word & BYTE_OPERATION) 1327 bc = ".w"; 1328 else 1329 bc = ".a"; 1330 } 1331 else if (insn & BYTE_OPERATION && opcode->fmt != 3) 1332 { 1333 if (extension_word != 0 && ((extension_word & BYTE_OPERATION) == 0)) 1334 bc = ".a"; 1335 else 1336 bc = ".b"; 1337 } 1338 else if (extension_word) 1339 { 1340 if (extension_word & (1 << 6)) 1341 bc = ".w"; 1342 else 1343 { 1344 bc = ".?"; 1345 sprintf (comm2, _("Warning: reserved use of A/L and B/W bits detected")); 1346 } 1347 } 1348 break; 1349 default: 1350 break; 1351 } 1352 } 1353 1354 if (cmd_len) 1355 break; 1356 } 1357 1358 if (cmd_len < 1) 1359 { 1360 /* Unknown opcode, or invalid combination of operands. */ 1361 if (extension_word) 1362 { 1363 prin (stream, ".word 0x%04x, 0x%04x; ????", extension_word, PS (insn)); 1364 if (*comm1) 1365 prin (stream, "\t %s", comm1); 1366 return 4; 1367 } 1368 (*prin) (stream, ".word 0x%04x; ????", PS (insn)); 1369 return 2; 1370 } 1371 1372 /* Display the repeat count (if set) for extended register mode. */ 1373 if (cmd_len == 2 && ((extension_word & 0xf) != 0)) 1374 { 1375 if (extension_word & (1 << 7)) 1376 prin (stream, "rpt r%d { ", extension_word & 0xf); 1377 else 1378 prin (stream, "rpt #%d { ", (extension_word & 0xf) + 1); 1379 } 1380 1381 /* Special case: RRC with an extension word and the ZC bit set is actually RRU. */ 1382 if (extension_word 1383 && (extension_word & IGNORE_CARRY_BIT) 1384 && strcmp (opcode->name, "rrc") == 0) 1385 (*prin) (stream, "rrux%s", bc); 1386 else if (extension_word && opcode->name[strlen (opcode->name) - 1] != 'x') 1387 (*prin) (stream, "%sx%s", opcode->name, bc); 1388 else 1389 (*prin) (stream, "%s%s", opcode->name, bc); 1390 1391 if (*op1) 1392 (*prin) (stream, "\t%s", op1); 1393 if (*op2) 1394 (*prin) (stream, ","); 1395 1396 if (strlen (op1) < 7) 1397 (*prin) (stream, "\t"); 1398 if (!strlen (op1)) 1399 (*prin) (stream, "\t"); 1400 1401 if (*op2) 1402 (*prin) (stream, "%s", op2); 1403 if (strlen (op2) < 8) 1404 (*prin) (stream, "\t"); 1405 1406 if (*comm1 || *comm2) 1407 (*prin) (stream, ";"); 1408 else if (cycles) 1409 { 1410 if (*op2) 1411 (*prin) (stream, ";"); 1412 else 1413 { 1414 if (strlen (op1) < 7) 1415 (*prin) (stream, ";"); 1416 else 1417 (*prin) (stream, "\t;"); 1418 } 1419 } 1420 if (*comm1) 1421 (*prin) (stream, "%s", comm1); 1422 if (*comm1 && *comm2) 1423 (*prin) (stream, ","); 1424 if (*comm2) 1425 (*prin) (stream, " %s", comm2); 1426 1427 if (extension_word) 1428 cmd_len += 2; 1429 1430 return cmd_len; 1431} 1432