Back to index

cell-binutils  2.17cvs20070401
tic54x-dis.c
Go to the documentation of this file.
00001 /* Disassembly routines for TMS320C54X architecture
00002    Copyright 1999, 2000, 2001 Free Software Foundation, Inc.
00003    Contributed by Timothy Wall (twall@cygnus.com)
00004 
00005    This program is free software; you can redistribute it and/or modify
00006    it under the terms of the GNU General Public License as published by
00007    the Free Software Foundation; either version 2 of the License, or
00008    (at your option) any later version.
00009 
00010    This program is distributed in the hope that it will be useful,
00011    but WITHOUT ANY WARRANTY; without even the implied warranty of
00012    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013    GNU General Public License for more details.
00014 
00015    You should have received a copy of the GNU General Public License
00016    along with this program; if not, write to the Free Software
00017    Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
00018    02110-1301, USA.  */
00019 
00020 #include <errno.h>
00021 #include <math.h>
00022 #include <stdlib.h>
00023 #include "sysdep.h"
00024 #include "dis-asm.h"
00025 #include "opcode/tic54x.h"
00026 #include "coff/tic54x.h"
00027 
00028 static int has_lkaddr (unsigned short, const template *);
00029 static int get_insn_size (unsigned short, const template *);
00030 static int print_instruction (disassemble_info *, bfd_vma,
00031                               unsigned short, const char *,
00032                               const enum optype [], int, int);
00033 static int print_parallel_instruction (disassemble_info *, bfd_vma,
00034                                        unsigned short, 
00035                                        const template *, int);
00036 static int sprint_dual_address (disassemble_info *,char [],
00037                                 unsigned short);
00038 static int sprint_indirect_address (disassemble_info *,char [],
00039                                     unsigned short);
00040 static int sprint_direct_address (disassemble_info *,char [],
00041                                   unsigned short);
00042 static int sprint_mmr (disassemble_info *,char [],int);
00043 static int sprint_condition (disassemble_info *,char *,unsigned short);
00044 static int sprint_cc2 (disassemble_info *,char *,unsigned short);
00045 
00046 int
00047 print_insn_tic54x (bfd_vma memaddr, disassemble_info *info)
00048 {
00049   bfd_byte opbuf[2];
00050   unsigned short opcode;
00051   int status, size;
00052   const template* tm;
00053 
00054   status = (*info->read_memory_func) (memaddr, opbuf, 2, info);
00055   if (status != 0)
00056   {
00057     (*info->memory_error_func) (status, memaddr, info);
00058     return -1;
00059   }
00060 
00061   opcode = bfd_getl16 (opbuf);
00062   tm = tic54x_get_insn (info, memaddr, opcode, &size);
00063 
00064   info->bytes_per_line = 2;
00065   info->bytes_per_chunk = 2;
00066   info->octets_per_byte = 2;
00067   info->display_endian = BFD_ENDIAN_LITTLE;
00068 
00069   if (tm->flags & FL_PAR)
00070   {
00071     if (!print_parallel_instruction (info, memaddr, opcode, tm, size))
00072       return -1;
00073   }
00074   else
00075   {
00076     if (!print_instruction (info, memaddr, opcode,
00077                             (char *) tm->name,
00078                             tm->operand_types,
00079                             size, (tm->flags & FL_EXT)))
00080       return -1;
00081   }
00082 
00083   return size * 2;
00084 }
00085 
00086 static int
00087 has_lkaddr (unsigned short memdata, const template *tm)
00088 {
00089   return (IS_LKADDR (memdata)
00090          && (OPTYPE (tm->operand_types[0]) == OP_Smem
00091              || OPTYPE (tm->operand_types[1]) == OP_Smem
00092              || OPTYPE (tm->operand_types[2]) == OP_Smem
00093              || OPTYPE (tm->operand_types[1]) == OP_Sind
00094               || OPTYPE (tm->operand_types[0]) == OP_Lmem
00095               || OPTYPE (tm->operand_types[1]) == OP_Lmem));
00096 }
00097 
00098 /* always returns 1 (whether an insn template was found) since we provide an
00099    "unknown instruction" template */
00100 const template*
00101 tic54x_get_insn (disassemble_info *info, bfd_vma addr, 
00102                  unsigned short memdata, int *size)
00103 {
00104   const template *tm = NULL;
00105 
00106   for (tm = tic54x_optab; tm->name; tm++)
00107   {
00108     if (tm->opcode == (memdata & tm->mask))
00109     {
00110       /* a few opcodes span two words */
00111       if (tm->flags & FL_EXT)
00112         {
00113           /* if lk addressing is used, the second half of the opcode gets
00114              pushed one word later */
00115           bfd_byte opbuf[2];
00116           bfd_vma addr2 = addr + 1 + has_lkaddr (memdata, tm);
00117           int status = (*info->read_memory_func) (addr2, opbuf, 2, info);
00118           // FIXME handle errors
00119           if (status == 0)
00120             {
00121               unsigned short data2 = bfd_getl16 (opbuf);
00122               if (tm->opcode2 == (data2 & tm->mask2))
00123                 {
00124                   if (size) *size = get_insn_size (memdata, tm);
00125                   return tm;
00126                 }
00127             }
00128         }
00129       else
00130         {
00131           if (size) *size = get_insn_size (memdata, tm);
00132           return tm;
00133         }
00134     }
00135   }
00136   for (tm = (template *) tic54x_paroptab; tm->name; tm++)
00137   {
00138     if (tm->opcode == (memdata & tm->mask))
00139     {
00140       if (size) *size = get_insn_size (memdata, tm);
00141       return tm;
00142     }
00143   }
00144 
00145   if (size) *size = 1;
00146   return &tic54x_unknown_opcode;
00147 }
00148 
00149 static int
00150 get_insn_size (unsigned short memdata, const template *insn)
00151 {
00152   int size;
00153 
00154   if (insn->flags & FL_PAR)
00155     {
00156       /* only non-parallel instructions support lk addressing */
00157       size = insn->words;
00158     }
00159   else
00160     {
00161       size = insn->words + has_lkaddr (memdata, insn);
00162     }
00163 
00164   return size;
00165 }
00166 
00167 int
00168 print_instruction (info, memaddr, opcode, tm_name, tm_operands, size, ext)
00169   disassemble_info *info;
00170   bfd_vma memaddr;
00171   unsigned short opcode;
00172   const char *tm_name;
00173   const enum optype tm_operands[];
00174   int size;
00175   int ext;
00176 {
00177   static int n;
00178   /* string storage for multiple operands */
00179   char operand[4][64] = { {0},{0},{0},{0}, };
00180   bfd_byte buf[2];
00181   unsigned long opcode2 = 0;
00182   unsigned long lkaddr = 0;
00183   enum optype src = OP_None;
00184   enum optype dst = OP_None;
00185   int i, shift;
00186   char *comma = "";
00187 
00188   info->fprintf_func (info->stream, "%-7s", tm_name);
00189 
00190   if (size > 1)
00191     {
00192       int status = (*info->read_memory_func) (memaddr + 1, buf, 2, info);
00193       if (status != 0)
00194         return 0;
00195       lkaddr = opcode2 = bfd_getl16 (buf);
00196       if (size > 2)
00197         {
00198           status = (*info->read_memory_func) (memaddr + 2, buf, 2, info);
00199           if (status != 0)
00200             return 0;
00201           opcode2 = bfd_getl16 (buf);
00202         }
00203     }
00204 
00205   for (i = 0; i < MAX_OPERANDS && OPTYPE (tm_operands[i]) != OP_None; i++)
00206     {
00207       char *next_comma = ",";
00208       int optional = (tm_operands[i] & OPT) != 0;
00209 
00210       switch (OPTYPE (tm_operands[i]))
00211         {
00212         case OP_Xmem:
00213           sprint_dual_address (info, operand[i], XMEM (opcode));
00214           info->fprintf_func (info->stream, "%s%s", comma, operand[i]);
00215           break;
00216         case OP_Ymem:
00217           sprint_dual_address (info, operand[i], YMEM (opcode));
00218           info->fprintf_func (info->stream, "%s%s", comma, operand[i]);
00219           break;
00220         case OP_Smem:
00221         case OP_Sind:
00222         case OP_Lmem:
00223           info->fprintf_func (info->stream, "%s", comma);
00224           if (INDIRECT (opcode))
00225             {
00226               if (MOD (opcode) >= 12)
00227                 {
00228                   bfd_vma addr = lkaddr;
00229                   int arf = ARF (opcode);
00230                   int mod = MOD (opcode);
00231                   if (mod == 15)
00232                       info->fprintf_func (info->stream, "*(");
00233                   else
00234                       info->fprintf_func (info->stream, "*%sar%d(",
00235                                           (mod == 13 || mod == 14 ? "+" : ""),
00236                                           arf);
00237                   (*(info->print_address_func)) ((bfd_vma) addr, info);
00238                   info->fprintf_func (info->stream, ")%s",
00239                                       mod == 14 ? "%" : "");
00240                 }
00241               else
00242                 {
00243                   sprint_indirect_address (info, operand[i], opcode);
00244                   info->fprintf_func (info->stream, "%s", operand[i]);
00245                 }
00246             }
00247           else
00248           {
00249             /* FIXME -- use labels (print_address_func) */
00250             /* in order to do this, we need to guess what DP is */
00251             sprint_direct_address (info, operand[i], opcode);
00252             info->fprintf_func (info->stream, "%s", operand[i]);
00253           }
00254           break;
00255         case OP_dmad:
00256           info->fprintf_func (info->stream, "%s", comma);
00257           (*(info->print_address_func)) ((bfd_vma) opcode2, info);
00258           break;
00259         case OP_xpmad:
00260           /* upper 7 bits of address are in the opcode */
00261           opcode2 += ((unsigned long) opcode & 0x7F) << 16;
00262           /* fall through */
00263         case OP_pmad:
00264           info->fprintf_func (info->stream, "%s", comma);
00265           (*(info->print_address_func)) ((bfd_vma) opcode2, info);
00266           break;
00267         case OP_MMRX:
00268           sprint_mmr (info, operand[i], MMRX (opcode));
00269           info->fprintf_func (info->stream, "%s%s", comma, operand[i]);
00270           break;
00271         case OP_MMRY:
00272           sprint_mmr (info, operand[i], MMRY (opcode));
00273           info->fprintf_func (info->stream, "%s%s", comma, operand[i]);
00274           break;
00275         case OP_MMR:
00276           sprint_mmr (info, operand[i], MMR (opcode));
00277           info->fprintf_func (info->stream, "%s%s", comma, operand[i]);
00278           break;
00279         case OP_PA:
00280           sprintf (operand[i], "pa%d", (unsigned) opcode2);
00281           info->fprintf_func (info->stream, "%s%s", comma, operand[i]);
00282           break;
00283         case OP_SRC:
00284           src = SRC (ext ? opcode2 : opcode) ? OP_B : OP_A;
00285           sprintf (operand[i], (src == OP_B) ? "b" : "a");
00286           info->fprintf_func (info->stream, "%s%s", comma, operand[i]);
00287           break;
00288         case OP_SRC1:
00289           src = SRC1 (ext ? opcode2 : opcode) ? OP_B : OP_A;
00290           sprintf (operand[i], (src == OP_B) ? "b" : "a");
00291           info->fprintf_func (info->stream, "%s%s", comma, operand[i]);
00292           break;
00293         case OP_RND:
00294           dst = DST (opcode) ? OP_B : OP_A;
00295           sprintf (operand[i], (dst == OP_B) ? "a" : "b");
00296           info->fprintf_func (info->stream, "%s%s", comma, operand[i]);
00297           break;
00298         case OP_DST:
00299           dst = DST (ext ? opcode2 : opcode) ? OP_B : OP_A;
00300           if (!optional || dst != src)
00301             {
00302               sprintf (operand[i], (dst == OP_B) ? "b" : "a");
00303               info->fprintf_func (info->stream, "%s%s", comma, operand[i]);
00304             }
00305           else
00306             next_comma = comma;
00307           break;
00308         case OP_B:
00309           sprintf (operand[i], "b");
00310           info->fprintf_func (info->stream, "%s%s", comma, operand[i]);
00311           break;
00312         case OP_A:
00313           sprintf (operand[i], "a");
00314           info->fprintf_func (info->stream, "%s%s", comma, operand[i]);
00315           break;
00316         case OP_ARX:
00317           sprintf (operand[i], "ar%d", (int) ARX (opcode));
00318           info->fprintf_func (info->stream, "%s%s", comma, operand[i]);
00319           break;
00320         case OP_SHIFT:
00321           shift = SHIFT (ext ? opcode2 : opcode);
00322           if (!optional || shift != 0)
00323             {
00324               sprintf (operand[i], "%d", shift);
00325               info->fprintf_func (info->stream, "%s%s", comma, operand[i]);
00326             }
00327           else
00328             next_comma = comma;
00329           break;
00330         case OP_SHFT:
00331           shift = SHFT (opcode);
00332           if (!optional || shift != 0)
00333             {
00334               sprintf (operand[i], "%d", (unsigned) shift);
00335               info->fprintf_func (info->stream, "%s%s", comma, operand[i]);
00336             }
00337           else
00338             next_comma = comma;
00339           break;
00340         case OP_lk:
00341           sprintf (operand[i], "#%d", (int) (short) opcode2);
00342           info->fprintf_func (info->stream, "%s%s", comma, operand[i]);
00343           break;
00344         case OP_T:
00345           sprintf (operand[i], "t");
00346           info->fprintf_func (info->stream, "%s%s", comma, operand[i]);
00347           break;
00348         case OP_TS:
00349           sprintf (operand[i], "ts");
00350           info->fprintf_func (info->stream, "%s%s", comma, operand[i]);
00351           break;
00352         case OP_k8:
00353           sprintf (operand[i], "%d", (int) ((signed char) (opcode & 0xFF)));
00354           info->fprintf_func (info->stream, "%s%s", comma, operand[i]);
00355           break;
00356         case OP_16:
00357           sprintf (operand[i], "16");
00358           info->fprintf_func (info->stream, "%s%s", comma, operand[i]);
00359           break;
00360         case OP_ASM:
00361           sprintf (operand[i], "asm");
00362           info->fprintf_func (info->stream, "%s%s", comma, operand[i]);
00363           break;
00364         case OP_BITC:
00365           sprintf (operand[i], "%d", (int) (opcode & 0xF));
00366           info->fprintf_func (info->stream, "%s%s", comma, operand[i]);
00367           break;
00368         case OP_CC:
00369           /* put all CC operands in the same operand */
00370           sprint_condition (info, operand[i], opcode);
00371           info->fprintf_func (info->stream, "%s%s", comma, operand[i]);
00372           i = MAX_OPERANDS;
00373           break;
00374         case OP_CC2:
00375           sprint_cc2 (info, operand[i], opcode);
00376           info->fprintf_func (info->stream, "%s%s", comma, operand[i]);
00377           break;
00378         case OP_CC3:
00379         {
00380           const char *code[] = { "eq", "lt", "gt", "neq" };
00381           sprintf (operand[i], code[CC3 (opcode)]);
00382           info->fprintf_func (info->stream, "%s%s", comma, operand[i]);
00383           break;
00384         }
00385         case OP_123:
00386           {
00387             int code = (opcode >> 8) & 0x3;
00388             sprintf (operand[i], "%d", (code == 0) ? 1 : (code == 2) ? 2 : 3);
00389             info->fprintf_func (info->stream, "%s%s", comma, operand[i]);
00390             break;
00391           }
00392         case OP_k5:
00393           sprintf (operand[i], "#%d",
00394                    (int) (((signed char) opcode & 0x1F) << 3) >> 3);
00395           info->fprintf_func (info->stream, "%s%s", comma, operand[i]);
00396           break;
00397         case OP_k8u:
00398           sprintf (operand[i], "#%d", (unsigned) (opcode & 0xFF));
00399           info->fprintf_func (info->stream, "%s%s", comma, operand[i]);
00400           break;
00401         case OP_k3:
00402           sprintf (operand[i], "#%d", (int) (opcode & 0x7));
00403           info->fprintf_func (info->stream, "%s%s", comma, operand[i]);
00404           break;
00405         case OP_lku:
00406           sprintf (operand[i], "#%d", (unsigned) opcode2);
00407           info->fprintf_func (info->stream, "%s%s", comma, operand[i]);
00408           break;
00409         case OP_N:
00410           n = (opcode >> 9) & 0x1;
00411           sprintf (operand[i], "st%d", n);
00412           info->fprintf_func (info->stream, "%s%s", comma, operand[i]);
00413           break;
00414         case OP_SBIT:
00415         {
00416           const char *status0[] = {
00417             "0", "1", "2", "3", "4", "5", "6", "7", "8",
00418             "ovb", "ova", "c", "tc", "13", "14", "15"
00419           };
00420           const char *status1[] = {
00421             "0", "1", "2", "3", "4",
00422             "cmpt", "frct", "c16", "sxm", "ovm", "10",
00423             "intm", "hm", "xf", "cpl", "braf"
00424           };
00425           sprintf (operand[i], "%s",
00426                    n ? status1[SBIT (opcode)] : status0[SBIT (opcode)]);
00427           info->fprintf_func (info->stream, "%s%s", comma, operand[i]);
00428           break;
00429         }
00430         case OP_12:
00431           sprintf (operand[i], "%d", (int) ((opcode >> 9) & 1) + 1);
00432           info->fprintf_func (info->stream, "%s%s", comma, operand[i]);
00433           break;
00434         case OP_TRN:
00435           sprintf (operand[i], "trn");
00436           info->fprintf_func (info->stream, "%s%s", comma, operand[i]);
00437           break;
00438         case OP_DP:
00439           sprintf (operand[i], "dp");
00440           info->fprintf_func (info->stream, "%s%s", comma, operand[i]);
00441           break;
00442         case OP_k9:
00443           /* FIXME-- this is DP, print the original address? */
00444           sprintf (operand[i], "#%d", (int) (opcode & 0x1FF));
00445           info->fprintf_func (info->stream, "%s%s", comma, operand[i]);
00446           break;
00447         case OP_ARP:
00448           sprintf (operand[i], "arp");
00449           info->fprintf_func (info->stream, "%s%s", comma, operand[i]);
00450           break;
00451         case OP_031:
00452           sprintf (operand[i], "%d", (int) (opcode & 0x1F));
00453           info->fprintf_func (info->stream, "%s%s", comma, operand[i]);
00454           break;
00455         default:
00456           sprintf (operand[i], "??? (0x%x)", tm_operands[i]);
00457           info->fprintf_func (info->stream, "%s%s", comma, operand[i]);
00458           break;
00459         }
00460       comma = next_comma;
00461     }
00462   return 1;
00463 }
00464 
00465 static int
00466 print_parallel_instruction (info, memaddr, opcode, ptm, size)
00467   disassemble_info *info;
00468   bfd_vma memaddr;
00469   unsigned short opcode;
00470   const template *ptm;
00471   int size;
00472 {
00473   print_instruction (info, memaddr, opcode,
00474                      ptm->name, ptm->operand_types, size, 0);
00475   info->fprintf_func (info->stream, " || ");
00476   return print_instruction (info, memaddr, opcode,
00477                             ptm->parname, ptm->paroperand_types, size, 0);
00478 }
00479 
00480 static int
00481 sprint_dual_address (info, buf, code)
00482   disassemble_info *info ATTRIBUTE_UNUSED;
00483   char buf[];
00484   unsigned short code;
00485 {
00486   const char *formats[] = {
00487     "*ar%d",
00488     "*ar%d-",
00489     "*ar%d+",
00490     "*ar%d+0%%",
00491   };
00492   return sprintf (buf, formats[XMOD (code)], XARX (code));
00493 }
00494 
00495 static int
00496 sprint_indirect_address (info, buf, opcode)
00497   disassemble_info *info ATTRIBUTE_UNUSED;
00498   char buf[];
00499   unsigned short opcode;
00500 {
00501   const char *formats[] = {
00502     "*ar%d",
00503     "*ar%d-",
00504     "*ar%d+",
00505     "*+ar%d",
00506     "*ar%d-0B",
00507     "*ar%d-0",
00508     "*ar%d+0",
00509     "*ar%d+0B",
00510     "*ar%d-%%",
00511     "*ar%d-0%%",
00512     "*ar%d+%%",
00513     "*ar%d+0%%",
00514   };
00515   return sprintf (buf, formats[MOD (opcode)], ARF (opcode));
00516 }
00517 
00518 static int
00519 sprint_direct_address (info, buf, opcode)
00520   disassemble_info *info ATTRIBUTE_UNUSED;
00521   char buf[];
00522   unsigned short opcode;
00523 {
00524   /* FIXME -- look up relocation if available */
00525   return sprintf (buf, "DP+0x%02x", (int) (opcode & 0x7F));
00526 }
00527 
00528 static int
00529 sprint_mmr (info, buf, mmr)
00530   disassemble_info *info ATTRIBUTE_UNUSED;
00531   char buf[];
00532   int mmr;
00533 {
00534   symbol *reg = (symbol *) mmregs;
00535   while (reg->name != NULL)
00536     {
00537       if (mmr == reg->value)
00538         {
00539           sprintf (buf, "%s", (reg + 1)->name);
00540           return 1;
00541         }
00542       ++reg;
00543     }
00544   sprintf (buf, "MMR(%d)", mmr); /* FIXME -- different targets.  */
00545   return 0;
00546 }
00547 
00548 static int
00549 sprint_cc2 (info, buf, opcode)
00550   disassemble_info *info ATTRIBUTE_UNUSED;
00551   char *buf;
00552   unsigned short opcode;
00553 {
00554   const char *cc2[] = {
00555     "??", "??", "ageq", "alt", "aneq", "aeq", "agt", "aleq",
00556     "??", "??", "bgeq", "blt", "bneq", "beq", "bgt", "bleq",
00557   };
00558   return sprintf (buf, "%s", cc2[opcode & 0xF]);
00559 }
00560 
00561 static int
00562 sprint_condition (info, buf, opcode)
00563   disassemble_info *info ATTRIBUTE_UNUSED;
00564   char *buf;
00565   unsigned short opcode;
00566 {
00567   char *start = buf;
00568   const char *cmp[] = {
00569       "??", "??", "geq", "lt", "neq", "eq", "gt", "leq"
00570   };
00571   if (opcode & 0x40)
00572     {
00573       char acc = (opcode & 0x8) ? 'b' : 'a';
00574       if (opcode & 0x7)
00575           buf += sprintf (buf, "%c%s%s", acc, cmp[(opcode & 0x7)],
00576                           (opcode & 0x20) ? ", " : "");
00577       if (opcode & 0x20)
00578           buf += sprintf (buf, "%c%s", acc, (opcode & 0x10) ? "ov" : "nov");
00579     }
00580   else if (opcode & 0x3F)
00581     {
00582       if (opcode & 0x30)
00583         buf += sprintf (buf, "%s%s",
00584                         ((opcode & 0x30) == 0x30) ? "tc" : "ntc",
00585                         (opcode & 0x0F) ? ", " : "");
00586       if (opcode & 0x0C)
00587         buf += sprintf (buf, "%s%s",
00588                         ((opcode & 0x0C) == 0x0C) ? "c" : "nc",
00589                         (opcode & 0x03) ? ", " : "");
00590       if (opcode & 0x03)
00591         buf += sprintf (buf, "%s",
00592                         ((opcode & 0x03) == 0x03) ? "bio" : "nbio");
00593     }
00594   else
00595     buf += sprintf (buf, "unc");
00596 
00597   return buf - start;
00598 }