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

Subversion Repositories or1k

[/] [or1k/] [trunk/] [gdb-5.3/] [opcodes/] [tic4x-dis.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1181 sfurman
/* Print instructions for the Texas TMS320C[34]X, for GDB and GNU Binutils.
2
 
3
   Copyright 2002 Free Software Foundation, Inc.
4
 
5
   Contributed by Michael P. Hayes (m.hayes@elec.canterbury.ac.nz)
6
 
7
   This program is free software; you can redistribute it and/or modify
8
   it under the terms of the GNU General Public License as published by
9
   the Free Software Foundation; either version 2 of the License, or
10
   (at your option) any later version.
11
 
12
   This program is distributed in the hope that it will be useful,
13
   but WITHOUT ANY WARRANTY; without even the implied warranty of
14
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
   GNU General Public License for more details.
16
 
17
   You should have received a copy of the GNU General Public License
18
   along with this program; if not, write to the Free Software
19
   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
20
 
21
#include <math.h>
22
#include "libiberty.h"
23
#include "dis-asm.h"
24
#include "opcode/tic4x.h"
25
 
26
#define C4X_DEBUG 0
27
 
28
#define C4X_HASH_SIZE 11 /* 11 and above should give unique entries.  */
29
 
30
typedef enum
31
  {
32
    IMMED_SINT,
33
    IMMED_SUINT,
34
    IMMED_SFLOAT,
35
    IMMED_INT,
36
    IMMED_UINT,
37
    IMMED_FLOAT
38
  }
39
immed_t;
40
 
41
typedef enum
42
  {
43
    INDIRECT_SHORT,
44
    INDIRECT_LONG,
45
    INDIRECT_C4X
46
  }
47
indirect_t;
48
 
49
static int c4x_version = 0;
50
static int c4x_dp = 0;
51
 
52
static int
53
c4x_pc_offset (unsigned int op)
54
{
55
  /* Determine the PC offset for a C[34]x instruction.
56
     This could be simplified using some boolean algebra
57
     but at the expense of readability.  */
58
  switch (op >> 24)
59
    {
60
    case 0x60:  /* br */
61
    case 0x62:  /* call  (C4x) */
62
    case 0x64:  /* rptb  (C4x) */
63
      return 1;
64
    case 0x61:  /* brd */
65
    case 0x63:  /* laj */
66
    case 0x65:  /* rptbd (C4x) */
67
      return 3;
68
    case 0x66:  /* swi */
69
    case 0x67:
70
      return 0;
71
    default:
72
      break;
73
    }
74
 
75
  switch ((op & 0xffe00000) >> 20)
76
    {
77
    case 0x6a0: /* bB */
78
    case 0x720: /* callB */
79
    case 0x740: /* trapB */
80
      return 1;
81
 
82
    case 0x6a2: /* bBd */
83
    case 0x6a6: /* bBat */
84
    case 0x6aa: /* bBaf */
85
    case 0x722: /* lajB */
86
    case 0x748: /* latB */
87
    case 0x798: /* rptbd */
88
      return 3;
89
 
90
    default:
91
      break;
92
    }
93
 
94
  switch ((op & 0xfe200000) >> 20)
95
    {
96
    case 0x6e0: /* dbB */
97
      return 1;
98
 
99
    case 0x6e2: /* dbBd */
100
      return 3;
101
 
102
    default:
103
      break;
104
    }
105
 
106
  return 0;
107
}
108
 
109
static int
110
c4x_print_char (struct disassemble_info * info, char ch)
111
{
112
  if (info != NULL)
113
    (*info->fprintf_func) (info->stream, "%c", ch);
114
  return 1;
115
}
116
 
117
static int
118
c4x_print_str (struct disassemble_info *info, char *str)
119
{
120
  if (info != NULL)
121
    (*info->fprintf_func) (info->stream, "%s", str);
122
  return 1;
123
}
124
 
125
static int
126
c4x_print_register (struct disassemble_info *info,
127
                    unsigned long regno)
128
{
129
  static c4x_register_t **registertable = NULL;
130
  unsigned int i;
131
 
132
  if (registertable == NULL)
133
    {
134
      registertable = (c4x_register_t **)
135
        xmalloc (sizeof (c4x_register_t *) * REG_TABLE_SIZE);
136
      for (i = 0; i < c3x_num_registers; i++)
137
        registertable[c3x_registers[i].regno] = (void *)&c3x_registers[i];
138
      if (IS_CPU_C4X (c4x_version))
139
        {
140
          /* Add C4x additional registers, overwriting
141
             any C3x registers if necessary.  */
142
          for (i = 0; i < c4x_num_registers; i++)
143
            registertable[c4x_registers[i].regno] = (void *)&c4x_registers[i];
144
        }
145
    }
146
  if ((int) regno > (IS_CPU_C4X (c4x_version) ? C4X_REG_MAX : C3X_REG_MAX))
147
    return 0;
148
  if (info != NULL)
149
    (*info->fprintf_func) (info->stream, "%s", registertable[regno]->name);
150
  return 1;
151
}
152
 
153
static int
154
c4x_print_addr (struct disassemble_info *info,
155
                unsigned long addr)
156
{
157
  if (info != NULL)
158
    (*info->print_address_func)(addr, info);
159
  return 1;
160
}
161
 
162
static int
163
c4x_print_relative (struct disassemble_info *info,
164
                    unsigned long pc,
165
                    long offset,
166
                    unsigned long opcode)
167
{
168
  return c4x_print_addr (info, pc + offset + c4x_pc_offset (opcode));
169
}
170
 
171
static int
172
c4x_print_direct (struct disassemble_info *info,
173
                  unsigned long arg)
174
{
175
  if (info != NULL)
176
    {
177
      (*info->fprintf_func) (info->stream, "@");
178
      c4x_print_addr (info, arg + (c4x_dp << 16));
179
    }
180
  return 1;
181
}
182
 
183
/* FIXME: make the floating point stuff not rely on host
184
   floating point arithmetic.  */
185
void
186
c4x_print_ftoa (unsigned int val,
187
                FILE *stream,
188
                int (*pfunc)())
189
{
190
  int e;
191
  int s;
192
  int f;
193
  double num = 0.0;
194
 
195
  e = EXTRS (val, 31, 24);      /* exponent */
196
  if (e != -128)
197
    {
198
      s = EXTRU (val, 23, 23);  /* sign bit */
199
      f = EXTRU (val, 22, 0);    /* mantissa */
200
      if (s)
201
        f += -2 * (1 << 23);
202
      else
203
        f += (1 << 23);
204
      num = f / (double)(1 << 23);
205
      num = ldexp (num, e);
206
    }
207
  (*pfunc)(stream, "%.9g", num);
208
}
209
 
210
static int
211
c4x_print_immed (struct disassemble_info *info,
212
                 immed_t type,
213
                 unsigned long arg)
214
{
215
  int s;
216
  int f;
217
  int e;
218
  double num = 0.0;
219
 
220
  if (info == NULL)
221
    return 1;
222
  switch (type)
223
    {
224
    case IMMED_SINT:
225
    case IMMED_INT:
226
      (*info->fprintf_func) (info->stream, "%d", (long)arg);
227
      break;
228
 
229
    case IMMED_SUINT:
230
    case IMMED_UINT:
231
      (*info->fprintf_func) (info->stream, "%u", arg);
232
      break;
233
 
234
    case IMMED_SFLOAT:
235
      e = EXTRS (arg, 15, 12);
236
      if (e != -8)
237
        {
238
          s = EXTRU (arg, 11, 11);
239
          f = EXTRU (arg, 10, 0);
240
          if (s)
241
            f += -2 * (1 << 11);
242
          else
243
            f += (1 << 11);
244
          num = f / (double)(1 << 11);
245
          num = ldexp (num, e);
246
        }
247
      (*info->fprintf_func) (info->stream, "%f", num);
248
      break;
249
    case IMMED_FLOAT:
250
      e = EXTRS (arg, 31, 24);
251
      if (e != -128)
252
        {
253
          s = EXTRU (arg, 23, 23);
254
          f = EXTRU (arg, 22, 0);
255
          if (s)
256
            f += -2 * (1 << 23);
257
          else
258
            f += (1 << 23);
259
          num = f / (double)(1 << 23);
260
          num = ldexp (num, e);
261
        }
262
      (*info->fprintf_func) (info->stream, "%f", num);
263
      break;
264
    }
265
  return 1;
266
}
267
 
268
static int
269
c4x_print_cond (struct disassemble_info *info,
270
                unsigned int cond)
271
{
272
  static c4x_cond_t **condtable = NULL;
273
  unsigned int i;
274
 
275
  if (condtable == NULL)
276
    {
277
      condtable = (c4x_cond_t **)xmalloc (sizeof (c4x_cond_t *) * 32);
278
      for (i = 0; i < num_conds; i++)
279
        condtable[c4x_conds[i].cond] = (void *)&c4x_conds[i];
280
    }
281
  if (cond > 31 || condtable[cond] == NULL)
282
    return 0;
283
  if (info != NULL)
284
    (*info->fprintf_func) (info->stream, "%s", condtable[cond]->name);
285
  return 1;
286
}
287
 
288
static int
289
c4x_print_indirect (struct disassemble_info *info,
290
                    indirect_t type,
291
                    unsigned long arg)
292
{
293
  unsigned int aregno;
294
  unsigned int modn;
295
  unsigned int disp;
296
  char *a;
297
 
298
  aregno = 0;
299
  modn = 0;
300
  disp = 1;
301
  switch(type)
302
    {
303
    case INDIRECT_C4X:          /* *+ARn(disp) */
304
      disp = EXTRU (arg, 7, 3);
305
      aregno = EXTRU (arg, 2, 0) + REG_AR0;
306
      modn = 0;
307
      break;
308
    case INDIRECT_SHORT:
309
      disp = 1;
310
      aregno = EXTRU (arg, 2, 0) + REG_AR0;
311
      modn = EXTRU (arg, 7, 3);
312
      break;
313
    case INDIRECT_LONG:
314
      disp = EXTRU (arg, 7, 0);
315
      aregno = EXTRU (arg, 10, 8) + REG_AR0;
316
      modn = EXTRU (arg, 15, 11);
317
      if (modn > 7 && disp != 0)
318
        return 0;
319
      break;
320
    default:
321
      abort ();
322
    }
323
  if (modn > C3X_MODN_MAX)
324
    return 0;
325
  a = c4x_indirects[modn].name;
326
  while (*a)
327
    {
328
      switch (*a)
329
        {
330
        case 'a':
331
          c4x_print_register (info, aregno);
332
          break;
333
        case 'd':
334
          c4x_print_immed (info, IMMED_UINT, disp);
335
          break;
336
        case 'y':
337
          c4x_print_str (info, "ir0");
338
          break;
339
        case 'z':
340
          c4x_print_str (info, "ir1");
341
          break;
342
        default:
343
          c4x_print_char (info, *a);
344
          break;
345
        }
346
      a++;
347
    }
348
  return 1;
349
}
350
 
351
static int
352
c4x_print_op (struct disassemble_info *info,
353
              unsigned long instruction,
354
              c4x_inst_t *p, unsigned long pc)
355
{
356
  int val;
357
  char *s;
358
  char *parallel = NULL;
359
 
360
  /* Print instruction name.  */
361
  s = p->name;
362
  while (*s && parallel == NULL)
363
    {
364
      switch (*s)
365
        {
366
        case 'B':
367
          if (! c4x_print_cond (info, EXTRU (instruction, 20, 16)))
368
            return 0;
369
          break;
370
        case 'C':
371
          if (! c4x_print_cond (info, EXTRU (instruction, 27, 23)))
372
            return 0;
373
          break;
374
        case '_':
375
          parallel = s + 1;     /* Skip past `_' in name */
376
          break;
377
        default:
378
          c4x_print_char (info, *s);
379
          break;
380
        }
381
      s++;
382
    }
383
 
384
  /* Print arguments.  */
385
  s = p->args;
386
  if (*s)
387
    c4x_print_char (info, ' ');
388
 
389
  while (*s)
390
    {
391
      switch (*s)
392
        {
393
        case '*': /* indirect 0--15 */
394
          if (! c4x_print_indirect (info, INDIRECT_LONG,
395
                                    EXTRU (instruction, 15, 0)))
396
            return 0;
397
          break;
398
 
399
        case '#': /* only used for ldp, ldpk */
400
          c4x_print_immed (info, IMMED_UINT, EXTRU (instruction, 15, 0));
401
          break;
402
 
403
        case '@': /* direct 0--15 */
404
          c4x_print_direct (info, EXTRU (instruction, 15, 0));
405
          break;
406
 
407
        case 'A': /* address register 24--22 */
408
          if (! c4x_print_register (info, EXTRU (instruction, 24, 22) +
409
                                    REG_AR0))
410
            return 0;
411
          break;
412
 
413
        case 'B': /* 24-bit unsigned int immediate br(d)/call/rptb
414
                     address 0--23.  */
415
          if (IS_CPU_C4X (c4x_version))
416
            c4x_print_relative (info, pc, EXTRS (instruction, 23, 0),
417
                                p->opcode);
418
          else
419
            c4x_print_addr (info, EXTRU (instruction, 23, 0));
420
          break;
421
 
422
        case 'C': /* indirect (short C4x) 0--7 */
423
          if (! IS_CPU_C4X (c4x_version))
424
            return 0;
425
          if (! c4x_print_indirect (info, INDIRECT_C4X,
426
                                    EXTRU (instruction, 7, 0)))
427
            return 0;
428
          break;
429
 
430
        case 'D':
431
          /* Cockup if get here...  */
432
          break;
433
 
434
        case 'E': /* register 0--7 */
435
          if (! c4x_print_register (info, EXTRU (instruction, 7, 0)))
436
            return 0;
437
          break;
438
 
439
        case 'F': /* 16-bit float immediate 0--15 */
440
          c4x_print_immed (info, IMMED_SFLOAT,
441
                           EXTRU (instruction, 15, 0));
442
          break;
443
 
444
        case 'I': /* indirect (short) 0--7 */
445
          if (! c4x_print_indirect (info, INDIRECT_SHORT,
446
                                    EXTRU (instruction, 7, 0)))
447
            return 0;
448
          break;
449
 
450
        case 'J': /* indirect (short) 8--15 */
451
          if (! c4x_print_indirect (info, INDIRECT_SHORT,
452
                                    EXTRU (instruction, 15, 8)))
453
            return 0;
454
          break;
455
 
456
        case 'G': /* register 8--15 */
457
          if (! c4x_print_register (info, EXTRU (instruction, 15, 8)))
458
            return 0;
459
          break;
460
 
461
        case 'H': /* register 16--18 */
462
          if (! c4x_print_register (info, EXTRU (instruction, 18, 16)))
463
            return 0;
464
          break;
465
 
466
        case 'K': /* register 19--21 */
467
          if (! c4x_print_register (info, EXTRU (instruction, 21, 19)))
468
            return 0;
469
          break;
470
 
471
        case 'L': /* register 22--24 */
472
          if (! c4x_print_register (info, EXTRU (instruction, 24, 22)))
473
            return 0;
474
          break;
475
 
476
        case 'M': /* register 22--22 */
477
          c4x_print_register (info, EXTRU (instruction, 22, 22) + REG_R2);
478
          break;
479
 
480
        case 'N': /* register 23--23 */
481
          c4x_print_register (info, EXTRU (instruction, 22, 22) + REG_R0);
482
          break;
483
 
484
        case 'O': /* indirect (short C4x) 8--15 */
485
          if (! IS_CPU_C4X (c4x_version))
486
            return 0;
487
          if (! c4x_print_indirect (info, INDIRECT_C4X,
488
                                    EXTRU (instruction, 15, 8)))
489
            return 0;
490
          break;
491
 
492
        case 'P': /* displacement 0--15 (used by Bcond and BcondD) */
493
          c4x_print_relative (info, pc, EXTRS (instruction, 15, 0),
494
                              p->opcode);
495
          break;
496
 
497
        case 'Q': /* register 0--15 */
498
          if (! c4x_print_register (info, EXTRU (instruction, 15, 0)))
499
            return 0;
500
          break;
501
 
502
        case 'R': /* register 16--20 */
503
          if (! c4x_print_register (info, EXTRU (instruction, 20, 16)))
504
            return 0;
505
          break;
506
 
507
        case 'S': /* 16-bit signed immediate 0--15 */
508
          c4x_print_immed (info, IMMED_SINT,
509
                           EXTRS (instruction, 15, 0));
510
          break;
511
 
512
        case 'T': /* 5-bit signed immediate 16--20  (C4x stik) */
513
          if (! IS_CPU_C4X (c4x_version))
514
            return 0;
515
          if (! c4x_print_immed (info, IMMED_SUINT,
516
                                 EXTRU (instruction, 20, 16)))
517
            return 0;
518
          break;
519
 
520
        case 'U': /* 16-bit unsigned int immediate 0--15 */
521
          c4x_print_immed (info, IMMED_SUINT, EXTRU (instruction, 15, 0));
522
          break;
523
 
524
        case 'V': /* 5/9-bit unsigned vector 0--4/8 */
525
          c4x_print_immed (info, IMMED_SUINT,
526
                           IS_CPU_C4X (c4x_version) ?
527
                           EXTRU (instruction, 8, 0) :
528
                           EXTRU (instruction, 4, 0) & ~0x20);
529
          break;
530
 
531
        case 'W': /* 8-bit signed immediate 0--7 */
532
          if (! IS_CPU_C4X (c4x_version))
533
            return 0;
534
          c4x_print_immed (info, IMMED_SINT, EXTRS (instruction, 7, 0));
535
          break;
536
 
537
        case 'X': /* expansion register 4--0 */
538
          val = EXTRU (instruction, 4, 0) + REG_IVTP;
539
          if (val < REG_IVTP || val > REG_TVTP)
540
            return 0;
541
          if (! c4x_print_register (info, val))
542
            return 0;
543
          break;
544
 
545
        case 'Y': /* address register 16--20 */
546
          val = EXTRU (instruction, 20, 16);
547
          if (val < REG_AR0 || val > REG_SP)
548
            return 0;
549
          if (! c4x_print_register (info, val))
550
            return 0;
551
          break;
552
 
553
        case 'Z': /* expansion register 16--20 */
554
          val = EXTRU (instruction, 20, 16) + REG_IVTP;
555
          if (val < REG_IVTP || val > REG_TVTP)
556
            return 0;
557
          if (! c4x_print_register (info, val))
558
            return 0;
559
          break;
560
 
561
        case '|':               /* Parallel instruction */
562
          c4x_print_str (info, " || ");
563
          c4x_print_str (info, parallel);
564
          c4x_print_char (info, ' ');
565
          break;
566
 
567
        case ';':
568
          c4x_print_char (info, ',');
569
          break;
570
 
571
        default:
572
          c4x_print_char (info, *s);
573
          break;
574
        }
575
      s++;
576
    }
577
  return 1;
578
}
579
 
580
static void
581
c4x_hash_opcode (c4x_inst_t **optable,
582
                 const c4x_inst_t *inst)
583
{
584
  int j;
585
  int opcode = inst->opcode >> (32 - C4X_HASH_SIZE);
586
  int opmask = inst->opmask >> (32 - C4X_HASH_SIZE);
587
 
588
  /* Use a C4X_HASH_SIZE bit index as a hash index.  We should
589
     have unique entries so there's no point having a linked list
590
     for each entry? */
591
  for (j = opcode; j < opmask; j++)
592
    if ((j & opmask) == opcode)
593
      {
594
#if C4X_DEBUG
595
        /* We should only have collisions for synonyms like
596
           ldp for ldi.  */
597
        if (optable[j] != NULL)
598
          printf("Collision at index %d, %s and %s\n",
599
                 j, optable[j]->name, inst->name);
600
#endif
601
        optable[j] = (void *)inst;
602
      }
603
}
604
 
605
/* Disassemble the instruction in 'instruction'.
606
   'pc' should be the address of this instruction, it will
607
   be used to print the target address if this is a relative jump or call
608
   the disassembled instruction is written to 'info'.
609
   The function returns the length of this instruction in words.  */
610
 
611
static int
612
c4x_disassemble (unsigned long pc,
613
                 unsigned long instruction,
614
                 struct disassemble_info *info)
615
{
616
  static c4x_inst_t **optable = NULL;
617
  c4x_inst_t *p;
618
  int i;
619
 
620
  c4x_version = info->mach;
621
 
622
  if (optable == NULL)
623
    {
624
      optable = (c4x_inst_t **)
625
        xcalloc (sizeof (c4x_inst_t *), (1 << C4X_HASH_SIZE));
626
      /* Install opcodes in reverse order so that preferred
627
         forms overwrite synonyms.  */
628
      for (i = c3x_num_insts - 1; i >= 0; i--)
629
        c4x_hash_opcode (optable, &c3x_insts[i]);
630
      if (IS_CPU_C4X (c4x_version))
631
        {
632
          for (i = c4x_num_insts - 1; i >= 0; i--)
633
            c4x_hash_opcode (optable, &c4x_insts[i]);
634
        }
635
    }
636
 
637
  /* See if we can pick up any loading of the DP register...  */
638
  if ((instruction >> 16) == 0x5070 || (instruction >> 16) == 0x1f70)
639
    c4x_dp = EXTRU (instruction, 15, 0);
640
 
641
  p = optable[instruction >> (32 - C4X_HASH_SIZE)];
642
  if (p != NULL && ((instruction & p->opmask) == p->opcode)
643
      && c4x_print_op (NULL, instruction, p, pc))
644
    c4x_print_op (info, instruction, p, pc);
645
  else
646
    (*info->fprintf_func) (info->stream, "%08x", instruction);
647
 
648
  /* Return size of insn in words.  */
649
  return 1;
650
}
651
 
652
/* The entry point from objdump and gdb.  */
653
int
654
print_insn_tic4x (memaddr, info)
655
     bfd_vma memaddr;
656
     struct disassemble_info *info;
657
{
658
  int status;
659
  unsigned long pc;
660
  unsigned long op;
661
  bfd_byte buffer[4];
662
 
663
  status = (*info->read_memory_func) (memaddr, buffer, 4, info);
664
  if (status != 0)
665
    {
666
      (*info->memory_error_func) (status, memaddr, info);
667
      return -1;
668
    }
669
 
670
  pc = memaddr;
671
  op = bfd_getl32 (buffer);
672
  info->bytes_per_line = 4;
673
  info->bytes_per_chunk = 4;
674
  info->octets_per_byte = 4;
675
  info->display_endian = BFD_ENDIAN_LITTLE;
676
  return c4x_disassemble (pc, op, info) * 4;
677
}

powered by: WebSVN 2.1.0

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