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