Home | History | Annotate | Download | only in opcodes
      1 /* Disassembly routines for TMS320C30 architecture
      2    Copyright (C) 1998-2016 Free Software Foundation, Inc.
      3    Contributed by Steven Haworth (steve (at) pm.cse.rmit.edu.au)
      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 "dis-asm.h"
     26 #include "opcode/tic30.h"
     27 
     28 #define NORMAL_INSN   1
     29 #define PARALLEL_INSN 2
     30 
     31 /* Gets the type of instruction based on the top 2 or 3 bits of the
     32    instruction word.  */
     33 #define GET_TYPE(insn) (insn & 0x80000000 ? insn & 0xC0000000 : insn & 0xE0000000)
     34 
     35 /* Instruction types.  */
     36 #define TWO_OPERAND_1 0x00000000
     37 #define TWO_OPERAND_2 0x40000000
     38 #define THREE_OPERAND 0x20000000
     39 #define PAR_STORE     0xC0000000
     40 #define MUL_ADDS      0x80000000
     41 #define BRANCHES      0x60000000
     42 
     43 /* Specific instruction id bits.  */
     44 #define NORMAL_IDEN    0x1F800000
     45 #define PAR_STORE_IDEN 0x3E000000
     46 #define MUL_ADD_IDEN   0x2C000000
     47 #define BR_IMM_IDEN    0x1F000000
     48 #define BR_COND_IDEN   0x1C3F0000
     49 
     50 /* Addressing modes.  */
     51 #define AM_REGISTER 0x00000000
     52 #define AM_DIRECT   0x00200000
     53 #define AM_INDIRECT 0x00400000
     54 #define AM_IMM      0x00600000
     55 
     56 #define P_FIELD 0x03000000
     57 
     58 #define REG_AR0 0x08
     59 #define LDP_INSN 0x08700000
     60 
     61 /* TMS320C30 program counter for current instruction.  */
     62 static unsigned int _pc;
     63 
     64 struct instruction
     65 {
     66   int type;
     67   insn_template *tm;
     68   partemplate *ptm;
     69 };
     70 
     71 static int
     72 get_tic30_instruction (unsigned long insn_word, struct instruction *insn)
     73 {
     74   switch (GET_TYPE (insn_word))
     75     {
     76     case TWO_OPERAND_1:
     77     case TWO_OPERAND_2:
     78     case THREE_OPERAND:
     79       insn->type = NORMAL_INSN;
     80       {
     81 	insn_template *current_optab = (insn_template *) tic30_optab;
     82 
     83 	for (; current_optab < tic30_optab_end; current_optab++)
     84 	  {
     85 	    if (GET_TYPE (current_optab->base_opcode) == GET_TYPE (insn_word))
     86 	      {
     87 		if (current_optab->operands == 0)
     88 		  {
     89 		    if (current_optab->base_opcode == insn_word)
     90 		      {
     91 			insn->tm = current_optab;
     92 			break;
     93 		      }
     94 		  }
     95 		else if ((current_optab->base_opcode & NORMAL_IDEN) == (insn_word & NORMAL_IDEN))
     96 		  {
     97 		    insn->tm = current_optab;
     98 		    break;
     99 		  }
    100 	      }
    101 	  }
    102       }
    103       break;
    104 
    105     case PAR_STORE:
    106       insn->type = PARALLEL_INSN;
    107       {
    108 	partemplate *current_optab = (partemplate *) tic30_paroptab;
    109 
    110 	for (; current_optab < tic30_paroptab_end; current_optab++)
    111 	  {
    112 	    if (GET_TYPE (current_optab->base_opcode) == GET_TYPE (insn_word))
    113 	      {
    114 		if ((current_optab->base_opcode & PAR_STORE_IDEN)
    115 		    == (insn_word & PAR_STORE_IDEN))
    116 		  {
    117 		    insn->ptm = current_optab;
    118 		    break;
    119 		  }
    120 	      }
    121 	  }
    122       }
    123       break;
    124 
    125     case MUL_ADDS:
    126       insn->type = PARALLEL_INSN;
    127       {
    128 	partemplate *current_optab = (partemplate *) tic30_paroptab;
    129 
    130 	for (; current_optab < tic30_paroptab_end; current_optab++)
    131 	  {
    132 	    if (GET_TYPE (current_optab->base_opcode) == GET_TYPE (insn_word))
    133 	      {
    134 		if ((current_optab->base_opcode & MUL_ADD_IDEN)
    135 		    == (insn_word & MUL_ADD_IDEN))
    136 		  {
    137 		    insn->ptm = current_optab;
    138 		    break;
    139 		  }
    140 	      }
    141 	  }
    142       }
    143       break;
    144 
    145     case BRANCHES:
    146       insn->type = NORMAL_INSN;
    147       {
    148 	insn_template *current_optab = (insn_template *) tic30_optab;
    149 
    150 	for (; current_optab < tic30_optab_end; current_optab++)
    151 	  {
    152 	    if (GET_TYPE (current_optab->base_opcode) == GET_TYPE (insn_word))
    153 	      {
    154 		if (current_optab->operand_types[0] & Imm24)
    155 		  {
    156 		    if ((current_optab->base_opcode & BR_IMM_IDEN)
    157 			== (insn_word & BR_IMM_IDEN))
    158 		      {
    159 			insn->tm = current_optab;
    160 			break;
    161 		      }
    162 		  }
    163 		else if (current_optab->operands > 0)
    164 		  {
    165 		    if ((current_optab->base_opcode & BR_COND_IDEN)
    166 			== (insn_word & BR_COND_IDEN))
    167 		      {
    168 			insn->tm = current_optab;
    169 			break;
    170 		      }
    171 		  }
    172 		else
    173 		  {
    174 		    if ((current_optab->base_opcode & (BR_COND_IDEN | 0x00800000))
    175 			== (insn_word & (BR_COND_IDEN | 0x00800000)))
    176 		      {
    177 			insn->tm = current_optab;
    178 			break;
    179 		      }
    180 		  }
    181 	      }
    182 	  }
    183       }
    184       break;
    185     default:
    186       return 0;
    187     }
    188   return 1;
    189 }
    190 
    191 static int
    192 get_register_operand (unsigned char fragment, char *buffer)
    193 {
    194   const reg *current_reg = tic30_regtab;
    195 
    196   if (buffer == NULL)
    197     return 0;
    198   for (; current_reg < tic30_regtab_end; current_reg++)
    199     {
    200       if ((fragment & 0x1F) == current_reg->opcode)
    201 	{
    202 	  strcpy (buffer, current_reg->name);
    203 	  return 1;
    204 	}
    205     }
    206   return 0;
    207 }
    208 
    209 static int
    210 get_indirect_operand (unsigned short fragment,
    211 		      int size,
    212 		      char *buffer)
    213 {
    214   unsigned char mod;
    215   unsigned arnum;
    216   unsigned char disp;
    217 
    218   if (buffer == NULL)
    219     return 0;
    220   /* Determine which bits identify the sections of the indirect
    221      operand based on the size in bytes.  */
    222   switch (size)
    223     {
    224     case 1:
    225       mod = (fragment & 0x00F8) >> 3;
    226       arnum = (fragment & 0x0007);
    227       disp = 0;
    228       break;
    229     case 2:
    230       mod = (fragment & 0xF800) >> 11;
    231       arnum = (fragment & 0x0700) >> 8;
    232       disp = (fragment & 0x00FF);
    233       break;
    234     default:
    235       return 0;
    236     }
    237   {
    238     const ind_addr_type *current_ind = tic30_indaddr_tab;
    239 
    240     for (; current_ind < tic30_indaddrtab_end; current_ind++)
    241       {
    242 	if (current_ind->modfield == mod)
    243 	  {
    244 	    if (current_ind->displacement == IMPLIED_DISP && size == 2)
    245 	      continue;
    246 
    247 	    else
    248 	      {
    249 		size_t i, len;
    250 		int bufcnt;
    251 
    252 		len = strlen (current_ind->syntax);
    253 		for (i = 0, bufcnt = 0; i < len; i++, bufcnt++)
    254 		  {
    255 		    buffer[bufcnt] = current_ind->syntax[i];
    256 		    if (buffer[bufcnt - 1] == 'a' && buffer[bufcnt] == 'r')
    257 		      buffer[++bufcnt] = arnum + '0';
    258 		    if (buffer[bufcnt] == '('
    259 			&& current_ind->displacement == DISP_REQUIRED)
    260 		      {
    261 			sprintf (&buffer[bufcnt + 1], "%u", disp);
    262 			bufcnt += strlen (&buffer[bufcnt + 1]);
    263 		      }
    264 		  }
    265 		buffer[bufcnt + 1] = '\0';
    266 		break;
    267 	      }
    268 	  }
    269       }
    270   }
    271   return 1;
    272 }
    273 
    274 static int
    275 cnvt_tmsfloat_ieee (unsigned long tmsfloat, int size, float *ieeefloat)
    276 {
    277   unsigned long exponent, sign, mant;
    278   union
    279   {
    280     unsigned long l;
    281     float f;
    282   } val;
    283 
    284   if (size == 2)
    285     {
    286       if ((tmsfloat & 0x0000F000) == 0x00008000)
    287 	tmsfloat = 0x80000000;
    288       else
    289 	{
    290 	  tmsfloat <<= 16;
    291 	  tmsfloat = (long) tmsfloat >> 4;
    292 	}
    293     }
    294   exponent = tmsfloat & 0xFF000000;
    295   if (exponent == 0x80000000)
    296     {
    297       *ieeefloat = 0.0;
    298       return 1;
    299     }
    300   exponent += 0x7F000000;
    301   sign = (tmsfloat & 0x00800000) << 8;
    302   mant = tmsfloat & 0x007FFFFF;
    303   if (exponent == 0xFF000000)
    304     {
    305       if (mant == 0)
    306 	*ieeefloat = ERANGE;
    307 #ifdef HUGE_VALF
    308       if (sign == 0)
    309 	*ieeefloat = HUGE_VALF;
    310       else
    311 	*ieeefloat = -HUGE_VALF;
    312 #else
    313       if (sign == 0)
    314 	*ieeefloat = 1.0 / 0.0;
    315       else
    316 	*ieeefloat = -1.0 / 0.0;
    317 #endif
    318       return 1;
    319     }
    320   exponent >>= 1;
    321   if (sign)
    322     {
    323       mant = (~mant) & 0x007FFFFF;
    324       mant += 1;
    325       exponent += mant & 0x00800000;
    326       exponent &= 0x7F800000;
    327       mant &= 0x007FFFFF;
    328     }
    329   if (tmsfloat == 0x80000000)
    330     sign = mant = exponent = 0;
    331   tmsfloat = sign | exponent | mant;
    332   val.l = tmsfloat;
    333   *ieeefloat = val.f;
    334   return 1;
    335 }
    336 
    337 static int
    338 print_two_operand (disassemble_info *info,
    339 		   unsigned long insn_word,
    340 		   struct instruction *insn)
    341 {
    342   char name[12];
    343   char operand[2][13] =
    344   {
    345     {0},
    346     {0}
    347   };
    348   float f_number;
    349 
    350   if (insn->tm == NULL)
    351     return 0;
    352   strcpy (name, insn->tm->name);
    353   if (insn->tm->opcode_modifier == AddressMode)
    354     {
    355       int src_op, dest_op;
    356       /* Determine whether instruction is a store or a normal instruction.  */
    357       if ((insn->tm->operand_types[1] & (Direct | Indirect))
    358 	  == (Direct | Indirect))
    359 	{
    360 	  src_op = 1;
    361 	  dest_op = 0;
    362 	}
    363       else
    364 	{
    365 	  src_op = 0;
    366 	  dest_op = 1;
    367 	}
    368       /* Get the destination register.  */
    369       if (insn->tm->operands == 2)
    370 	get_register_operand ((insn_word & 0x001F0000) >> 16, operand[dest_op]);
    371       /* Get the source operand based on addressing mode.  */
    372       switch (insn_word & AddressMode)
    373 	{
    374 	case AM_REGISTER:
    375 	  /* Check for the NOP instruction before getting the operand.  */
    376 	  if ((insn->tm->operand_types[0] & NotReq) == 0)
    377 	    get_register_operand ((insn_word & 0x0000001F), operand[src_op]);
    378 	  break;
    379 	case AM_DIRECT:
    380 	  sprintf (operand[src_op], "@0x%lX", (insn_word & 0x0000FFFF));
    381 	  break;
    382 	case AM_INDIRECT:
    383 	  get_indirect_operand ((insn_word & 0x0000FFFF), 2, operand[src_op]);
    384 	  break;
    385 	case AM_IMM:
    386 	  /* Get the value of the immediate operand based on variable type.  */
    387 	  switch (insn->tm->imm_arg_type)
    388 	    {
    389 	    case Imm_Float:
    390 	      cnvt_tmsfloat_ieee ((insn_word & 0x0000FFFF), 2, &f_number);
    391 	      sprintf (operand[src_op], "%2.2f", f_number);
    392 	      break;
    393 	    case Imm_SInt:
    394 	      sprintf (operand[src_op], "%d", (short) (insn_word & 0x0000FFFF));
    395 	      break;
    396 	    case Imm_UInt:
    397 	      sprintf (operand[src_op], "%lu", (insn_word & 0x0000FFFF));
    398 	      break;
    399 	    default:
    400 	      return 0;
    401 	    }
    402 	  /* Handle special case for LDP instruction.  */
    403 	  if ((insn_word & 0xFFFFFF00) == LDP_INSN)
    404 	    {
    405 	      strcpy (name, "ldp");
    406 	      sprintf (operand[0], "0x%06lX", (insn_word & 0x000000FF) << 16);
    407 	      operand[1][0] = '\0';
    408 	    }
    409 	}
    410     }
    411   /* Handle case for stack and rotate instructions.  */
    412   else if (insn->tm->operands == 1)
    413     {
    414       if (insn->tm->opcode_modifier == StackOp)
    415 	get_register_operand ((insn_word & 0x001F0000) >> 16, operand[0]);
    416     }
    417   /* Output instruction to stream.  */
    418   info->fprintf_func (info->stream, "   %s %s%c%s", name,
    419 		      operand[0][0] ? operand[0] : "",
    420 		      operand[1][0] ? ',' : ' ',
    421 		      operand[1][0] ? operand[1] : "");
    422   return 1;
    423 }
    424 
    425 static int
    426 print_three_operand (disassemble_info *info,
    427 		     unsigned long insn_word,
    428 		     struct instruction *insn)
    429 {
    430   char operand[3][13] =
    431   {
    432     {0},
    433     {0},
    434     {0}
    435   };
    436 
    437   if (insn->tm == NULL)
    438     return 0;
    439   switch (insn_word & AddressMode)
    440     {
    441     case AM_REGISTER:
    442       get_register_operand ((insn_word & 0x000000FF), operand[0]);
    443       get_register_operand ((insn_word & 0x0000FF00) >> 8, operand[1]);
    444       break;
    445     case AM_DIRECT:
    446       get_register_operand ((insn_word & 0x000000FF), operand[0]);
    447       get_indirect_operand ((insn_word & 0x0000FF00) >> 8, 1, operand[1]);
    448       break;
    449     case AM_INDIRECT:
    450       get_indirect_operand ((insn_word & 0x000000FF), 1, operand[0]);
    451       get_register_operand ((insn_word & 0x0000FF00) >> 8, operand[1]);
    452       break;
    453     case AM_IMM:
    454       get_indirect_operand ((insn_word & 0x000000FF), 1, operand[0]);
    455       get_indirect_operand ((insn_word & 0x0000FF00) >> 8, 1, operand[1]);
    456       break;
    457     default:
    458       return 0;
    459     }
    460   if (insn->tm->operands == 3)
    461     get_register_operand ((insn_word & 0x001F0000) >> 16, operand[2]);
    462   info->fprintf_func (info->stream, "   %s %s,%s%c%s", insn->tm->name,
    463 		      operand[0], operand[1],
    464 		      operand[2][0] ? ',' : ' ',
    465 		      operand[2][0] ? operand[2] : "");
    466   return 1;
    467 }
    468 
    469 static int
    470 print_par_insn (disassemble_info *info,
    471 		unsigned long insn_word,
    472 		struct instruction *insn)
    473 {
    474   size_t i, len;
    475   char *name1, *name2;
    476   char operand[2][3][13] =
    477   {
    478     {
    479       {0},
    480       {0},
    481       {0}
    482     },
    483     {
    484       {0},
    485       {0},
    486       {0}
    487     }
    488   };
    489 
    490   if (insn->ptm == NULL)
    491     return 0;
    492   /* Parse out the names of each of the parallel instructions from the
    493      q_insn1_insn2 format.  */
    494   name1 = (char *) strdup (insn->ptm->name + 2);
    495   name2 = "";
    496   len = strlen (name1);
    497   for (i = 0; i < len; i++)
    498     {
    499       if (name1[i] == '_')
    500 	{
    501 	  name2 = &name1[i + 1];
    502 	  name1[i] = '\0';
    503 	  break;
    504 	}
    505     }
    506   /* Get the operands of the instruction based on the operand order.  */
    507   switch (insn->ptm->oporder)
    508     {
    509     case OO_4op1:
    510       get_indirect_operand ((insn_word & 0x000000FF), 1, operand[0][0]);
    511       get_indirect_operand ((insn_word & 0x0000FF00) >> 8, 1, operand[1][1]);
    512       get_register_operand ((insn_word >> 16) & 0x07, operand[1][0]);
    513       get_register_operand ((insn_word >> 22) & 0x07, operand[0][1]);
    514       break;
    515     case OO_4op2:
    516       get_indirect_operand ((insn_word & 0x000000FF), 1, operand[0][0]);
    517       get_indirect_operand ((insn_word & 0x0000FF00) >> 8, 1, operand[1][0]);
    518       get_register_operand ((insn_word >> 19) & 0x07, operand[1][1]);
    519       get_register_operand ((insn_word >> 22) & 0x07, operand[0][1]);
    520       break;
    521     case OO_4op3:
    522       get_indirect_operand ((insn_word & 0x000000FF), 1, operand[0][1]);
    523       get_indirect_operand ((insn_word & 0x0000FF00) >> 8, 1, operand[1][1]);
    524       get_register_operand ((insn_word >> 16) & 0x07, operand[1][0]);
    525       get_register_operand ((insn_word >> 22) & 0x07, operand[0][0]);
    526       break;
    527     case OO_5op1:
    528       get_indirect_operand ((insn_word & 0x000000FF), 1, operand[0][0]);
    529       get_indirect_operand ((insn_word & 0x0000FF00) >> 8, 1, operand[1][1]);
    530       get_register_operand ((insn_word >> 16) & 0x07, operand[1][0]);
    531       get_register_operand ((insn_word >> 19) & 0x07, operand[0][1]);
    532       get_register_operand ((insn_word >> 22) & 0x07, operand[0][2]);
    533       break;
    534     case OO_5op2:
    535       get_indirect_operand ((insn_word & 0x000000FF), 1, operand[0][1]);
    536       get_indirect_operand ((insn_word & 0x0000FF00) >> 8, 1, operand[1][1]);
    537       get_register_operand ((insn_word >> 16) & 0x07, operand[1][0]);
    538       get_register_operand ((insn_word >> 19) & 0x07, operand[0][0]);
    539       get_register_operand ((insn_word >> 22) & 0x07, operand[0][2]);
    540       break;
    541     case OO_PField:
    542       if (insn_word & 0x00800000)
    543 	get_register_operand (0x01, operand[0][2]);
    544       else
    545 	get_register_operand (0x00, operand[0][2]);
    546       if (insn_word & 0x00400000)
    547 	get_register_operand (0x03, operand[1][2]);
    548       else
    549 	get_register_operand (0x02, operand[1][2]);
    550       switch (insn_word & P_FIELD)
    551 	{
    552 	case 0x00000000:
    553 	  get_indirect_operand ((insn_word & 0x000000FF), 1, operand[0][1]);
    554 	  get_indirect_operand ((insn_word & 0x0000FF00) >> 8, 1, operand[0][0]);
    555 	  get_register_operand ((insn_word >> 16) & 0x07, operand[1][1]);
    556 	  get_register_operand ((insn_word >> 19) & 0x07, operand[1][0]);
    557 	  break;
    558 	case 0x01000000:
    559 	  get_indirect_operand ((insn_word & 0x000000FF), 1, operand[1][0]);
    560 	  get_indirect_operand ((insn_word & 0x0000FF00) >> 8, 1, operand[0][0]);
    561 	  get_register_operand ((insn_word >> 16) & 0x07, operand[1][1]);
    562 	  get_register_operand ((insn_word >> 19) & 0x07, operand[0][1]);
    563 	  break;
    564 	case 0x02000000:
    565 	  get_indirect_operand ((insn_word & 0x000000FF), 1, operand[1][1]);
    566 	  get_indirect_operand ((insn_word & 0x0000FF00) >> 8, 1, operand[1][0]);
    567 	  get_register_operand ((insn_word >> 16) & 0x07, operand[0][1]);
    568 	  get_register_operand ((insn_word >> 19) & 0x07, operand[0][0]);
    569 	  break;
    570 	case 0x03000000:
    571 	  get_indirect_operand ((insn_word & 0x000000FF), 1, operand[1][1]);
    572 	  get_indirect_operand ((insn_word & 0x0000FF00) >> 8, 1, operand[0][0]);
    573 	  get_register_operand ((insn_word >> 16) & 0x07, operand[1][0]);
    574 	  get_register_operand ((insn_word >> 19) & 0x07, operand[0][1]);
    575 	  break;
    576 	}
    577       break;
    578     default:
    579       return 0;
    580     }
    581   info->fprintf_func (info->stream, "   %s %s,%s%c%s", name1,
    582 		      operand[0][0], operand[0][1],
    583 		      operand[0][2][0] ? ',' : ' ',
    584 		      operand[0][2][0] ? operand[0][2] : "");
    585   info->fprintf_func (info->stream, "\n\t\t\t|| %s %s,%s%c%s", name2,
    586 		      operand[1][0], operand[1][1],
    587 		      operand[1][2][0] ? ',' : ' ',
    588 		      operand[1][2][0] ? operand[1][2] : "");
    589   free (name1);
    590   return 1;
    591 }
    592 
    593 static int
    594 print_branch (disassemble_info *info,
    595 	      unsigned long insn_word,
    596 	      struct instruction *insn)
    597 {
    598   char operand[2][13] =
    599   {
    600     {0},
    601     {0}
    602   };
    603   unsigned long address;
    604   int print_label = 0;
    605 
    606   if (insn->tm == NULL)
    607     return 0;
    608   /* Get the operands for 24-bit immediate jumps.  */
    609   if (insn->tm->operand_types[0] & Imm24)
    610     {
    611       address = insn_word & 0x00FFFFFF;
    612       sprintf (operand[0], "0x%lX", address);
    613       print_label = 1;
    614     }
    615   /* Get the operand for the trap instruction.  */
    616   else if (insn->tm->operand_types[0] & IVector)
    617     {
    618       address = insn_word & 0x0000001F;
    619       sprintf (operand[0], "0x%lX", address);
    620     }
    621   else
    622     {
    623       address = insn_word & 0x0000FFFF;
    624       /* Get the operands for the DB instructions.  */
    625       if (insn->tm->operands == 2)
    626 	{
    627 	  get_register_operand (((insn_word & 0x01C00000) >> 22) + REG_AR0, operand[0]);
    628 	  if (insn_word & PCRel)
    629 	    {
    630 	      sprintf (operand[1], "%d", (short) address);
    631 	      print_label = 1;
    632 	    }
    633 	  else
    634 	    get_register_operand (insn_word & 0x0000001F, operand[1]);
    635 	}
    636       /* Get the operands for the standard branches.  */
    637       else if (insn->tm->operands == 1)
    638 	{
    639 	  if (insn_word & PCRel)
    640 	    {
    641 	      address = (short) address;
    642 	      sprintf (operand[0], "%ld", address);
    643 	      print_label = 1;
    644 	    }
    645 	  else
    646 	    get_register_operand (insn_word & 0x0000001F, operand[0]);
    647 	}
    648     }
    649   info->fprintf_func (info->stream, "   %s %s%c%s", insn->tm->name,
    650 		      operand[0][0] ? operand[0] : "",
    651 		      operand[1][0] ? ',' : ' ',
    652 		      operand[1][0] ? operand[1] : "");
    653   /* Print destination of branch in relation to current symbol.  */
    654   if (print_label && info->symbols)
    655     {
    656       asymbol *sym = *info->symbols;
    657 
    658       if ((insn->tm->opcode_modifier == PCRel) && (insn_word & PCRel))
    659 	{
    660 	  address = (_pc + 1 + (short) address) - ((sym->section->vma + sym->value) / 4);
    661 	  /* Check for delayed instruction, if so adjust destination.  */
    662 	  if (insn_word & 0x00200000)
    663 	    address += 2;
    664 	}
    665       else
    666 	{
    667 	  address -= ((sym->section->vma + sym->value) / 4);
    668 	}
    669       if (address == 0)
    670 	info->fprintf_func (info->stream, " <%s>", sym->name);
    671       else
    672 	info->fprintf_func (info->stream, " <%s %c %lu>", sym->name,
    673 			    ((short) address < 0) ? '-' : '+',
    674 			    address);
    675     }
    676   return 1;
    677 }
    678 
    679 int
    680 print_insn_tic30 (bfd_vma pc, disassemble_info *info)
    681 {
    682   unsigned long insn_word;
    683   struct instruction insn = { 0, NULL, NULL };
    684   bfd_vma bufaddr = pc - info->buffer_vma;
    685 
    686   /* Obtain the current instruction word from the buffer.  */
    687   insn_word = (*(info->buffer + bufaddr) << 24) | (*(info->buffer + bufaddr + 1) << 16) |
    688     (*(info->buffer + bufaddr + 2) << 8) | *(info->buffer + bufaddr + 3);
    689   _pc = pc / 4;
    690   /* Get the instruction refered to by the current instruction word
    691      and print it out based on its type.  */
    692   if (!get_tic30_instruction (insn_word, &insn))
    693     return -1;
    694   switch (GET_TYPE (insn_word))
    695     {
    696     case TWO_OPERAND_1:
    697     case TWO_OPERAND_2:
    698       if (!print_two_operand (info, insn_word, &insn))
    699 	return -1;
    700       break;
    701     case THREE_OPERAND:
    702       if (!print_three_operand (info, insn_word, &insn))
    703 	return -1;
    704       break;
    705     case PAR_STORE:
    706     case MUL_ADDS:
    707       if (!print_par_insn (info, insn_word, &insn))
    708 	return -1;
    709       break;
    710     case BRANCHES:
    711       if (!print_branch (info, insn_word, &insn))
    712 	return -1;
    713       break;
    714     }
    715   return 4;
    716 }
    717