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