Back to index

cell-binutils  2.17cvs20070401
tic30-dis.c
Go to the documentation of this file.
00001 /* Disassembly routines for TMS320C30 architecture
00002    Copyright 1998, 1999, 2000, 2002, 2005 Free Software Foundation, Inc.
00003    Contributed by Steven Haworth (steve@pm.cse.rmit.edu.au)
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 "sysdep.h"
00023 #include "dis-asm.h"
00024 #include "opcode/tic30.h"
00025 
00026 #define NORMAL_INSN   1
00027 #define PARALLEL_INSN 2
00028 
00029 /* Gets the type of instruction based on the top 2 or 3 bits of the
00030    instruction word.  */
00031 #define GET_TYPE(insn) (insn & 0x80000000 ? insn & 0xC0000000 : insn & 0xE0000000)
00032 
00033 /* Instruction types.  */
00034 #define TWO_OPERAND_1 0x00000000
00035 #define TWO_OPERAND_2 0x40000000
00036 #define THREE_OPERAND 0x20000000
00037 #define PAR_STORE     0xC0000000
00038 #define MUL_ADDS      0x80000000
00039 #define BRANCHES      0x60000000
00040 
00041 /* Specific instruction id bits.  */
00042 #define NORMAL_IDEN    0x1F800000
00043 #define PAR_STORE_IDEN 0x3E000000
00044 #define MUL_ADD_IDEN   0x2C000000
00045 #define BR_IMM_IDEN    0x1F000000
00046 #define BR_COND_IDEN   0x1C3F0000
00047 
00048 /* Addressing modes.  */
00049 #define AM_REGISTER 0x00000000
00050 #define AM_DIRECT   0x00200000
00051 #define AM_INDIRECT 0x00400000
00052 #define AM_IMM      0x00600000
00053 
00054 #define P_FIELD 0x03000000
00055 
00056 #define REG_AR0 0x08
00057 #define LDP_INSN 0x08700000
00058 
00059 /* TMS320C30 program counter for current instruction.  */
00060 static unsigned int _pc;
00061 
00062 struct instruction
00063 {
00064   int type;
00065   template *tm;
00066   partemplate *ptm;
00067 };
00068 
00069 static int
00070 get_tic30_instruction (unsigned long insn_word, struct instruction *insn)
00071 {
00072   switch (GET_TYPE (insn_word))
00073     {
00074     case TWO_OPERAND_1:
00075     case TWO_OPERAND_2:
00076     case THREE_OPERAND:
00077       insn->type = NORMAL_INSN;
00078       {
00079        template *current_optab = (template *) tic30_optab;
00080 
00081        for (; current_optab < tic30_optab_end; current_optab++)
00082          {
00083            if (GET_TYPE (current_optab->base_opcode) == GET_TYPE (insn_word))
00084              {
00085               if (current_optab->operands == 0)
00086                 {
00087                   if (current_optab->base_opcode == insn_word)
00088                     {
00089                      insn->tm = current_optab;
00090                      break;
00091                     }
00092                 }
00093               else if ((current_optab->base_opcode & NORMAL_IDEN) == (insn_word & NORMAL_IDEN))
00094                 {
00095                   insn->tm = current_optab;
00096                   break;
00097                 }
00098              }
00099          }
00100       }
00101       break;
00102 
00103     case PAR_STORE:
00104       insn->type = PARALLEL_INSN;
00105       {
00106        partemplate *current_optab = (partemplate *) tic30_paroptab;
00107 
00108        for (; current_optab < tic30_paroptab_end; current_optab++)
00109          {
00110            if (GET_TYPE (current_optab->base_opcode) == GET_TYPE (insn_word))
00111              {
00112               if ((current_optab->base_opcode & PAR_STORE_IDEN)
00113                   == (insn_word & PAR_STORE_IDEN))
00114                 {
00115                   insn->ptm = current_optab;
00116                   break;
00117                 }
00118              }
00119          }
00120       }
00121       break;
00122 
00123     case MUL_ADDS:
00124       insn->type = PARALLEL_INSN;
00125       {
00126        partemplate *current_optab = (partemplate *) tic30_paroptab;
00127 
00128        for (; current_optab < tic30_paroptab_end; current_optab++)
00129          {
00130            if (GET_TYPE (current_optab->base_opcode) == GET_TYPE (insn_word))
00131              {
00132               if ((current_optab->base_opcode & MUL_ADD_IDEN)
00133                   == (insn_word & MUL_ADD_IDEN))
00134                 {
00135                   insn->ptm = current_optab;
00136                   break;
00137                 }
00138              }
00139          }
00140       }
00141       break;
00142 
00143     case BRANCHES:
00144       insn->type = NORMAL_INSN;
00145       {
00146        template *current_optab = (template *) tic30_optab;
00147 
00148        for (; current_optab < tic30_optab_end; current_optab++)
00149          {
00150            if (GET_TYPE (current_optab->base_opcode) == GET_TYPE (insn_word))
00151              {
00152               if (current_optab->operand_types[0] & Imm24)
00153                 {
00154                   if ((current_optab->base_opcode & BR_IMM_IDEN)
00155                      == (insn_word & BR_IMM_IDEN))
00156                     {
00157                      insn->tm = current_optab;
00158                      break;
00159                     }
00160                 }
00161               else if (current_optab->operands > 0)
00162                 {
00163                   if ((current_optab->base_opcode & BR_COND_IDEN)
00164                      == (insn_word & BR_COND_IDEN))
00165                     {
00166                      insn->tm = current_optab;
00167                      break;
00168                     }
00169                 }
00170               else
00171                 {
00172                   if ((current_optab->base_opcode & (BR_COND_IDEN | 0x00800000))
00173                      == (insn_word & (BR_COND_IDEN | 0x00800000)))
00174                     {
00175                      insn->tm = current_optab;
00176                      break;
00177                     }
00178                 }
00179              }
00180          }
00181       }
00182       break;
00183     default:
00184       return 0;
00185     }
00186   return 1;
00187 }
00188 
00189 static int
00190 get_register_operand (unsigned char fragment, char *buffer)
00191 {
00192   const reg *current_reg = tic30_regtab;
00193 
00194   if (buffer == NULL)
00195     return 0;
00196   for (; current_reg < tic30_regtab_end; current_reg++)
00197     {
00198       if ((fragment & 0x1F) == current_reg->opcode)
00199        {
00200          strcpy (buffer, current_reg->name);
00201          return 1;
00202        }
00203     }
00204   return 0;
00205 }
00206 
00207 static int
00208 get_indirect_operand (unsigned short fragment,
00209                     int size,
00210                     char *buffer)
00211 {
00212   unsigned char mod;
00213   unsigned arnum;
00214   unsigned char disp;
00215 
00216   if (buffer == NULL)
00217     return 0;
00218   /* Determine which bits identify the sections of the indirect
00219      operand based on the size in bytes.  */
00220   switch (size)
00221     {
00222     case 1:
00223       mod = (fragment & 0x00F8) >> 3;
00224       arnum = (fragment & 0x0007);
00225       disp = 0;
00226       break;
00227     case 2:
00228       mod = (fragment & 0xF800) >> 11;
00229       arnum = (fragment & 0x0700) >> 8;
00230       disp = (fragment & 0x00FF);
00231       break;
00232     default:
00233       return 0;
00234     }
00235   {
00236     const ind_addr_type *current_ind = tic30_indaddr_tab;
00237 
00238     for (; current_ind < tic30_indaddrtab_end; current_ind++)
00239       {
00240        if (current_ind->modfield == mod)
00241          {
00242            if (current_ind->displacement == IMPLIED_DISP && size == 2)
00243              continue;
00244 
00245            else
00246              {
00247               size_t i, len;
00248               int bufcnt;
00249 
00250               len = strlen (current_ind->syntax);
00251               for (i = 0, bufcnt = 0; i < len; i++, bufcnt++)
00252                 {
00253                   buffer[bufcnt] = current_ind->syntax[i];
00254                   if (buffer[bufcnt - 1] == 'a' && buffer[bufcnt] == 'r')
00255                     buffer[++bufcnt] = arnum + '0';
00256                   if (buffer[bufcnt] == '('
00257                      && current_ind->displacement == DISP_REQUIRED)
00258                     {
00259                      sprintf (&buffer[bufcnt + 1], "%u", disp);
00260                      bufcnt += strlen (&buffer[bufcnt + 1]);
00261                     }
00262                 }
00263               buffer[bufcnt + 1] = '\0';
00264               break;
00265              }
00266          }
00267       }
00268   }
00269   return 1;
00270 }
00271 
00272 static int
00273 cnvt_tmsfloat_ieee (unsigned long tmsfloat, int size, float *ieeefloat)
00274 {
00275   unsigned long exp, sign, mant;
00276   union
00277   {
00278     unsigned long l;
00279     float f;
00280   } val;
00281 
00282   if (size == 2)
00283     {
00284       if ((tmsfloat & 0x0000F000) == 0x00008000)
00285        tmsfloat = 0x80000000;
00286       else
00287        {
00288          tmsfloat <<= 16;
00289          tmsfloat = (long) tmsfloat >> 4;
00290        }
00291     }
00292   exp = tmsfloat & 0xFF000000;
00293   if (exp == 0x80000000)
00294     {
00295       *ieeefloat = 0.0;
00296       return 1;
00297     }
00298   exp += 0x7F000000;
00299   sign = (tmsfloat & 0x00800000) << 8;
00300   mant = tmsfloat & 0x007FFFFF;
00301   if (exp == 0xFF000000)
00302     {
00303       if (mant == 0)
00304        *ieeefloat = ERANGE;
00305 #ifdef HUGE_VALF
00306       if (sign == 0)
00307        *ieeefloat = HUGE_VALF;
00308       else
00309        *ieeefloat = -HUGE_VALF;
00310 #else
00311       if (sign == 0)
00312        *ieeefloat = 1.0 / 0.0;
00313       else
00314        *ieeefloat = -1.0 / 0.0;
00315 #endif
00316       return 1;
00317     }
00318   exp >>= 1;
00319   if (sign)
00320     {
00321       mant = (~mant) & 0x007FFFFF;
00322       mant += 1;
00323       exp += mant & 0x00800000;
00324       exp &= 0x7F800000;
00325       mant &= 0x007FFFFF;
00326     }
00327   if (tmsfloat == 0x80000000)
00328     sign = mant = exp = 0;
00329   tmsfloat = sign | exp | mant;
00330   val.l = tmsfloat;
00331   *ieeefloat = val.f;
00332   return 1;
00333 }
00334 
00335 static int
00336 print_two_operand (disassemble_info *info,
00337                  unsigned long insn_word,
00338                  struct instruction *insn)
00339 {
00340   char name[12];
00341   char operand[2][13] =
00342   {
00343     {0},
00344     {0}
00345   };
00346   float f_number;
00347 
00348   if (insn->tm == NULL)
00349     return 0;
00350   strcpy (name, insn->tm->name);
00351   if (insn->tm->opcode_modifier == AddressMode)
00352     {
00353       int src_op, dest_op;
00354       /* Determine whether instruction is a store or a normal instruction.  */
00355       if ((insn->tm->operand_types[1] & (Direct | Indirect))
00356          == (Direct | Indirect))
00357        {
00358          src_op = 1;
00359          dest_op = 0;
00360        }
00361       else
00362        {
00363          src_op = 0;
00364          dest_op = 1;
00365        }
00366       /* Get the destination register.  */
00367       if (insn->tm->operands == 2)
00368        get_register_operand ((insn_word & 0x001F0000) >> 16, operand[dest_op]);
00369       /* Get the source operand based on addressing mode.  */
00370       switch (insn_word & AddressMode)
00371        {
00372        case AM_REGISTER:
00373          /* Check for the NOP instruction before getting the operand.  */
00374          if ((insn->tm->operand_types[0] & NotReq) == 0)
00375            get_register_operand ((insn_word & 0x0000001F), operand[src_op]);
00376          break;
00377        case AM_DIRECT:
00378          sprintf (operand[src_op], "@0x%lX", (insn_word & 0x0000FFFF));
00379          break;
00380        case AM_INDIRECT:
00381          get_indirect_operand ((insn_word & 0x0000FFFF), 2, operand[src_op]);
00382          break;
00383        case AM_IMM:
00384          /* Get the value of the immediate operand based on variable type.  */
00385          switch (insn->tm->imm_arg_type)
00386            {
00387            case Imm_Float:
00388              cnvt_tmsfloat_ieee ((insn_word & 0x0000FFFF), 2, &f_number);
00389              sprintf (operand[src_op], "%2.2f", f_number);
00390              break;
00391            case Imm_SInt:
00392              sprintf (operand[src_op], "%d", (short) (insn_word & 0x0000FFFF));
00393              break;
00394            case Imm_UInt:
00395              sprintf (operand[src_op], "%lu", (insn_word & 0x0000FFFF));
00396              break;
00397            default:
00398              return 0;
00399            }
00400          /* Handle special case for LDP instruction.  */
00401          if ((insn_word & 0xFFFFFF00) == LDP_INSN)
00402            {
00403              strcpy (name, "ldp");
00404              sprintf (operand[0], "0x%06lX", (insn_word & 0x000000FF) << 16);
00405              operand[1][0] = '\0';
00406            }
00407        }
00408     }
00409   /* Handle case for stack and rotate instructions.  */
00410   else if (insn->tm->operands == 1)
00411     {
00412       if (insn->tm->opcode_modifier == StackOp)
00413        get_register_operand ((insn_word & 0x001F0000) >> 16, operand[0]);
00414     }
00415   /* Output instruction to stream.  */
00416   info->fprintf_func (info->stream, "   %s %s%c%s", name,
00417                     operand[0][0] ? operand[0] : "",
00418                     operand[1][0] ? ',' : ' ',
00419                     operand[1][0] ? operand[1] : "");
00420   return 1;
00421 }
00422 
00423 static int
00424 print_three_operand (disassemble_info *info,
00425                    unsigned long insn_word,
00426                    struct instruction *insn)
00427 {
00428   char operand[3][13] =
00429   {
00430     {0},
00431     {0},
00432     {0}
00433   };
00434 
00435   if (insn->tm == NULL)
00436     return 0;
00437   switch (insn_word & AddressMode)
00438     {
00439     case AM_REGISTER:
00440       get_register_operand ((insn_word & 0x000000FF), operand[0]);
00441       get_register_operand ((insn_word & 0x0000FF00) >> 8, operand[1]);
00442       break;
00443     case AM_DIRECT:
00444       get_register_operand ((insn_word & 0x000000FF), operand[0]);
00445       get_indirect_operand ((insn_word & 0x0000FF00) >> 8, 1, operand[1]);
00446       break;
00447     case AM_INDIRECT:
00448       get_indirect_operand ((insn_word & 0x000000FF), 1, operand[0]);
00449       get_register_operand ((insn_word & 0x0000FF00) >> 8, operand[1]);
00450       break;
00451     case AM_IMM:
00452       get_indirect_operand ((insn_word & 0x000000FF), 1, operand[0]);
00453       get_indirect_operand ((insn_word & 0x0000FF00) >> 8, 1, operand[1]);
00454       break;
00455     default:
00456       return 0;
00457     }
00458   if (insn->tm->operands == 3)
00459     get_register_operand ((insn_word & 0x001F0000) >> 16, operand[2]);
00460   info->fprintf_func (info->stream, "   %s %s,%s%c%s", insn->tm->name,
00461                     operand[0], operand[1],
00462                     operand[2][0] ? ',' : ' ',
00463                     operand[2][0] ? operand[2] : "");
00464   return 1;
00465 }
00466 
00467 static int
00468 print_par_insn (disassemble_info *info,
00469               unsigned long insn_word,
00470               struct instruction *insn)
00471 {
00472   size_t i, len;
00473   char *name1, *name2;
00474   char operand[2][3][13] =
00475   {
00476     {
00477       {0},
00478       {0},
00479       {0}
00480     },
00481     {
00482       {0},
00483       {0},
00484       {0}
00485     }
00486   };
00487 
00488   if (insn->ptm == NULL)
00489     return 0;
00490   /* Parse out the names of each of the parallel instructions from the
00491      q_insn1_insn2 format.  */
00492   name1 = (char *) strdup (insn->ptm->name + 2);
00493   name2 = "";
00494   len = strlen (name1);
00495   for (i = 0; i < len; i++)
00496     {
00497       if (name1[i] == '_')
00498        {
00499          name2 = &name1[i + 1];
00500          name1[i] = '\0';
00501          break;
00502        }
00503     }
00504   /* Get the operands of the instruction based on the operand order.  */
00505   switch (insn->ptm->oporder)
00506     {
00507     case OO_4op1:
00508       get_indirect_operand ((insn_word & 0x000000FF), 1, operand[0][0]);
00509       get_indirect_operand ((insn_word & 0x0000FF00) >> 8, 1, operand[1][1]);
00510       get_register_operand ((insn_word >> 16) & 0x07, operand[1][0]);
00511       get_register_operand ((insn_word >> 22) & 0x07, operand[0][1]);
00512       break;
00513     case OO_4op2:
00514       get_indirect_operand ((insn_word & 0x000000FF), 1, operand[0][0]);
00515       get_indirect_operand ((insn_word & 0x0000FF00) >> 8, 1, operand[1][0]);
00516       get_register_operand ((insn_word >> 19) & 0x07, operand[1][1]);
00517       get_register_operand ((insn_word >> 22) & 0x07, operand[0][1]);
00518       break;
00519     case OO_4op3:
00520       get_indirect_operand ((insn_word & 0x000000FF), 1, operand[0][1]);
00521       get_indirect_operand ((insn_word & 0x0000FF00) >> 8, 1, operand[1][1]);
00522       get_register_operand ((insn_word >> 16) & 0x07, operand[1][0]);
00523       get_register_operand ((insn_word >> 22) & 0x07, operand[0][0]);
00524       break;
00525     case OO_5op1:
00526       get_indirect_operand ((insn_word & 0x000000FF), 1, operand[0][0]);
00527       get_indirect_operand ((insn_word & 0x0000FF00) >> 8, 1, operand[1][1]);
00528       get_register_operand ((insn_word >> 16) & 0x07, operand[1][0]);
00529       get_register_operand ((insn_word >> 19) & 0x07, operand[0][1]);
00530       get_register_operand ((insn_word >> 22) & 0x07, operand[0][2]);
00531       break;
00532     case OO_5op2:
00533       get_indirect_operand ((insn_word & 0x000000FF), 1, operand[0][1]);
00534       get_indirect_operand ((insn_word & 0x0000FF00) >> 8, 1, operand[1][1]);
00535       get_register_operand ((insn_word >> 16) & 0x07, operand[1][0]);
00536       get_register_operand ((insn_word >> 19) & 0x07, operand[0][0]);
00537       get_register_operand ((insn_word >> 22) & 0x07, operand[0][2]);
00538       break;
00539     case OO_PField:
00540       if (insn_word & 0x00800000)
00541        get_register_operand (0x01, operand[0][2]);
00542       else
00543        get_register_operand (0x00, operand[0][2]);
00544       if (insn_word & 0x00400000)
00545        get_register_operand (0x03, operand[1][2]);
00546       else
00547        get_register_operand (0x02, operand[1][2]);
00548       switch (insn_word & P_FIELD)
00549        {
00550        case 0x00000000:
00551          get_indirect_operand ((insn_word & 0x000000FF), 1, operand[0][1]);
00552          get_indirect_operand ((insn_word & 0x0000FF00) >> 8, 1, operand[0][0]);
00553          get_register_operand ((insn_word >> 16) & 0x07, operand[1][1]);
00554          get_register_operand ((insn_word >> 19) & 0x07, operand[1][0]);
00555          break;
00556        case 0x01000000:
00557          get_indirect_operand ((insn_word & 0x000000FF), 1, operand[1][0]);
00558          get_indirect_operand ((insn_word & 0x0000FF00) >> 8, 1, operand[0][0]);
00559          get_register_operand ((insn_word >> 16) & 0x07, operand[1][1]);
00560          get_register_operand ((insn_word >> 19) & 0x07, operand[0][1]);
00561          break;
00562        case 0x02000000:
00563          get_indirect_operand ((insn_word & 0x000000FF), 1, operand[1][1]);
00564          get_indirect_operand ((insn_word & 0x0000FF00) >> 8, 1, operand[1][0]);
00565          get_register_operand ((insn_word >> 16) & 0x07, operand[0][1]);
00566          get_register_operand ((insn_word >> 19) & 0x07, operand[0][0]);
00567          break;
00568        case 0x03000000:
00569          get_indirect_operand ((insn_word & 0x000000FF), 1, operand[1][1]);
00570          get_indirect_operand ((insn_word & 0x0000FF00) >> 8, 1, operand[0][0]);
00571          get_register_operand ((insn_word >> 16) & 0x07, operand[1][0]);
00572          get_register_operand ((insn_word >> 19) & 0x07, operand[0][1]);
00573          break;
00574        }
00575       break;
00576     default:
00577       return 0;
00578     }
00579   info->fprintf_func (info->stream, "   %s %s,%s%c%s", name1,
00580                     operand[0][0], operand[0][1],
00581                     operand[0][2][0] ? ',' : ' ',
00582                     operand[0][2][0] ? operand[0][2] : "");
00583   info->fprintf_func (info->stream, "\n\t\t\t|| %s %s,%s%c%s", name2,
00584                     operand[1][0], operand[1][1],
00585                     operand[1][2][0] ? ',' : ' ',
00586                     operand[1][2][0] ? operand[1][2] : "");
00587   free (name1);
00588   return 1;
00589 }
00590 
00591 static int
00592 print_branch (disassemble_info *info,
00593              unsigned long insn_word,
00594              struct instruction *insn)
00595 {
00596   char operand[2][13] =
00597   {
00598     {0},
00599     {0}
00600   };
00601   unsigned long address;
00602   int print_label = 0;
00603 
00604   if (insn->tm == NULL)
00605     return 0;
00606   /* Get the operands for 24-bit immediate jumps.  */
00607   if (insn->tm->operand_types[0] & Imm24)
00608     {
00609       address = insn_word & 0x00FFFFFF;
00610       sprintf (operand[0], "0x%lX", address);
00611       print_label = 1;
00612     }
00613   /* Get the operand for the trap instruction.  */
00614   else if (insn->tm->operand_types[0] & IVector)
00615     {
00616       address = insn_word & 0x0000001F;
00617       sprintf (operand[0], "0x%lX", address);
00618     }
00619   else
00620     {
00621       address = insn_word & 0x0000FFFF;
00622       /* Get the operands for the DB instructions.  */
00623       if (insn->tm->operands == 2)
00624        {
00625          get_register_operand (((insn_word & 0x01C00000) >> 22) + REG_AR0, operand[0]);
00626          if (insn_word & PCRel)
00627            {
00628              sprintf (operand[1], "%d", (short) address);
00629              print_label = 1;
00630            }
00631          else
00632            get_register_operand (insn_word & 0x0000001F, operand[1]);
00633        }
00634       /* Get the operands for the standard branches.  */
00635       else if (insn->tm->operands == 1)
00636        {
00637          if (insn_word & PCRel)
00638            {
00639              address = (short) address;
00640              sprintf (operand[0], "%ld", address);
00641              print_label = 1;
00642            }
00643          else
00644            get_register_operand (insn_word & 0x0000001F, operand[0]);
00645        }
00646     }
00647   info->fprintf_func (info->stream, "   %s %s%c%s", insn->tm->name,
00648                     operand[0][0] ? operand[0] : "",
00649                     operand[1][0] ? ',' : ' ',
00650                     operand[1][0] ? operand[1] : "");
00651   /* Print destination of branch in relation to current symbol.  */
00652   if (print_label && info->symbols)
00653     {
00654       asymbol *sym = *info->symbols;
00655 
00656       if ((insn->tm->opcode_modifier == PCRel) && (insn_word & PCRel))
00657        {
00658          address = (_pc + 1 + (short) address) - ((sym->section->vma + sym->value) / 4);
00659          /* Check for delayed instruction, if so adjust destination.  */
00660          if (insn_word & 0x00200000)
00661            address += 2;
00662        }
00663       else
00664        {
00665          address -= ((sym->section->vma + sym->value) / 4);
00666        }
00667       if (address == 0)
00668        info->fprintf_func (info->stream, " <%s>", sym->name);
00669       else
00670        info->fprintf_func (info->stream, " <%s %c %d>", sym->name,
00671                          ((short) address < 0) ? '-' : '+',
00672                          abs (address));
00673     }
00674   return 1;
00675 }
00676 
00677 int
00678 print_insn_tic30 (bfd_vma pc, disassemble_info *info)
00679 {
00680   unsigned long insn_word;
00681   struct instruction insn = { 0, NULL, NULL };
00682   bfd_vma bufaddr = pc - info->buffer_vma;
00683 
00684   /* Obtain the current instruction word from the buffer.  */
00685   insn_word = (*(info->buffer + bufaddr) << 24) | (*(info->buffer + bufaddr + 1) << 16) |
00686     (*(info->buffer + bufaddr + 2) << 8) | *(info->buffer + bufaddr + 3);
00687   _pc = pc / 4;
00688   /* Get the instruction refered to by the current instruction word
00689      and print it out based on its type.  */
00690   if (!get_tic30_instruction (insn_word, &insn))
00691     return -1;
00692   switch (GET_TYPE (insn_word))
00693     {
00694     case TWO_OPERAND_1:
00695     case TWO_OPERAND_2:
00696       if (!print_two_operand (info, insn_word, &insn))
00697        return -1;
00698       break;
00699     case THREE_OPERAND:
00700       if (!print_three_operand (info, insn_word, &insn))
00701        return -1;
00702       break;
00703     case PAR_STORE:
00704     case MUL_ADDS:
00705       if (!print_par_insn (info, insn_word, &insn))
00706        return -1;
00707       break;
00708     case BRANCHES:
00709       if (!print_branch (info, insn_word, &insn))
00710        return -1;
00711       break;
00712     }
00713   return 4;
00714 }