Home | History | Annotate | Line # | Download | only in opcodes
d10v-dis.c revision 1.1.1.5.4.1
      1          1.1  christos /* Disassemble D10V instructions.
      2  1.1.1.5.4.1  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.5.4.1  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