Home | History | Annotate | Download | only in opcodes
      1 /* Disassemble D10V instructions.
      2    Copyright (C) 1996-2016 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/d10v.h"
     24 #include "dis-asm.h"
     25 
     26 /* The PC wraps at 18 bits, except for the segment number,
     27    so use this mask to keep the parts we want.  */
     28 #define PC_MASK	0x0303FFFF
     29 
     30 static void
     31 print_operand (struct d10v_operand *oper,
     32 	       unsigned long insn,
     33 	       struct d10v_opcode *op,
     34 	       bfd_vma memaddr,
     35 	       struct disassemble_info *info)
     36 {
     37   int num, shift;
     38 
     39   if (oper->flags == OPERAND_ATMINUS)
     40     {
     41       (*info->fprintf_func) (info->stream, "@-");
     42       return;
     43     }
     44   if (oper->flags == OPERAND_MINUS)
     45     {
     46       (*info->fprintf_func) (info->stream, "-");
     47       return;
     48     }
     49   if (oper->flags == OPERAND_PLUS)
     50     {
     51       (*info->fprintf_func) (info->stream, "+");
     52       return;
     53     }
     54   if (oper->flags == OPERAND_ATSIGN)
     55     {
     56       (*info->fprintf_func) (info->stream, "@");
     57       return;
     58     }
     59   if (oper->flags == OPERAND_ATPAR)
     60     {
     61       (*info->fprintf_func) (info->stream, "@(");
     62       return;
     63     }
     64 
     65   shift = oper->shift;
     66 
     67   /* The LONG_L format shifts registers over by 15.  */
     68   if (op->format == LONG_L && (oper->flags & OPERAND_REG))
     69     shift += 15;
     70 
     71   num = (insn >> shift) & (0x7FFFFFFF >> (31 - oper->bits));
     72 
     73   if (oper->flags & OPERAND_REG)
     74     {
     75       int i;
     76       int match = 0;
     77 
     78       num += (oper->flags
     79 	      & (OPERAND_GPR | OPERAND_FFLAG | OPERAND_CFLAG | OPERAND_CONTROL));
     80       if (oper->flags & (OPERAND_ACC0 | OPERAND_ACC1))
     81 	num += num ? OPERAND_ACC1 : OPERAND_ACC0;
     82       for (i = 0; i < d10v_reg_name_cnt (); i++)
     83 	{
     84 	  if (num == (d10v_predefined_registers[i].value & ~ OPERAND_SP))
     85 	    {
     86 	      if (d10v_predefined_registers[i].pname)
     87 		(*info->fprintf_func) (info->stream, "%s",
     88 				       d10v_predefined_registers[i].pname);
     89 	      else
     90 		(*info->fprintf_func) (info->stream, "%s",
     91 				       d10v_predefined_registers[i].name);
     92 	      match = 1;
     93 	      break;
     94 	    }
     95 	}
     96       if (match == 0)
     97 	{
     98 	  /* This would only get executed if a register was not in the
     99 	     register table.  */
    100 	  if (oper->flags & (OPERAND_ACC0 | OPERAND_ACC1))
    101 	    (*info->fprintf_func) (info->stream, "a");
    102 	  else if (oper->flags & OPERAND_CONTROL)
    103 	    (*info->fprintf_func) (info->stream, "cr");
    104 	  else if (oper->flags & OPERAND_REG)
    105 	    (*info->fprintf_func) (info->stream, "r");
    106 	  (*info->fprintf_func) (info->stream, "%d", num & REGISTER_MASK);
    107 	}
    108     }
    109   else
    110     {
    111       /* Addresses are right-shifted by 2.  */
    112       if (oper->flags & OPERAND_ADDR)
    113 	{
    114 	  long max;
    115 	  int neg = 0;
    116 
    117 	  max = (1 << (oper->bits - 1));
    118 	  if (num & max)
    119 	    {
    120 	      num = -num & ((1 << oper->bits) - 1);
    121 	      neg = 1;
    122 	    }
    123 	  num = num << 2;
    124 	  if (info->flags & INSN_HAS_RELOC)
    125 	    (*info->print_address_func) (num & PC_MASK, info);
    126 	  else
    127 	    {
    128 	      if (neg)
    129 		(*info->print_address_func) ((memaddr - num) & PC_MASK, info);
    130 	      else
    131 		(*info->print_address_func) ((memaddr + num) & PC_MASK, info);
    132 	    }
    133 	}
    134       else
    135 	{
    136 	  if (oper->flags & OPERAND_SIGNED)
    137 	    {
    138 	      int max = (1 << (oper->bits - 1));
    139 	      if (num & max)
    140 		{
    141 		  num = -num & ((1 << oper->bits) - 1);
    142 		  (*info->fprintf_func) (info->stream, "-");
    143 		}
    144 	    }
    145 	  (*info->fprintf_func) (info->stream, "0x%x", num);
    146 	}
    147     }
    148 }
    149 
    150 static void
    151 dis_long (unsigned long insn,
    152 	  bfd_vma memaddr,
    153 	  struct disassemble_info *info)
    154 {
    155   int i;
    156   struct d10v_opcode *op = (struct d10v_opcode *) d10v_opcodes;
    157   struct d10v_operand *oper;
    158   int need_paren = 0;
    159   int match = 0;
    160 
    161   while (op->name)
    162     {
    163       if ((op->format & LONG_OPCODE)
    164 	  && ((op->mask & insn) == (unsigned long) op->opcode))
    165 	{
    166 	  match = 1;
    167 	  (*info->fprintf_func) (info->stream, "%s\t", op->name);
    168 
    169 	  for (i = 0; op->operands[i]; i++)
    170 	    {
    171 	      oper = (struct d10v_operand *) &d10v_operands[op->operands[i]];
    172 	      if (oper->flags == OPERAND_ATPAR)
    173 		need_paren = 1;
    174 	      print_operand (oper, insn, op, memaddr, info);
    175 	      if (op->operands[i + 1] && oper->bits
    176 		  && d10v_operands[op->operands[i + 1]].flags != OPERAND_PLUS
    177 		  && d10v_operands[op->operands[i + 1]].flags != OPERAND_MINUS)
    178 		(*info->fprintf_func) (info->stream, ", ");
    179 	    }
    180 	  break;
    181 	}
    182       op++;
    183     }
    184 
    185   if (!match)
    186     (*info->fprintf_func) (info->stream, ".long\t0x%08lx", insn);
    187 
    188   if (need_paren)
    189     (*info->fprintf_func) (info->stream, ")");
    190 }
    191 
    192 static void
    193 dis_2_short (unsigned long insn,
    194 	     bfd_vma memaddr,
    195 	     struct disassemble_info *info,
    196 	     int order)
    197 {
    198   int i, j;
    199   unsigned int ins[2];
    200   struct d10v_opcode *op;
    201   int match, num_match = 0;
    202   struct d10v_operand *oper;
    203   int need_paren = 0;
    204 
    205   ins[0] = (insn & 0x3FFFFFFF) >> 15;
    206   ins[1] = insn & 0x00007FFF;
    207 
    208   for (j = 0; j < 2; j++)
    209     {
    210       op = (struct d10v_opcode *) d10v_opcodes;
    211       match = 0;
    212       while (op->name)
    213 	{
    214 	  if ((op->format & SHORT_OPCODE)
    215 	      && ((((unsigned int) op->mask) & ins[j])
    216 		  == (unsigned int) op->opcode))
    217 	    {
    218 	      (*info->fprintf_func) (info->stream, "%s\t", op->name);
    219 	      for (i = 0; op->operands[i]; i++)
    220 		{
    221 		  oper = (struct d10v_operand *) &d10v_operands[op->operands[i]];
    222 		  if (oper->flags == OPERAND_ATPAR)
    223 		    need_paren = 1;
    224 		  print_operand (oper, ins[j], op, memaddr, info);
    225 		  if (op->operands[i + 1] && oper->bits
    226 		      && d10v_operands[op->operands[i + 1]].flags != OPERAND_PLUS
    227 		      && d10v_operands[op->operands[i + 1]].flags != OPERAND_MINUS)
    228 		    (*info->fprintf_func) (info->stream, ", ");
    229 		}
    230 	      match = 1;
    231 	      num_match++;
    232 	      break;
    233 	    }
    234 	  op++;
    235 	}
    236       if (!match)
    237 	(*info->fprintf_func) (info->stream, "unknown");
    238 
    239       switch (order)
    240 	{
    241 	case 0:
    242 	  (*info->fprintf_func) (info->stream, "\t->\t");
    243 	  order = -1;
    244 	  break;
    245 	case 1:
    246 	  (*info->fprintf_func) (info->stream, "\t<-\t");
    247 	  order = -1;
    248 	  break;
    249 	case 2:
    250 	  (*info->fprintf_func) (info->stream, "\t||\t");
    251 	  order = -1;
    252 	  break;
    253 	default:
    254 	  break;
    255 	}
    256     }
    257 
    258   if (num_match == 0)
    259     (*info->fprintf_func) (info->stream, ".long\t0x%08lx", insn);
    260 
    261   if (need_paren)
    262     (*info->fprintf_func) (info->stream, ")");
    263 }
    264 
    265 int
    266 print_insn_d10v (bfd_vma memaddr, struct disassemble_info *info)
    267 {
    268   int status;
    269   bfd_byte buffer[4];
    270   unsigned long insn;
    271 
    272   status = (*info->read_memory_func) (memaddr, buffer, 4, info);
    273   if (status != 0)
    274     {
    275       (*info->memory_error_func) (status, memaddr, info);
    276       return -1;
    277     }
    278   insn = bfd_getb32 (buffer);
    279 
    280   status = insn & FM11;
    281   switch (status)
    282     {
    283     case 0:
    284       dis_2_short (insn, memaddr, info, 2);
    285       break;
    286     case FM01:
    287       dis_2_short (insn, memaddr, info, 0);
    288       break;
    289     case FM10:
    290       dis_2_short (insn, memaddr, info, 1);
    291       break;
    292     case FM11:
    293       dis_long (insn, memaddr, info);
    294       break;
    295     }
    296   return 4;
    297 }
    298