Home | History | Annotate | Download | only in opcodes
      1 /* Disassemble D30V instructions.
      2    Copyright (C) 1997-2014 Free Software Foundation, Inc.
      3 
      4    This file is part of the GNU opcodes library.
      5 
      6    This library is free software; you can redistribute it and/or modify
      7    it under the terms of the GNU General Public License as published by
      8    the Free Software Foundation; either version 3, or (at your option)
      9    any later version.
     10 
     11    It is distributed in the hope that it will be useful, but WITHOUT
     12    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
     13    or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
     14    License for more details.
     15 
     16    You should have received a copy of the GNU General Public License
     17    along with this program; if not, write to the Free Software
     18    Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
     19    MA 02110-1301, USA.  */
     20 
     21 #include "sysdep.h"
     22 #include <stdio.h>
     23 #include "opcode/d30v.h"
     24 #include "dis-asm.h"
     25 #include "opintl.h"
     26 
     27 #define PC_MASK 0xFFFFFFFF
     28 
     29 /* Return 0 if lookup fails,
     30    1 if found and only one form,
     31    2 if found and there are short and long forms.  */
     32 
     33 static int
     34 lookup_opcode (struct d30v_insn *insn, long num, int is_long)
     35 {
     36   int i = 0, op_index;
     37   struct d30v_format *f;
     38   struct d30v_opcode *op = (struct d30v_opcode *) d30v_opcode_table;
     39   int op1 = (num >> 25) & 0x7;
     40   int op2 = (num >> 20) & 0x1f;
     41   int mod = (num >> 18) & 0x3;
     42 
     43   /* Find the opcode.  */
     44   do
     45     {
     46       if ((op->op1 == op1) && (op->op2 == op2))
     47 	break;
     48       op++;
     49     }
     50   while (op->name);
     51 
     52   if (!op || !op->name)
     53     return 0;
     54 
     55   while (op->op1 == op1 && op->op2 == op2)
     56     {
     57       /* Scan through all the formats for the opcode.  */
     58       op_index = op->format[i++];
     59       do
     60 	{
     61 	  f = (struct d30v_format *) &d30v_format_table[op_index];
     62 	  while (f->form == op_index)
     63 	    {
     64 	      if ((!is_long || f->form >= LONG) && (f->modifier == mod))
     65 		{
     66 		  insn->form = f;
     67 		  break;
     68 		}
     69 	      f++;
     70 	    }
     71 	  if (insn->form)
     72 	    break;
     73 	}
     74       while ((op_index = op->format[i++]) != 0);
     75       if (insn->form)
     76 	break;
     77       op++;
     78       i = 0;
     79     }
     80   if (insn->form == NULL)
     81     return 0;
     82 
     83   insn->op = op;
     84   insn->ecc = (num >> 28) & 0x7;
     85   if (op->format[1])
     86     return 2;
     87   else
     88     return 1;
     89 }
     90 
     91 static int
     92 extract_value (long long num, struct d30v_operand *oper, int is_long)
     93 {
     94   int val;
     95   int shift = 12 - oper->position;
     96   int mask = (0xFFFFFFFF >> (32 - oper->bits));
     97 
     98   if (is_long)
     99     {
    100       if (oper->bits == 32)
    101 	/* Piece together 32-bit constant.  */
    102 	val = ((num & 0x3FFFF)
    103 	       | ((num & 0xFF00000) >> 2)
    104 	       | ((num & 0x3F00000000LL) >> 6));
    105       else
    106 	val = (num >> (32 + shift)) & mask;
    107     }
    108   else
    109     val = (num >> shift) & mask;
    110 
    111   if (oper->flags & OPERAND_SHIFT)
    112     val <<= 3;
    113 
    114   return val;
    115 }
    116 
    117 static void
    118 print_insn (struct disassemble_info *info,
    119 	    bfd_vma memaddr,
    120 	    long long num,
    121 	    struct d30v_insn *insn,
    122 	    int is_long,
    123 	    int show_ext)
    124 {
    125   int val, opnum, need_comma = 0;
    126   struct d30v_operand *oper;
    127   int i, match, opind = 0, need_paren = 0, found_control = 0;
    128 
    129   (*info->fprintf_func) (info->stream, "%s", insn->op->name);
    130 
    131   /* Check for CMP or CMPU.  */
    132   if (d30v_operand_table[insn->form->operands[0]].flags & OPERAND_NAME)
    133     {
    134       opind++;
    135       val =
    136 	extract_value (num,
    137 		       (struct d30v_operand *) &d30v_operand_table[insn->form->operands[0]],
    138 		       is_long);
    139       (*info->fprintf_func) (info->stream, "%s", d30v_cc_names[val]);
    140     }
    141 
    142   /* Add in ".s" or ".l".  */
    143   if (show_ext == 2)
    144     {
    145       if (is_long)
    146 	(*info->fprintf_func) (info->stream, ".l");
    147       else
    148 	(*info->fprintf_func) (info->stream, ".s");
    149     }
    150 
    151   if (insn->ecc)
    152     (*info->fprintf_func) (info->stream, "/%s", d30v_ecc_names[insn->ecc]);
    153 
    154   (*info->fprintf_func) (info->stream, "\t");
    155 
    156   while ((opnum = insn->form->operands[opind++]) != 0)
    157     {
    158       int bits;
    159 
    160       oper = (struct d30v_operand *) &d30v_operand_table[opnum];
    161       bits = oper->bits;
    162       if (oper->flags & OPERAND_SHIFT)
    163 	bits += 3;
    164 
    165       if (need_comma
    166 	  && oper->flags != OPERAND_PLUS
    167 	  && oper->flags != OPERAND_MINUS)
    168 	{
    169 	  need_comma = 0;
    170 	  (*info->fprintf_func) (info->stream, ", ");
    171 	}
    172 
    173       if (oper->flags == OPERAND_ATMINUS)
    174 	{
    175 	  (*info->fprintf_func) (info->stream, "@-");
    176 	  continue;
    177 	}
    178       if (oper->flags == OPERAND_MINUS)
    179 	{
    180 	  (*info->fprintf_func) (info->stream, "-");
    181 	  continue;
    182 	}
    183       if (oper->flags == OPERAND_PLUS)
    184 	{
    185 	  (*info->fprintf_func) (info->stream, "+");
    186 	  continue;
    187 	}
    188       if (oper->flags == OPERAND_ATSIGN)
    189 	{
    190 	  (*info->fprintf_func) (info->stream, "@");
    191 	  continue;
    192 	}
    193       if (oper->flags == OPERAND_ATPAR)
    194 	{
    195 	  (*info->fprintf_func) (info->stream, "@(");
    196 	  need_paren = 1;
    197 	  continue;
    198 	}
    199 
    200       if (oper->flags == OPERAND_SPECIAL)
    201 	continue;
    202 
    203       val = extract_value (num, oper, is_long);
    204 
    205       if (oper->flags & OPERAND_REG)
    206 	{
    207 	  match = 0;
    208 	  if (oper->flags & OPERAND_CONTROL)
    209 	    {
    210 	      struct d30v_operand *oper3 =
    211 		(struct d30v_operand *) &d30v_operand_table[insn->form->operands[2]];
    212 	      int id = extract_value (num, oper3, is_long);
    213 
    214 	      found_control = 1;
    215 	      switch (id)
    216 		{
    217 		case 0:
    218 		  val |= OPERAND_CONTROL;
    219 		  break;
    220 		case 1:
    221 		case 2:
    222 		  val = OPERAND_CONTROL + MAX_CONTROL_REG + id;
    223 		  break;
    224 		case 3:
    225 		  val |= OPERAND_FLAG;
    226 		  break;
    227 		default:
    228 		  fprintf (stderr, "illegal id (%d)\n", id);
    229 		}
    230 	    }
    231 	  else if (oper->flags & OPERAND_ACC)
    232 	    val |= OPERAND_ACC;
    233 	  else if (oper->flags & OPERAND_FLAG)
    234 	    val |= OPERAND_FLAG;
    235 	  for (i = 0; i < reg_name_cnt (); i++)
    236 	    {
    237 	      if (val == pre_defined_registers[i].value)
    238 		{
    239 		  if (pre_defined_registers[i].pname)
    240 		    (*info->fprintf_func)
    241 		      (info->stream, "%s", pre_defined_registers[i].pname);
    242 		  else
    243 		    (*info->fprintf_func)
    244 		      (info->stream, "%s", pre_defined_registers[i].name);
    245 		  match = 1;
    246 		  break;
    247 		}
    248 	    }
    249 	  if (match == 0)
    250 	    {
    251 	      /* This would only get executed if a register was not in
    252 		 the register table.  */
    253 	      (*info->fprintf_func)
    254 		(info->stream, _("<unknown register %d>"), val & 0x3F);
    255 	    }
    256 	}
    257       /* repeati has a relocation, but its first argument is a plain
    258 	 immediate.  OTOH instructions like djsri have a pc-relative
    259 	 delay target, but an absolute jump target.  Therefore, a test
    260 	 of insn->op->reloc_flag is not specific enough; we must test
    261 	 if the actual operand we are handling now is pc-relative.  */
    262       else if (oper->flags & OPERAND_PCREL)
    263 	{
    264 	  int neg = 0;
    265 
    266 	  /* IMM6S3 is unsigned.  */
    267 	  if (oper->flags & OPERAND_SIGNED || bits == 32)
    268 	    {
    269 	      long max;
    270 	      max = (1 << (bits - 1));
    271 	      if (val & max)
    272 		{
    273 		  if (bits == 32)
    274 		    val = -val;
    275 		  else
    276 		    val = -val & ((1 << bits) - 1);
    277 		  neg = 1;
    278 		}
    279 	    }
    280 	  if (neg)
    281 	    {
    282 	      (*info->fprintf_func) (info->stream, "-%x\t(", val);
    283 	      (*info->print_address_func) ((memaddr - val) & PC_MASK, info);
    284 	      (*info->fprintf_func) (info->stream, ")");
    285 	    }
    286 	  else
    287 	    {
    288 	      (*info->fprintf_func) (info->stream, "%x\t(", val);
    289 	      (*info->print_address_func) ((memaddr + val) & PC_MASK, info);
    290 	      (*info->fprintf_func) (info->stream, ")");
    291 	    }
    292 	}
    293       else if (insn->op->reloc_flag == RELOC_ABS)
    294 	{
    295 	  (*info->print_address_func) (val, info);
    296 	}
    297       else
    298 	{
    299 	  if (oper->flags & OPERAND_SIGNED)
    300 	    {
    301 	      int max = (1 << (bits - 1));
    302 
    303 	      if (val & max)
    304 		{
    305 		  val = -val;
    306 		  if (bits < 32)
    307 		    val &= ((1 << bits) - 1);
    308 		  (*info->fprintf_func) (info->stream, "-");
    309 		}
    310 	    }
    311 	  (*info->fprintf_func) (info->stream, "0x%x", val);
    312 	}
    313       /* If there is another operand, then write a comma and space.  */
    314       if (insn->form->operands[opind] && !(found_control && opind == 2))
    315 	need_comma = 1;
    316     }
    317   if (need_paren)
    318     (*info->fprintf_func) (info->stream, ")");
    319 }
    320 
    321 int
    322 print_insn_d30v (bfd_vma memaddr, struct disassemble_info *info)
    323 {
    324   int status, result;
    325   bfd_byte buffer[12];
    326   unsigned long in1, in2;
    327   struct d30v_insn insn;
    328   long long num;
    329 
    330   insn.form = NULL;
    331 
    332   info->bytes_per_line = 8;
    333   info->bytes_per_chunk = 4;
    334   info->display_endian = BFD_ENDIAN_BIG;
    335 
    336   status = (*info->read_memory_func) (memaddr, buffer, 4, info);
    337   if (status != 0)
    338     {
    339       (*info->memory_error_func) (status, memaddr, info);
    340       return -1;
    341     }
    342   in1 = bfd_getb32 (buffer);
    343 
    344   status = (*info->read_memory_func) (memaddr + 4, buffer, 4, info);
    345   if (status != 0)
    346     {
    347       info->bytes_per_line = 8;
    348       if (!(result = lookup_opcode (&insn, in1, 0)))
    349 	(*info->fprintf_func) (info->stream, ".long\t0x%lx", in1);
    350       else
    351 	print_insn (info, memaddr, (long long) in1, &insn, 0, result);
    352       return 4;
    353     }
    354   in2 = bfd_getb32 (buffer);
    355 
    356   if (in1 & in2 & FM01)
    357     {
    358       /* LONG instruction.  */
    359       if (!(result = lookup_opcode (&insn, in1, 1)))
    360 	{
    361 	  (*info->fprintf_func) (info->stream, ".long\t0x%lx,0x%lx", in1, in2);
    362 	  return 8;
    363 	}
    364       num = (long long) in1 << 32 | in2;
    365       print_insn (info, memaddr, num, &insn, 1, result);
    366     }
    367   else
    368     {
    369       num = in1;
    370       if (!(result = lookup_opcode (&insn, in1, 0)))
    371 	(*info->fprintf_func) (info->stream, ".long\t0x%lx", in1);
    372       else
    373 	print_insn (info, memaddr, num, &insn, 0, result);
    374 
    375       switch (((in1 >> 31) << 1) | (in2 >> 31))
    376 	{
    377 	case 0:
    378 	  (*info->fprintf_func) (info->stream, "\t||\t");
    379 	  break;
    380 	case 1:
    381 	  (*info->fprintf_func) (info->stream, "\t->\t");
    382 	  break;
    383 	case 2:
    384 	  (*info->fprintf_func) (info->stream, "\t<-\t");
    385 	default:
    386 	  break;
    387 	}
    388 
    389       insn.form = NULL;
    390       num = in2;
    391       if (!(result = lookup_opcode (&insn, in2, 0)))
    392 	(*info->fprintf_func) (info->stream, ".long\t0x%lx", in2);
    393       else
    394 	print_insn (info, memaddr, num, &insn, 0, result);
    395     }
    396   return 8;
    397 }
    398