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