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

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-stable/] [binutils-2.20.1/] [opcodes/] [msp430-dis.c] - Blame information for rev 861

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

Line No. Rev Author Line
1 205 julius
/* Disassemble MSP430 instructions.
2
   Copyright (C) 2002, 2004, 2005, 2007, 2009 Free Software Foundation, Inc.
3
 
4
   Contributed by Dmitry Diky <diwil@mail.ru>
5
 
6
   This file is part of the GNU opcodes library.
7
 
8
   This library is free software; you can redistribute it and/or modify
9
   it under the terms of the GNU General Public License as published by
10
   the Free Software Foundation; either version 3, or (at your option)
11
   any later version.
12
 
13
   It is distributed in the hope that it will be useful, but WITHOUT
14
   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15
   or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
16
   License for more details.
17
 
18
   You should have received a copy of the GNU General Public License
19
   along with this program; if not, write to the Free Software
20
   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
21
   MA 02110-1301, USA.  */
22
 
23
#include <stdio.h>
24
#include <ctype.h>
25
#include <string.h>
26
#include <sys/types.h>
27
 
28
#include "dis-asm.h"
29
#include "opintl.h"
30
#include "libiberty.h"
31
 
32
#define DASM_SECTION
33
#include "opcode/msp430.h"
34
#undef DASM_SECTION
35
 
36
 
37
#define PS(x)   (0xffff & (x))
38
 
39
static unsigned short
40
msp430dis_opcode (bfd_vma addr, disassemble_info *info)
41
{
42
  bfd_byte buffer[2];
43
  int status;
44
 
45
  status = info->read_memory_func (addr, buffer, 2, info);
46
  if (status != 0)
47
    {
48
      info->memory_error_func (status, addr, info);
49
      return -1;
50
    }
51
  return bfd_getl16 (buffer);
52
}
53
 
54
static int
55
msp430_nooperands (struct msp430_opcode_s *opcode,
56
                   bfd_vma addr ATTRIBUTE_UNUSED,
57
                   unsigned short insn ATTRIBUTE_UNUSED,
58
                   char *comm,
59
                   int *cycles)
60
{
61
  /* Pop with constant.  */
62
  if (insn == 0x43b2)
63
    return 0;
64
  if (insn == opcode->bin_opcode)
65
    return 2;
66
 
67
  if (opcode->fmt == 0)
68
    {
69
      if ((insn & 0x0f00) != 3 || (insn & 0x0f00) != 2)
70
        return 0;
71
 
72
      strcpy (comm, "emulated...");
73
      *cycles = 1;
74
    }
75
  else
76
    {
77
      strcpy (comm, "return from interupt");
78
      *cycles = 5;
79
    }
80
 
81
  return 2;
82
}
83
 
84
static int
85
msp430_singleoperand (disassemble_info *info,
86
                      struct msp430_opcode_s *opcode,
87
                      bfd_vma addr,
88
                      unsigned short insn,
89
                      char *op,
90
                      char *comm,
91
                      int *cycles)
92
{
93
  int regs = 0, regd = 0;
94
  int ad = 0, as = 0;
95
  int where = 0;
96
  int cmd_len = 2;
97
  short dst = 0;
98
 
99
  regd = insn & 0x0f;
100
  regs = (insn & 0x0f00) >> 8;
101
  as = (insn & 0x0030) >> 4;
102
  ad = (insn & 0x0080) >> 7;
103
 
104
  switch (opcode->fmt)
105
    {
106
    case 0:                      /* Emulated work with dst register.  */
107
      if (regs != 2 && regs != 3 && regs != 1)
108
        return 0;
109
 
110
      /* Check if not clr insn.  */
111
      if (opcode->bin_opcode == 0x4300 && (ad || as))
112
        return 0;
113
 
114
      /* Check if really inc, incd insns.  */
115
      if ((opcode->bin_opcode & 0xff00) == 0x5300 && as == 3)
116
        return 0;
117
 
118
      if (ad == 0)
119
        {
120
          *cycles = 1;
121
 
122
          /* Register.  */
123
          if (regd == 0)
124
            {
125
              *cycles += 1;
126
              sprintf (op, "r0");
127
            }
128
          else if (regd == 1)
129
            sprintf (op, "r1");
130
 
131
          else if (regd == 2)
132
            sprintf (op, "r2");
133
 
134
          else
135
            sprintf (op, "r%d", regd);
136
        }
137
      else      /* ad == 1 msp430dis_opcode.  */
138
        {
139
          if (regd == 0)
140
            {
141
              /* PC relative.  */
142
              dst = msp430dis_opcode (addr + 2, info);
143
              cmd_len += 2;
144
              *cycles = 4;
145
              sprintf (op, "0x%04x", dst);
146
              sprintf (comm, "PC rel. abs addr 0x%04x",
147
                       PS ((short) (addr + 2) + dst));
148
            }
149
          else if (regd == 2)
150
            {
151
              /* Absolute.  */
152
              dst = msp430dis_opcode (addr + 2, info);
153
              cmd_len += 2;
154
              *cycles = 4;
155
              sprintf (op, "&0x%04x", PS (dst));
156
            }
157
          else
158
            {
159
              dst = msp430dis_opcode (addr + 2, info);
160
              cmd_len += 2;
161
              *cycles = 4;
162
              sprintf (op, "%d(r%d)", dst, regd);
163
            }
164
        }
165
      break;
166
 
167
    case 2:     /* rrc, push, call, swpb, rra, sxt, push, call, reti etc...  */
168
      if (as == 0)
169
        {
170
          if (regd == 3)
171
            {
172
              /* Constsnts.  */
173
              sprintf (op, "#0");
174
              sprintf (comm, "r3 As==00");
175
            }
176
          else
177
            {
178
              /* Register.  */
179
              sprintf (op, "r%d", regd);
180
            }
181
          *cycles = 1;
182
        }
183
      else if (as == 2)
184
        {
185
          *cycles = 1;
186
          if (regd == 2)
187
            {
188
              sprintf (op, "#4");
189
              sprintf (comm, "r2 As==10");
190
            }
191
          else if (regd == 3)
192
            {
193
              sprintf (op, "#2");
194
              sprintf (comm, "r3 As==10");
195
            }
196
          else
197
            {
198
              *cycles = 3;
199
              /* Indexed register mode @Rn.  */
200
              sprintf (op, "@r%d", regd);
201
            }
202
        }
203
      else if (as == 3)
204
        {
205
          *cycles = 1;
206
          if (regd == 2)
207
            {
208
              sprintf (op, "#8");
209
              sprintf (comm, "r2 As==11");
210
            }
211
          else if (regd == 3)
212
            {
213
              sprintf (op, "#-1");
214
              sprintf (comm, "r3 As==11");
215
            }
216
          else if (regd == 0)
217
            {
218
              *cycles = 3;
219
              /* absolute. @pc+ */
220
              dst = msp430dis_opcode (addr + 2, info);
221
              cmd_len += 2;
222
              sprintf (op, "#%d", dst);
223
              sprintf (comm, "#0x%04x", PS (dst));
224
            }
225
          else
226
            {
227
              *cycles = 3;
228
              sprintf (op, "@r%d+", regd);
229
            }
230
        }
231
      else if (as == 1)
232
        {
233
          *cycles = 4;
234
          if (regd == 0)
235
            {
236
              /* PC relative.  */
237
              dst = msp430dis_opcode (addr + 2, info);
238
              cmd_len += 2;
239
              sprintf (op, "0x%04x", PS (dst));
240
              sprintf (comm, "PC rel. 0x%04x",
241
                       PS ((short) addr + 2 + dst));
242
            }
243
          else if (regd == 2)
244
            {
245
              /* Absolute.  */
246
              dst = msp430dis_opcode (addr + 2, info);
247
              cmd_len += 2;
248
              sprintf (op, "&0x%04x", PS (dst));
249
            }
250
          else if (regd == 3)
251
            {
252
              *cycles = 1;
253
              sprintf (op, "#1");
254
              sprintf (comm, "r3 As==01");
255
            }
256
          else
257
            {
258
              /* Indexd.  */
259
              dst = msp430dis_opcode (addr + 2, info);
260
              cmd_len += 2;
261
              sprintf (op, "%d(r%d)", dst, regd);
262
            }
263
        }
264
      break;
265
 
266
    case 3:                     /* Jumps.  */
267
      where = insn & 0x03ff;
268
      if (where & 0x200)
269
        where |= ~0x03ff;
270
      if (where > 512 || where < -511)
271
        return 0;
272
 
273
      where *= 2;
274
      sprintf (op, "$%+-8d", where + 2);
275
      sprintf (comm, "abs 0x%x", PS ((short) (addr) + 2 + where));
276
      *cycles = 2;
277
      return 2;
278
      break;
279
    default:
280
      cmd_len = 0;
281
    }
282
 
283
  return cmd_len;
284
}
285
 
286
static int
287
msp430_doubleoperand (disassemble_info *info,
288
                      struct msp430_opcode_s *opcode,
289
                      bfd_vma addr,
290
                      unsigned short insn,
291
                      char *op1,
292
                      char *op2,
293
                      char *comm1,
294
                      char *comm2,
295
                      int *cycles)
296
{
297
  int regs = 0, regd = 0;
298
  int ad = 0, as = 0;
299
  int cmd_len = 2;
300
  short dst = 0;
301
 
302
  regd = insn & 0x0f;
303
  regs = (insn & 0x0f00) >> 8;
304
  as = (insn & 0x0030) >> 4;
305
  ad = (insn & 0x0080) >> 7;
306
 
307
  if (opcode->fmt == 0)
308
    {
309
      /* Special case: rla and rlc are the only 2 emulated instructions that
310
         fall into two operand instructions.  */
311
      /* With dst, there are only:
312
         Rm             Register,
313
         x(Rm)          Indexed,
314
         0xXXXX         Relative,
315
         &0xXXXX        Absolute
316
         emulated_ins   dst
317
         basic_ins      dst, dst.  */
318
 
319
      if (regd != regs || as != ad)
320
        return 0;                /* May be 'data' section.  */
321
 
322
      if (ad == 0)
323
        {
324
          /* Register mode.  */
325
          if (regd == 3)
326
            {
327
              strcpy (comm1, _("Illegal as emulation instr"));
328
              return -1;
329
            }
330
 
331
          sprintf (op1, "r%d", regd);
332
          *cycles = 1;
333
        }
334
      else                      /* ad == 1 */
335
        {
336
          if (regd == 0)
337
            {
338
              /* PC relative, Symbolic.  */
339
              dst = msp430dis_opcode (addr + 2, info);
340
              cmd_len += 4;
341
              *cycles = 6;
342
              sprintf (op1, "0x%04x", PS (dst));
343
              sprintf (comm1, "PC rel. 0x%04x",
344
                       PS ((short) addr + 2 + dst));
345
 
346
            }
347
          else if (regd == 2)
348
            {
349
              /* Absolute.  */
350
              dst = msp430dis_opcode (addr + 2, info);
351
              /* If the 'src' field is not the same as the dst
352
                 then this is not an rla instruction.  */
353
              if (dst != msp430dis_opcode (addr + 4, info))
354
                return 0;
355
              cmd_len += 4;
356
              *cycles = 6;
357
              sprintf (op1, "&0x%04x", PS (dst));
358
            }
359
          else
360
            {
361
              /* Indexed.  */
362
              dst = msp430dis_opcode (addr + 2, info);
363
              cmd_len += 4;
364
              *cycles = 6;
365
              sprintf (op1, "%d(r%d)", dst, regd);
366
            }
367
        }
368
 
369
      *op2 = 0;
370
      *comm2 = 0;
371
      return cmd_len;
372
    }
373
 
374
  /* Two operands exactly.  */
375
  if (ad == 0 && regd == 3)
376
    {
377
      /* R2/R3 are illegal as dest: may be data section.  */
378
      strcpy (comm1, _("Illegal as 2-op instr"));
379
      return -1;
380
    }
381
 
382
  /* Source.  */
383
  if (as == 0)
384
    {
385
      *cycles = 1;
386
      if (regs == 3)
387
        {
388
          /* Constsnts.  */
389
          sprintf (op1, "#0");
390
          sprintf (comm1, "r3 As==00");
391
        }
392
      else
393
        {
394
          /* Register.  */
395
          sprintf (op1, "r%d", regs);
396
        }
397
    }
398
  else if (as == 2)
399
    {
400
      *cycles = 1;
401
 
402
      if (regs == 2)
403
        {
404
          sprintf (op1, "#4");
405
          sprintf (comm1, "r2 As==10");
406
        }
407
      else if (regs == 3)
408
        {
409
          sprintf (op1, "#2");
410
          sprintf (comm1, "r3 As==10");
411
        }
412
      else
413
        {
414
          *cycles = 2;
415
 
416
          /* Indexed register mode @Rn.  */
417
          sprintf (op1, "@r%d", regs);
418
        }
419
      if (!regs)
420
        *cycles = 3;
421
    }
422
  else if (as == 3)
423
    {
424
      if (regs == 2)
425
        {
426
          sprintf (op1, "#8");
427
          sprintf (comm1, "r2 As==11");
428
          *cycles = 1;
429
        }
430
      else if (regs == 3)
431
        {
432
          sprintf (op1, "#-1");
433
          sprintf (comm1, "r3 As==11");
434
          *cycles = 1;
435
        }
436
      else if (regs == 0)
437
        {
438
          *cycles = 3;
439
          /* Absolute. @pc+.  */
440
          dst = msp430dis_opcode (addr + 2, info);
441
          cmd_len += 2;
442
          sprintf (op1, "#%d", dst);
443
          sprintf (comm1, "#0x%04x", PS (dst));
444
        }
445
      else
446
        {
447
          *cycles = 2;
448
          sprintf (op1, "@r%d+", regs);
449
        }
450
    }
451
  else if (as == 1)
452
    {
453
      if (regs == 0)
454
        {
455
          *cycles = 4;
456
          /* PC relative.  */
457
          dst = msp430dis_opcode (addr + 2, info);
458
          cmd_len += 2;
459
          sprintf (op1, "0x%04x", PS (dst));
460
          sprintf (comm1, "PC rel. 0x%04x",
461
                   PS ((short) addr + 2 + dst));
462
        }
463
      else if (regs == 2)
464
        {
465
          *cycles = 2;
466
          /* Absolute.  */
467
          dst = msp430dis_opcode (addr + 2, info);
468
          cmd_len += 2;
469
          sprintf (op1, "&0x%04x", PS (dst));
470
          sprintf (comm1, "0x%04x", PS (dst));
471
        }
472
      else if (regs == 3)
473
        {
474
          *cycles = 1;
475
          sprintf (op1, "#1");
476
          sprintf (comm1, "r3 As==01");
477
        }
478
      else
479
        {
480
          *cycles = 3;
481
          /* Indexed.  */
482
          dst = msp430dis_opcode (addr + 2, info);
483
          cmd_len += 2;
484
          sprintf (op1, "%d(r%d)", dst, regs);
485
        }
486
    }
487
 
488
  /* Destination. Special care needed on addr + XXXX.  */
489
 
490
  if (ad == 0)
491
    {
492
      /* Register.  */
493
      if (regd == 0)
494
        {
495
          *cycles += 1;
496
          sprintf (op2, "r0");
497
        }
498
      else if (regd == 1)
499
        sprintf (op2, "r1");
500
 
501
      else if (regd == 2)
502
        sprintf (op2, "r2");
503
 
504
      else
505
        sprintf (op2, "r%d", regd);
506
    }
507
  else  /* ad == 1.  */
508
    {
509
      * cycles += 3;
510
 
511
      if (regd == 0)
512
        {
513
          /* PC relative.  */
514
          *cycles += 1;
515
          dst = msp430dis_opcode (addr + cmd_len, info);
516
          sprintf (op2, "0x%04x", PS (dst));
517
          sprintf (comm2, "PC rel. 0x%04x",
518
                   PS ((short) addr + cmd_len + dst));
519
          cmd_len += 2;
520
        }
521
      else if (regd == 2)
522
        {
523
          /* Absolute.  */
524
          dst = msp430dis_opcode (addr + cmd_len, info);
525
          cmd_len += 2;
526
          sprintf (op2, "&0x%04x", PS (dst));
527
        }
528
      else
529
        {
530
          dst = msp430dis_opcode (addr + cmd_len, info);
531
          cmd_len += 2;
532
          sprintf (op2, "%d(r%d)", dst, regd);
533
        }
534
    }
535
 
536
  return cmd_len;
537
}
538
 
539
static int
540
msp430_branchinstr (disassemble_info *info,
541
                    struct msp430_opcode_s *opcode ATTRIBUTE_UNUSED,
542
                    bfd_vma addr ATTRIBUTE_UNUSED,
543
                    unsigned short insn,
544
                    char *op1,
545
                    char *comm1,
546
                    int *cycles)
547
{
548
  int regs = 0, regd = 0;
549
  int ad = 0, as = 0;
550
  int cmd_len = 2;
551
  short dst = 0;
552
 
553
  regd = insn & 0x0f;
554
  regs = (insn & 0x0f00) >> 8;
555
  as = (insn & 0x0030) >> 4;
556
  ad = (insn & 0x0080) >> 7;
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.