fix set but unused variable warnings
[deliverable/binutils-gdb.git] / opcodes / msp430-dis.c
1 /* Disassemble MSP430 instructions.
2 Copyright (C) 2002, 2004, 2005, 2007, 2009, 2010
3 Free Software Foundation, Inc.
4
5 Contributed by Dmitry Diky <diwil@mail.ru>
6
7 This file is part of the GNU opcodes library.
8
9 This library is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 3, or (at your option)
12 any later version.
13
14 It is distributed in the hope that it will be useful, but WITHOUT
15 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
16 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
17 License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
22 MA 02110-1301, USA. */
23
24 #include <stdio.h>
25 #include <ctype.h>
26 #include <string.h>
27 #include <sys/types.h>
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
40 static unsigned short
41 msp430dis_opcode (bfd_vma addr, disassemble_info *info)
42 {
43 bfd_byte buffer[2];
44 int status;
45
46 status = info->read_memory_func (addr, buffer, 2, info);
47 if (status != 0)
48 {
49 info->memory_error_func (status, addr, info);
50 return -1;
51 }
52 return bfd_getl16 (buffer);
53 }
54
55 static int
56 msp430_nooperands (struct msp430_opcode_s *opcode,
57 bfd_vma addr ATTRIBUTE_UNUSED,
58 unsigned short insn ATTRIBUTE_UNUSED,
59 char *comm,
60 int *cycles)
61 {
62 /* Pop with constant. */
63 if (insn == 0x43b2)
64 return 0;
65 if (insn == opcode->bin_opcode)
66 return 2;
67
68 if (opcode->fmt == 0)
69 {
70 if ((insn & 0x0f00) != 3 || (insn & 0x0f00) != 2)
71 return 0;
72
73 strcpy (comm, "emulated...");
74 *cycles = 1;
75 }
76 else
77 {
78 strcpy (comm, "return from interupt");
79 *cycles = 5;
80 }
81
82 return 2;
83 }
84
85 static int
86 msp430_singleoperand (disassemble_info *info,
87 struct msp430_opcode_s *opcode,
88 bfd_vma addr,
89 unsigned short insn,
90 char *op,
91 char *comm,
92 int *cycles)
93 {
94 int regs = 0, regd = 0;
95 int ad = 0, as = 0;
96 int where = 0;
97 int cmd_len = 2;
98 short dst = 0;
99
100 regd = insn & 0x0f;
101 regs = (insn & 0x0f00) >> 8;
102 as = (insn & 0x0030) >> 4;
103 ad = (insn & 0x0080) >> 7;
104
105 switch (opcode->fmt)
106 {
107 case 0: /* Emulated work with dst register. */
108 if (regs != 2 && regs != 3 && regs != 1)
109 return 0;
110
111 /* Check if not clr insn. */
112 if (opcode->bin_opcode == 0x4300 && (ad || as))
113 return 0;
114
115 /* Check if really inc, incd insns. */
116 if ((opcode->bin_opcode & 0xff00) == 0x5300 && as == 3)
117 return 0;
118
119 if (ad == 0)
120 {
121 *cycles = 1;
122
123 /* Register. */
124 if (regd == 0)
125 {
126 *cycles += 1;
127 sprintf (op, "r0");
128 }
129 else if (regd == 1)
130 sprintf (op, "r1");
131
132 else if (regd == 2)
133 sprintf (op, "r2");
134
135 else
136 sprintf (op, "r%d", regd);
137 }
138 else /* ad == 1 msp430dis_opcode. */
139 {
140 if (regd == 0)
141 {
142 /* PC relative. */
143 dst = msp430dis_opcode (addr + 2, info);
144 cmd_len += 2;
145 *cycles = 4;
146 sprintf (op, "0x%04x", dst);
147 sprintf (comm, "PC rel. abs addr 0x%04x",
148 PS ((short) (addr + 2) + dst));
149 }
150 else if (regd == 2)
151 {
152 /* Absolute. */
153 dst = msp430dis_opcode (addr + 2, info);
154 cmd_len += 2;
155 *cycles = 4;
156 sprintf (op, "&0x%04x", PS (dst));
157 }
158 else
159 {
160 dst = msp430dis_opcode (addr + 2, info);
161 cmd_len += 2;
162 *cycles = 4;
163 sprintf (op, "%d(r%d)", dst, regd);
164 }
165 }
166 break;
167
168 case 2: /* rrc, push, call, swpb, rra, sxt, push, call, reti etc... */
169 if (as == 0)
170 {
171 if (regd == 3)
172 {
173 /* Constsnts. */
174 sprintf (op, "#0");
175 sprintf (comm, "r3 As==00");
176 }
177 else
178 {
179 /* Register. */
180 sprintf (op, "r%d", regd);
181 }
182 *cycles = 1;
183 }
184 else if (as == 2)
185 {
186 *cycles = 1;
187 if (regd == 2)
188 {
189 sprintf (op, "#4");
190 sprintf (comm, "r2 As==10");
191 }
192 else if (regd == 3)
193 {
194 sprintf (op, "#2");
195 sprintf (comm, "r3 As==10");
196 }
197 else
198 {
199 *cycles = 3;
200 /* Indexed register mode @Rn. */
201 sprintf (op, "@r%d", regd);
202 }
203 }
204 else if (as == 3)
205 {
206 *cycles = 1;
207 if (regd == 2)
208 {
209 sprintf (op, "#8");
210 sprintf (comm, "r2 As==11");
211 }
212 else if (regd == 3)
213 {
214 sprintf (op, "#-1");
215 sprintf (comm, "r3 As==11");
216 }
217 else if (regd == 0)
218 {
219 *cycles = 3;
220 /* absolute. @pc+ */
221 dst = msp430dis_opcode (addr + 2, info);
222 cmd_len += 2;
223 sprintf (op, "#%d", dst);
224 sprintf (comm, "#0x%04x", PS (dst));
225 }
226 else
227 {
228 *cycles = 3;
229 sprintf (op, "@r%d+", regd);
230 }
231 }
232 else if (as == 1)
233 {
234 *cycles = 4;
235 if (regd == 0)
236 {
237 /* PC relative. */
238 dst = msp430dis_opcode (addr + 2, info);
239 cmd_len += 2;
240 sprintf (op, "0x%04x", PS (dst));
241 sprintf (comm, "PC rel. 0x%04x",
242 PS ((short) addr + 2 + dst));
243 }
244 else if (regd == 2)
245 {
246 /* Absolute. */
247 dst = msp430dis_opcode (addr + 2, info);
248 cmd_len += 2;
249 sprintf (op, "&0x%04x", PS (dst));
250 }
251 else if (regd == 3)
252 {
253 *cycles = 1;
254 sprintf (op, "#1");
255 sprintf (comm, "r3 As==01");
256 }
257 else
258 {
259 /* Indexd. */
260 dst = msp430dis_opcode (addr + 2, info);
261 cmd_len += 2;
262 sprintf (op, "%d(r%d)", dst, regd);
263 }
264 }
265 break;
266
267 case 3: /* Jumps. */
268 where = insn & 0x03ff;
269 if (where & 0x200)
270 where |= ~0x03ff;
271 if (where > 512 || where < -511)
272 return 0;
273
274 where *= 2;
275 sprintf (op, "$%+-8d", where + 2);
276 sprintf (comm, "abs 0x%x", PS ((short) (addr) + 2 + where));
277 *cycles = 2;
278 return 2;
279 break;
280 default:
281 cmd_len = 0;
282 }
283
284 return cmd_len;
285 }
286
287 static int
288 msp430_doubleoperand (disassemble_info *info,
289 struct msp430_opcode_s *opcode,
290 bfd_vma addr,
291 unsigned short insn,
292 char *op1,
293 char *op2,
294 char *comm1,
295 char *comm2,
296 int *cycles)
297 {
298 int regs = 0, regd = 0;
299 int ad = 0, as = 0;
300 int cmd_len = 2;
301 short dst = 0;
302
303 regd = insn & 0x0f;
304 regs = (insn & 0x0f00) >> 8;
305 as = (insn & 0x0030) >> 4;
306 ad = (insn & 0x0080) >> 7;
307
308 if (opcode->fmt == 0)
309 {
310 /* Special case: rla and rlc are the only 2 emulated instructions that
311 fall into two operand instructions. */
312 /* With dst, there are only:
313 Rm Register,
314 x(Rm) Indexed,
315 0xXXXX Relative,
316 &0xXXXX Absolute
317 emulated_ins dst
318 basic_ins dst, dst. */
319
320 if (regd != regs || as != ad)
321 return 0; /* May be 'data' section. */
322
323 if (ad == 0)
324 {
325 /* Register mode. */
326 if (regd == 3)
327 {
328 strcpy (comm1, _("Illegal as emulation instr"));
329 return -1;
330 }
331
332 sprintf (op1, "r%d", regd);
333 *cycles = 1;
334 }
335 else /* ad == 1 */
336 {
337 if (regd == 0)
338 {
339 /* PC relative, Symbolic. */
340 dst = msp430dis_opcode (addr + 2, info);
341 cmd_len += 4;
342 *cycles = 6;
343 sprintf (op1, "0x%04x", PS (dst));
344 sprintf (comm1, "PC rel. 0x%04x",
345 PS ((short) addr + 2 + dst));
346
347 }
348 else if (regd == 2)
349 {
350 /* Absolute. */
351 dst = msp430dis_opcode (addr + 2, info);
352 /* If the 'src' field is not the same as the dst
353 then this is not an rla instruction. */
354 if (dst != msp430dis_opcode (addr + 4, info))
355 return 0;
356 cmd_len += 4;
357 *cycles = 6;
358 sprintf (op1, "&0x%04x", PS (dst));
359 }
360 else
361 {
362 /* Indexed. */
363 dst = msp430dis_opcode (addr + 2, info);
364 cmd_len += 4;
365 *cycles = 6;
366 sprintf (op1, "%d(r%d)", dst, regd);
367 }
368 }
369
370 *op2 = 0;
371 *comm2 = 0;
372 return cmd_len;
373 }
374
375 /* Two operands exactly. */
376 if (ad == 0 && regd == 3)
377 {
378 /* R2/R3 are illegal as dest: may be data section. */
379 strcpy (comm1, _("Illegal as 2-op instr"));
380 return -1;
381 }
382
383 /* Source. */
384 if (as == 0)
385 {
386 *cycles = 1;
387 if (regs == 3)
388 {
389 /* Constsnts. */
390 sprintf (op1, "#0");
391 sprintf (comm1, "r3 As==00");
392 }
393 else
394 {
395 /* Register. */
396 sprintf (op1, "r%d", regs);
397 }
398 }
399 else if (as == 2)
400 {
401 *cycles = 1;
402
403 if (regs == 2)
404 {
405 sprintf (op1, "#4");
406 sprintf (comm1, "r2 As==10");
407 }
408 else if (regs == 3)
409 {
410 sprintf (op1, "#2");
411 sprintf (comm1, "r3 As==10");
412 }
413 else
414 {
415 *cycles = 2;
416
417 /* Indexed register mode @Rn. */
418 sprintf (op1, "@r%d", regs);
419 }
420 if (!regs)
421 *cycles = 3;
422 }
423 else if (as == 3)
424 {
425 if (regs == 2)
426 {
427 sprintf (op1, "#8");
428 sprintf (comm1, "r2 As==11");
429 *cycles = 1;
430 }
431 else if (regs == 3)
432 {
433 sprintf (op1, "#-1");
434 sprintf (comm1, "r3 As==11");
435 *cycles = 1;
436 }
437 else if (regs == 0)
438 {
439 *cycles = 3;
440 /* Absolute. @pc+. */
441 dst = msp430dis_opcode (addr + 2, info);
442 cmd_len += 2;
443 sprintf (op1, "#%d", dst);
444 sprintf (comm1, "#0x%04x", PS (dst));
445 }
446 else
447 {
448 *cycles = 2;
449 sprintf (op1, "@r%d+", regs);
450 }
451 }
452 else if (as == 1)
453 {
454 if (regs == 0)
455 {
456 *cycles = 4;
457 /* PC relative. */
458 dst = msp430dis_opcode (addr + 2, info);
459 cmd_len += 2;
460 sprintf (op1, "0x%04x", PS (dst));
461 sprintf (comm1, "PC rel. 0x%04x",
462 PS ((short) addr + 2 + dst));
463 }
464 else if (regs == 2)
465 {
466 *cycles = 2;
467 /* Absolute. */
468 dst = msp430dis_opcode (addr + 2, info);
469 cmd_len += 2;
470 sprintf (op1, "&0x%04x", PS (dst));
471 sprintf (comm1, "0x%04x", PS (dst));
472 }
473 else if (regs == 3)
474 {
475 *cycles = 1;
476 sprintf (op1, "#1");
477 sprintf (comm1, "r3 As==01");
478 }
479 else
480 {
481 *cycles = 3;
482 /* Indexed. */
483 dst = msp430dis_opcode (addr + 2, info);
484 cmd_len += 2;
485 sprintf (op1, "%d(r%d)", dst, regs);
486 }
487 }
488
489 /* Destination. Special care needed on addr + XXXX. */
490
491 if (ad == 0)
492 {
493 /* Register. */
494 if (regd == 0)
495 {
496 *cycles += 1;
497 sprintf (op2, "r0");
498 }
499 else if (regd == 1)
500 sprintf (op2, "r1");
501
502 else if (regd == 2)
503 sprintf (op2, "r2");
504
505 else
506 sprintf (op2, "r%d", regd);
507 }
508 else /* ad == 1. */
509 {
510 * cycles += 3;
511
512 if (regd == 0)
513 {
514 /* PC relative. */
515 *cycles += 1;
516 dst = msp430dis_opcode (addr + cmd_len, info);
517 sprintf (op2, "0x%04x", PS (dst));
518 sprintf (comm2, "PC rel. 0x%04x",
519 PS ((short) addr + cmd_len + dst));
520 cmd_len += 2;
521 }
522 else if (regd == 2)
523 {
524 /* Absolute. */
525 dst = msp430dis_opcode (addr + cmd_len, info);
526 cmd_len += 2;
527 sprintf (op2, "&0x%04x", PS (dst));
528 }
529 else
530 {
531 dst = msp430dis_opcode (addr + cmd_len, info);
532 cmd_len += 2;
533 sprintf (op2, "%d(r%d)", dst, regd);
534 }
535 }
536
537 return cmd_len;
538 }
539
540 static int
541 msp430_branchinstr (disassemble_info *info,
542 struct msp430_opcode_s *opcode ATTRIBUTE_UNUSED,
543 bfd_vma addr ATTRIBUTE_UNUSED,
544 unsigned short insn,
545 char *op1,
546 char *comm1,
547 int *cycles)
548 {
549 int regs = 0, regd = 0;
550 int as = 0;
551 int cmd_len = 2;
552 short dst = 0;
553
554 regd = insn & 0x0f;
555 regs = (insn & 0x0f00) >> 8;
556 as = (insn & 0x0030) >> 4;
557
558 if (regd != 0) /* Destination register is not a PC. */
559 return 0;
560
561 /* dst is a source register. */
562 if (as == 0)
563 {
564 /* Constants. */
565 if (regs == 3)
566 {
567 *cycles = 1;
568 sprintf (op1, "#0");
569 sprintf (comm1, "r3 As==00");
570 }
571 else
572 {
573 /* Register. */
574 *cycles = 1;
575 sprintf (op1, "r%d", regs);
576 }
577 }
578 else if (as == 2)
579 {
580 if (regs == 2)
581 {
582 *cycles = 2;
583 sprintf (op1, "#4");
584 sprintf (comm1, "r2 As==10");
585 }
586 else if (regs == 3)
587 {
588 *cycles = 1;
589 sprintf (op1, "#2");
590 sprintf (comm1, "r3 As==10");
591 }
592 else
593 {
594 /* Indexed register mode @Rn. */
595 *cycles = 2;
596 sprintf (op1, "@r%d", regs);
597 }
598 }
599 else if (as == 3)
600 {
601 if (regs == 2)
602 {
603 *cycles = 1;
604 sprintf (op1, "#8");
605 sprintf (comm1, "r2 As==11");
606 }
607 else if (regs == 3)
608 {
609 *cycles = 1;
610 sprintf (op1, "#-1");
611 sprintf (comm1, "r3 As==11");
612 }
613 else if (regs == 0)
614 {
615 /* Absolute. @pc+ */
616 *cycles = 3;
617 dst = msp430dis_opcode (addr + 2, info);
618 cmd_len += 2;
619 sprintf (op1, "#0x%04x", PS (dst));
620 }
621 else
622 {
623 *cycles = 2;
624 sprintf (op1, "@r%d+", regs);
625 }
626 }
627 else if (as == 1)
628 {
629 * cycles = 3;
630
631 if (regs == 0)
632 {
633 /* PC relative. */
634 dst = msp430dis_opcode (addr + 2, info);
635 cmd_len += 2;
636 (*cycles)++;
637 sprintf (op1, "0x%04x", PS (dst));
638 sprintf (comm1, "PC rel. 0x%04x",
639 PS ((short) addr + 2 + dst));
640 }
641 else if (regs == 2)
642 {
643 /* Absolute. */
644 dst = msp430dis_opcode (addr + 2, info);
645 cmd_len += 2;
646 sprintf (op1, "&0x%04x", PS (dst));
647 }
648 else if (regs == 3)
649 {
650 (*cycles)--;
651 sprintf (op1, "#1");
652 sprintf (comm1, "r3 As==01");
653 }
654 else
655 {
656 /* Indexd. */
657 dst = msp430dis_opcode (addr + 2, info);
658 cmd_len += 2;
659 sprintf (op1, "%d(r%d)", dst, regs);
660 }
661 }
662
663 return cmd_len;
664 }
665
666 int
667 print_insn_msp430 (bfd_vma addr, disassemble_info *info)
668 {
669 void *stream = info->stream;
670 fprintf_ftype prin = info->fprintf_func;
671 struct msp430_opcode_s *opcode;
672 char op1[32], op2[32], comm1[64], comm2[64];
673 int cmd_len = 0;
674 unsigned short insn;
675 int cycles = 0;
676 char *bc = "";
677 char dinfo[32]; /* Debug purposes. */
678
679 insn = msp430dis_opcode (addr, info);
680 sprintf (dinfo, "0x%04x", insn);
681
682 if (((int) addr & 0xffff) > 0xffdf)
683 {
684 (*prin) (stream, "interrupt service routine at 0x%04x", 0xffff & insn);
685 return 2;
686 }
687
688 *comm1 = 0;
689 *comm2 = 0;
690
691 for (opcode = msp430_opcodes; opcode->name; opcode++)
692 {
693 if ((insn & opcode->bin_mask) == opcode->bin_opcode
694 && opcode->bin_opcode != 0x9300)
695 {
696 *op1 = 0;
697 *op2 = 0;
698 *comm1 = 0;
699 *comm2 = 0;
700
701 /* r0 as destination. Ad should be zero. */
702 if (opcode->insn_opnumb == 3 && (insn & 0x000f) == 0
703 && (0x0080 & insn) == 0)
704 {
705 cmd_len =
706 msp430_branchinstr (info, opcode, addr, insn, op1, comm1,
707 &cycles);
708 if (cmd_len)
709 break;
710 }
711
712 switch (opcode->insn_opnumb)
713 {
714 case 0:
715 cmd_len = msp430_nooperands (opcode, addr, insn, comm1, &cycles);
716 break;
717 case 2:
718 cmd_len =
719 msp430_doubleoperand (info, opcode, addr, insn, op1, op2,
720 comm1, comm2, &cycles);
721 if (insn & BYTE_OPERATION)
722 bc = ".b";
723 break;
724 case 1:
725 cmd_len =
726 msp430_singleoperand (info, opcode, addr, insn, op1, comm1,
727 &cycles);
728 if (insn & BYTE_OPERATION && opcode->fmt != 3)
729 bc = ".b";
730 break;
731 default:
732 break;
733 }
734 }
735
736 if (cmd_len)
737 break;
738 }
739
740 dinfo[5] = 0;
741
742 if (cmd_len < 1)
743 {
744 /* Unknown opcode, or invalid combination of operands. */
745 (*prin) (stream, ".word 0x%04x; ????", PS (insn));
746 return 2;
747 }
748
749 (*prin) (stream, "%s%s", opcode->name, bc);
750
751 if (*op1)
752 (*prin) (stream, "\t%s", op1);
753 if (*op2)
754 (*prin) (stream, ",");
755
756 if (strlen (op1) < 7)
757 (*prin) (stream, "\t");
758 if (!strlen (op1))
759 (*prin) (stream, "\t");
760
761 if (*op2)
762 (*prin) (stream, "%s", op2);
763 if (strlen (op2) < 8)
764 (*prin) (stream, "\t");
765
766 if (*comm1 || *comm2)
767 (*prin) (stream, ";");
768 else if (cycles)
769 {
770 if (*op2)
771 (*prin) (stream, ";");
772 else
773 {
774 if (strlen (op1) < 7)
775 (*prin) (stream, ";");
776 else
777 (*prin) (stream, "\t;");
778 }
779 }
780 if (*comm1)
781 (*prin) (stream, "%s", comm1);
782 if (*comm1 && *comm2)
783 (*prin) (stream, ",");
784 if (*comm2)
785 (*prin) (stream, " %s", comm2);
786 return cmd_len;
787 }
This page took 0.046746 seconds and 5 git commands to generate.