Fixup gdb.python/py-value.exp for bare-metal aarch64-elf
[deliverable/binutils-gdb.git] / opcodes / msp430-dis.c
CommitLineData
2469cfa2 1/* Disassemble MSP430 instructions.
6f2750fe 2 Copyright (C) 2002-2016 Free Software Foundation, Inc.
13761a11 3
2469cfa2 4 Contributed by Dmitry Diky <diwil@mail.ru>
43e65147 5
9b201bb5
NC
6 This file is part of the GNU opcodes library.
7
8 This library is free software; you can redistribute it and/or modify
2469cfa2 9 it under the terms of the GNU General Public License as published by
9b201bb5
NC
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
2469cfa2
NC
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
47b0e7ad
NC
20 Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
21 MA 02110-1301, USA. */
2469cfa2 22
5eb3690e 23#include "sysdep.h"
2469cfa2
NC
24#include <stdio.h>
25#include <ctype.h>
2469cfa2 26#include <sys/types.h>
77d66e7b 27#include <errno.h>
2469cfa2
NC
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
2469cfa2
NC
38#define PS(x) (0xffff & (x))
39
77d66e7b
NC
40static bfd_boolean
41msp430dis_read_two_bytes (bfd_vma addr,
42 disassemble_info * info,
43 bfd_byte * buffer,
44 char * comm)
2469cfa2 45{
2469cfa2
NC
46 int status;
47
48 status = info->read_memory_func (addr, buffer, 2, info);
77d66e7b
NC
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
2469cfa2
NC
62 {
63 info->memory_error_func (status, addr, info);
77d66e7b
NC
64 if (comm)
65 sprintf (comm, _("Error: read from memory failed"));
66 }
67
68 return FALSE;
69}
70
71static bfd_boolean
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 bfd_boolean
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;
2469cfa2 113 }
2469cfa2
NC
114}
115
47b0e7ad
NC
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)
2469cfa2
NC
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 {
13be46a2 131 if ((insn & 0x0f00) != 0x0300 || (insn & 0x0f00) != 0x0200)
2469cfa2
NC
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
13761a11
NC
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
47b0e7ad
NC
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,
13761a11 199 unsigned short extension_word,
47b0e7ad 200 int *cycles)
2469cfa2
NC
201{
202 int regs = 0, regd = 0;
203 int ad = 0, as = 0;
204 int where = 0;
205 int cmd_len = 2;
13761a11
NC
206 int dst = 0;
207 int fmt;
208 int extended_dst = extension_word & 0xf;
2469cfa2
NC
209
210 regd = insn & 0x0f;
211 regs = (insn & 0x0f00) >> 8;
212 as = (insn & 0x0030) >> 4;
213 ad = (insn & 0x0080) >> 7;
214
13761a11
NC
215 if (opcode->fmt < 0)
216 fmt = (- opcode->fmt) - 1;
217 else
218 fmt = opcode->fmt;
219
220 switch (fmt)
2469cfa2
NC
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 }
47b0e7ad 253 else /* ad == 1 msp430dis_opcode. */
2469cfa2
NC
254 {
255 if (regd == 0)
256 {
257 /* PC relative. */
77d66e7b 258 if (msp430dis_opcode_signed (addr + 2, info, &dst, comm))
13761a11 259 {
77d66e7b
NC
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 }
13761a11 272 }
2469cfa2
NC
273 }
274 else if (regd == 2)
275 {
276 /* Absolute. */
77d66e7b 277 if (msp430dis_opcode_signed (addr + 2, info, &dst, comm))
13761a11 278 {
77d66e7b
NC
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 }
13761a11 287 }
2469cfa2
NC
288 }
289 else
290 {
77d66e7b 291 if (msp430dis_opcode_signed (addr + 2, info, &dst, comm))
13761a11 292 {
77d66e7b
NC
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);
13761a11 302 }
2469cfa2
NC
303 }
304 }
305 break;
306
307 case 2: /* rrc, push, call, swpb, rra, sxt, push, call, reti etc... */
2469cfa2
NC
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 {
13761a11 325 * cycles = print_as2_reg_name (regd, op, comm, 1, 1, 3);
2469cfa2
NC
326 }
327 else if (as == 3)
328 {
13761a11 329 if (regd == 0)
2469cfa2
NC
330 {
331 *cycles = 3;
332 /* absolute. @pc+ */
77d66e7b 333 if (msp430dis_opcode_signed (addr + 2, info, &dst, comm))
13761a11 334 {
77d66e7b 335 cmd_len += 2;
13761a11
NC
336 sprintf (op, "#%d", dst);
337 if (dst > 9 || dst < 0)
77d66e7b
NC
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 }
13761a11 348 }
2469cfa2
NC
349 }
350 else
13761a11 351 * cycles = print_as3_reg_name (regd, op, comm, 1, 1, 3);
2469cfa2
NC
352 }
353 else if (as == 1)
354 {
355 *cycles = 4;
356 if (regd == 0)
357 {
358 /* PC relative. */
77d66e7b 359 if (msp430dis_opcode_signed (addr + 2, info, &dst, comm))
13761a11 360 {
77d66e7b
NC
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 }
13761a11 372 }
2469cfa2
NC
373 }
374 else if (regd == 2)
375 {
376 /* Absolute. */
77d66e7b 377 if (msp430dis_opcode_signed (addr + 2, info, &dst, comm))
13761a11 378 {
77d66e7b
NC
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 }
13761a11 386 }
2469cfa2
NC
387 }
388 else if (regd == 3)
389 {
390 *cycles = 1;
391 sprintf (op, "#1");
392 sprintf (comm, "r3 As==01");
393 }
394 else
395 {
13761a11 396 /* Indexed. */
77d66e7b 397 if (msp430dis_opcode_signed (addr + 2, info, &dst, comm))
13761a11 398 {
77d66e7b
NC
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);
13761a11 409 }
2469cfa2
NC
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);
13761a11 423 sprintf (comm, "abs 0x%lx", (long) (addr + 2 + where));
2469cfa2
NC
424 *cycles = 2;
425 return 2;
426 break;
77d66e7b 427
2469cfa2
NC
428 default:
429 cmd_len = 0;
430 }
431
432 return cmd_len;
433}
434
47b0e7ad
NC
435static int
436msp430_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,
13761a11 444 unsigned short extension_word,
47b0e7ad 445 int *cycles)
2469cfa2
NC
446{
447 int regs = 0, regd = 0;
448 int ad = 0, as = 0;
449 int cmd_len = 2;
13761a11
NC
450 int dst = 0;
451 int fmt;
452 int extended_dst = extension_word & 0xf;
453 int extended_src = (extension_word >> 7) & 0xf;
2469cfa2
NC
454
455 regd = insn & 0x0f;
456 regs = (insn & 0x0f00) >> 8;
457 as = (insn & 0x0030) >> 4;
458 ad = (insn & 0x0080) >> 7;
459
13761a11
NC
460 if (opcode->fmt < 0)
461 fmt = (- opcode->fmt) - 1;
462 else
463 fmt = opcode->fmt;
464
465 if (fmt == 0)
2469cfa2
NC
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,
43e65147 473 &0xXXXX Absolute
2469cfa2
NC
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 {
77d66e7b 485 strcpy (comm1, _("Warning: illegal as emulation instr"));
2469cfa2
NC
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. */
77d66e7b 497 if (msp430dis_opcode_signed (addr + 2, info, &dst, comm1))
13761a11 498 {
77d66e7b
NC
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 }
13761a11 513 }
2469cfa2
NC
514 }
515 else if (regd == 2)
516 {
517 /* Absolute. */
77d66e7b 518 if (msp430dis_opcode_signed (addr + 2, info, &dst, comm1))
13761a11 519 {
77d66e7b
NC
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 }
13761a11 537 }
2469cfa2
NC
538 }
539 else
540 {
541 /* Indexed. */
77d66e7b 542 if (msp430dis_opcode_signed (addr + 2, info, &dst, comm1))
13761a11 543 {
77d66e7b
NC
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);
13761a11 555 }
2469cfa2
NC
556 }
557 }
558
559 *op2 = 0;
560 *comm2 = 0;
13761a11 561
2469cfa2
NC
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. */
77d66e7b 569 strcpy (comm1, _("Warning: illegal as 2-op instr"));
2469cfa2
NC
570 return -1;
571 }
572
573 /* Source. */
574 if (as == 0)
575 {
576 *cycles = 1;
577 if (regs == 3)
578 {
13761a11 579 /* Constants. */
2469cfa2
NC
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 {
13761a11 591 * cycles = print_as2_reg_name (regs, op1, comm1, 1, 1, regs == 0 ? 3 : 2);
2469cfa2
NC
592 }
593 else if (as == 3)
594 {
13761a11 595 if (regs == 0)
2469cfa2
NC
596 {
597 *cycles = 3;
47b0e7ad 598 /* Absolute. @pc+. */
77d66e7b 599 if (msp430dis_opcode_signed (addr + 2, info, &dst, comm1))
13761a11 600 {
77d66e7b 601 cmd_len += 2;
13761a11
NC
602 sprintf (op1, "#%d", dst);
603 if (dst > 9 || dst < 0)
77d66e7b
NC
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 }
13761a11 615 }
2469cfa2
NC
616 }
617 else
13761a11 618 * cycles = print_as3_reg_name (regs, op1, comm1, 1, 1, 2);
2469cfa2
NC
619 }
620 else if (as == 1)
621 {
622 if (regs == 0)
623 {
624 *cycles = 4;
625 /* PC relative. */
77d66e7b 626 if (msp430dis_opcode_signed (addr + 2, info, &dst, comm1))
13761a11 627 {
77d66e7b
NC
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 }
13761a11 642 }
2469cfa2
NC
643 }
644 else if (regs == 2)
645 {
646 *cycles = 2;
647 /* Absolute. */
77d66e7b 648 if (msp430dis_opcode_signed (addr + 2, info, &dst, comm1))
13761a11 649 {
77d66e7b
NC
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 }
13761a11 660 }
2469cfa2
NC
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. */
77d66e7b 672 if (msp430dis_opcode_signed (addr + 2, info, &dst, comm1))
13761a11 673 {
77d66e7b
NC
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);
13761a11 685 }
2469cfa2
NC
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 }
47b0e7ad 708 else /* ad == 1. */
2469cfa2
NC
709 {
710 * cycles += 3;
711
712 if (regd == 0)
713 {
714 /* PC relative. */
715 *cycles += 1;
77d66e7b 716 if (msp430dis_opcode_signed (addr + cmd_len, info, &dst, comm2))
13761a11 717 {
77d66e7b
NC
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 }
13761a11 730 }
2469cfa2
NC
731 cmd_len += 2;
732 }
733 else if (regd == 2)
734 {
735 /* Absolute. */
77d66e7b 736 if (msp430dis_opcode_signed (addr + cmd_len, info, &dst, comm2))
13761a11 737 {
77d66e7b
NC
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 }
13761a11 745 }
2469cfa2
NC
746 }
747 else
748 {
77d66e7b 749 if (msp430dis_opcode_signed (addr + cmd_len, info, &dst, comm2))
13761a11 750 {
77d66e7b 751 cmd_len += 2;
13761a11 752 if (dst > 9 || dst < 0)
77d66e7b
NC
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);
13761a11 763 }
2469cfa2
NC
764 }
765 }
766
767 return cmd_len;
768}
769
47b0e7ad
NC
770static int
771msp430_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)
2469cfa2
NC
778{
779 int regs = 0, regd = 0;
c7e2358a 780 int as = 0;
2469cfa2 781 int cmd_len = 2;
77d66e7b
NC
782 int dst = 0;
783 unsigned short udst = 0;
2469cfa2
NC
784
785 regd = insn & 0x0f;
786 regs = (insn & 0x0f00) >> 8;
787 as = (insn & 0x0030) >> 4;
2469cfa2
NC
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 {
13761a11 811 * cycles = print_as2_reg_name (regs, op1, comm1, 2, 1, 2);
2469cfa2
NC
812 }
813 else if (as == 3)
814 {
13761a11 815 if (regs == 0)
2469cfa2
NC
816 {
817 /* Absolute. @pc+ */
818 *cycles = 3;
77d66e7b
NC
819 if (msp430dis_opcode_unsigned (addr + 2, info, &udst, comm1))
820 {
821 cmd_len += 2;
822 sprintf (op1, "#0x%04x", PS (udst));
823 }
2469cfa2
NC
824 }
825 else
13761a11 826 * cycles = print_as3_reg_name (regs, op1, comm1, 1, 1, 2);
2469cfa2
NC
827 }
828 else if (as == 1)
829 {
830 * cycles = 3;
831
832 if (regs == 0)
833 {
834 /* PC relative. */
77d66e7b
NC
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 }
2469cfa2
NC
843 }
844 else if (regs == 2)
845 {
846 /* Absolute. */
77d66e7b
NC
847 if (msp430dis_opcode_unsigned (addr + 2, info, &udst, comm1))
848 {
849 cmd_len += 2;
850 sprintf (op1, "&0x%04x", PS (udst));
851 }
2469cfa2
NC
852 }
853 else if (regs == 3)
854 {
855 (*cycles)--;
856 sprintf (op1, "#1");
857 sprintf (comm1, "r3 As==01");
858 }
859 else
860 {
13761a11 861 /* Indexed. */
77d66e7b
NC
862 if (msp430dis_opcode_signed (addr + 2, info, &dst, comm1))
863 {
864 cmd_len += 2;
865 sprintf (op1, "%d(r%d)", dst, regs);
866 }
2469cfa2
NC
867 }
868 }
869
870 return cmd_len;
871}
47b0e7ad 872
13761a11
NC
873static int
874msp430x_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;
77d66e7b 886 int dst = 0;
13761a11
NC
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;
77d66e7b
NC
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 }
13761a11
NC
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 */
77d66e7b
NC
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 }
13761a11
NC
926 break;
927
928 case 9: /* CALLA pcrel-sym */
77d66e7b
NC
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 }
13761a11
NC
937 break;
938
939 case 11: /* CALLA #imm20 */
77d66e7b
NC
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 }
13761a11
NC
947 break;
948
949 default:
77d66e7b 950 strcpy (comm1, _("Warning: unrecognised CALLA addressing mode"));
13761a11
NC
951 return -1;
952 }
953
954 return cmd_len;
955}
956
47b0e7ad
NC
957int
958print_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 = "";
13761a11 968 unsigned short extension_word = 0;
77d66e7b 969 unsigned short bits;
47b0e7ad 970
77d66e7b 971 if (! msp430dis_opcode_unsigned (addr, info, &insn, NULL))
13761a11
NC
972 {
973 prin (stream, ".word 0xffff; ????");
974 return 2;
975 }
47b0e7ad
NC
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
13761a11
NC
986 /* Check for an extension word. */
987 if ((insn & 0xf800) == 0x1800)
988 {
989 extension_word = insn;
990 addr += 2;
77d66e7b 991 if (! msp430dis_opcode_unsigned (addr, info, &insn, NULL))
13761a11
NC
992 {
993 prin (stream, ".word 0x%04x, 0xffff; ????",
994 extension_word);
995 return 4;
996 }
997 }
998
47b0e7ad
NC
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. */
13761a11
NC
1010 if (opcode->insn_opnumb == 3
1011 && (insn & 0x000f) == 0
1012 && (insn & 0x0080) == 0)
47b0e7ad 1013 {
13761a11 1014 cmd_len +=
47b0e7ad
NC
1015 msp430_branchinstr (info, opcode, addr, insn, op1, comm1,
1016 &cycles);
1017 if (cmd_len)
1018 break;
1019 }
1020
13761a11
NC
1021 switch (opcode->insn_opnumb)
1022 {
1023 int n;
1024 int reg;
1025
1026 case 4:
1027 cmd_len += msp430x_calla_instr (info, addr, insn,
1028 op1, comm1, & cycles);
1029 break;
1030
1031 case 5: /* PUSHM/POPM */
1032 n = (insn & 0xf0) >> 4;
1033 reg = (insn & 0xf);
1034
1035 sprintf (op1, "#%d", n + 1);
1036 if (opcode->bin_opcode == 0x1400)
1037 /* PUSHM */
1038 sprintf (op2, "r%d", reg);
1039 else
1040 /* POPM */
1041 sprintf (op2, "r%d", reg + n);
1042 if (insn & 0x100)
1043 sprintf (comm1, "16-bit words");
1044 else
1045 {
1046 sprintf (comm1, "20-bit words");
1047 bc =".a";
1048 }
43e65147 1049
13761a11
NC
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;
77d66e7b
NC
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 }
13761a11
NC
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;
43e65147 1100
13761a11
NC
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;
43e65147 1110
13761a11
NC
1111 case 2: /* MOVA &abs20, Rdst */
1112 cmd_len = 4;
1113 n <<= 16;
77d66e7b
NC
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 }
13761a11 1123 break;
43e65147 1124
13761a11
NC
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;
77d66e7b 1130 if (msp430dis_opcode_signed (addr + 2, info, &n, comm1))
13761a11 1131 {
77d66e7b
NC
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 }
13761a11
NC
1141 }
1142 break;
1143
1144 case 6: /* MOVA Rsrc, &abs20 */
1145 cmd_len = 4;
1146 reg <<= 16;
77d66e7b
NC
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 }
13761a11
NC
1155 break;
1156
1157 case 7: /* MOVA Rsrc, x(Rdst) */
1158 cmd_len = 4;
1159 sprintf (op1, "r%d", n);
77d66e7b 1160 if (msp430dis_opcode_signed (addr + 2, info, &n, comm2))
13761a11 1161 {
77d66e7b
NC
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 }
13761a11
NC
1171 }
1172 break;
43e65147 1173
13761a11
NC
1174 case 8: /* MOVA #imm20, Rdst */
1175 cmd_len = 4;
1176 n <<= 16;
77d66e7b
NC
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 }
13761a11 1188 break;
43e65147 1189
13761a11
NC
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
47b0e7ad
NC
1207 switch (opcode->insn_opnumb)
1208 {
1209 case 0:
13761a11 1210 cmd_len += msp430_nooperands (opcode, addr, insn, comm1, &cycles);
47b0e7ad
NC
1211 break;
1212 case 2:
13761a11 1213 cmd_len +=
47b0e7ad 1214 msp430_doubleoperand (info, opcode, addr, insn, op1, op2,
13761a11
NC
1215 comm1, comm2,
1216 extension_word,
1217 &cycles);
47b0e7ad 1218 if (insn & BYTE_OPERATION)
13761a11
NC
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 {
c1d9289f 1227 if (extension_word & BYTE_OPERATION)
13761a11
NC
1228 bc = ".w";
1229 else
1230 {
1231 bc = ".?";
77d66e7b 1232 sprintf (comm2, _("Warning: reserved use of A/L and B/W bits detected"));
13761a11
NC
1233 }
1234 }
43e65147 1235
47b0e7ad
NC
1236 break;
1237 case 1:
13761a11 1238 cmd_len +=
47b0e7ad 1239 msp430_singleoperand (info, opcode, addr, insn, op1, comm1,
13761a11 1240 extension_word,
47b0e7ad 1241 &cycles);
13761a11
NC
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 = ".?";
77d66e7b 1249 sprintf (comm2, _("Warning: reserved use of A/L and B/W bits detected"));
13761a11
NC
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 = ".?";
77d66e7b 1270 sprintf (comm2, _("Warning: reserved use of A/L and B/W bits detected"));
13761a11
NC
1271 }
1272 }
47b0e7ad
NC
1273 break;
1274 default:
1275 break;
1276 }
1277 }
1278
1279 if (cmd_len)
1280 break;
1281 }
1282
47b0e7ad
NC
1283 if (cmd_len < 1)
1284 {
1285 /* Unknown opcode, or invalid combination of operands. */
13761a11
NC
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 }
47b0e7ad
NC
1293 (*prin) (stream, ".word 0x%04x; ????", PS (insn));
1294 return 2;
1295 }
1296
13761a11
NC
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
c1d9289f
NC
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')
13761a11
NC
1312 (*prin) (stream, "%sx%s", opcode->name, bc);
1313 else
1314 (*prin) (stream, "%s%s", opcode->name, bc);
47b0e7ad
NC
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);
13761a11
NC
1351
1352 if (extension_word)
1353 cmd_len += 2;
1354
47b0e7ad
NC
1355 return cmd_len;
1356}
This page took 0.847343 seconds and 4 git commands to generate.