Annotation of src/external/gpl3/binutils/dist/opcodes/msp430-dis.c, Revision 1.1.1.5
1.1 skrll 1: /* Disassemble MSP430 instructions.
1.1.1.5 ! christos 2: Copyright (C) 2002-2016 Free Software Foundation, Inc.
1.1.1.4 christos 3:
1.1 skrll 4: Contributed by Dmitry Diky <diwil@mail.ru>
1.1.1.4 christos 5:
1.1 skrll 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:
1.1.1.3 christos 23: #include "sysdep.h"
1.1 skrll 24: #include <stdio.h>
25: #include <ctype.h>
26: #include <sys/types.h>
1.1.1.5 ! christos 27: #include <errno.h>
1.1 skrll 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:
1.1.1.5 ! christos 40: static bfd_boolean
! 41: msp430dis_read_two_bytes (bfd_vma addr,
! 42: disassemble_info * info,
! 43: bfd_byte * buffer,
! 44: char * comm)
1.1 skrll 45: {
46: int status;
47:
48: status = info->read_memory_func (addr, buffer, 2, info);
1.1.1.5 ! christos 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
1.1 skrll 62: {
63: info->memory_error_func (status, addr, info);
1.1.1.5 ! christos 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;
1.1 skrll 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: {
1.1.1.4 christos 131: if ((insn & 0x0f00) != 0x0300 || (insn & 0x0f00) != 0x0200)
1.1 skrll 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
1.1.1.4 christos 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
1.1 skrll 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,
1.1.1.4 christos 199: unsigned short extension_word,
1.1 skrll 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;
1.1.1.4 christos 206: int dst = 0;
207: int fmt;
208: int extended_dst = extension_word & 0xf;
1.1 skrll 209:
210: regd = insn & 0x0f;
211: regs = (insn & 0x0f00) >> 8;
212: as = (insn & 0x0030) >> 4;
213: ad = (insn & 0x0080) >> 7;
214:
1.1.1.4 christos 215: if (opcode->fmt < 0)
216: fmt = (- opcode->fmt) - 1;
217: else
218: fmt = opcode->fmt;
219:
220: switch (fmt)
1.1 skrll 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. */
1.1.1.5 ! christos 258: if (msp430dis_opcode_signed (addr + 2, info, &dst, comm))
1.1.1.4 christos 259: {
1.1.1.5 ! christos 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: }
1.1.1.4 christos 272: }
1.1 skrll 273: }
274: else if (regd == 2)
275: {
276: /* Absolute. */
1.1.1.5 ! christos 277: if (msp430dis_opcode_signed (addr + 2, info, &dst, comm))
1.1.1.4 christos 278: {
1.1.1.5 ! christos 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: }
1.1.1.4 christos 287: }
1.1 skrll 288: }
289: else
290: {
1.1.1.5 ! christos 291: if (msp430dis_opcode_signed (addr + 2, info, &dst, comm))
1.1.1.4 christos 292: {
1.1.1.5 ! christos 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);
1.1.1.4 christos 302: }
1.1 skrll 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: {
1.1.1.4 christos 325: * cycles = print_as2_reg_name (regd, op, comm, 1, 1, 3);
1.1 skrll 326: }
327: else if (as == 3)
328: {
1.1.1.4 christos 329: if (regd == 0)
1.1 skrll 330: {
331: *cycles = 3;
332: /* absolute. @pc+ */
1.1.1.5 ! christos 333: if (msp430dis_opcode_signed (addr + 2, info, &dst, comm))
1.1.1.4 christos 334: {
1.1.1.5 ! christos 335: cmd_len += 2;
1.1.1.4 christos 336: sprintf (op, "#%d", dst);
337: if (dst > 9 || dst < 0)
1.1.1.5 ! christos 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: }
1.1.1.4 christos 348: }
1.1 skrll 349: }
350: else
1.1.1.4 christos 351: * cycles = print_as3_reg_name (regd, op, comm, 1, 1, 3);
1.1 skrll 352: }
353: else if (as == 1)
354: {
355: *cycles = 4;
356: if (regd == 0)
357: {
358: /* PC relative. */
1.1.1.5 ! christos 359: if (msp430dis_opcode_signed (addr + 2, info, &dst, comm))
1.1.1.4 christos 360: {
1.1.1.5 ! christos 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: }
1.1.1.4 christos 372: }
1.1 skrll 373: }
374: else if (regd == 2)
375: {
376: /* Absolute. */
1.1.1.5 ! christos 377: if (msp430dis_opcode_signed (addr + 2, info, &dst, comm))
1.1.1.4 christos 378: {
1.1.1.5 ! christos 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: }
1.1.1.4 christos 386: }
1.1 skrll 387: }
388: else if (regd == 3)
389: {
390: *cycles = 1;
391: sprintf (op, "#1");
392: sprintf (comm, "r3 As==01");
393: }
394: else
395: {
1.1.1.4 christos 396: /* Indexed. */
1.1.1.5 ! christos 397: if (msp430dis_opcode_signed (addr + 2, info, &dst, comm))
1.1.1.4 christos 398: {
1.1.1.5 ! christos 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);
1.1.1.4 christos 409: }
1.1 skrll 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);
1.1.1.4 christos 423: sprintf (comm, "abs 0x%lx", (long) (addr + 2 + where));
1.1 skrll 424: *cycles = 2;
425: return 2;
426: break;
1.1.1.5 ! christos 427:
1.1 skrll 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,
1.1.1.4 christos 444: unsigned short extension_word,
1.1 skrll 445: int *cycles)
446: {
447: int regs = 0, regd = 0;
448: int ad = 0, as = 0;
449: int cmd_len = 2;
1.1.1.4 christos 450: int dst = 0;
451: int fmt;
452: int extended_dst = extension_word & 0xf;
453: int extended_src = (extension_word >> 7) & 0xf;
1.1 skrll 454:
455: regd = insn & 0x0f;
456: regs = (insn & 0x0f00) >> 8;
457: as = (insn & 0x0030) >> 4;
458: ad = (insn & 0x0080) >> 7;
459:
1.1.1.4 christos 460: if (opcode->fmt < 0)
461: fmt = (- opcode->fmt) - 1;
462: else
463: fmt = opcode->fmt;
464:
465: if (fmt == 0)
1.1 skrll 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,
1.1.1.4 christos 473: &0xXXXX Absolute
1.1 skrll 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: {
1.1.1.5 ! christos 485: strcpy (comm1, _("Warning: illegal as emulation instr"));
1.1 skrll 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. */
1.1.1.5 ! christos 497: if (msp430dis_opcode_signed (addr + 2, info, &dst, comm1))
1.1.1.4 christos 498: {
1.1.1.5 ! christos 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: }
1.1.1.4 christos 513: }
1.1 skrll 514: }
515: else if (regd == 2)
516: {
517: /* Absolute. */
1.1.1.5 ! christos 518: if (msp430dis_opcode_signed (addr + 2, info, &dst, comm1))
1.1.1.4 christos 519: {
1.1.1.5 ! christos 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: }
1.1.1.4 christos 537: }
1.1 skrll 538: }
539: else
540: {
541: /* Indexed. */
1.1.1.5 ! christos 542: if (msp430dis_opcode_signed (addr + 2, info, &dst, comm1))
1.1.1.4 christos 543: {
1.1.1.5 ! christos 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);
1.1.1.4 christos 555: }
1.1 skrll 556: }
557: }
558:
559: *op2 = 0;
560: *comm2 = 0;
1.1.1.4 christos 561:
1.1 skrll 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. */
1.1.1.5 ! christos 569: strcpy (comm1, _("Warning: illegal as 2-op instr"));
1.1 skrll 570: return -1;
571: }
572:
573: /* Source. */
574: if (as == 0)
575: {
576: *cycles = 1;
577: if (regs == 3)
578: {
1.1.1.4 christos 579: /* Constants. */
1.1 skrll 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: {
1.1.1.4 christos 591: * cycles = print_as2_reg_name (regs, op1, comm1, 1, 1, regs == 0 ? 3 : 2);
1.1 skrll 592: }
593: else if (as == 3)
594: {
1.1.1.4 christos 595: if (regs == 0)
1.1 skrll 596: {
597: *cycles = 3;
598: /* Absolute. @pc+. */
1.1.1.5 ! christos 599: if (msp430dis_opcode_signed (addr + 2, info, &dst, comm1))
! 600: {
! 601: cmd_len += 2;
1.1.1.4 christos 602: sprintf (op1, "#%d", dst);
603: if (dst > 9 || dst < 0)
1.1.1.5 ! christos 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: }
1.1.1.4 christos 615: }
1.1 skrll 616: }
617: else
1.1.1.4 christos 618: * cycles = print_as3_reg_name (regs, op1, comm1, 1, 1, 2);
1.1 skrll 619: }
620: else if (as == 1)
621: {
622: if (regs == 0)
623: {
624: *cycles = 4;
625: /* PC relative. */
1.1.1.5 ! christos 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: }
1.1.1.4 christos 642: }
1.1 skrll 643: }
644: else if (regs == 2)
645: {
646: *cycles = 2;
647: /* Absolute. */
1.1.1.5 ! christos 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: }
1.1.1.4 christos 660: }
1.1 skrll 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. */
1.1.1.5 ! christos 672: if (msp430dis_opcode_signed (addr + 2, info, &dst, comm1))
1.1.1.4 christos 673: {
1.1.1.5 ! christos 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: }
1.1 skrll 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;
1.1.1.5 ! christos 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: }
1.1.1.4 christos 730: }
1.1 skrll 731: cmd_len += 2;
732: }
733: else if (regd == 2)
734: {
735: /* Absolute. */
1.1.1.5 ! christos 736: if (msp430dis_opcode_signed (addr + cmd_len, info, &dst, comm2))
1.1.1.4 christos 737: {
1.1.1.5 ! christos 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: }
1.1.1.4 christos 745: }
1.1 skrll 746: }
747: else
748: {
1.1.1.5 ! christos 749: if (msp430dis_opcode_signed (addr + cmd_len, info, &dst, comm2))
! 750: {
! 751: cmd_len += 2;
1.1.1.4 christos 752: if (dst > 9 || dst < 0)
1.1.1.5 ! christos 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);
1.1.1.4 christos 763: }
1.1 skrll 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;
1.1.1.2 christos 780: int as = 0;
1.1 skrll 781: int cmd_len = 2;
1.1.1.5 ! christos 782: int dst = 0;
! 783: unsigned short udst = 0;
1.1 skrll 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: {
1.1.1.4 christos 811: * cycles = print_as2_reg_name (regs, op1, comm1, 2, 1, 2);
1.1 skrll 812: }
813: else if (as == 3)
814: {
1.1.1.4 christos 815: if (regs == 0)
1.1 skrll 816: {
817: /* Absolute. @pc+ */
818: *cycles = 3;
1.1.1.5 ! christos 819: if (msp430dis_opcode_unsigned (addr + 2, info, &udst, comm1))
! 820: {
! 821: cmd_len += 2;
! 822: sprintf (op1, "#0x%04x", PS (udst));
! 823: }
1.1 skrll 824: }
825: else
1.1.1.4 christos 826: * cycles = print_as3_reg_name (regs, op1, comm1, 1, 1, 2);
1.1 skrll 827: }
828: else if (as == 1)
829: {
830: * cycles = 3;
831:
832: if (regs == 0)
833: {
834: /* PC relative. */
1.1.1.5 ! christos 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: }
1.1 skrll 843: }
844: else if (regs == 2)
845: {
846: /* Absolute. */
1.1.1.5 ! christos 847: if (msp430dis_opcode_unsigned (addr + 2, info, &udst, comm1))
! 848: {
! 849: cmd_len += 2;
! 850: sprintf (op1, "&0x%04x", PS (udst));
! 851: }
1.1 skrll 852: }
853: else if (regs == 3)
854: {
855: (*cycles)--;
856: sprintf (op1, "#1");
857: sprintf (comm1, "r3 As==01");
858: }
859: else
860: {
1.1.1.4 christos 861: /* Indexed. */
1.1.1.5 ! christos 862: if (msp430dis_opcode_signed (addr + 2, info, &dst, comm1))
! 863: {
! 864: cmd_len += 2;
! 865: sprintf (op1, "%d(r%d)", dst, regs);
! 866: }
1.1 skrll 867: }
868: }
869:
870: return cmd_len;
871: }
872:
1.1.1.4 christos 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;
1.1.1.5 ! christos 886: int dst = 0;
1.1.1.4 christos 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;
1.1.1.5 ! christos 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: }
1.1.1.4 christos 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 */
1.1.1.5 ! christos 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: }
1.1.1.4 christos 926: break;
927:
928: case 9: /* CALLA pcrel-sym */
1.1.1.5 ! christos 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: }
1.1.1.4 christos 937: break;
938:
939: case 11: /* CALLA #imm20 */
1.1.1.5 ! christos 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: }
1.1.1.4 christos 947: break;
948:
949: default:
1.1.1.5 ! christos 950: strcpy (comm1, _("Warning: unrecognised CALLA addressing mode"));
1.1.1.4 christos 951: return -1;
952: }
953:
954: return cmd_len;
955: }
956:
1.1 skrll 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 = "";
1.1.1.4 christos 968: unsigned short extension_word = 0;
1.1.1.5 ! christos 969: unsigned short bits;
1.1 skrll 970:
1.1.1.5 ! christos 971: if (! msp430dis_opcode_unsigned (addr, info, &insn, NULL))
1.1.1.4 christos 972: {
973: prin (stream, ".word 0xffff; ????");
974: return 2;
975: }
1.1 skrll 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:
1.1.1.4 christos 986: /* Check for an extension word. */
987: if ((insn & 0xf800) == 0x1800)
988: {
989: extension_word = insn;
990: addr += 2;
1.1.1.5 ! christos 991: if (! msp430dis_opcode_unsigned (addr, info, &insn, NULL))
1.1.1.4 christos 992: {
993: prin (stream, ".word 0x%04x, 0xffff; ????",
994: extension_word);
995: return 4;
996: }
997: }
998:
1.1 skrll 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. */
1.1.1.4 christos 1010: if (opcode->insn_opnumb == 3
1011: && (insn & 0x000f) == 0
1012: && (insn & 0x0080) == 0)
1.1 skrll 1013: {
1.1.1.4 christos 1014: cmd_len +=
1.1 skrll 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: {
1.1.1.4 christos 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;
1.1.1.5 ! christos 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: }
1.1.1.4 christos 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;
1.1.1.5 ! christos 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: }
1.1.1.4 christos 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;
1.1.1.5 ! christos 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: }
1.1.1.4 christos 1141: }
1142: break;
1143:
1144: case 6: /* MOVA Rsrc, &abs20 */
1145: cmd_len = 4;
1146: reg <<= 16;
1.1.1.5 ! christos 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: }
1.1.1.4 christos 1155: break;
1156:
1157: case 7: /* MOVA Rsrc, x(Rdst) */
1158: cmd_len = 4;
1159: sprintf (op1, "r%d", n);
1.1.1.5 ! christos 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: }
1.1.1.4 christos 1171: }
1172: break;
1173:
1174: case 8: /* MOVA #imm20, Rdst */
1175: cmd_len = 4;
1176: n <<= 16;
1.1.1.5 ! christos 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: }
1.1.1.4 christos 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: {
1.1 skrll 1209: case 0:
1.1.1.4 christos 1210: cmd_len += msp430_nooperands (opcode, addr, insn, comm1, &cycles);
1.1 skrll 1211: break;
1212: case 2:
1.1.1.4 christos 1213: cmd_len +=
1.1 skrll 1214: msp430_doubleoperand (info, opcode, addr, insn, op1, op2,
1.1.1.4 christos 1215: comm1, comm2,
1216: extension_word,
1217: &cycles);
1.1 skrll 1218: if (insn & BYTE_OPERATION)
1.1.1.4 christos 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: {
1.1.1.5 ! christos 1227: if (extension_word & BYTE_OPERATION)
1.1.1.4 christos 1228: bc = ".w";
1229: else
1230: {
1231: bc = ".?";
1.1.1.5 ! christos 1232: sprintf (comm2, _("Warning: reserved use of A/L and B/W bits detected"));
1.1.1.4 christos 1233: }
1234: }
1235:
1.1 skrll 1236: break;
1237: case 1:
1.1.1.4 christos 1238: cmd_len +=
1.1 skrll 1239: msp430_singleoperand (info, opcode, addr, insn, op1, comm1,
1.1.1.4 christos 1240: extension_word,
1.1 skrll 1241: &cycles);
1.1.1.4 christos 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 = ".?";
1.1.1.5 ! christos 1249: sprintf (comm2, _("Warning: reserved use of A/L and B/W bits detected"));
1.1.1.4 christos 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 = ".?";
1.1.1.5 ! christos 1270: sprintf (comm2, _("Warning: reserved use of A/L and B/W bits detected"));
1.1.1.4 christos 1271: }
1272: }
1.1 skrll 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. */
1.1.1.4 christos 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: }
1.1 skrll 1293: (*prin) (stream, ".word 0x%04x; ????", PS (insn));
1294: return 2;
1295: }
1296:
1.1.1.4 christos 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:
1.1.1.5 ! christos 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')
1.1.1.4 christos 1312: (*prin) (stream, "%sx%s", opcode->name, bc);
1313: else
1314: (*prin) (stream, "%s%s", opcode->name, bc);
1.1 skrll 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);
1.1.1.4 christos 1351:
1352: if (extension_word)
1353: cmd_len += 2;
1354:
1.1 skrll 1355: return cmd_len;
1356: }
CVSweb <webmaster@jp.NetBSD.org>