OpenCores
URL https://opencores.org/ocsvn/open8_urisc/open8_urisc/trunk

Subversion Repositories open8_urisc

[/] [open8_urisc/] [trunk/] [gnu/] [binutils/] [opcodes/] [msp430-dis.c] - Blame information for rev 143

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 18 khays
/* 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
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.