Home | History | Annotate | Line # | Download | only in opcodes
tic30-dis.c revision 1.1.1.11
      1 /* Disassembly routines for TMS320C30 architecture
      2    Copyright (C) 1998-2026 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 "disassemble.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 #define OPERAND_BUFFER_LEN 15
    192 
    193 static int
    194 get_register_operand (unsigned char fragment, char *buffer)
    195 {
    196   const reg *current_reg = tic30_regtab;
    197 
    198   if (buffer == NULL)
    199     return 0;
    200   for (; current_reg < tic30_regtab_end; current_reg++)
    201     {
    202       if ((fragment & 0x1F) == current_reg->opcode)
    203 	{
    204 	  strncpy (buffer, current_reg->name, OPERAND_BUFFER_LEN - 1);
    205 	  buffer[OPERAND_BUFFER_LEN - 1] = 0;
    206 	  return 1;
    207 	}
    208     }
    209   return 0;
    210 }
    211 
    212 static int
    213 get_indirect_operand (unsigned short fragment,
    214 		      int size,
    215 		      char *buffer)
    216 {
    217   unsigned char mod;
    218   unsigned arnum;
    219   unsigned char disp;
    220 
    221   if (buffer == NULL)
    222     return 0;
    223   /* Determine which bits identify the sections of the indirect
    224      operand based on the size in bytes.  */
    225   switch (size)
    226     {
    227     case 1:
    228       mod = (fragment & 0x00F8) >> 3;
    229       arnum = (fragment & 0x0007);
    230       disp = 0;
    231       break;
    232     case 2:
    233       mod = (fragment & 0xF800) >> 11;
    234       arnum = (fragment & 0x0700) >> 8;
    235       disp = (fragment & 0x00FF);
    236       break;
    237     default:
    238       return 0;
    239     }
    240   {
    241     const ind_addr_type *current_ind = tic30_indaddr_tab;
    242 
    243     for (; current_ind < tic30_indaddrtab_end; current_ind++)
    244       {
    245 	if (current_ind->modfield == mod)
    246 	  {
    247 	    if (current_ind->displacement == IMPLIED_DISP && size == 2)
    248 	      continue;
    249 
    250 	    else
    251 	      {
    252 		size_t i, len;
    253 		int bufcnt;
    254 
    255 		len = strlen (current_ind->syntax);
    256 
    257 		for (i = 0, bufcnt = 0; i < len; i++, bufcnt++)
    258 		  {
    259 		    buffer[bufcnt] = current_ind->syntax[i];
    260 
    261 		    if (bufcnt > 0
    262 			&& bufcnt < OPERAND_BUFFER_LEN - 1
    263 			&& buffer[bufcnt - 1] == 'a'
    264 			&& buffer[bufcnt] == 'r')
    265 		      buffer[++bufcnt] = arnum + '0';
    266 
    267 		    if (bufcnt < OPERAND_BUFFER_LEN - 1
    268 			&& buffer[bufcnt] == '('
    269 			&& current_ind->displacement == DISP_REQUIRED)
    270 		      {
    271 			snprintf (buffer + (bufcnt + 1),
    272 				 OPERAND_BUFFER_LEN - (bufcnt + 1),
    273 				 "%u", disp);
    274 			bufcnt += strlen (buffer + (bufcnt + 1));
    275 		      }
    276 		  }
    277 		buffer[bufcnt + 1] = '\0';
    278 		break;
    279 	      }
    280 	  }
    281       }
    282   }
    283   return 1;
    284 }
    285 
    286 static int
    287 cnvt_tmsfloat_ieee (unsigned long tmsfloat, int size, float *ieeefloat)
    288 {
    289   unsigned long exponent, sign, mant;
    290   union
    291   {
    292     unsigned long l;
    293     float f;
    294   } val;
    295 
    296   if (size == 2)
    297     {
    298       if ((tmsfloat & 0x0000F000) == 0x00008000)
    299 	tmsfloat = 0x80000000;
    300       else
    301 	{
    302 	  tmsfloat <<= 16;
    303 	  tmsfloat = (long) tmsfloat >> 4;
    304 	}
    305     }
    306   exponent = tmsfloat & 0xFF000000;
    307   if (exponent == 0x80000000)
    308     {
    309       *ieeefloat = 0.0;
    310       return 1;
    311     }
    312   exponent += 0x7F000000;
    313   sign = (tmsfloat & 0x00800000) << 8;
    314   mant = tmsfloat & 0x007FFFFF;
    315   if (exponent == 0xFF000000)
    316     {
    317       if (mant == 0)
    318 	*ieeefloat = ERANGE;
    319 #ifdef HUGE_VALF
    320       if (sign == 0)
    321 	*ieeefloat = HUGE_VALF;
    322       else
    323 	*ieeefloat = -HUGE_VALF;
    324 #else
    325       if (sign == 0)
    326 	*ieeefloat = 1.0 / 0.0;
    327       else
    328 	*ieeefloat = -1.0 / 0.0;
    329 #endif
    330       return 1;
    331     }
    332   exponent >>= 1;
    333   if (sign)
    334     {
    335       mant = (~mant) & 0x007FFFFF;
    336       mant += 1;
    337       exponent += mant & 0x00800000;
    338       exponent &= 0x7F800000;
    339       mant &= 0x007FFFFF;
    340     }
    341   if (tmsfloat == 0x80000000)
    342     sign = mant = exponent = 0;
    343   tmsfloat = sign | exponent | mant;
    344   val.l = tmsfloat;
    345   *ieeefloat = val.f;
    346   return 1;
    347 }
    348 
    349 static int
    350 print_two_operand (disassemble_info *info,
    351 		   unsigned long insn_word,
    352 		   struct instruction *insn)
    353 {
    354   char name[12];
    355   char operand[2][OPERAND_BUFFER_LEN] =
    356   {
    357     {0},
    358     {0}
    359   };
    360   float f_number;
    361 
    362   if (insn->tm == NULL)
    363     return 0;
    364   strcpy (name, insn->tm->name);
    365   if (insn->tm->opcode_modifier == AddressMode)
    366     {
    367       int src_op, dest_op;
    368       /* Determine whether instruction is a store or a normal instruction.  */
    369       if ((insn->tm->operand_types[1] & (Direct | Indirect))
    370 	  == (Direct | Indirect))
    371 	{
    372 	  src_op = 1;
    373 	  dest_op = 0;
    374 	}
    375       else
    376 	{
    377 	  src_op = 0;
    378 	  dest_op = 1;
    379 	}
    380       /* Get the destination register.  */
    381       if (insn->tm->operands == 2)
    382 	get_register_operand ((insn_word & 0x001F0000) >> 16, operand[dest_op]);
    383       /* Get the source operand based on addressing mode.  */
    384       switch (insn_word & AddressMode)
    385 	{
    386 	case AM_REGISTER:
    387 	  /* Check for the NOP instruction before getting the operand.  */
    388 	  if ((insn->tm->operand_types[0] & NotReq) == 0)
    389 	    get_register_operand ((insn_word & 0x0000001F), operand[src_op]);
    390 	  break;
    391 	case AM_DIRECT:
    392 	  sprintf (operand[src_op], "@0x%lX", (insn_word & 0x0000FFFF));
    393 	  break;
    394 	case AM_INDIRECT:
    395 	  get_indirect_operand ((insn_word & 0x0000FFFF), 2, operand[src_op]);
    396 	  break;
    397 	case AM_IMM:
    398 	  /* Get the value of the immediate operand based on variable type.  */
    399 	  switch (insn->tm->imm_arg_type)
    400 	    {
    401 	    case Imm_Float:
    402 	      cnvt_tmsfloat_ieee ((insn_word & 0x0000FFFF), 2, &f_number);
    403 	      sprintf (operand[src_op], "%2.2f", f_number);
    404 	      break;
    405 	    case Imm_SInt:
    406 	      sprintf (operand[src_op], "%d", (short) (insn_word & 0x0000FFFF));
    407 	      break;
    408 	    case Imm_UInt:
    409 	      sprintf (operand[src_op], "%lu", (insn_word & 0x0000FFFF));
    410 	      break;
    411 	    default:
    412 	      return 0;
    413 	    }
    414 	  /* Handle special case for LDP instruction.  */
    415 	  if ((insn_word & 0xFFFFFF00) == LDP_INSN)
    416 	    {
    417 	      strcpy (name, "ldp");
    418 	      sprintf (operand[0], "0x%06lX", (insn_word & 0x000000FF) << 16);
    419 	      operand[1][0] = '\0';
    420 	    }
    421 	}
    422     }
    423   /* Handle case for stack and rotate instructions.  */
    424   else if (insn->tm->operands == 1)
    425     {
    426       if (insn->tm->opcode_modifier == StackOp)
    427 	get_register_operand ((insn_word & 0x001F0000) >> 16, operand[0]);
    428     }
    429   /* Output instruction to stream.  */
    430   info->fprintf_func (info->stream, "   %s %s%c%s", name,
    431 		      operand[0][0] ? operand[0] : "",
    432 		      operand[1][0] ? ',' : ' ',
    433 		      operand[1][0] ? operand[1] : "");
    434   return 1;
    435 }
    436 
    437 static int
    438 print_three_operand (disassemble_info *info,
    439 		     unsigned long insn_word,
    440 		     struct instruction *insn)
    441 {
    442   char operand[3][OPERAND_BUFFER_LEN] =
    443   {
    444     {0},
    445     {0},
    446     {0}
    447   };
    448 
    449   if (insn->tm == NULL)
    450     return 0;
    451   switch (insn_word & AddressMode)
    452     {
    453     case AM_REGISTER:
    454       get_register_operand ((insn_word & 0x000000FF), operand[0]);
    455       get_register_operand ((insn_word & 0x0000FF00) >> 8, operand[1]);
    456       break;
    457     case AM_DIRECT:
    458       get_register_operand ((insn_word & 0x000000FF), operand[0]);
    459       get_indirect_operand ((insn_word & 0x0000FF00) >> 8, 1, operand[1]);
    460       break;
    461     case AM_INDIRECT:
    462       get_indirect_operand ((insn_word & 0x000000FF), 1, operand[0]);
    463       get_register_operand ((insn_word & 0x0000FF00) >> 8, operand[1]);
    464       break;
    465     case AM_IMM:
    466       get_indirect_operand ((insn_word & 0x000000FF), 1, operand[0]);
    467       get_indirect_operand ((insn_word & 0x0000FF00) >> 8, 1, operand[1]);
    468       break;
    469     default:
    470       return 0;
    471     }
    472   if (insn->tm->operands == 3)
    473     get_register_operand ((insn_word & 0x001F0000) >> 16, operand[2]);
    474   info->fprintf_func (info->stream, "   %s %s,%s%c%s", insn->tm->name,
    475 		      operand[0], operand[1],
    476 		      operand[2][0] ? ',' : ' ',
    477 		      operand[2][0] ? operand[2] : "");
    478   return 1;
    479 }
    480 
    481 static int
    482 print_par_insn (disassemble_info *info,
    483 		unsigned long insn_word,
    484 		struct instruction *insn)
    485 {
    486   size_t i, len;
    487   char *name1, *name2;
    488   char operand[2][3][OPERAND_BUFFER_LEN] =
    489   {
    490     {
    491       {0},
    492       {0},
    493       {0}
    494     },
    495     {
    496       {0},
    497       {0},
    498       {0}
    499     }
    500   };
    501 
    502   if (insn->ptm == NULL)
    503     return 0;
    504   /* Parse out the names of each of the parallel instructions from the
    505      q_insn1_insn2 format.  */
    506   name1 = (char *) strdup (insn->ptm->name + 2);
    507   name2 = "";
    508   len = strlen (name1);
    509   for (i = 0; i < len; i++)
    510     {
    511       if (name1[i] == '_')
    512 	{
    513 	  name2 = &name1[i + 1];
    514 	  name1[i] = '\0';
    515 	  break;
    516 	}
    517     }
    518   /* Get the operands of the instruction based on the operand order.  */
    519   switch (insn->ptm->oporder)
    520     {
    521     case OO_4op1:
    522       get_indirect_operand ((insn_word & 0x000000FF), 1, operand[0][0]);
    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][1]);
    526       break;
    527     case OO_4op2:
    528       get_indirect_operand ((insn_word & 0x000000FF), 1, operand[0][0]);
    529       get_indirect_operand ((insn_word & 0x0000FF00) >> 8, 1, operand[1][0]);
    530       get_register_operand ((insn_word >> 19) & 0x07, operand[1][1]);
    531       get_register_operand ((insn_word >> 22) & 0x07, operand[0][1]);
    532       break;
    533     case OO_4op3:
    534       get_indirect_operand ((insn_word & 0x000000FF), 1, operand[0][1]);
    535       get_indirect_operand ((insn_word & 0x0000FF00) >> 8, 1, operand[1][1]);
    536       get_register_operand ((insn_word >> 16) & 0x07, operand[1][0]);
    537       get_register_operand ((insn_word >> 22) & 0x07, operand[0][0]);
    538       break;
    539     case OO_5op1:
    540       get_indirect_operand ((insn_word & 0x000000FF), 1, operand[0][0]);
    541       get_indirect_operand ((insn_word & 0x0000FF00) >> 8, 1, operand[1][1]);
    542       get_register_operand ((insn_word >> 16) & 0x07, operand[1][0]);
    543       get_register_operand ((insn_word >> 19) & 0x07, operand[0][1]);
    544       get_register_operand ((insn_word >> 22) & 0x07, operand[0][2]);
    545       break;
    546     case OO_5op2:
    547       get_indirect_operand ((insn_word & 0x000000FF), 1, operand[0][1]);
    548       get_indirect_operand ((insn_word & 0x0000FF00) >> 8, 1, operand[1][1]);
    549       get_register_operand ((insn_word >> 16) & 0x07, operand[1][0]);
    550       get_register_operand ((insn_word >> 19) & 0x07, operand[0][0]);
    551       get_register_operand ((insn_word >> 22) & 0x07, operand[0][2]);
    552       break;
    553     case OO_PField:
    554       if (insn_word & 0x00800000)
    555 	get_register_operand (0x01, operand[0][2]);
    556       else
    557 	get_register_operand (0x00, operand[0][2]);
    558       if (insn_word & 0x00400000)
    559 	get_register_operand (0x03, operand[1][2]);
    560       else
    561 	get_register_operand (0x02, operand[1][2]);
    562       switch (insn_word & P_FIELD)
    563 	{
    564 	case 0x00000000:
    565 	  get_indirect_operand ((insn_word & 0x000000FF), 1, operand[0][1]);
    566 	  get_indirect_operand ((insn_word & 0x0000FF00) >> 8, 1, operand[0][0]);
    567 	  get_register_operand ((insn_word >> 16) & 0x07, operand[1][1]);
    568 	  get_register_operand ((insn_word >> 19) & 0x07, operand[1][0]);
    569 	  break;
    570 	case 0x01000000:
    571 	  get_indirect_operand ((insn_word & 0x000000FF), 1, operand[1][0]);
    572 	  get_indirect_operand ((insn_word & 0x0000FF00) >> 8, 1, operand[0][0]);
    573 	  get_register_operand ((insn_word >> 16) & 0x07, operand[1][1]);
    574 	  get_register_operand ((insn_word >> 19) & 0x07, operand[0][1]);
    575 	  break;
    576 	case 0x02000000:
    577 	  get_indirect_operand ((insn_word & 0x000000FF), 1, operand[1][1]);
    578 	  get_indirect_operand ((insn_word & 0x0000FF00) >> 8, 1, operand[1][0]);
    579 	  get_register_operand ((insn_word >> 16) & 0x07, operand[0][1]);
    580 	  get_register_operand ((insn_word >> 19) & 0x07, operand[0][0]);
    581 	  break;
    582 	case 0x03000000:
    583 	  get_indirect_operand ((insn_word & 0x000000FF), 1, operand[1][1]);
    584 	  get_indirect_operand ((insn_word & 0x0000FF00) >> 8, 1, operand[0][0]);
    585 	  get_register_operand ((insn_word >> 16) & 0x07, operand[1][0]);
    586 	  get_register_operand ((insn_word >> 19) & 0x07, operand[0][1]);
    587 	  break;
    588 	}
    589       break;
    590     default:
    591       return 0;
    592     }
    593   info->fprintf_func (info->stream, "   %s %s,%s%c%s", name1,
    594 		      operand[0][0], operand[0][1],
    595 		      operand[0][2][0] ? ',' : ' ',
    596 		      operand[0][2][0] ? operand[0][2] : "");
    597   info->fprintf_func (info->stream, "\n\t\t\t|| %s %s,%s%c%s", name2,
    598 		      operand[1][0], operand[1][1],
    599 		      operand[1][2][0] ? ',' : ' ',
    600 		      operand[1][2][0] ? operand[1][2] : "");
    601   free (name1);
    602   return 1;
    603 }
    604 
    605 static int
    606 print_branch (disassemble_info *info,
    607 	      unsigned long insn_word,
    608 	      struct instruction *insn)
    609 {
    610   char operand[2][OPERAND_BUFFER_LEN] =
    611   {
    612     {0},
    613     {0}
    614   };
    615   unsigned long address;
    616   int print_label = 0;
    617 
    618   if (insn->tm == NULL)
    619     return 0;
    620   /* Get the operands for 24-bit immediate jumps.  */
    621   if (insn->tm->operand_types[0] & Imm24)
    622     {
    623       address = insn_word & 0x00FFFFFF;
    624       sprintf (operand[0], "0x%lX", address);
    625       print_label = 1;
    626     }
    627   /* Get the operand for the trap instruction.  */
    628   else if (insn->tm->operand_types[0] & IVector)
    629     {
    630       address = insn_word & 0x0000001F;
    631       sprintf (operand[0], "0x%lX", address);
    632     }
    633   else
    634     {
    635       address = insn_word & 0x0000FFFF;
    636       /* Get the operands for the DB instructions.  */
    637       if (insn->tm->operands == 2)
    638 	{
    639 	  get_register_operand (((insn_word & 0x01C00000) >> 22) + REG_AR0, operand[0]);
    640 	  if (insn_word & PCRel)
    641 	    {
    642 	      sprintf (operand[1], "%d", (short) address);
    643 	      print_label = 1;
    644 	    }
    645 	  else
    646 	    get_register_operand (insn_word & 0x0000001F, operand[1]);
    647 	}
    648       /* Get the operands for the standard branches.  */
    649       else if (insn->tm->operands == 1)
    650 	{
    651 	  if (insn_word & PCRel)
    652 	    {
    653 	      address = (short) address;
    654 	      sprintf (operand[0], "%ld", address);
    655 	      print_label = 1;
    656 	    }
    657 	  else
    658 	    get_register_operand (insn_word & 0x0000001F, operand[0]);
    659 	}
    660     }
    661   info->fprintf_func (info->stream, "   %s %s%c%s", insn->tm->name,
    662 		      operand[0][0] ? operand[0] : "",
    663 		      operand[1][0] ? ',' : ' ',
    664 		      operand[1][0] ? operand[1] : "");
    665   /* Print destination of branch in relation to current symbol.  */
    666   if (print_label && info->symbols)
    667     {
    668       asymbol *sym = *info->symbols;
    669 
    670       if ((insn->tm->opcode_modifier == PCRel) && (insn_word & PCRel))
    671 	{
    672 	  address = (_pc + 1 + (short) address) - ((sym->section->vma + sym->value) / 4);
    673 	  /* Check for delayed instruction, if so adjust destination.  */
    674 	  if (insn_word & 0x00200000)
    675 	    address += 2;
    676 	}
    677       else
    678 	{
    679 	  address -= ((sym->section->vma + sym->value) / 4);
    680 	}
    681       if (address == 0)
    682 	info->fprintf_func (info->stream, " <%s>", sym->name);
    683       else
    684 	info->fprintf_func (info->stream, " <%s %c %lu>", sym->name,
    685 			    ((short) address < 0) ? '-' : '+',
    686 			    address);
    687     }
    688   return 1;
    689 }
    690 
    691 int
    692 print_insn_tic30 (bfd_vma pc, disassemble_info *info)
    693 {
    694   unsigned long insn_word;
    695   struct instruction insn = { 0, NULL, NULL };
    696   bfd_vma bufaddr = pc - info->buffer_vma;
    697 
    698   if (bufaddr + 3 >= info->buffer_length)
    699     return -1;
    700 
    701   /* Obtain the current instruction word from the buffer.  */
    702   insn_word = (((unsigned) *(info->buffer + bufaddr) << 24)
    703 	       | (*(info->buffer + bufaddr + 1) << 16)
    704 	       | (*(info->buffer + bufaddr + 2) << 8)
    705 	       | *(info->buffer + bufaddr + 3));
    706   _pc = pc / 4;
    707   /* Get the instruction referred to by the current instruction word
    708      and print it out based on its type.  */
    709   if (!get_tic30_instruction (insn_word, &insn))
    710     return -1;
    711   switch (GET_TYPE (insn_word))
    712     {
    713     case TWO_OPERAND_1:
    714     case TWO_OPERAND_2:
    715       if (!print_two_operand (info, insn_word, &insn))
    716 	return -1;
    717       break;
    718     case THREE_OPERAND:
    719       if (!print_three_operand (info, insn_word, &insn))
    720 	return -1;
    721       break;
    722     case PAR_STORE:
    723     case MUL_ADDS:
    724       if (!print_par_insn (info, insn_word, &insn))
    725 	return -1;
    726       break;
    727     case BRANCHES:
    728       if (!print_branch (info, insn_word, &insn))
    729 	return -1;
    730       break;
    731     }
    732   return 4;
    733 }
    734