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