(root)/
binutils-2.41/
opcodes/
tic54x-dis.c
       1  /* Disassembly routines for TMS320C54X architecture
       2     Copyright (C) 1999-2023 Free Software Foundation, Inc.
       3     Contributed by Timothy Wall (twall@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 "disassemble.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", ((opcode & 0x1F) ^ 0x10) - 0x10);
     398            info->fprintf_func (info->stream, "%s%s", comma, operand[i]);
     399            break;
     400          case OP_k8u:
     401            sprintf (operand[i], "#%d", (unsigned) (opcode & 0xFF));
     402            info->fprintf_func (info->stream, "%s%s", comma, operand[i]);
     403            break;
     404          case OP_k3:
     405            sprintf (operand[i], "#%d", (int) (opcode & 0x7));
     406            info->fprintf_func (info->stream, "%s%s", comma, operand[i]);
     407            break;
     408          case OP_lku:
     409            sprintf (operand[i], "#%d", (unsigned) opcode2);
     410            info->fprintf_func (info->stream, "%s%s", comma, operand[i]);
     411            break;
     412          case OP_N:
     413            n = (opcode >> 9) & 0x1;
     414            sprintf (operand[i], "st%d", n);
     415            info->fprintf_func (info->stream, "%s%s", comma, operand[i]);
     416            break;
     417          case OP_SBIT:
     418          {
     419            const char *status0[] = {
     420              "0", "1", "2", "3", "4", "5", "6", "7", "8",
     421              "ovb", "ova", "c", "tc", "13", "14", "15"
     422            };
     423            const char *status1[] = {
     424              "0", "1", "2", "3", "4",
     425              "cmpt", "frct", "c16", "sxm", "ovm", "10",
     426              "intm", "hm", "xf", "cpl", "braf"
     427            };
     428            sprintf (operand[i], "%s",
     429                     n ? status1[SBIT (opcode)] : status0[SBIT (opcode)]);
     430            info->fprintf_func (info->stream, "%s%s", comma, operand[i]);
     431            break;
     432          }
     433          case OP_12:
     434            sprintf (operand[i], "%d", (int) ((opcode >> 9) & 1) + 1);
     435            info->fprintf_func (info->stream, "%s%s", comma, operand[i]);
     436            break;
     437          case OP_TRN:
     438            sprintf (operand[i], "trn");
     439            info->fprintf_func (info->stream, "%s%s", comma, operand[i]);
     440            break;
     441          case OP_DP:
     442            sprintf (operand[i], "dp");
     443            info->fprintf_func (info->stream, "%s%s", comma, operand[i]);
     444            break;
     445          case OP_k9:
     446            /* FIXME-- this is DP, print the original address? */
     447            sprintf (operand[i], "#%d", (int) (opcode & 0x1FF));
     448            info->fprintf_func (info->stream, "%s%s", comma, operand[i]);
     449            break;
     450          case OP_ARP:
     451            sprintf (operand[i], "arp");
     452            info->fprintf_func (info->stream, "%s%s", comma, operand[i]);
     453            break;
     454          case OP_031:
     455            sprintf (operand[i], "%d", (int) (opcode & 0x1F));
     456            info->fprintf_func (info->stream, "%s%s", comma, operand[i]);
     457            break;
     458          default:
     459            sprintf (operand[i], "??? (0x%x)", tm_operands[i]);
     460            info->fprintf_func (info->stream, "%s%s", comma, operand[i]);
     461            break;
     462          }
     463        comma = next_comma;
     464      }
     465    return 1;
     466  }
     467  
     468  static int
     469  print_parallel_instruction (disassemble_info *info,
     470  			    bfd_vma memaddr,
     471  			    unsigned short opcode,
     472  			    const insn_template *ptm,
     473  			    int size)
     474  {
     475    print_instruction (info, memaddr, opcode,
     476                       ptm->name, ptm->operand_types, size, 0);
     477    info->fprintf_func (info->stream, " || ");
     478    return print_instruction (info, memaddr, opcode,
     479                              ptm->parname, ptm->paroperand_types, size, 0);
     480  }
     481  
     482  static int
     483  sprint_dual_address (disassemble_info *info ATTRIBUTE_UNUSED,
     484  		     char buf[],
     485  		     unsigned short code)
     486  {
     487    const char *formats[] = {
     488      "*ar%d",
     489      "*ar%d-",
     490      "*ar%d+",
     491      "*ar%d+0%%",
     492    };
     493    return sprintf (buf, formats[XMOD (code)], XARX (code));
     494  }
     495  
     496  static int
     497  sprint_indirect_address (disassemble_info *info ATTRIBUTE_UNUSED,
     498  			 char buf[],
     499  			 unsigned short opcode)
     500  {
     501    const char *formats[] = {
     502      "*ar%d",
     503      "*ar%d-",
     504      "*ar%d+",
     505      "*+ar%d",
     506      "*ar%d-0B",
     507      "*ar%d-0",
     508      "*ar%d+0",
     509      "*ar%d+0B",
     510      "*ar%d-%%",
     511      "*ar%d-0%%",
     512      "*ar%d+%%",
     513      "*ar%d+0%%",
     514    };
     515    return sprintf (buf, formats[MOD (opcode)], ARF (opcode));
     516  }
     517  
     518  static int
     519  sprint_direct_address (disassemble_info *info ATTRIBUTE_UNUSED,
     520  		       char buf[],
     521  		       unsigned short opcode)
     522  {
     523    /* FIXME -- look up relocation if available */
     524    return sprintf (buf, "DP+0x%02x", (int) (opcode & 0x7F));
     525  }
     526  
     527  static int
     528  sprint_mmr (disassemble_info *info ATTRIBUTE_UNUSED,
     529  	    char buf[],
     530  	    int mmr)
     531  {
     532    const tic54x_symbol *reg = tic54x_mmregs;
     533    while (reg->name != NULL)
     534      {
     535        if (mmr == reg->value)
     536          {
     537            sprintf (buf, "%s", (reg + 1)->name);
     538            return 1;
     539          }
     540        ++reg;
     541      }
     542    sprintf (buf, "MMR(%d)", mmr); /* FIXME -- different targets.  */
     543    return 0;
     544  }
     545  
     546  static int
     547  sprint_cc2 (disassemble_info *info ATTRIBUTE_UNUSED,
     548  	    char *buf,
     549  	    unsigned short opcode)
     550  {
     551    const char *cc2[] = {
     552      "??", "??", "ageq", "alt", "aneq", "aeq", "agt", "aleq",
     553      "??", "??", "bgeq", "blt", "bneq", "beq", "bgt", "bleq",
     554    };
     555    return sprintf (buf, "%s", cc2[opcode & 0xF]);
     556  }
     557  
     558  static int
     559  sprint_condition (disassemble_info *info ATTRIBUTE_UNUSED,
     560  		  char *buf,
     561  		  unsigned short opcode)
     562  {
     563    char *start = buf;
     564    const char *cmp[] = {
     565        "??", "??", "geq", "lt", "neq", "eq", "gt", "leq"
     566    };
     567    if (opcode & 0x40)
     568      {
     569        char acc = (opcode & 0x8) ? 'b' : 'a';
     570        if (opcode & 0x7)
     571            buf += sprintf (buf, "%c%s%s", acc, cmp[(opcode & 0x7)],
     572                            (opcode & 0x20) ? ", " : "");
     573        if (opcode & 0x20)
     574            buf += sprintf (buf, "%c%s", acc, (opcode & 0x10) ? "ov" : "nov");
     575      }
     576    else if (opcode & 0x3F)
     577      {
     578        if (opcode & 0x30)
     579          buf += sprintf (buf, "%s%s",
     580                          ((opcode & 0x30) == 0x30) ? "tc" : "ntc",
     581                          (opcode & 0x0F) ? ", " : "");
     582        if (opcode & 0x0C)
     583          buf += sprintf (buf, "%s%s",
     584                          ((opcode & 0x0C) == 0x0C) ? "c" : "nc",
     585                          (opcode & 0x03) ? ", " : "");
     586        if (opcode & 0x03)
     587          buf += sprintf (buf, "%s",
     588                          ((opcode & 0x03) == 0x03) ? "bio" : "nbio");
     589      }
     590    else
     591      buf += sprintf (buf, "unc");
     592  
     593    return buf - start;
     594  }