Arm64: fix build with old glibc
[deliverable/binutils-gdb.git] / opcodes / msp430-dis.c
CommitLineData
2469cfa2 1/* Disassemble MSP430 instructions.
82704155 2 Copyright (C) 2002-2019 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 28
88c1242d 29#include "disassemble.h"
2469cfa2
NC
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 }
d95014a2
YQ
273 else
274 return -1;
2469cfa2
NC
275 }
276 else if (regd == 2)
277 {
278 /* Absolute. */
77d66e7b 279 if (msp430dis_opcode_signed (addr + 2, info, &dst, comm))
13761a11 280 {
77d66e7b
NC
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 }
13761a11 289 }
d95014a2
YQ
290 else
291 return -1;
2469cfa2
NC
292 }
293 else
294 {
77d66e7b 295 if (msp430dis_opcode_signed (addr + 2, info, &dst, comm))
13761a11 296 {
77d66e7b
NC
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);
13761a11 306 }
d95014a2
YQ
307 else
308 return -1;
2469cfa2
NC
309 }
310 }
311 break;
312
313 case 2: /* rrc, push, call, swpb, rra, sxt, push, call, reti etc... */
2469cfa2
NC
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 {
13761a11 331 * cycles = print_as2_reg_name (regd, op, comm, 1, 1, 3);
2469cfa2
NC
332 }
333 else if (as == 3)
334 {
13761a11 335 if (regd == 0)
2469cfa2
NC
336 {
337 *cycles = 3;
338 /* absolute. @pc+ */
77d66e7b 339 if (msp430dis_opcode_signed (addr + 2, info, &dst, comm))
13761a11 340 {
77d66e7b 341 cmd_len += 2;
13761a11
NC
342 sprintf (op, "#%d", dst);
343 if (dst > 9 || dst < 0)
77d66e7b
NC
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 }
13761a11 354 }
d95014a2
YQ
355 else
356 return -1;
2469cfa2
NC
357 }
358 else
13761a11 359 * cycles = print_as3_reg_name (regd, op, comm, 1, 1, 3);
2469cfa2
NC
360 }
361 else if (as == 1)
362 {
363 *cycles = 4;
364 if (regd == 0)
365 {
366 /* PC relative. */
77d66e7b 367 if (msp430dis_opcode_signed (addr + 2, info, &dst, comm))
13761a11 368 {
77d66e7b
NC
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 }
13761a11 380 }
d95014a2
YQ
381 else
382 return -1;
2469cfa2
NC
383 }
384 else if (regd == 2)
385 {
386 /* Absolute. */
77d66e7b 387 if (msp430dis_opcode_signed (addr + 2, info, &dst, comm))
13761a11 388 {
77d66e7b
NC
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 }
13761a11 396 }
d95014a2
YQ
397 else
398 return -1;
2469cfa2
NC
399 }
400 else if (regd == 3)
401 {
402 *cycles = 1;
403 sprintf (op, "#1");
404 sprintf (comm, "r3 As==01");
405 }
406 else
407 {
13761a11 408 /* Indexed. */
77d66e7b 409 if (msp430dis_opcode_signed (addr + 2, info, &dst, comm))
13761a11 410 {
77d66e7b
NC
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);
13761a11 421 }
d95014a2
YQ
422 else
423 return -1;
2469cfa2
NC
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);
13761a11 437 sprintf (comm, "abs 0x%lx", (long) (addr + 2 + where));
2469cfa2
NC
438 *cycles = 2;
439 return 2;
440 break;
77d66e7b 441
2469cfa2
NC
442 default:
443 cmd_len = 0;
444 }
445
446 return cmd_len;
447}
448
47b0e7ad
NC
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,
13761a11 458 unsigned short extension_word,
47b0e7ad 459 int *cycles)
2469cfa2
NC
460{
461 int regs = 0, regd = 0;
462 int ad = 0, as = 0;
463 int cmd_len = 2;
13761a11
NC
464 int dst = 0;
465 int fmt;
466 int extended_dst = extension_word & 0xf;
467 int extended_src = (extension_word >> 7) & 0xf;
2469cfa2
NC
468
469 regd = insn & 0x0f;
470 regs = (insn & 0x0f00) >> 8;
471 as = (insn & 0x0030) >> 4;
472 ad = (insn & 0x0080) >> 7;
473
13761a11
NC
474 if (opcode->fmt < 0)
475 fmt = (- opcode->fmt) - 1;
476 else
477 fmt = opcode->fmt;
478
479 if (fmt == 0)
2469cfa2
NC
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,
43e65147 487 &0xXXXX Absolute
2469cfa2
NC
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 {
77d66e7b 499 strcpy (comm1, _("Warning: illegal as emulation instr"));
2469cfa2
NC
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. */
77d66e7b 511 if (msp430dis_opcode_signed (addr + 2, info, &dst, comm1))
13761a11 512 {
77d66e7b
NC
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 }
13761a11 527 }
d95014a2
YQ
528 else
529 return -1;
2469cfa2
NC
530 }
531 else if (regd == 2)
532 {
533 /* Absolute. */
77d66e7b 534 if (msp430dis_opcode_signed (addr + 2, info, &dst, comm1))
13761a11 535 {
77d66e7b
NC
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 }
d95014a2
YQ
545 else
546 return -1;
77d66e7b
NC
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 }
13761a11 555 }
d95014a2
YQ
556 else
557 return -1;
2469cfa2
NC
558 }
559 else
560 {
561 /* Indexed. */
77d66e7b 562 if (msp430dis_opcode_signed (addr + 2, info, &dst, comm1))
13761a11 563 {
77d66e7b
NC
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);
13761a11 575 }
d95014a2
YQ
576 else
577 return -1;
2469cfa2
NC
578 }
579 }
580
581 *op2 = 0;
582 *comm2 = 0;
13761a11 583
2469cfa2
NC
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. */
77d66e7b 591 strcpy (comm1, _("Warning: illegal as 2-op instr"));
2469cfa2
NC
592 return -1;
593 }
594
595 /* Source. */
596 if (as == 0)
597 {
598 *cycles = 1;
599 if (regs == 3)
600 {
13761a11 601 /* Constants. */
2469cfa2
NC
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 {
13761a11 613 * cycles = print_as2_reg_name (regs, op1, comm1, 1, 1, regs == 0 ? 3 : 2);
2469cfa2
NC
614 }
615 else if (as == 3)
616 {
13761a11 617 if (regs == 0)
2469cfa2
NC
618 {
619 *cycles = 3;
47b0e7ad 620 /* Absolute. @pc+. */
77d66e7b 621 if (msp430dis_opcode_signed (addr + 2, info, &dst, comm1))
13761a11 622 {
77d66e7b 623 cmd_len += 2;
13761a11
NC
624 sprintf (op1, "#%d", dst);
625 if (dst > 9 || dst < 0)
77d66e7b
NC
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 }
13761a11 637 }
d95014a2
YQ
638 else
639 return -1;
2469cfa2
NC
640 }
641 else
13761a11 642 * cycles = print_as3_reg_name (regs, op1, comm1, 1, 1, 2);
2469cfa2
NC
643 }
644 else if (as == 1)
645 {
646 if (regs == 0)
647 {
648 *cycles = 4;
649 /* PC relative. */
77d66e7b 650 if (msp430dis_opcode_signed (addr + 2, info, &dst, comm1))
13761a11 651 {
77d66e7b
NC
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 }
13761a11 666 }
d95014a2
YQ
667 else
668 return -1;
2469cfa2
NC
669 }
670 else if (regs == 2)
671 {
672 *cycles = 2;
673 /* Absolute. */
77d66e7b 674 if (msp430dis_opcode_signed (addr + 2, info, &dst, comm1))
13761a11 675 {
77d66e7b
NC
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 }
13761a11 686 }
d95014a2
YQ
687 else
688 return -1;
2469cfa2
NC
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. */
77d66e7b 700 if (msp430dis_opcode_signed (addr + 2, info, &dst, comm1))
13761a11 701 {
77d66e7b
NC
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);
13761a11 713 }
d95014a2
YQ
714 else
715 return -1;
2469cfa2
NC
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 }
47b0e7ad 738 else /* ad == 1. */
2469cfa2
NC
739 {
740 * cycles += 3;
741
742 if (regd == 0)
743 {
744 /* PC relative. */
745 *cycles += 1;
77d66e7b 746 if (msp430dis_opcode_signed (addr + cmd_len, info, &dst, comm2))
13761a11 747 {
77d66e7b
NC
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 }
13761a11 760 }
d95014a2
YQ
761 else
762 return -1;
2469cfa2
NC
763 cmd_len += 2;
764 }
765 else if (regd == 2)
766 {
767 /* Absolute. */
77d66e7b 768 if (msp430dis_opcode_signed (addr + cmd_len, info, &dst, comm2))
13761a11 769 {
77d66e7b
NC
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 }
13761a11 777 }
d95014a2
YQ
778 else
779 return -1;
2469cfa2
NC
780 }
781 else
782 {
77d66e7b 783 if (msp430dis_opcode_signed (addr + cmd_len, info, &dst, comm2))
13761a11 784 {
77d66e7b 785 cmd_len += 2;
13761a11 786 if (dst > 9 || dst < 0)
77d66e7b
NC
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);
13761a11 797 }
d95014a2
YQ
798 else
799 return -1;
2469cfa2
NC
800 }
801 }
802
803 return cmd_len;
804}
805
47b0e7ad
NC
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)
2469cfa2
NC
814{
815 int regs = 0, regd = 0;
c7e2358a 816 int as = 0;
2469cfa2 817 int cmd_len = 2;
77d66e7b
NC
818 int dst = 0;
819 unsigned short udst = 0;
2469cfa2
NC
820
821 regd = insn & 0x0f;
822 regs = (insn & 0x0f00) >> 8;
823 as = (insn & 0x0030) >> 4;
2469cfa2
NC
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 {
13761a11 847 * cycles = print_as2_reg_name (regs, op1, comm1, 2, 1, 2);
2469cfa2
NC
848 }
849 else if (as == 3)
850 {
13761a11 851 if (regs == 0)
2469cfa2
NC
852 {
853 /* Absolute. @pc+ */
854 *cycles = 3;
77d66e7b
NC
855 if (msp430dis_opcode_unsigned (addr + 2, info, &udst, comm1))
856 {
857 cmd_len += 2;
858 sprintf (op1, "#0x%04x", PS (udst));
859 }
d95014a2
YQ
860 else
861 return -1;
2469cfa2
NC
862 }
863 else
13761a11 864 * cycles = print_as3_reg_name (regs, op1, comm1, 1, 1, 2);
2469cfa2
NC
865 }
866 else if (as == 1)
867 {
868 * cycles = 3;
869
870 if (regs == 0)
871 {
872 /* PC relative. */
77d66e7b
NC
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 }
d95014a2
YQ
881 else
882 return -1;
2469cfa2
NC
883 }
884 else if (regs == 2)
885 {
886 /* Absolute. */
77d66e7b
NC
887 if (msp430dis_opcode_unsigned (addr + 2, info, &udst, comm1))
888 {
889 cmd_len += 2;
890 sprintf (op1, "&0x%04x", PS (udst));
891 }
d95014a2
YQ
892 else
893 return -1;
2469cfa2
NC
894 }
895 else if (regs == 3)
896 {
897 (*cycles)--;
898 sprintf (op1, "#1");
899 sprintf (comm1, "r3 As==01");
900 }
901 else
902 {
13761a11 903 /* Indexed. */
77d66e7b
NC
904 if (msp430dis_opcode_signed (addr + 2, info, &dst, comm1))
905 {
906 cmd_len += 2;
907 sprintf (op1, "%d(r%d)", dst, regs);
908 }
d95014a2
YQ
909 else
910 return -1;
2469cfa2
NC
911 }
912 }
913
914 return cmd_len;
915}
47b0e7ad 916
13761a11
NC
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;
77d66e7b 930 int dst = 0;
13761a11
NC
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;
77d66e7b
NC
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 }
d95014a2
YQ
950 else
951 return -1;
13761a11
NC
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 */
77d66e7b
NC
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 }
d95014a2
YQ
972 else
973 return -1;
13761a11
NC
974 break;
975
976 case 9: /* CALLA pcrel-sym */
77d66e7b
NC
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 }
d95014a2
YQ
985 else
986 return -1;
13761a11
NC
987 break;
988
989 case 11: /* CALLA #imm20 */
77d66e7b
NC
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 }
d95014a2
YQ
997 else
998 return -1;
13761a11
NC
999 break;
1000
1001 default:
77d66e7b 1002 strcpy (comm1, _("Warning: unrecognised CALLA addressing mode"));
13761a11
NC
1003 return -1;
1004 }
1005
1006 return cmd_len;
1007}
1008
47b0e7ad
NC
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 = "";
13761a11 1020 unsigned short extension_word = 0;
77d66e7b 1021 unsigned short bits;
47b0e7ad 1022
77d66e7b 1023 if (! msp430dis_opcode_unsigned (addr, info, &insn, NULL))
d95014a2 1024 return -1;
47b0e7ad
NC
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
13761a11
NC
1035 /* Check for an extension word. */
1036 if ((insn & 0xf800) == 0x1800)
1037 {
1038 extension_word = insn;
1039 addr += 2;
77d66e7b 1040 if (! msp430dis_opcode_unsigned (addr, info, &insn, NULL))
d95014a2 1041 return -1;
13761a11
NC
1042 }
1043
47b0e7ad
NC
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. */
13761a11
NC
1055 if (opcode->insn_opnumb == 3
1056 && (insn & 0x000f) == 0
1057 && (insn & 0x0080) == 0)
47b0e7ad 1058 {
d95014a2 1059 int ret =
47b0e7ad
NC
1060 msp430_branchinstr (info, opcode, addr, insn, op1, comm1,
1061 &cycles);
d95014a2
YQ
1062
1063 if (ret == -1)
1064 return -1;
1065 cmd_len += ret;
47b0e7ad
NC
1066 if (cmd_len)
1067 break;
1068 }
1069
13761a11
NC
1070 switch (opcode->insn_opnumb)
1071 {
1072 int n;
1073 int reg;
d95014a2 1074 int ret;
13761a11
NC
1075
1076 case 4:
d95014a2
YQ
1077 ret = msp430x_calla_instr (info, addr, insn,
1078 op1, comm1, & cycles);
1079 if (ret == -1)
1080 return -1;
1081 cmd_len += ret;
13761a11
NC
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 }
43e65147 1102
13761a11
NC
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;
77d66e7b
NC
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 }
d95014a2
YQ
1136 else
1137 return -1;
13761a11
NC
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;
43e65147 1155
13761a11
NC
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;
43e65147 1165
13761a11
NC
1166 case 2: /* MOVA &abs20, Rdst */
1167 cmd_len = 4;
1168 n <<= 16;
77d66e7b
NC
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 }
d95014a2
YQ
1178 else
1179 return -1;
13761a11 1180 break;
43e65147 1181
13761a11
NC
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;
77d66e7b 1187 if (msp430dis_opcode_signed (addr + 2, info, &n, comm1))
13761a11 1188 {
77d66e7b
NC
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 }
13761a11 1198 }
d95014a2
YQ
1199 else
1200 return -1;
13761a11
NC
1201 break;
1202
1203 case 6: /* MOVA Rsrc, &abs20 */
1204 cmd_len = 4;
1205 reg <<= 16;
77d66e7b
NC
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 }
d95014a2
YQ
1214 else
1215 return -1;
13761a11
NC
1216 break;
1217
1218 case 7: /* MOVA Rsrc, x(Rdst) */
1219 cmd_len = 4;
1220 sprintf (op1, "r%d", n);
77d66e7b 1221 if (msp430dis_opcode_signed (addr + 2, info, &n, comm2))
13761a11 1222 {
77d66e7b
NC
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 }
13761a11 1232 }
d95014a2
YQ
1233 else
1234 return -1;
13761a11 1235 break;
43e65147 1236
13761a11
NC
1237 case 8: /* MOVA #imm20, Rdst */
1238 cmd_len = 4;
1239 n <<= 16;
77d66e7b
NC
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 }
d95014a2
YQ
1251 else
1252 return -1;
13761a11 1253 break;
43e65147 1254
13761a11
NC
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
47b0e7ad
NC
1272 switch (opcode->insn_opnumb)
1273 {
d95014a2
YQ
1274 int ret;
1275
47b0e7ad 1276 case 0:
13761a11 1277 cmd_len += msp430_nooperands (opcode, addr, insn, comm1, &cycles);
47b0e7ad
NC
1278 break;
1279 case 2:
d95014a2 1280 ret =
47b0e7ad 1281 msp430_doubleoperand (info, opcode, addr, insn, op1, op2,
13761a11
NC
1282 comm1, comm2,
1283 extension_word,
1284 &cycles);
d95014a2
YQ
1285
1286 if (ret == -1)
1287 return -1;
1288 cmd_len += ret;
47b0e7ad 1289 if (insn & BYTE_OPERATION)
13761a11
NC
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 {
c1d9289f 1298 if (extension_word & BYTE_OPERATION)
13761a11
NC
1299 bc = ".w";
1300 else
1301 {
1302 bc = ".?";
77d66e7b 1303 sprintf (comm2, _("Warning: reserved use of A/L and B/W bits detected"));
13761a11
NC
1304 }
1305 }
43e65147 1306
47b0e7ad
NC
1307 break;
1308 case 1:
d95014a2 1309 ret =
47b0e7ad 1310 msp430_singleoperand (info, opcode, addr, insn, op1, comm1,
13761a11 1311 extension_word,
47b0e7ad 1312 &cycles);
d95014a2
YQ
1313
1314 if (ret == -1)
1315 return -1;
1316 cmd_len += ret;
13761a11
NC
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 = ".?";
77d66e7b 1324 sprintf (comm2, _("Warning: reserved use of A/L and B/W bits detected"));
13761a11
NC
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 = ".?";
77d66e7b 1345 sprintf (comm2, _("Warning: reserved use of A/L and B/W bits detected"));
13761a11
NC
1346 }
1347 }
47b0e7ad
NC
1348 break;
1349 default:
1350 break;
1351 }
1352 }
1353
1354 if (cmd_len)
1355 break;
1356 }
1357
47b0e7ad
NC
1358 if (cmd_len < 1)
1359 {
1360 /* Unknown opcode, or invalid combination of operands. */
13761a11
NC
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 }
47b0e7ad
NC
1368 (*prin) (stream, ".word 0x%04x; ????", PS (insn));
1369 return 2;
1370 }
1371
13761a11
NC
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
c1d9289f
NC
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')
13761a11
NC
1387 (*prin) (stream, "%sx%s", opcode->name, bc);
1388 else
1389 (*prin) (stream, "%s%s", opcode->name, bc);
47b0e7ad
NC
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);
13761a11
NC
1426
1427 if (extension_word)
1428 cmd_len += 2;
1429
47b0e7ad
NC
1430 return cmd_len;
1431}
This page took 0.813893 seconds and 4 git commands to generate.