Home | History | Annotate | Download | only in opcodes
      1 /* Disassembly routines for TMS320C54X architecture
      2    Copyright (C) 1999-2014 Free Software Foundation, Inc.
      3    Contributed by Timothy Wall (twall (at) cygnus.com)
      4 
      5    This file is part of the GNU opcodes library.
      6 
      7    This library 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 3, or (at your option)
     10    any later version.
     11 
     12    It is distributed in the hope that it will be useful, but WITHOUT
     13    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
     14    or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
     15    License for more details.
     16 
     17    You should have received a copy of the GNU General Public License
     18    along with this file; see the file COPYING.  If not, write to the
     19    Free Software Foundation, 51 Franklin Street - Fifth Floor, Boston,
     20    MA 02110-1301, USA.  */
     21 
     22 #include "sysdep.h"
     23 #include <errno.h>
     24 #include <math.h>
     25 #include <stdlib.h>
     26 #include "dis-asm.h"
     27 #include "opcode/tic54x.h"
     28 #include "coff/tic54x.h"
     29 
     30 static int has_lkaddr (unsigned short, const insn_template *);
     31 static int get_insn_size (unsigned short, const insn_template *);
     32 static int print_instruction (disassemble_info *, bfd_vma,
     33                               unsigned short, const char *,
     34                               const enum optype [], int, int);
     35 static int print_parallel_instruction (disassemble_info *, bfd_vma,
     36                                        unsigned short,
     37                                        const insn_template *, int);
     38 static int sprint_dual_address (disassemble_info *,char [],
     39                                 unsigned short);
     40 static int sprint_indirect_address (disassemble_info *,char [],
     41                                     unsigned short);
     42 static int sprint_direct_address (disassemble_info *,char [],
     43                                   unsigned short);
     44 static int sprint_mmr (disassemble_info *,char [],int);
     45 static int sprint_condition (disassemble_info *,char *,unsigned short);
     46 static int sprint_cc2 (disassemble_info *,char *,unsigned short);
     47 
     48 int
     49 print_insn_tic54x (bfd_vma memaddr, disassemble_info *info)
     50 {
     51   bfd_byte opbuf[2];
     52   unsigned short opcode;
     53   int status, size;
     54   const insn_template* tm;
     55 
     56   status = (*info->read_memory_func) (memaddr, opbuf, 2, info);
     57   if (status != 0)
     58   {
     59     (*info->memory_error_func) (status, memaddr, info);
     60     return -1;
     61   }
     62 
     63   opcode = bfd_getl16 (opbuf);
     64   tm = tic54x_get_insn (info, memaddr, opcode, &size);
     65 
     66   info->bytes_per_line = 2;
     67   info->bytes_per_chunk = 2;
     68   info->octets_per_byte = 2;
     69   info->display_endian = BFD_ENDIAN_LITTLE;
     70 
     71   if (tm->flags & FL_PAR)
     72   {
     73     if (!print_parallel_instruction (info, memaddr, opcode, tm, size))
     74       return -1;
     75   }
     76   else
     77   {
     78     if (!print_instruction (info, memaddr, opcode,
     79                             (char *) tm->name,
     80                             tm->operand_types,
     81                             size, (tm->flags & FL_EXT)))
     82       return -1;
     83   }
     84 
     85   return size * 2;
     86 }
     87 
     88 static int
     89 has_lkaddr (unsigned short memdata, const insn_template *tm)
     90 {
     91   return (IS_LKADDR (memdata)
     92 	  && (OPTYPE (tm->operand_types[0]) == OP_Smem
     93 	      || OPTYPE (tm->operand_types[1]) == OP_Smem
     94 	      || OPTYPE (tm->operand_types[2]) == OP_Smem
     95 	      || OPTYPE (tm->operand_types[1]) == OP_Sind
     96               || OPTYPE (tm->operand_types[0]) == OP_Lmem
     97               || OPTYPE (tm->operand_types[1]) == OP_Lmem));
     98 }
     99 
    100 /* always returns 1 (whether an insn template was found) since we provide an
    101    "unknown instruction" template */
    102 const insn_template*
    103 tic54x_get_insn (disassemble_info *info, bfd_vma addr,
    104                  unsigned short memdata, int *size)
    105 {
    106   const insn_template *tm = NULL;
    107 
    108   for (tm = tic54x_optab; tm->name; tm++)
    109   {
    110     if (tm->opcode == (memdata & tm->mask))
    111     {
    112       /* a few opcodes span two words */
    113       if (tm->flags & FL_EXT)
    114         {
    115           /* if lk addressing is used, the second half of the opcode gets
    116              pushed one word later */
    117           bfd_byte opbuf[2];
    118           bfd_vma addr2 = addr + 1 + has_lkaddr (memdata, tm);
    119           int status = (*info->read_memory_func) (addr2, opbuf, 2, info);
    120           // FIXME handle errors
    121           if (status == 0)
    122             {
    123               unsigned short data2 = bfd_getl16 (opbuf);
    124               if (tm->opcode2 == (data2 & tm->mask2))
    125                 {
    126                   if (size) *size = get_insn_size (memdata, tm);
    127                   return tm;
    128                 }
    129             }
    130         }
    131       else
    132         {
    133           if (size) *size = get_insn_size (memdata, tm);
    134           return tm;
    135         }
    136     }
    137   }
    138   for (tm = (insn_template *) tic54x_paroptab; tm->name; tm++)
    139   {
    140     if (tm->opcode == (memdata & tm->mask))
    141     {
    142       if (size) *size = get_insn_size (memdata, tm);
    143       return tm;
    144     }
    145   }
    146 
    147   if (size) *size = 1;
    148   return &tic54x_unknown_opcode;
    149 }
    150 
    151 static int
    152 get_insn_size (unsigned short memdata, const insn_template *insn)
    153 {
    154   int size;
    155 
    156   if (insn->flags & FL_PAR)
    157     {
    158       /* only non-parallel instructions support lk addressing */
    159       size = insn->words;
    160     }
    161   else
    162     {
    163       size = insn->words + has_lkaddr (memdata, insn);
    164     }
    165 
    166   return size;
    167 }
    168 
    169 int
    170 print_instruction (disassemble_info *info,
    171 		   bfd_vma memaddr,
    172 		   unsigned short opcode,
    173 		   const char *tm_name,
    174 		   const enum optype tm_operands[],
    175 		   int size,
    176 		   int ext)
    177 {
    178   static int n;
    179   /* string storage for multiple operands */
    180   char operand[4][64] = { {0},{0},{0},{0}, };
    181   bfd_byte buf[2];
    182   unsigned long opcode2 = 0;
    183   unsigned long lkaddr = 0;
    184   enum optype src = OP_None;
    185   enum optype dst = OP_None;
    186   int i, shift;
    187   char *comma = "";
    188 
    189   info->fprintf_func (info->stream, "%-7s", tm_name);
    190 
    191   if (size > 1)
    192     {
    193       int status = (*info->read_memory_func) (memaddr + 1, buf, 2, info);
    194       if (status != 0)
    195         return 0;
    196       lkaddr = opcode2 = bfd_getl16 (buf);
    197       if (size > 2)
    198         {
    199           status = (*info->read_memory_func) (memaddr + 2, buf, 2, info);
    200           if (status != 0)
    201             return 0;
    202           opcode2 = bfd_getl16 (buf);
    203         }
    204     }
    205 
    206   for (i = 0; i < MAX_OPERANDS && OPTYPE (tm_operands[i]) != OP_None; i++)
    207     {
    208       char *next_comma = ",";
    209       int optional = (tm_operands[i] & OPT) != 0;
    210 
    211       switch (OPTYPE (tm_operands[i]))
    212         {
    213         case OP_Xmem:
    214           sprint_dual_address (info, operand[i], XMEM (opcode));
    215           info->fprintf_func (info->stream, "%s%s", comma, operand[i]);
    216           break;
    217         case OP_Ymem:
    218           sprint_dual_address (info, operand[i], YMEM (opcode));
    219           info->fprintf_func (info->stream, "%s%s", comma, operand[i]);
    220           break;
    221         case OP_Smem:
    222         case OP_Sind:
    223         case OP_Lmem:
    224           info->fprintf_func (info->stream, "%s", comma);
    225           if (INDIRECT (opcode))
    226             {
    227               if (MOD (opcode) >= 12)
    228                 {
    229                   bfd_vma addr = lkaddr;
    230                   int arf = ARF (opcode);
    231                   int mod = MOD (opcode);
    232                   if (mod == 15)
    233                       info->fprintf_func (info->stream, "*(");
    234                   else
    235                       info->fprintf_func (info->stream, "*%sar%d(",
    236                                           (mod == 13 || mod == 14 ? "+" : ""),
    237                                           arf);
    238                   (*(info->print_address_func)) ((bfd_vma) addr, info);
    239                   info->fprintf_func (info->stream, ")%s",
    240                                       mod == 14 ? "%" : "");
    241                 }
    242               else
    243                 {
    244                   sprint_indirect_address (info, operand[i], opcode);
    245                   info->fprintf_func (info->stream, "%s", operand[i]);
    246                 }
    247             }
    248           else
    249           {
    250             /* FIXME -- use labels (print_address_func) */
    251             /* in order to do this, we need to guess what DP is */
    252             sprint_direct_address (info, operand[i], opcode);
    253             info->fprintf_func (info->stream, "%s", operand[i]);
    254           }
    255           break;
    256         case OP_dmad:
    257           info->fprintf_func (info->stream, "%s", comma);
    258           (*(info->print_address_func)) ((bfd_vma) opcode2, info);
    259           break;
    260         case OP_xpmad:
    261           /* upper 7 bits of address are in the opcode */
    262           opcode2 += ((unsigned long) opcode & 0x7F) << 16;
    263           /* fall through */
    264         case OP_pmad:
    265           info->fprintf_func (info->stream, "%s", comma);
    266           (*(info->print_address_func)) ((bfd_vma) opcode2, info);
    267           break;
    268         case OP_MMRX:
    269           sprint_mmr (info, operand[i], MMRX (opcode));
    270           info->fprintf_func (info->stream, "%s%s", comma, operand[i]);
    271           break;
    272         case OP_MMRY:
    273           sprint_mmr (info, operand[i], MMRY (opcode));
    274           info->fprintf_func (info->stream, "%s%s", comma, operand[i]);
    275           break;
    276         case OP_MMR:
    277           sprint_mmr (info, operand[i], MMR (opcode));
    278           info->fprintf_func (info->stream, "%s%s", comma, operand[i]);
    279           break;
    280         case OP_PA:
    281           sprintf (operand[i], "pa%d", (unsigned) opcode2);
    282           info->fprintf_func (info->stream, "%s%s", comma, operand[i]);
    283           break;
    284         case OP_SRC:
    285           src = SRC (ext ? opcode2 : opcode) ? OP_B : OP_A;
    286           sprintf (operand[i], (src == OP_B) ? "b" : "a");
    287           info->fprintf_func (info->stream, "%s%s", comma, operand[i]);
    288           break;
    289         case OP_SRC1:
    290           src = SRC1 (ext ? opcode2 : opcode) ? OP_B : OP_A;
    291           sprintf (operand[i], (src == OP_B) ? "b" : "a");
    292           info->fprintf_func (info->stream, "%s%s", comma, operand[i]);
    293           break;
    294         case OP_RND:
    295           dst = DST (opcode) ? OP_B : OP_A;
    296           sprintf (operand[i], (dst == OP_B) ? "a" : "b");
    297           info->fprintf_func (info->stream, "%s%s", comma, operand[i]);
    298           break;
    299         case OP_DST:
    300           dst = DST (ext ? opcode2 : opcode) ? OP_B : OP_A;
    301           if (!optional || dst != src)
    302             {
    303               sprintf (operand[i], (dst == OP_B) ? "b" : "a");
    304               info->fprintf_func (info->stream, "%s%s", comma, operand[i]);
    305             }
    306           else
    307             next_comma = comma;
    308           break;
    309         case OP_B:
    310           sprintf (operand[i], "b");
    311           info->fprintf_func (info->stream, "%s%s", comma, operand[i]);
    312           break;
    313         case OP_A:
    314           sprintf (operand[i], "a");
    315           info->fprintf_func (info->stream, "%s%s", comma, operand[i]);
    316           break;
    317         case OP_ARX:
    318           sprintf (operand[i], "ar%d", (int) ARX (opcode));
    319           info->fprintf_func (info->stream, "%s%s", comma, operand[i]);
    320           break;
    321         case OP_SHIFT:
    322           shift = SHIFT (ext ? opcode2 : opcode);
    323           if (!optional || shift != 0)
    324             {
    325               sprintf (operand[i], "%d", shift);
    326               info->fprintf_func (info->stream, "%s%s", comma, operand[i]);
    327             }
    328           else
    329             next_comma = comma;
    330           break;
    331         case OP_SHFT:
    332           shift = SHFT (opcode);
    333           if (!optional || shift != 0)
    334             {
    335               sprintf (operand[i], "%d", (unsigned) shift);
    336               info->fprintf_func (info->stream, "%s%s", comma, operand[i]);
    337             }
    338           else
    339             next_comma = comma;
    340           break;
    341         case OP_lk:
    342           sprintf (operand[i], "#%d", (int) (short) opcode2);
    343           info->fprintf_func (info->stream, "%s%s", comma, operand[i]);
    344           break;
    345         case OP_T:
    346           sprintf (operand[i], "t");
    347           info->fprintf_func (info->stream, "%s%s", comma, operand[i]);
    348           break;
    349         case OP_TS:
    350           sprintf (operand[i], "ts");
    351           info->fprintf_func (info->stream, "%s%s", comma, operand[i]);
    352           break;
    353         case OP_k8:
    354           sprintf (operand[i], "%d", (int) ((signed char) (opcode & 0xFF)));
    355           info->fprintf_func (info->stream, "%s%s", comma, operand[i]);
    356           break;
    357         case OP_16:
    358           sprintf (operand[i], "16");
    359           info->fprintf_func (info->stream, "%s%s", comma, operand[i]);
    360           break;
    361         case OP_ASM:
    362           sprintf (operand[i], "asm");
    363           info->fprintf_func (info->stream, "%s%s", comma, operand[i]);
    364           break;
    365         case OP_BITC:
    366           sprintf (operand[i], "%d", (int) (opcode & 0xF));
    367           info->fprintf_func (info->stream, "%s%s", comma, operand[i]);
    368           break;
    369         case OP_CC:
    370           /* put all CC operands in the same operand */
    371           sprint_condition (info, operand[i], opcode);
    372           info->fprintf_func (info->stream, "%s%s", comma, operand[i]);
    373           i = MAX_OPERANDS;
    374           break;
    375         case OP_CC2:
    376           sprint_cc2 (info, operand[i], opcode);
    377           info->fprintf_func (info->stream, "%s%s", comma, operand[i]);
    378           break;
    379         case OP_CC3:
    380         {
    381           const char *code[] = { "eq", "lt", "gt", "neq" };
    382 
    383 	  /* Do not use sprintf with only two parameters as a
    384 	     compiler warning could be generated in such conditions.  */
    385 	  sprintf (operand[i], "%s", code[CC3 (opcode)]);
    386           info->fprintf_func (info->stream, "%s%s", comma, operand[i]);
    387           break;
    388         }
    389         case OP_123:
    390           {
    391             int code = (opcode >> 8) & 0x3;
    392             sprintf (operand[i], "%d", (code == 0) ? 1 : (code == 2) ? 2 : 3);
    393             info->fprintf_func (info->stream, "%s%s", comma, operand[i]);
    394             break;
    395           }
    396         case OP_k5:
    397           sprintf (operand[i], "#%d",
    398                    (int) (((signed char) opcode & 0x1F) << 3) >> 3);
    399           info->fprintf_func (info->stream, "%s%s", comma, operand[i]);
    400           break;
    401         case OP_k8u:
    402           sprintf (operand[i], "#%d", (unsigned) (opcode & 0xFF));
    403           info->fprintf_func (info->stream, "%s%s", comma, operand[i]);
    404           break;
    405         case OP_k3:
    406           sprintf (operand[i], "#%d", (int) (opcode & 0x7));
    407           info->fprintf_func (info->stream, "%s%s", comma, operand[i]);
    408           break;
    409         case OP_lku:
    410           sprintf (operand[i], "#%d", (unsigned) opcode2);
    411           info->fprintf_func (info->stream, "%s%s", comma, operand[i]);
    412           break;
    413         case OP_N:
    414           n = (opcode >> 9) & 0x1;
    415           sprintf (operand[i], "st%d", n);
    416           info->fprintf_func (info->stream, "%s%s", comma, operand[i]);
    417           break;
    418         case OP_SBIT:
    419         {
    420           const char *status0[] = {
    421             "0", "1", "2", "3", "4", "5", "6", "7", "8",
    422             "ovb", "ova", "c", "tc", "13", "14", "15"
    423           };
    424           const char *status1[] = {
    425             "0", "1", "2", "3", "4",
    426             "cmpt", "frct", "c16", "sxm", "ovm", "10",
    427             "intm", "hm", "xf", "cpl", "braf"
    428           };
    429           sprintf (operand[i], "%s",
    430                    n ? status1[SBIT (opcode)] : status0[SBIT (opcode)]);
    431           info->fprintf_func (info->stream, "%s%s", comma, operand[i]);
    432           break;
    433         }
    434         case OP_12:
    435           sprintf (operand[i], "%d", (int) ((opcode >> 9) & 1) + 1);
    436           info->fprintf_func (info->stream, "%s%s", comma, operand[i]);
    437           break;
    438         case OP_TRN:
    439           sprintf (operand[i], "trn");
    440           info->fprintf_func (info->stream, "%s%s", comma, operand[i]);
    441           break;
    442         case OP_DP:
    443           sprintf (operand[i], "dp");
    444           info->fprintf_func (info->stream, "%s%s", comma, operand[i]);
    445           break;
    446         case OP_k9:
    447           /* FIXME-- this is DP, print the original address? */
    448           sprintf (operand[i], "#%d", (int) (opcode & 0x1FF));
    449           info->fprintf_func (info->stream, "%s%s", comma, operand[i]);
    450           break;
    451         case OP_ARP:
    452           sprintf (operand[i], "arp");
    453           info->fprintf_func (info->stream, "%s%s", comma, operand[i]);
    454           break;
    455         case OP_031:
    456           sprintf (operand[i], "%d", (int) (opcode & 0x1F));
    457           info->fprintf_func (info->stream, "%s%s", comma, operand[i]);
    458           break;
    459         default:
    460           sprintf (operand[i], "??? (0x%x)", tm_operands[i]);
    461           info->fprintf_func (info->stream, "%s%s", comma, operand[i]);
    462           break;
    463         }
    464       comma = next_comma;
    465     }
    466   return 1;
    467 }
    468 
    469 static int
    470 print_parallel_instruction (disassemble_info *info,
    471 			    bfd_vma memaddr,
    472 			    unsigned short opcode,
    473 			    const insn_template *ptm,
    474 			    int size)
    475 {
    476   print_instruction (info, memaddr, opcode,
    477                      ptm->name, ptm->operand_types, size, 0);
    478   info->fprintf_func (info->stream, " || ");
    479   return print_instruction (info, memaddr, opcode,
    480                             ptm->parname, ptm->paroperand_types, size, 0);
    481 }
    482 
    483 static int
    484 sprint_dual_address (disassemble_info *info ATTRIBUTE_UNUSED,
    485 		     char buf[],
    486 		     unsigned short code)
    487 {
    488   const char *formats[] = {
    489     "*ar%d",
    490     "*ar%d-",
    491     "*ar%d+",
    492     "*ar%d+0%%",
    493   };
    494   return sprintf (buf, formats[XMOD (code)], XARX (code));
    495 }
    496 
    497 static int
    498 sprint_indirect_address (disassemble_info *info ATTRIBUTE_UNUSED,
    499 			 char buf[],
    500 			 unsigned short opcode)
    501 {
    502   const char *formats[] = {
    503     "*ar%d",
    504     "*ar%d-",
    505     "*ar%d+",
    506     "*+ar%d",
    507     "*ar%d-0B",
    508     "*ar%d-0",
    509     "*ar%d+0",
    510     "*ar%d+0B",
    511     "*ar%d-%%",
    512     "*ar%d-0%%",
    513     "*ar%d+%%",
    514     "*ar%d+0%%",
    515   };
    516   return sprintf (buf, formats[MOD (opcode)], ARF (opcode));
    517 }
    518 
    519 static int
    520 sprint_direct_address (disassemble_info *info ATTRIBUTE_UNUSED,
    521 		       char buf[],
    522 		       unsigned short opcode)
    523 {
    524   /* FIXME -- look up relocation if available */
    525   return sprintf (buf, "DP+0x%02x", (int) (opcode & 0x7F));
    526 }
    527 
    528 static int
    529 sprint_mmr (disassemble_info *info ATTRIBUTE_UNUSED,
    530 	    char buf[],
    531 	    int mmr)
    532 {
    533   symbol *reg = (symbol *) mmregs;
    534   while (reg->name != NULL)
    535     {
    536       if (mmr == reg->value)
    537         {
    538           sprintf (buf, "%s", (reg + 1)->name);
    539           return 1;
    540         }
    541       ++reg;
    542     }
    543   sprintf (buf, "MMR(%d)", mmr); /* FIXME -- different targets.  */
    544   return 0;
    545 }
    546 
    547 static int
    548 sprint_cc2 (disassemble_info *info ATTRIBUTE_UNUSED,
    549 	    char *buf,
    550 	    unsigned short opcode)
    551 {
    552   const char *cc2[] = {
    553     "??", "??", "ageq", "alt", "aneq", "aeq", "agt", "aleq",
    554     "??", "??", "bgeq", "blt", "bneq", "beq", "bgt", "bleq",
    555   };
    556   return sprintf (buf, "%s", cc2[opcode & 0xF]);
    557 }
    558 
    559 static int
    560 sprint_condition (disassemble_info *info ATTRIBUTE_UNUSED,
    561 		  char *buf,
    562 		  unsigned short opcode)
    563 {
    564   char *start = buf;
    565   const char *cmp[] = {
    566       "??", "??", "geq", "lt", "neq", "eq", "gt", "leq"
    567   };
    568   if (opcode & 0x40)
    569     {
    570       char acc = (opcode & 0x8) ? 'b' : 'a';
    571       if (opcode & 0x7)
    572           buf += sprintf (buf, "%c%s%s", acc, cmp[(opcode & 0x7)],
    573                           (opcode & 0x20) ? ", " : "");
    574       if (opcode & 0x20)
    575           buf += sprintf (buf, "%c%s", acc, (opcode & 0x10) ? "ov" : "nov");
    576     }
    577   else if (opcode & 0x3F)
    578     {
    579       if (opcode & 0x30)
    580         buf += sprintf (buf, "%s%s",
    581                         ((opcode & 0x30) == 0x30) ? "tc" : "ntc",
    582                         (opcode & 0x0F) ? ", " : "");
    583       if (opcode & 0x0C)
    584         buf += sprintf (buf, "%s%s",
    585                         ((opcode & 0x0C) == 0x0C) ? "c" : "nc",
    586                         (opcode & 0x03) ? ", " : "");
    587       if (opcode & 0x03)
    588         buf += sprintf (buf, "%s",
    589                         ((opcode & 0x03) == 0x03) ? "bio" : "nbio");
    590     }
    591   else
    592     buf += sprintf (buf, "unc");
    593 
    594   return buf - start;
    595 }
    596