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