Home | History | Annotate | Line # | Download | only in opcodes
arc-dis.c revision 1.9.2.1
      1      1.1  christos /* Instruction printing code for the ARC.
      2  1.9.2.1  perseant    Copyright (C) 1994-2022 Free Software Foundation, Inc.
      3      1.6  christos 
      4      1.6  christos    Contributed by Claudiu Zissulescu (claziss (at) synopsys.com)
      5      1.1  christos 
      6      1.1  christos    This file is part of libopcodes.
      7      1.1  christos 
      8      1.1  christos    This library is free software; you can redistribute it and/or modify
      9      1.1  christos    it under the terms of the GNU General Public License as published by
     10      1.1  christos    the Free Software Foundation; either version 3, or (at your option)
     11      1.1  christos    any later version.
     12      1.1  christos 
     13      1.1  christos    It is distributed in the hope that it will be useful, but WITHOUT
     14      1.1  christos    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
     15      1.1  christos    or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
     16      1.1  christos    License for more details.
     17      1.1  christos 
     18      1.1  christos    You should have received a copy of the GNU General Public License
     19      1.1  christos    along with this program; if not, write to the Free Software
     20      1.1  christos    Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
     21      1.1  christos    MA 02110-1301, USA.  */
     22      1.1  christos 
     23      1.1  christos #include "sysdep.h"
     24      1.6  christos #include <stdio.h>
     25      1.6  christos #include <assert.h>
     26      1.1  christos #include "dis-asm.h"
     27      1.1  christos #include "opcode/arc.h"
     28      1.6  christos #include "elf/arc.h"
     29      1.6  christos #include "arc-dis.h"
     30      1.6  christos #include "arc-ext.h"
     31      1.1  christos #include "elf-bfd.h"
     32      1.6  christos #include "libiberty.h"
     33      1.1  christos #include "opintl.h"
     34      1.1  christos 
     35      1.6  christos /* Structure used to iterate over, and extract the values for, operands of
     36      1.6  christos    an opcode.  */
     37      1.6  christos 
     38      1.6  christos struct arc_operand_iterator
     39      1.6  christos {
     40      1.7  christos   /* The complete instruction value to extract operands from.  */
     41      1.7  christos   unsigned long long insn;
     42      1.7  christos 
     43      1.7  christos   /* The LIMM if this is being tracked separately.  This field is only
     44      1.7  christos      valid if we find the LIMM operand in the operand list.  */
     45      1.7  christos   unsigned limm;
     46      1.7  christos 
     47      1.7  christos   /* The opcode this iterator is operating on.  */
     48      1.7  christos   const struct arc_opcode *opcode;
     49      1.7  christos 
     50      1.7  christos   /* The index into the opcodes operand index list.  */
     51      1.7  christos   const unsigned char *opidx;
     52      1.7  christos };
     53      1.7  christos 
     54      1.7  christos /* A private data used by ARC decoder.  */
     55      1.7  christos struct arc_disassemble_info
     56      1.7  christos {
     57      1.7  christos   /* The current disassembled arc opcode.  */
     58      1.7  christos   const struct arc_opcode *opcode;
     59      1.7  christos 
     60      1.7  christos   /* Instruction length w/o limm field.  */
     61      1.7  christos   unsigned insn_len;
     62      1.7  christos 
     63      1.7  christos   /* TRUE if we have limm.  */
     64  1.9.2.1  perseant   bool limm_p;
     65      1.6  christos 
     66      1.7  christos   /* LIMM value, if exists.  */
     67      1.7  christos   unsigned limm;
     68      1.6  christos 
     69      1.7  christos   /* Condition code, if exists.  */
     70      1.7  christos   unsigned condition_code;
     71      1.6  christos 
     72      1.7  christos   /* Writeback mode.  */
     73      1.7  christos   unsigned writeback_mode;
     74      1.6  christos 
     75      1.7  christos   /* Number of operands.  */
     76      1.7  christos   unsigned operands_count;
     77      1.6  christos 
     78      1.7  christos   struct arc_insn_operand operands[MAX_INSN_ARGS];
     79      1.6  christos };
     80      1.6  christos 
     81      1.6  christos /* Globals variables.  */
     82      1.6  christos 
     83      1.6  christos static const char * const regnames[64] =
     84      1.6  christos {
     85      1.6  christos   "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
     86      1.6  christos   "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
     87      1.6  christos   "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
     88      1.6  christos   "r24", "r25", "gp", "fp", "sp", "ilink", "r30", "blink",
     89      1.6  christos 
     90      1.6  christos   "r32", "r33", "r34", "r35", "r36", "r37", "r38", "r39",
     91      1.6  christos   "r40", "r41", "r42", "r43", "r44", "r45", "r46", "r47",
     92      1.6  christos   "r48", "r49", "r50", "r51", "r52", "r53", "r54", "r55",
     93      1.9  christos   "r56", "r57", "r58", "r59", "lp_count", "reserved", "LIMM", "pcl"
     94      1.6  christos };
     95      1.6  christos 
     96      1.6  christos static const char * const addrtypenames[ARC_NUM_ADDRTYPES] =
     97      1.6  christos {
     98      1.6  christos   "bd", "jid", "lbd", "mbd", "sd", "sm", "xa", "xd",
     99      1.6  christos   "cd", "cbd", "cjid", "clbd", "cm", "csd", "cxa", "cxd"
    100      1.6  christos };
    101      1.6  christos 
    102      1.6  christos static int addrtypenames_max = ARC_NUM_ADDRTYPES - 1;
    103      1.1  christos 
    104      1.6  christos static const char * const addrtypeunknown = "unknown";
    105      1.1  christos 
    106      1.6  christos /* This structure keeps track which instruction class(es)
    107      1.6  christos    should be ignored durring disassembling.  */
    108      1.1  christos 
    109      1.6  christos typedef struct skipclass
    110      1.1  christos {
    111      1.6  christos   insn_class_t     insn_class;
    112      1.6  christos   insn_subclass_t  subclass;
    113      1.6  christos   struct skipclass *nxt;
    114      1.6  christos } skipclass_t, *linkclass;
    115      1.6  christos 
    116      1.6  christos /* Intial classes of instructions to be consider first when
    117      1.6  christos    disassembling.  */
    118      1.6  christos static linkclass decodelist = NULL;
    119      1.6  christos 
    120      1.8  christos /* ISA mask value enforced via disassembler info options.  ARC_OPCODE_NONE
    121      1.8  christos    value means that no CPU is enforced.  */
    122      1.8  christos 
    123      1.8  christos static unsigned enforced_isa_mask = ARC_OPCODE_NONE;
    124      1.8  christos 
    125      1.8  christos /* True if we want to print using only hex numbers.  */
    126  1.9.2.1  perseant static bool print_hex = false;
    127      1.8  christos 
    128      1.6  christos /* Macros section.  */
    129      1.6  christos 
    130      1.6  christos #ifdef DEBUG
    131      1.6  christos # define pr_debug(fmt, args...) fprintf (stderr, fmt, ##args)
    132      1.6  christos #else
    133      1.6  christos # define pr_debug(fmt, args...)
    134      1.6  christos #endif
    135      1.6  christos 
    136      1.6  christos #define ARRANGE_ENDIAN(info, buf)					\
    137      1.6  christos   (info->endian == BFD_ENDIAN_LITTLE ? bfd_getm32 (bfd_getl32 (buf))	\
    138      1.6  christos    : bfd_getb32 (buf))
    139      1.1  christos 
    140      1.9  christos #define BITS(word,s,e)  (((word) >> (s)) & ((1ull << ((e) - (s)) << 1) - 1))
    141      1.7  christos #define OPCODE_32BIT_INSN(word)	(BITS ((word), 27, 31))
    142      1.1  christos 
    143      1.6  christos /* Functions implementation.  */
    144      1.1  christos 
    145      1.7  christos /* Initialize private data.  */
    146  1.9.2.1  perseant static bool
    147      1.7  christos init_arc_disasm_info (struct disassemble_info *info)
    148      1.1  christos {
    149      1.7  christos   struct arc_disassemble_info *arc_infop
    150      1.7  christos     = calloc (sizeof (*arc_infop), 1);
    151      1.7  christos 
    152      1.7  christos   if (arc_infop == NULL)
    153  1.9.2.1  perseant     return false;
    154      1.7  christos 
    155      1.7  christos   info->private_data = arc_infop;
    156  1.9.2.1  perseant   return true;
    157      1.1  christos }
    158      1.1  christos 
    159      1.6  christos /* Add a new element to the decode list.  */
    160      1.6  christos 
    161      1.6  christos static void
    162      1.6  christos add_to_decodelist (insn_class_t     insn_class,
    163      1.6  christos 		   insn_subclass_t  subclass)
    164      1.1  christos {
    165      1.6  christos   linkclass t = (linkclass) xmalloc (sizeof (skipclass_t));
    166      1.6  christos 
    167      1.6  christos   t->insn_class = insn_class;
    168      1.6  christos   t->subclass = subclass;
    169      1.6  christos   t->nxt = decodelist;
    170      1.6  christos   decodelist = t;
    171      1.1  christos }
    172      1.1  christos 
    173      1.6  christos /* Return TRUE if we need to skip the opcode from being
    174      1.6  christos    disassembled.  */
    175      1.6  christos 
    176  1.9.2.1  perseant static bool
    177      1.7  christos skip_this_opcode (const struct arc_opcode *opcode)
    178      1.1  christos {
    179      1.6  christos   linkclass t = decodelist;
    180      1.6  christos 
    181      1.6  christos   /* Check opcode for major 0x06, return if it is not in.  */
    182      1.7  christos   if (arc_opcode_len (opcode) == 4
    183      1.9  christos       && (OPCODE_32BIT_INSN (opcode->opcode) != 0x06
    184      1.9  christos 	  /* Can be an APEX extensions.  */
    185      1.9  christos 	  && OPCODE_32BIT_INSN (opcode->opcode) != 0x07))
    186  1.9.2.1  perseant     return false;
    187      1.6  christos 
    188      1.7  christos   /* or not a known truble class.  */
    189      1.7  christos   switch (opcode->insn_class)
    190      1.7  christos     {
    191      1.7  christos     case FLOAT:
    192      1.7  christos     case DSP:
    193      1.8  christos     case ARITH:
    194      1.9  christos     case MPY:
    195      1.7  christos       break;
    196      1.7  christos     default:
    197  1.9.2.1  perseant       return false;
    198      1.7  christos     }
    199      1.7  christos 
    200      1.7  christos   while (t != NULL)
    201      1.6  christos     {
    202      1.6  christos       if ((t->insn_class == opcode->insn_class)
    203      1.6  christos 	  && (t->subclass == opcode->subclass))
    204  1.9.2.1  perseant 	return false;
    205      1.6  christos       t = t->nxt;
    206      1.6  christos     }
    207      1.1  christos 
    208  1.9.2.1  perseant   return true;
    209      1.1  christos }
    210      1.1  christos 
    211      1.6  christos static bfd_vma
    212      1.6  christos bfd_getm32 (unsigned int data)
    213      1.1  christos {
    214      1.6  christos   bfd_vma value = 0;
    215      1.6  christos 
    216      1.6  christos   value = ((data & 0xff00) | (data & 0xff)) << 16;
    217      1.6  christos   value |= ((data & 0xff0000) | (data & 0xff000000)) >> 16;
    218      1.6  christos   return value;
    219      1.1  christos }
    220      1.1  christos 
    221  1.9.2.1  perseant static bool
    222      1.6  christos special_flag_p (const char *opname,
    223      1.6  christos 		const char *flgname)
    224      1.1  christos {
    225      1.6  christos   const struct arc_flag_special *flg_spec;
    226      1.6  christos   unsigned i, j, flgidx;
    227      1.1  christos 
    228      1.6  christos   for (i = 0; i < arc_num_flag_special; i++)
    229      1.1  christos     {
    230      1.6  christos       flg_spec = &arc_flag_special_cases[i];
    231      1.6  christos 
    232      1.6  christos       if (strcmp (opname, flg_spec->name))
    233      1.6  christos 	continue;
    234      1.6  christos 
    235      1.6  christos       /* Found potential special case instruction.  */
    236      1.6  christos       for (j=0;; ++j)
    237      1.6  christos 	{
    238      1.6  christos 	  flgidx = flg_spec->flags[j];
    239      1.6  christos 	  if (flgidx == 0)
    240      1.6  christos 	    break; /* End of the array.  */
    241      1.1  christos 
    242      1.6  christos 	  if (strcmp (flgname, arc_flag_operands[flgidx].name) == 0)
    243  1.9.2.1  perseant 	    return true;
    244      1.6  christos 	}
    245      1.1  christos     }
    246  1.9.2.1  perseant   return false;
    247      1.1  christos }
    248      1.1  christos 
    249      1.6  christos /* Find opcode from ARC_TABLE given the instruction described by INSN and
    250      1.6  christos    INSNLEN.  The ISA_MASK restricts the possible matches in ARC_TABLE.  */
    251      1.6  christos 
    252      1.6  christos static const struct arc_opcode *
    253      1.6  christos find_format_from_table (struct disassemble_info *info,
    254      1.6  christos 			const struct arc_opcode *arc_table,
    255      1.7  christos                         unsigned long long insn,
    256      1.6  christos 			unsigned int insn_len,
    257      1.6  christos                         unsigned isa_mask,
    258  1.9.2.1  perseant 			bool *has_limm,
    259  1.9.2.1  perseant 			bool overlaps)
    260      1.1  christos {
    261      1.6  christos   unsigned int i = 0;
    262      1.6  christos   const struct arc_opcode *opcode = NULL;
    263      1.7  christos   const struct arc_opcode *t_op = NULL;
    264      1.6  christos   const unsigned char *opidx;
    265      1.6  christos   const unsigned char *flgidx;
    266  1.9.2.1  perseant   bool warn_p = false;
    267      1.6  christos 
    268      1.6  christos   do
    269      1.6  christos     {
    270  1.9.2.1  perseant       bool invalid = false;
    271      1.6  christos 
    272      1.6  christos       opcode = &arc_table[i++];
    273      1.6  christos 
    274      1.7  christos       if (!(opcode->cpu & isa_mask))
    275      1.6  christos 	continue;
    276      1.6  christos 
    277      1.7  christos       if (arc_opcode_len (opcode) != (int) insn_len)
    278      1.6  christos 	continue;
    279      1.6  christos 
    280      1.7  christos       if ((insn & opcode->mask) != opcode->opcode)
    281      1.6  christos 	continue;
    282      1.6  christos 
    283  1.9.2.1  perseant       *has_limm = false;
    284      1.6  christos 
    285      1.6  christos       /* Possible candidate, check the operands.  */
    286      1.6  christos       for (opidx = opcode->operands; *opidx; opidx++)
    287      1.6  christos 	{
    288      1.7  christos 	  int value, limmind;
    289      1.6  christos 	  const struct arc_operand *operand = &arc_operands[*opidx];
    290      1.6  christos 
    291      1.6  christos 	  if (operand->flags & ARC_OPERAND_FAKE)
    292      1.6  christos 	    continue;
    293      1.6  christos 
    294      1.6  christos 	  if (operand->extract)
    295      1.7  christos 	    value = (*operand->extract) (insn, &invalid);
    296      1.6  christos 	  else
    297      1.9  christos 	    value = (insn >> operand->shift) & ((1ull << operand->bits) - 1);
    298      1.6  christos 
    299      1.6  christos 	  /* Check for LIMM indicator.  If it is there, then make sure
    300      1.6  christos 	     we pick the right format.  */
    301      1.7  christos 	  limmind = (isa_mask & ARC_OPCODE_ARCV2) ? 0x1E : 0x3E;
    302      1.6  christos 	  if (operand->flags & ARC_OPERAND_IR
    303      1.6  christos 	      && !(operand->flags & ARC_OPERAND_LIMM))
    304      1.1  christos 	    {
    305      1.6  christos 	      if ((value == 0x3E && insn_len == 4)
    306      1.7  christos 		  || (value == limmind && insn_len == 2))
    307      1.1  christos 		{
    308  1.9.2.1  perseant 		  invalid = true;
    309      1.6  christos 		  break;
    310      1.1  christos 		}
    311      1.1  christos 	    }
    312      1.1  christos 
    313      1.6  christos 	  if (operand->flags & ARC_OPERAND_LIMM
    314      1.6  christos 	      && !(operand->flags & ARC_OPERAND_DUPLICATE))
    315  1.9.2.1  perseant 	    *has_limm = true;
    316      1.6  christos 	}
    317      1.6  christos 
    318      1.6  christos       /* Check the flags.  */
    319      1.6  christos       for (flgidx = opcode->flags; *flgidx; flgidx++)
    320      1.6  christos 	{
    321      1.6  christos 	  /* Get a valid flag class.  */
    322      1.6  christos 	  const struct arc_flag_class *cl_flags = &arc_flag_classes[*flgidx];
    323      1.6  christos 	  const unsigned *flgopridx;
    324      1.6  christos 	  int foundA = 0, foundB = 0;
    325      1.6  christos 	  unsigned int value;
    326      1.6  christos 
    327      1.6  christos 	  /* Check first the extensions.  */
    328      1.6  christos 	  if (cl_flags->flag_class & F_CLASS_EXTEND)
    329      1.1  christos 	    {
    330      1.7  christos 	      value = (insn & 0x1F);
    331      1.6  christos 	      if (arcExtMap_condCodeName (value))
    332      1.6  christos 		continue;
    333      1.6  christos 	    }
    334      1.1  christos 
    335      1.7  christos 	  /* Check for the implicit flags.  */
    336      1.7  christos 	  if (cl_flags->flag_class & F_CLASS_IMPLICIT)
    337      1.7  christos 	    continue;
    338      1.7  christos 
    339      1.6  christos 	  for (flgopridx = cl_flags->flags; *flgopridx; ++flgopridx)
    340      1.1  christos 	    {
    341      1.6  christos 	      const struct arc_flag_operand *flg_operand =
    342      1.6  christos 		&arc_flag_operands[*flgopridx];
    343      1.1  christos 
    344      1.7  christos 	      value = (insn >> flg_operand->shift)
    345      1.6  christos 		& ((1 << flg_operand->bits) - 1);
    346      1.6  christos 	      if (value == flg_operand->code)
    347      1.6  christos 		foundA = 1;
    348      1.6  christos 	      if (value)
    349      1.6  christos 		foundB = 1;
    350      1.1  christos 	    }
    351      1.6  christos 
    352      1.6  christos 	  if (!foundA && foundB)
    353      1.1  christos 	    {
    354  1.9.2.1  perseant 	      invalid = true;
    355      1.6  christos 	      break;
    356      1.6  christos 	    }
    357      1.6  christos 	}
    358      1.6  christos 
    359      1.6  christos       if (invalid)
    360      1.6  christos 	continue;
    361      1.6  christos 
    362      1.6  christos       if (insn_len == 4
    363      1.7  christos 	  && overlaps)
    364      1.7  christos 	{
    365  1.9.2.1  perseant 	  warn_p = true;
    366      1.7  christos 	  t_op = opcode;
    367      1.7  christos 	  if (skip_this_opcode (opcode))
    368      1.7  christos 	    continue;
    369      1.7  christos 	}
    370      1.6  christos 
    371      1.6  christos       /* The instruction is valid.  */
    372      1.6  christos       return opcode;
    373      1.6  christos     }
    374      1.6  christos   while (opcode->mask);
    375      1.6  christos 
    376      1.7  christos   if (warn_p)
    377      1.6  christos     {
    378  1.9.2.1  perseant       info->fprintf_styled_func
    379  1.9.2.1  perseant 	(info->stream, dis_style_text,
    380  1.9.2.1  perseant 	 _("\nWarning: disassembly may be wrong due to "
    381  1.9.2.1  perseant 	   "guessed opcode class choice.\n"
    382  1.9.2.1  perseant 	   "Use -M<class[,class]> to select the correct "
    383  1.9.2.1  perseant 	   "opcode class(es).\n\t\t\t\t"));
    384      1.7  christos       return t_op;
    385      1.6  christos     }
    386      1.6  christos 
    387      1.6  christos   return NULL;
    388      1.6  christos }
    389      1.6  christos 
    390      1.6  christos /* Find opcode for INSN, trying various different sources.  The instruction
    391      1.6  christos    length in INSN_LEN will be updated if the instruction requires a LIMM
    392      1.7  christos    extension.
    393      1.6  christos 
    394      1.6  christos    A pointer to the opcode is placed into OPCODE_RESULT, and ITER is
    395      1.7  christos    initialised, ready to iterate over the operands of the found opcode.  If
    396      1.7  christos    the found opcode requires a LIMM then the LIMM value will be loaded into a
    397      1.7  christos    field of ITER.
    398      1.6  christos 
    399      1.6  christos    This function returns TRUE in almost all cases, FALSE is reserved to
    400      1.7  christos    indicate an error (failing to find an opcode is not an error) a returned
    401      1.7  christos    result of FALSE would indicate that the disassembler can't continue.
    402      1.7  christos 
    403      1.7  christos    If no matching opcode is found then the returned result will be TRUE, the
    404      1.7  christos    value placed into OPCODE_RESULT will be NULL, ITER will be undefined, and
    405      1.7  christos    INSN_LEN will be unchanged.
    406      1.7  christos 
    407      1.7  christos    If a matching opcode is found, then the returned result will be TRUE, the
    408      1.7  christos    opcode pointer is placed into OPCODE_RESULT, INSN_LEN will be increased by
    409      1.7  christos    4 if the instruction requires a LIMM, and the LIMM value will have been
    410      1.7  christos    loaded into a field of ITER.  Finally, ITER will have been initialised so
    411      1.7  christos    that calls to OPERAND_ITERATOR_NEXT will iterate over the opcode's
    412      1.7  christos    operands.  */
    413      1.6  christos 
    414  1.9.2.1  perseant static bool
    415      1.6  christos find_format (bfd_vma                       memaddr,
    416      1.7  christos 	     unsigned long long            insn,
    417      1.6  christos 	     unsigned int *                insn_len,
    418      1.6  christos              unsigned                      isa_mask,
    419      1.6  christos 	     struct disassemble_info *     info,
    420      1.6  christos              const struct arc_opcode **    opcode_result,
    421      1.6  christos              struct arc_operand_iterator * iter)
    422      1.6  christos {
    423      1.6  christos   const struct arc_opcode *opcode = NULL;
    424  1.9.2.1  perseant   bool needs_limm = false;
    425      1.7  christos   const extInstruction_t *einsn, *i;
    426      1.7  christos   unsigned limm = 0;
    427      1.7  christos   struct arc_disassemble_info *arc_infop = info->private_data;
    428      1.6  christos 
    429      1.6  christos   /* First, try the extension instructions.  */
    430      1.7  christos   if (*insn_len == 4)
    431      1.6  christos     {
    432      1.7  christos       einsn = arcExtMap_insn (OPCODE_32BIT_INSN (insn), insn);
    433      1.7  christos       for (i = einsn; (i != NULL) && (opcode == NULL); i = i->next)
    434      1.7  christos 	{
    435      1.7  christos 	  const char *errmsg = NULL;
    436      1.1  christos 
    437      1.7  christos 	  opcode = arcExtMap_genOpcode (i, isa_mask, &errmsg);
    438      1.7  christos 	  if (opcode == NULL)
    439      1.7  christos 	    {
    440  1.9.2.1  perseant 	      (*info->fprintf_styled_func)
    441  1.9.2.1  perseant 		(info->stream, dis_style_text,
    442  1.9.2.1  perseant 		 _("An error occurred while generating "
    443  1.9.2.1  perseant 		   "the extension instruction operations"));
    444      1.7  christos 	      *opcode_result = NULL;
    445  1.9.2.1  perseant 	      return false;
    446      1.7  christos 	    }
    447      1.7  christos 
    448      1.7  christos 	  opcode = find_format_from_table (info, opcode, insn, *insn_len,
    449  1.9.2.1  perseant 					   isa_mask, &needs_limm, false);
    450      1.6  christos 	}
    451      1.6  christos     }
    452      1.1  christos 
    453      1.6  christos   /* Then, try finding the first match in the opcode table.  */
    454      1.6  christos   if (opcode == NULL)
    455      1.6  christos     opcode = find_format_from_table (info, arc_opcodes, insn, *insn_len,
    456  1.9.2.1  perseant 				     isa_mask, &needs_limm, true);
    457      1.1  christos 
    458      1.9  christos   if (opcode != NULL && needs_limm)
    459      1.6  christos     {
    460      1.6  christos       bfd_byte buffer[4];
    461      1.6  christos       int status;
    462      1.1  christos 
    463      1.6  christos       status = (*info->read_memory_func) (memaddr + *insn_len, buffer,
    464      1.6  christos                                           4, info);
    465      1.6  christos       if (status != 0)
    466      1.6  christos         {
    467      1.6  christos           opcode = NULL;
    468      1.6  christos         }
    469      1.6  christos       else
    470      1.6  christos         {
    471      1.7  christos           limm = ARRANGE_ENDIAN (info, buffer);
    472      1.6  christos           *insn_len += 4;
    473      1.6  christos         }
    474      1.6  christos     }
    475      1.1  christos 
    476      1.7  christos   if (opcode != NULL)
    477      1.6  christos     {
    478      1.6  christos       iter->insn = insn;
    479      1.7  christos       iter->limm = limm;
    480      1.7  christos       iter->opcode = opcode;
    481      1.7  christos       iter->opidx = opcode->operands;
    482      1.6  christos     }
    483      1.1  christos 
    484      1.6  christos   *opcode_result = opcode;
    485      1.7  christos 
    486      1.7  christos   /* Update private data.  */
    487      1.7  christos   arc_infop->opcode = opcode;
    488      1.9  christos   arc_infop->limm = limm;
    489      1.7  christos   arc_infop->limm_p = needs_limm;
    490      1.7  christos 
    491  1.9.2.1  perseant   return true;
    492      1.1  christos }
    493      1.1  christos 
    494      1.1  christos static void
    495      1.6  christos print_flags (const struct arc_opcode *opcode,
    496      1.7  christos 	     unsigned long long *insn,
    497      1.6  christos 	     struct disassemble_info *info)
    498      1.1  christos {
    499      1.6  christos   const unsigned char *flgidx;
    500      1.6  christos   unsigned int value;
    501      1.7  christos   struct arc_disassemble_info *arc_infop = info->private_data;
    502      1.6  christos 
    503      1.6  christos   /* Now extract and print the flags.  */
    504      1.6  christos   for (flgidx = opcode->flags; *flgidx; flgidx++)
    505      1.1  christos     {
    506      1.6  christos       /* Get a valid flag class.  */
    507      1.6  christos       const struct arc_flag_class *cl_flags = &arc_flag_classes[*flgidx];
    508      1.6  christos       const unsigned *flgopridx;
    509      1.1  christos 
    510      1.6  christos       /* Check first the extensions.  */
    511      1.6  christos       if (cl_flags->flag_class & F_CLASS_EXTEND)
    512      1.1  christos 	{
    513      1.6  christos 	  const char *name;
    514      1.6  christos 	  value = (insn[0] & 0x1F);
    515      1.1  christos 
    516      1.6  christos 	  name = arcExtMap_condCodeName (value);
    517      1.6  christos 	  if (name)
    518      1.6  christos 	    {
    519  1.9.2.1  perseant 	      (*info->fprintf_styled_func) (info->stream, dis_style_mnemonic,
    520  1.9.2.1  perseant 					    ".%s", name);
    521      1.6  christos 	      continue;
    522      1.6  christos 	    }
    523      1.1  christos 	}
    524      1.6  christos 
    525      1.6  christos       for (flgopridx = cl_flags->flags; *flgopridx; ++flgopridx)
    526      1.1  christos 	{
    527      1.6  christos 	  const struct arc_flag_operand *flg_operand =
    528      1.6  christos 	    &arc_flag_operands[*flgopridx];
    529      1.6  christos 
    530      1.7  christos 	  /* Implicit flags are only used for the insn decoder.  */
    531      1.7  christos 	  if (cl_flags->flag_class & F_CLASS_IMPLICIT)
    532      1.7  christos 	    {
    533      1.7  christos 	      if (cl_flags->flag_class & F_CLASS_COND)
    534      1.7  christos 		arc_infop->condition_code = flg_operand->code;
    535      1.7  christos 	      else if (cl_flags->flag_class & F_CLASS_WB)
    536      1.7  christos 		arc_infop->writeback_mode = flg_operand->code;
    537      1.7  christos 	      else if (cl_flags->flag_class & F_CLASS_ZZ)
    538      1.7  christos 		info->data_size = flg_operand->code;
    539      1.7  christos 	      continue;
    540      1.7  christos 	    }
    541      1.7  christos 
    542      1.6  christos 	  if (!flg_operand->favail)
    543      1.6  christos 	    continue;
    544      1.6  christos 
    545      1.6  christos 	  value = (insn[0] >> flg_operand->shift)
    546      1.6  christos 	    & ((1 << flg_operand->bits) - 1);
    547      1.6  christos 	  if (value == flg_operand->code)
    548      1.6  christos 	    {
    549      1.6  christos 	       /* FIXME!: print correctly nt/t flag.  */
    550      1.6  christos 	      if (!special_flag_p (opcode->name, flg_operand->name))
    551  1.9.2.1  perseant 		(*info->fprintf_styled_func) (info->stream,
    552  1.9.2.1  perseant 					      dis_style_mnemonic, ".");
    553      1.6  christos 	      else if (info->insn_type == dis_dref)
    554      1.6  christos 		{
    555      1.6  christos 		  switch (flg_operand->name[0])
    556      1.6  christos 		    {
    557      1.6  christos 		    case 'b':
    558      1.6  christos 		      info->data_size = 1;
    559      1.6  christos 		      break;
    560      1.6  christos 		    case 'h':
    561      1.6  christos 		    case 'w':
    562      1.6  christos 		      info->data_size = 2;
    563      1.6  christos 		      break;
    564      1.6  christos 		    default:
    565      1.6  christos 		      info->data_size = 4;
    566      1.6  christos 		      break;
    567      1.6  christos 		    }
    568      1.6  christos 		}
    569      1.6  christos 	      if (flg_operand->name[0] == 'd'
    570      1.6  christos 		  && flg_operand->name[1] == 0)
    571      1.6  christos 		info->branch_delay_insns = 1;
    572      1.6  christos 
    573      1.6  christos 	      /* Check if it is a conditional flag.  */
    574      1.6  christos 	      if (cl_flags->flag_class & F_CLASS_COND)
    575      1.6  christos 		{
    576      1.6  christos 		  if (info->insn_type == dis_jsr)
    577      1.6  christos 		    info->insn_type = dis_condjsr;
    578      1.6  christos 		  else if (info->insn_type == dis_branch)
    579      1.6  christos 		    info->insn_type = dis_condbranch;
    580      1.7  christos 		  arc_infop->condition_code = flg_operand->code;
    581      1.6  christos 		}
    582      1.6  christos 
    583      1.7  christos 	      /* Check for the write back modes.  */
    584      1.7  christos 	      if (cl_flags->flag_class & F_CLASS_WB)
    585      1.7  christos 		arc_infop->writeback_mode = flg_operand->code;
    586      1.7  christos 
    587  1.9.2.1  perseant 	      (*info->fprintf_styled_func) (info->stream, dis_style_mnemonic,
    588  1.9.2.1  perseant 					    "%s", flg_operand->name);
    589      1.6  christos 	    }
    590      1.1  christos 	}
    591      1.1  christos     }
    592      1.1  christos }
    593      1.1  christos 
    594      1.6  christos static const char *
    595      1.6  christos get_auxreg (const struct arc_opcode *opcode,
    596      1.6  christos 	    int value,
    597      1.6  christos 	    unsigned isa_mask)
    598      1.6  christos {
    599      1.6  christos   const char *name;
    600      1.6  christos   unsigned int i;
    601      1.6  christos   const struct arc_aux_reg *auxr = &arc_aux_regs[0];
    602      1.6  christos 
    603      1.6  christos   if (opcode->insn_class != AUXREG)
    604      1.6  christos     return NULL;
    605      1.6  christos 
    606      1.6  christos   name = arcExtMap_auxRegName (value);
    607      1.6  christos   if (name)
    608      1.6  christos     return name;
    609      1.6  christos 
    610      1.6  christos   for (i = 0; i < arc_num_aux_regs; i++, auxr++)
    611      1.6  christos     {
    612      1.6  christos       if (!(auxr->cpu & isa_mask))
    613      1.6  christos 	continue;
    614      1.6  christos 
    615      1.6  christos       if (auxr->subclass != NONE)
    616      1.6  christos 	return NULL;
    617      1.1  christos 
    618      1.6  christos       if (auxr->address == value)
    619      1.6  christos 	return auxr->name;
    620      1.6  christos     }
    621      1.6  christos   return NULL;
    622      1.6  christos }
    623      1.6  christos 
    624      1.6  christos /* Convert a value representing an address type to a string used to refer to
    625      1.6  christos    the address type in assembly code.  */
    626      1.6  christos 
    627      1.6  christos static const char *
    628      1.6  christos get_addrtype (int value)
    629      1.1  christos {
    630      1.6  christos   if (value < 0 || value > addrtypenames_max)
    631      1.6  christos     return addrtypeunknown;
    632      1.6  christos 
    633      1.6  christos   return addrtypenames[value];
    634      1.6  christos }
    635      1.6  christos 
    636      1.6  christos /* Calculate the instruction length for an instruction starting with MSB
    637      1.6  christos    and LSB, the most and least significant byte.  The ISA_MASK is used to
    638      1.6  christos    filter the instructions considered to only those that are part of the
    639      1.6  christos    current architecture.
    640      1.6  christos 
    641      1.6  christos    The instruction lengths are calculated from the ARC_OPCODE table, and
    642      1.6  christos    cached for later use.  */
    643      1.6  christos 
    644      1.6  christos static unsigned int
    645      1.6  christos arc_insn_length (bfd_byte msb, bfd_byte lsb, struct disassemble_info *info)
    646      1.6  christos {
    647      1.6  christos   bfd_byte major_opcode = msb >> 3;
    648      1.1  christos 
    649      1.6  christos   switch (info->mach)
    650      1.1  christos     {
    651      1.6  christos     case bfd_mach_arc_arc700:
    652      1.6  christos       /* The nps400 extension set requires this special casing of the
    653      1.6  christos 	 instruction length calculation.  Right now this is not causing any
    654      1.6  christos 	 problems as none of the known extensions overlap in opcode space,
    655      1.6  christos 	 but, if they ever do then we might need to start carrying
    656      1.6  christos 	 information around in the elf about which extensions are in use.  */
    657      1.6  christos       if (major_opcode == 0xb)
    658      1.6  christos         {
    659      1.6  christos           bfd_byte minor_opcode = lsb & 0x1f;
    660      1.6  christos 
    661      1.7  christos 	  if (minor_opcode < 4)
    662      1.7  christos 	    return 6;
    663      1.7  christos 	  else if (minor_opcode == 0x10 || minor_opcode == 0x11)
    664      1.7  christos 	    return 8;
    665      1.6  christos         }
    666      1.7  christos       if (major_opcode == 0xa)
    667      1.7  christos         {
    668      1.7  christos           return 8;
    669      1.7  christos         }
    670      1.7  christos       /* Fall through.  */
    671      1.6  christos     case bfd_mach_arc_arc600:
    672      1.6  christos       return (major_opcode > 0xb) ? 2 : 4;
    673      1.6  christos       break;
    674      1.6  christos 
    675      1.6  christos     case bfd_mach_arc_arcv2:
    676      1.6  christos       return (major_opcode > 0x7) ? 2 : 4;
    677      1.6  christos       break;
    678      1.6  christos 
    679      1.6  christos     default:
    680      1.9  christos       return 0;
    681      1.6  christos     }
    682      1.6  christos }
    683      1.6  christos 
    684      1.6  christos /* Extract and return the value of OPERAND from the instruction whose value
    685      1.6  christos    is held in the array INSN.  */
    686      1.1  christos 
    687      1.6  christos static int
    688      1.7  christos extract_operand_value (const struct arc_operand *operand,
    689      1.7  christos 		       unsigned long long insn,
    690      1.7  christos 		       unsigned limm)
    691      1.6  christos {
    692      1.6  christos   int value;
    693      1.1  christos 
    694      1.6  christos   /* Read the limm operand, if required.  */
    695      1.6  christos   if (operand->flags & ARC_OPERAND_LIMM)
    696      1.6  christos     /* The second part of the instruction value will have been loaded as
    697      1.6  christos        part of the find_format call made earlier.  */
    698      1.7  christos     value = limm;
    699      1.6  christos   else
    700      1.6  christos     {
    701      1.6  christos       if (operand->extract)
    702  1.9.2.1  perseant 	value = (*operand->extract) (insn, (bool *) NULL);
    703      1.1  christos       else
    704      1.6  christos         {
    705      1.6  christos           if (operand->flags & ARC_OPERAND_ALIGNED32)
    706      1.6  christos             {
    707      1.7  christos               value = (insn >> operand->shift)
    708      1.6  christos                 & ((1 << (operand->bits - 2)) - 1);
    709      1.6  christos               value = value << 2;
    710      1.6  christos             }
    711      1.6  christos           else
    712      1.6  christos             {
    713      1.7  christos               value = (insn >> operand->shift) & ((1 << operand->bits) - 1);
    714      1.6  christos             }
    715      1.6  christos           if (operand->flags & ARC_OPERAND_SIGNED)
    716      1.6  christos             {
    717      1.6  christos               int signbit = 1 << (operand->bits - 1);
    718      1.6  christos               value = (value ^ signbit) - signbit;
    719      1.6  christos             }
    720      1.6  christos         }
    721      1.6  christos     }
    722      1.6  christos 
    723      1.6  christos   return value;
    724      1.6  christos }
    725      1.6  christos 
    726      1.6  christos /* Find the next operand, and the operands value from ITER.  Return TRUE if
    727      1.6  christos    there is another operand, otherwise return FALSE.  If there is an
    728      1.6  christos    operand returned then the operand is placed into OPERAND, and the value
    729      1.6  christos    into VALUE.  If there is no operand returned then OPERAND and VALUE are
    730      1.6  christos    unchanged.  */
    731      1.6  christos 
    732  1.9.2.1  perseant static bool
    733      1.6  christos operand_iterator_next (struct arc_operand_iterator *iter,
    734      1.6  christos                        const struct arc_operand **operand,
    735      1.6  christos                        int *value)
    736      1.6  christos {
    737      1.7  christos   if (*iter->opidx == 0)
    738      1.6  christos     {
    739      1.7  christos       *operand = NULL;
    740  1.9.2.1  perseant       return false;
    741      1.6  christos     }
    742      1.1  christos 
    743      1.7  christos   *operand = &arc_operands[*iter->opidx];
    744      1.7  christos   *value = extract_operand_value (*operand, iter->insn, iter->limm);
    745      1.7  christos   iter->opidx++;
    746      1.6  christos 
    747  1.9.2.1  perseant   return true;
    748      1.6  christos }
    749      1.6  christos 
    750      1.6  christos /* Helper for parsing the options.  */
    751      1.6  christos 
    752      1.6  christos static void
    753      1.7  christos parse_option (const char *option)
    754      1.6  christos {
    755      1.8  christos   if (disassembler_options_cmp (option, "dsp") == 0)
    756      1.6  christos     add_to_decodelist (DSP, NONE);
    757      1.6  christos 
    758      1.8  christos   else if (disassembler_options_cmp (option, "spfp") == 0)
    759      1.6  christos     add_to_decodelist (FLOAT, SPX);
    760      1.1  christos 
    761      1.8  christos   else if (disassembler_options_cmp (option, "dpfp") == 0)
    762      1.6  christos     add_to_decodelist (FLOAT, DPX);
    763      1.1  christos 
    764      1.8  christos   else if (disassembler_options_cmp (option, "quarkse_em") == 0)
    765      1.7  christos     {
    766      1.7  christos       add_to_decodelist (FLOAT, DPX);
    767      1.7  christos       add_to_decodelist (FLOAT, SPX);
    768      1.8  christos       add_to_decodelist (FLOAT, QUARKSE1);
    769      1.8  christos       add_to_decodelist (FLOAT, QUARKSE2);
    770      1.7  christos     }
    771      1.6  christos 
    772      1.8  christos   else if (disassembler_options_cmp (option, "fpuda") == 0)
    773      1.6  christos     add_to_decodelist (FLOAT, DPA);
    774      1.6  christos 
    775      1.9  christos   else if (disassembler_options_cmp (option, "nps400") == 0)
    776      1.9  christos     {
    777      1.9  christos       add_to_decodelist (ACL, NPS400);
    778      1.9  christos       add_to_decodelist (ARITH, NPS400);
    779      1.9  christos       add_to_decodelist (BITOP, NPS400);
    780      1.9  christos       add_to_decodelist (BMU, NPS400);
    781      1.9  christos       add_to_decodelist (CONTROL, NPS400);
    782      1.9  christos       add_to_decodelist (DMA, NPS400);
    783      1.9  christos       add_to_decodelist (DPI, NPS400);
    784      1.9  christos       add_to_decodelist (MEMORY, NPS400);
    785      1.9  christos       add_to_decodelist (MISC, NPS400);
    786      1.9  christos       add_to_decodelist (NET, NPS400);
    787      1.9  christos       add_to_decodelist (PMU, NPS400);
    788      1.9  christos       add_to_decodelist (PROTOCOL_DECODE, NPS400);
    789      1.9  christos       add_to_decodelist (ULTRAIP, NPS400);
    790      1.9  christos     }
    791      1.9  christos 
    792      1.8  christos   else if (disassembler_options_cmp (option, "fpus") == 0)
    793      1.1  christos     {
    794      1.6  christos       add_to_decodelist (FLOAT, SP);
    795      1.6  christos       add_to_decodelist (FLOAT, CVT);
    796      1.1  christos     }
    797      1.1  christos 
    798      1.8  christos   else if (disassembler_options_cmp (option, "fpud") == 0)
    799      1.6  christos     {
    800      1.6  christos       add_to_decodelist (FLOAT, DP);
    801      1.6  christos       add_to_decodelist (FLOAT, CVT);
    802      1.6  christos     }
    803  1.9.2.1  perseant   else if (startswith (option, "hex"))
    804  1.9.2.1  perseant     print_hex = true;
    805      1.6  christos   else
    806      1.8  christos     /* xgettext:c-format */
    807      1.8  christos     opcodes_error_handler (_("unrecognised disassembler option: %s"), option);
    808      1.8  christos }
    809      1.8  christos 
    810      1.8  christos #define ARC_CPU_TYPE_A6xx(NAME,EXTRA)			\
    811      1.8  christos   { #NAME, ARC_OPCODE_ARC600, "ARC600" }
    812      1.8  christos #define ARC_CPU_TYPE_A7xx(NAME,EXTRA)			\
    813      1.8  christos   { #NAME, ARC_OPCODE_ARC700, "ARC700" }
    814      1.8  christos #define ARC_CPU_TYPE_AV2EM(NAME,EXTRA)			\
    815      1.8  christos   { #NAME,  ARC_OPCODE_ARCv2EM, "ARC EM" }
    816      1.8  christos #define ARC_CPU_TYPE_AV2HS(NAME,EXTRA)			\
    817      1.8  christos   { #NAME,  ARC_OPCODE_ARCv2HS, "ARC HS" }
    818      1.8  christos #define ARC_CPU_TYPE_NONE				\
    819      1.8  christos   { 0, 0, 0 }
    820      1.8  christos 
    821      1.8  christos /* A table of CPU names and opcode sets.  */
    822      1.8  christos static const struct cpu_type
    823      1.8  christos {
    824      1.8  christos   const char *name;
    825      1.8  christos   unsigned flags;
    826      1.8  christos   const char *isa;
    827      1.8  christos }
    828      1.8  christos   cpu_types[] =
    829      1.8  christos {
    830      1.8  christos   #include "elf/arc-cpu.def"
    831      1.8  christos };
    832      1.8  christos 
    833      1.8  christos /* Helper for parsing the CPU options.  Accept any of the ARC architectures
    834      1.8  christos    values.  OPTION should be a value passed to cpu=.  */
    835      1.8  christos 
    836      1.8  christos static unsigned
    837      1.8  christos parse_cpu_option (const char *option)
    838      1.8  christos {
    839      1.8  christos   int i;
    840      1.8  christos 
    841      1.8  christos   for (i = 0; cpu_types[i].name; ++i)
    842      1.8  christos     {
    843      1.8  christos       if (!disassembler_options_cmp (cpu_types[i].name, option))
    844      1.8  christos 	{
    845      1.8  christos 	  return cpu_types[i].flags;
    846      1.8  christos 	}
    847      1.8  christos     }
    848      1.8  christos 
    849      1.8  christos   /* xgettext:c-format */
    850      1.8  christos   opcodes_error_handler (_("unrecognised disassembler CPU option: %s"), option);
    851      1.8  christos   return ARC_OPCODE_NONE;
    852      1.6  christos }
    853      1.1  christos 
    854      1.6  christos /* Go over the options list and parse it.  */
    855      1.1  christos 
    856      1.6  christos static void
    857      1.7  christos parse_disassembler_options (const char *options)
    858      1.6  christos {
    859      1.8  christos   const char *option;
    860      1.8  christos 
    861      1.6  christos   if (options == NULL)
    862      1.6  christos     return;
    863      1.6  christos 
    864      1.8  christos   /* Disassembler might be reused for difference CPU's, and cpu option set for
    865      1.8  christos      the first one shouldn't be applied to second (which might not have
    866      1.8  christos      explicit cpu in its options.  Therefore it is required to reset enforced
    867      1.8  christos      CPU when new options are being parsed.  */
    868      1.8  christos   enforced_isa_mask = ARC_OPCODE_NONE;
    869      1.8  christos 
    870      1.8  christos   FOR_EACH_DISASSEMBLER_OPTION (option, options)
    871      1.8  christos     {
    872      1.8  christos       /* A CPU option?  Cannot use STRING_COMMA_LEN because strncmp is also a
    873      1.8  christos 	 preprocessor macro.  */
    874      1.8  christos       if (strncmp (option, "cpu=", 4) == 0)
    875      1.8  christos 	/* Strip leading `cpu=`.  */
    876      1.8  christos 	enforced_isa_mask = parse_cpu_option (option + 4);
    877      1.8  christos       else
    878      1.8  christos 	parse_option (option);
    879      1.6  christos     }
    880      1.1  christos }
    881      1.1  christos 
    882      1.7  christos /* Return the instruction type for an instruction described by OPCODE.  */
    883      1.7  christos 
    884      1.7  christos static enum dis_insn_type
    885      1.7  christos arc_opcode_to_insn_type (const struct arc_opcode *opcode)
    886      1.7  christos {
    887      1.7  christos   enum dis_insn_type insn_type;
    888      1.7  christos 
    889      1.7  christos   switch (opcode->insn_class)
    890      1.7  christos     {
    891      1.7  christos     case BRANCH:
    892      1.7  christos     case BBIT0:
    893      1.7  christos     case BBIT1:
    894      1.7  christos     case BI:
    895      1.7  christos     case BIH:
    896      1.7  christos     case BRCC:
    897      1.7  christos     case EI:
    898      1.7  christos     case JLI:
    899      1.7  christos     case JUMP:
    900      1.7  christos     case LOOP:
    901      1.7  christos       if (!strncmp (opcode->name, "bl", 2)
    902      1.7  christos 	  || !strncmp (opcode->name, "jl", 2))
    903      1.7  christos 	{
    904      1.7  christos 	  if (opcode->subclass == COND)
    905      1.7  christos 	    insn_type = dis_condjsr;
    906      1.7  christos 	  else
    907      1.7  christos 	    insn_type = dis_jsr;
    908      1.7  christos 	}
    909      1.7  christos       else
    910      1.7  christos 	{
    911      1.7  christos 	  if (opcode->subclass == COND)
    912      1.7  christos 	    insn_type = dis_condbranch;
    913      1.7  christos 	  else
    914      1.7  christos 	    insn_type = dis_branch;
    915      1.7  christos 	}
    916      1.7  christos       break;
    917      1.7  christos     case LOAD:
    918      1.7  christos     case STORE:
    919      1.7  christos     case MEMORY:
    920      1.7  christos     case ENTER:
    921      1.7  christos     case PUSH:
    922      1.7  christos     case POP:
    923      1.7  christos       insn_type = dis_dref;
    924      1.7  christos       break;
    925      1.7  christos     case LEAVE:
    926      1.7  christos       insn_type = dis_branch;
    927      1.7  christos       break;
    928      1.7  christos     default:
    929      1.7  christos       insn_type = dis_nonbranch;
    930      1.7  christos       break;
    931      1.7  christos     }
    932      1.7  christos 
    933      1.7  christos   return insn_type;
    934      1.7  christos }
    935      1.7  christos 
    936      1.6  christos /* Disassemble ARC instructions.  */
    937      1.1  christos 
    938      1.1  christos static int
    939      1.6  christos print_insn_arc (bfd_vma memaddr,
    940      1.6  christos 		struct disassemble_info *info)
    941      1.1  christos {
    942      1.7  christos   bfd_byte buffer[8];
    943      1.7  christos   unsigned int highbyte, lowbyte;
    944      1.6  christos   int status;
    945      1.6  christos   unsigned int insn_len;
    946      1.7  christos   unsigned long long insn = 0;
    947      1.8  christos   unsigned isa_mask = ARC_OPCODE_NONE;
    948      1.6  christos   const struct arc_opcode *opcode;
    949  1.9.2.1  perseant   bool need_comma;
    950  1.9.2.1  perseant   bool open_braket;
    951      1.6  christos   int size;
    952      1.6  christos   const struct arc_operand *operand;
    953      1.8  christos   int value, vpcl;
    954      1.6  christos   struct arc_operand_iterator iter;
    955      1.7  christos   struct arc_disassemble_info *arc_infop;
    956  1.9.2.1  perseant   bool rpcl = false, rset = false;
    957      1.6  christos 
    958      1.6  christos   if (info->disassembler_options)
    959      1.6  christos     {
    960      1.6  christos       parse_disassembler_options (info->disassembler_options);
    961      1.6  christos 
    962      1.6  christos       /* Avoid repeated parsing of the options.  */
    963      1.6  christos       info->disassembler_options = NULL;
    964      1.6  christos     }
    965      1.6  christos 
    966      1.7  christos   if (info->private_data == NULL && !init_arc_disasm_info (info))
    967      1.7  christos     return -1;
    968      1.7  christos 
    969      1.6  christos   memset (&iter, 0, sizeof (iter));
    970      1.7  christos   highbyte  = ((info->endian == BFD_ENDIAN_LITTLE) ? 1 : 0);
    971      1.7  christos   lowbyte = ((info->endian == BFD_ENDIAN_LITTLE) ? 0 : 1);
    972      1.6  christos 
    973      1.8  christos   /* Figure out CPU type, unless it was enforced via disassembler options.  */
    974      1.8  christos   if (enforced_isa_mask == ARC_OPCODE_NONE)
    975      1.8  christos     {
    976      1.8  christos       Elf_Internal_Ehdr *header = NULL;
    977      1.8  christos 
    978      1.8  christos       if (info->section && info->section->owner)
    979      1.8  christos 	header = elf_elfheader (info->section->owner);
    980      1.6  christos 
    981      1.8  christos       switch (info->mach)
    982      1.8  christos 	{
    983      1.8  christos 	case bfd_mach_arc_arc700:
    984      1.8  christos 	  isa_mask = ARC_OPCODE_ARC700;
    985      1.8  christos 	  break;
    986      1.1  christos 
    987      1.8  christos 	case bfd_mach_arc_arc600:
    988      1.8  christos 	  isa_mask = ARC_OPCODE_ARC600;
    989      1.8  christos 	  break;
    990      1.1  christos 
    991      1.8  christos 	case bfd_mach_arc_arcv2:
    992      1.8  christos 	default:
    993      1.8  christos 	  isa_mask = ARC_OPCODE_ARCv2EM;
    994      1.8  christos 	  /* TODO: Perhaps remove definition of header since it is only used at
    995      1.8  christos 	     this location.  */
    996      1.8  christos 	  if (header != NULL
    997      1.8  christos 	      && (header->e_flags & EF_ARC_MACH_MSK) == EF_ARC_CPU_ARCV2HS)
    998      1.8  christos 	    isa_mask = ARC_OPCODE_ARCv2HS;
    999      1.8  christos 	  break;
   1000      1.1  christos 	}
   1001      1.8  christos     }
   1002      1.8  christos   else
   1003      1.8  christos     isa_mask = enforced_isa_mask;
   1004      1.8  christos 
   1005      1.8  christos   if (isa_mask == ARC_OPCODE_ARCv2HS)
   1006      1.8  christos     {
   1007      1.8  christos       /* FPU instructions are not extensions for HS.  */
   1008      1.8  christos       add_to_decodelist (FLOAT, SP);
   1009      1.8  christos       add_to_decodelist (FLOAT, DP);
   1010      1.8  christos       add_to_decodelist (FLOAT, CVT);
   1011      1.6  christos     }
   1012      1.1  christos 
   1013      1.6  christos   /* This variable may be set by the instruction decoder.  It suggests
   1014      1.6  christos      the number of bytes objdump should display on a single line.  If
   1015      1.6  christos      the instruction decoder sets this, it should always set it to
   1016      1.6  christos      the same value in order to get reasonable looking output.  */
   1017      1.6  christos   info->bytes_per_line  = 8;
   1018      1.6  christos 
   1019      1.6  christos   /* In the next lines, we set two info variables control the way
   1020      1.6  christos      objdump displays the raw data.  For example, if bytes_per_line is
   1021      1.6  christos      8 and bytes_per_chunk is 4, the output will look like this:
   1022      1.6  christos      00:   00000000 00000000
   1023      1.6  christos      with the chunks displayed according to "display_endian".  */
   1024      1.6  christos   if (info->section
   1025      1.6  christos       && !(info->section->flags & SEC_CODE))
   1026      1.6  christos     {
   1027      1.6  christos       /* This is not a CODE section.  */
   1028      1.6  christos       switch (info->section->size)
   1029      1.6  christos 	{
   1030      1.6  christos 	case 1:
   1031      1.6  christos 	case 2:
   1032      1.6  christos 	case 4:
   1033      1.6  christos 	  size = info->section->size;
   1034      1.1  christos 	  break;
   1035      1.1  christos 	default:
   1036      1.6  christos 	  size = (info->section->size & 0x01) ? 1 : 4;
   1037      1.1  christos 	  break;
   1038      1.1  christos 	}
   1039      1.6  christos       info->bytes_per_chunk = 1;
   1040      1.6  christos       info->display_endian = info->endian;
   1041      1.6  christos     }
   1042      1.6  christos   else
   1043      1.6  christos     {
   1044      1.6  christos       size = 2;
   1045      1.6  christos       info->bytes_per_chunk = 2;
   1046      1.6  christos       info->display_endian = info->endian;
   1047      1.6  christos     }
   1048      1.1  christos 
   1049      1.6  christos   /* Read the insn into a host word.  */
   1050      1.6  christos   status = (*info->read_memory_func) (memaddr, buffer, size, info);
   1051      1.8  christos 
   1052      1.6  christos   if (status != 0)
   1053      1.6  christos     {
   1054      1.6  christos       (*info->memory_error_func) (status, memaddr, info);
   1055      1.6  christos       return -1;
   1056      1.6  christos     }
   1057      1.1  christos 
   1058      1.6  christos   if (info->section
   1059      1.6  christos       && !(info->section->flags & SEC_CODE))
   1060      1.6  christos     {
   1061      1.6  christos       /* Data section.  */
   1062      1.6  christos       unsigned long data;
   1063      1.1  christos 
   1064      1.6  christos       data = bfd_get_bits (buffer, size * 8,
   1065      1.6  christos 			   info->display_endian == BFD_ENDIAN_BIG);
   1066      1.6  christos       switch (size)
   1067      1.1  christos 	{
   1068      1.6  christos 	case 1:
   1069  1.9.2.1  perseant 	  (*info->fprintf_styled_func) (info->stream,
   1070  1.9.2.1  perseant 					dis_style_assembler_directive,
   1071  1.9.2.1  perseant 					".byte");
   1072  1.9.2.1  perseant 	  (*info->fprintf_styled_func) (info->stream, dis_style_text, "\t");
   1073  1.9.2.1  perseant 	  (*info->fprintf_styled_func) (info->stream, dis_style_immediate,
   1074  1.9.2.1  perseant 					"0x%02lx", data);
   1075      1.1  christos 	  break;
   1076      1.6  christos 	case 2:
   1077  1.9.2.1  perseant 	  (*info->fprintf_styled_func) (info->stream,
   1078  1.9.2.1  perseant 					dis_style_assembler_directive,
   1079  1.9.2.1  perseant 					".short");
   1080  1.9.2.1  perseant 	  (*info->fprintf_styled_func) (info->stream, dis_style_text, "\t");
   1081  1.9.2.1  perseant 	  (*info->fprintf_styled_func) (info->stream, dis_style_immediate,
   1082  1.9.2.1  perseant 					"0x%04lx", data);
   1083      1.1  christos 	  break;
   1084      1.6  christos 	case 4:
   1085  1.9.2.1  perseant 	  (*info->fprintf_styled_func) (info->stream,
   1086  1.9.2.1  perseant 					dis_style_assembler_directive,
   1087  1.9.2.1  perseant 					".word");
   1088  1.9.2.1  perseant 	  (*info->fprintf_styled_func) (info->stream, dis_style_text, "\t");
   1089  1.9.2.1  perseant 	  (*info->fprintf_styled_func) (info->stream, dis_style_immediate,
   1090  1.9.2.1  perseant 					"0x%08lx", data);
   1091      1.1  christos 	  break;
   1092      1.6  christos 	default:
   1093      1.9  christos 	  return -1;
   1094      1.1  christos 	}
   1095      1.6  christos       return size;
   1096      1.6  christos     }
   1097      1.1  christos 
   1098      1.7  christos   insn_len = arc_insn_length (buffer[highbyte], buffer[lowbyte], info);
   1099      1.6  christos   pr_debug ("instruction length = %d bytes\n", insn_len);
   1100      1.9  christos   if (insn_len == 0)
   1101      1.9  christos     return -1;
   1102      1.9  christos 
   1103      1.7  christos   arc_infop = info->private_data;
   1104      1.7  christos   arc_infop->insn_len = insn_len;
   1105      1.1  christos 
   1106      1.6  christos   switch (insn_len)
   1107      1.6  christos     {
   1108      1.6  christos     case 2:
   1109      1.7  christos       insn = (buffer[highbyte] << 8) | buffer[lowbyte];
   1110      1.1  christos       break;
   1111      1.1  christos 
   1112      1.6  christos     case 4:
   1113      1.7  christos       {
   1114      1.7  christos 	/* This is a long instruction: Read the remaning 2 bytes.  */
   1115      1.7  christos 	status = (*info->read_memory_func) (memaddr + 2, &buffer[2], 2, info);
   1116      1.7  christos 	if (status != 0)
   1117      1.7  christos 	  {
   1118      1.7  christos 	    (*info->memory_error_func) (status, memaddr + 2, info);
   1119      1.7  christos 	    return -1;
   1120      1.7  christos 	  }
   1121      1.7  christos 	insn = (unsigned long long) ARRANGE_ENDIAN (info, buffer);
   1122      1.7  christos       }
   1123      1.7  christos       break;
   1124      1.7  christos 
   1125      1.7  christos     case 6:
   1126      1.7  christos       {
   1127      1.7  christos 	status = (*info->read_memory_func) (memaddr + 2, &buffer[2], 4, info);
   1128      1.7  christos 	if (status != 0)
   1129      1.7  christos 	  {
   1130      1.7  christos 	    (*info->memory_error_func) (status, memaddr + 2, info);
   1131      1.7  christos 	    return -1;
   1132      1.7  christos 	  }
   1133      1.7  christos 	insn = (unsigned long long) ARRANGE_ENDIAN (info, &buffer[2]);
   1134      1.7  christos 	insn |= ((unsigned long long) buffer[highbyte] << 40)
   1135      1.7  christos 	  | ((unsigned long long) buffer[lowbyte] << 32);
   1136      1.7  christos       }
   1137      1.7  christos       break;
   1138      1.7  christos 
   1139      1.7  christos     case 8:
   1140      1.7  christos       {
   1141      1.7  christos 	status = (*info->read_memory_func) (memaddr + 2, &buffer[2], 6, info);
   1142      1.7  christos 	if (status != 0)
   1143      1.7  christos 	  {
   1144      1.7  christos 	    (*info->memory_error_func) (status, memaddr + 2, info);
   1145      1.7  christos 	    return -1;
   1146      1.7  christos 	  }
   1147      1.7  christos 	insn =
   1148      1.7  christos 	  ((((unsigned long long) ARRANGE_ENDIAN (info, buffer)) << 32)
   1149      1.7  christos 	   | ((unsigned long long) ARRANGE_ENDIAN (info, &buffer[4])));
   1150      1.7  christos       }
   1151      1.1  christos       break;
   1152      1.7  christos 
   1153      1.7  christos     default:
   1154      1.7  christos       /* There is no instruction whose length is not 2, 4, 6, or 8.  */
   1155      1.9  christos       return -1;
   1156      1.1  christos     }
   1157      1.1  christos 
   1158      1.7  christos   pr_debug ("instruction value = %llx\n", insn);
   1159      1.7  christos 
   1160      1.6  christos   /* Set some defaults for the insn info.  */
   1161      1.6  christos   info->insn_info_valid    = 1;
   1162      1.6  christos   info->branch_delay_insns = 0;
   1163      1.7  christos   info->data_size	   = 4;
   1164      1.6  christos   info->insn_type	   = dis_nonbranch;
   1165      1.6  christos   info->target		   = 0;
   1166      1.6  christos   info->target2		   = 0;
   1167      1.6  christos 
   1168      1.6  christos   /* FIXME to be moved in dissasemble_init_for_target.  */
   1169  1.9.2.1  perseant   info->disassembler_needs_relocs = true;
   1170      1.6  christos 
   1171      1.6  christos   /* Find the first match in the opcode table.  */
   1172      1.6  christos   if (!find_format (memaddr, insn, &insn_len, isa_mask, info, &opcode, &iter))
   1173      1.6  christos     return -1;
   1174      1.6  christos 
   1175      1.6  christos   if (!opcode)
   1176      1.6  christos     {
   1177      1.7  christos       switch (insn_len)
   1178      1.7  christos 	{
   1179      1.7  christos 	case 2:
   1180  1.9.2.1  perseant 	  (*info->fprintf_styled_func) (info->stream,
   1181  1.9.2.1  perseant 					dis_style_assembler_directive,
   1182  1.9.2.1  perseant 					".short");
   1183  1.9.2.1  perseant 	  (*info->fprintf_styled_func) (info->stream, dis_style_text, "\t");
   1184  1.9.2.1  perseant 	  (*info->fprintf_styled_func) (info->stream, dis_style_immediate,
   1185  1.9.2.1  perseant 					"0x%04llx", insn & 0xffff);
   1186      1.7  christos 	  break;
   1187      1.9  christos 
   1188      1.7  christos 	case 4:
   1189  1.9.2.1  perseant 	  (*info->fprintf_styled_func) (info->stream,
   1190  1.9.2.1  perseant 					dis_style_assembler_directive,
   1191  1.9.2.1  perseant 					".word");
   1192  1.9.2.1  perseant 	  (*info->fprintf_styled_func) (info->stream, dis_style_text, "\t");
   1193  1.9.2.1  perseant 	  (*info->fprintf_styled_func) (info->stream, dis_style_immediate,
   1194  1.9.2.1  perseant 					"0x%08llx", insn & 0xffffffff);
   1195      1.7  christos 	  break;
   1196      1.9  christos 
   1197      1.7  christos 	case 6:
   1198  1.9.2.1  perseant 	  (*info->fprintf_styled_func) (info->stream,
   1199  1.9.2.1  perseant 					dis_style_assembler_directive,
   1200  1.9.2.1  perseant 					".long");
   1201  1.9.2.1  perseant 	  (*info->fprintf_styled_func) (info->stream, dis_style_text, "\t");
   1202  1.9.2.1  perseant 	  (*info->fprintf_styled_func) (info->stream, dis_style_immediate,
   1203  1.9.2.1  perseant 				       "0x%08llx", insn & 0xffffffff);
   1204  1.9.2.1  perseant 	  (*info->fprintf_styled_func) (info->stream, dis_style_text, " ");
   1205  1.9.2.1  perseant 	  (*info->fprintf_styled_func) (info->stream, dis_style_immediate,
   1206  1.9.2.1  perseant 					"0x%04llx", (insn >> 32) & 0xffff);
   1207      1.7  christos 	  break;
   1208      1.9  christos 
   1209      1.7  christos 	case 8:
   1210  1.9.2.1  perseant 	  (*info->fprintf_styled_func) (info->stream,
   1211  1.9.2.1  perseant 					dis_style_assembler_directive,
   1212  1.9.2.1  perseant 					".long");
   1213  1.9.2.1  perseant 	  (*info->fprintf_styled_func) (info->stream, dis_style_text, "\t");
   1214  1.9.2.1  perseant 	  (*info->fprintf_styled_func) (info->stream, dis_style_immediate,
   1215  1.9.2.1  perseant 					"0x%08llx", insn & 0xffffffff);
   1216  1.9.2.1  perseant 	  (*info->fprintf_styled_func) (info->stream, dis_style_text, " ");
   1217  1.9.2.1  perseant 	  (*info->fprintf_styled_func) (info->stream, dis_style_immediate,
   1218  1.9.2.1  perseant 					"0x%08llx", (insn >> 32));
   1219      1.7  christos 	  break;
   1220      1.9  christos 
   1221      1.7  christos 	default:
   1222      1.9  christos 	  return -1;
   1223      1.7  christos 	}
   1224      1.6  christos 
   1225      1.6  christos       info->insn_type = dis_noninsn;
   1226      1.6  christos       return insn_len;
   1227      1.6  christos     }
   1228      1.6  christos 
   1229      1.6  christos   /* Print the mnemonic.  */
   1230  1.9.2.1  perseant   (*info->fprintf_styled_func) (info->stream, dis_style_mnemonic,
   1231  1.9.2.1  perseant 				"%s", opcode->name);
   1232      1.6  christos 
   1233      1.6  christos   /* Preselect the insn class.  */
   1234      1.7  christos   info->insn_type = arc_opcode_to_insn_type (opcode);
   1235      1.6  christos 
   1236      1.7  christos   pr_debug ("%s: 0x%08llx\n", opcode->name, opcode->opcode);
   1237      1.1  christos 
   1238      1.7  christos   print_flags (opcode, &insn, info);
   1239      1.6  christos 
   1240      1.6  christos   if (opcode->operands[0] != 0)
   1241  1.9.2.1  perseant     (*info->fprintf_styled_func) (info->stream, dis_style_text, "\t");
   1242      1.1  christos 
   1243  1.9.2.1  perseant   need_comma = false;
   1244  1.9.2.1  perseant   open_braket = false;
   1245      1.7  christos   arc_infop->operands_count = 0;
   1246      1.1  christos 
   1247      1.6  christos   /* Now extract and print the operands.  */
   1248      1.6  christos   operand = NULL;
   1249      1.8  christos   vpcl = 0;
   1250      1.6  christos   while (operand_iterator_next (&iter, &operand, &value))
   1251      1.6  christos     {
   1252      1.6  christos       if (open_braket && (operand->flags & ARC_OPERAND_BRAKET))
   1253      1.1  christos 	{
   1254  1.9.2.1  perseant 	  (*info->fprintf_styled_func) (info->stream, dis_style_text, "]");
   1255  1.9.2.1  perseant 	  open_braket = false;
   1256      1.6  christos 	  continue;
   1257      1.1  christos 	}
   1258      1.1  christos 
   1259      1.6  christos       /* Only take input from real operands.  */
   1260      1.6  christos       if (ARC_OPERAND_IS_FAKE (operand))
   1261      1.6  christos 	continue;
   1262      1.1  christos 
   1263      1.6  christos       if ((operand->flags & ARC_OPERAND_IGNORE)
   1264      1.6  christos 	  && (operand->flags & ARC_OPERAND_IR)
   1265      1.7  christos 	  && value == -1)
   1266      1.6  christos 	continue;
   1267      1.1  christos 
   1268      1.6  christos       if (operand->flags & ARC_OPERAND_COLON)
   1269      1.7  christos 	{
   1270  1.9.2.1  perseant 	  (*info->fprintf_styled_func) (info->stream, dis_style_text, ":");
   1271      1.7  christos 	  continue;
   1272      1.7  christos 	}
   1273      1.1  christos 
   1274      1.6  christos       if (need_comma)
   1275  1.9.2.1  perseant 	(*info->fprintf_styled_func) (info->stream, dis_style_text,",");
   1276      1.1  christos 
   1277      1.6  christos       if (!open_braket && (operand->flags & ARC_OPERAND_BRAKET))
   1278      1.1  christos 	{
   1279  1.9.2.1  perseant 	  (*info->fprintf_styled_func) (info->stream, dis_style_text, "[");
   1280  1.9.2.1  perseant 	  open_braket = true;
   1281  1.9.2.1  perseant 	  need_comma = false;
   1282      1.6  christos 	  continue;
   1283      1.1  christos 	}
   1284      1.6  christos 
   1285  1.9.2.1  perseant       need_comma = true;
   1286      1.6  christos 
   1287      1.8  christos       if (operand->flags & ARC_OPERAND_PCREL)
   1288      1.8  christos 	{
   1289  1.9.2.1  perseant 	  rpcl = true;
   1290      1.8  christos 	  vpcl = value;
   1291  1.9.2.1  perseant 	  rset = true;
   1292      1.8  christos 
   1293      1.8  christos 	  info->target = (bfd_vma) (memaddr & ~3) + value;
   1294      1.8  christos 	}
   1295      1.8  christos       else if (!(operand->flags & ARC_OPERAND_IR))
   1296      1.8  christos 	{
   1297      1.8  christos 	  vpcl = value;
   1298  1.9.2.1  perseant 	  rset = true;
   1299      1.8  christos 	}
   1300      1.8  christos 
   1301      1.6  christos       /* Print the operand as directed by the flags.  */
   1302      1.6  christos       if (operand->flags & ARC_OPERAND_IR)
   1303      1.1  christos 	{
   1304      1.6  christos 	  const char *rname;
   1305      1.6  christos 
   1306      1.6  christos 	  assert (value >=0 && value < 64);
   1307      1.6  christos 	  rname = arcExtMap_coreRegName (value);
   1308      1.6  christos 	  if (!rname)
   1309      1.6  christos 	    rname = regnames[value];
   1310  1.9.2.1  perseant 	  (*info->fprintf_styled_func) (info->stream, dis_style_register,
   1311  1.9.2.1  perseant 					"%s", rname);
   1312      1.9  christos 
   1313      1.9  christos 	  /* Check if we have a double register to print.  */
   1314      1.6  christos 	  if (operand->flags & ARC_OPERAND_TRUNCATE)
   1315      1.1  christos 	    {
   1316      1.9  christos 	      if ((value & 0x01) == 0)
   1317      1.9  christos 		{
   1318      1.9  christos 		  rname = arcExtMap_coreRegName (value + 1);
   1319      1.9  christos 		  if (!rname)
   1320      1.9  christos 		    rname = regnames[value + 1];
   1321      1.9  christos 		}
   1322      1.9  christos 	      else
   1323      1.9  christos 		rname = _("\nWarning: illegal use of double register "
   1324      1.9  christos 			  "pair.\n");
   1325  1.9.2.1  perseant 	      (*info->fprintf_styled_func) (info->stream, dis_style_register,
   1326  1.9.2.1  perseant 					    "%s", rname);
   1327      1.1  christos 	    }
   1328      1.8  christos 	  if (value == 63)
   1329  1.9.2.1  perseant 	    rpcl = true;
   1330      1.8  christos 	  else
   1331  1.9.2.1  perseant 	    rpcl = false;
   1332      1.6  christos 	}
   1333      1.6  christos       else if (operand->flags & ARC_OPERAND_LIMM)
   1334      1.6  christos 	{
   1335      1.6  christos 	  const char *rname = get_auxreg (opcode, value, isa_mask);
   1336      1.6  christos 
   1337      1.6  christos 	  if (rname && open_braket)
   1338  1.9.2.1  perseant 	    (*info->fprintf_styled_func) (info->stream, dis_style_register,
   1339  1.9.2.1  perseant 					  "%s", rname);
   1340      1.1  christos 	  else
   1341      1.6  christos 	    {
   1342  1.9.2.1  perseant 	      (*info->fprintf_styled_func) (info->stream, dis_style_immediate,
   1343  1.9.2.1  perseant 					    "%#x", value);
   1344      1.6  christos 	      if (info->insn_type == dis_branch
   1345      1.6  christos 		  || info->insn_type == dis_jsr)
   1346      1.6  christos 		info->target = (bfd_vma) value;
   1347      1.6  christos 	    }
   1348      1.1  christos 	}
   1349      1.6  christos       else if (operand->flags & ARC_OPERAND_SIGNED)
   1350      1.1  christos 	{
   1351      1.6  christos 	  const char *rname = get_auxreg (opcode, value, isa_mask);
   1352      1.6  christos 	  if (rname && open_braket)
   1353  1.9.2.1  perseant 	    (*info->fprintf_styled_func) (info->stream, dis_style_register,
   1354  1.9.2.1  perseant 					  "%s", rname);
   1355      1.6  christos 	  else
   1356      1.8  christos 	    {
   1357      1.8  christos 	      if (print_hex)
   1358  1.9.2.1  perseant 		(*info->fprintf_styled_func) (info->stream, dis_style_immediate,
   1359  1.9.2.1  perseant 					      "%#x", value);
   1360      1.8  christos 	      else
   1361  1.9.2.1  perseant 		(*info->fprintf_styled_func) (info->stream, dis_style_immediate,
   1362  1.9.2.1  perseant 					      "%d", value);
   1363      1.8  christos 	    }
   1364      1.1  christos 	}
   1365      1.6  christos       else if (operand->flags & ARC_OPERAND_ADDRTYPE)
   1366      1.7  christos 	{
   1367      1.7  christos 	  const char *addrtype = get_addrtype (value);
   1368  1.9.2.1  perseant 	  (*info->fprintf_styled_func) (info->stream, dis_style_address,
   1369  1.9.2.1  perseant 					"%s", addrtype);
   1370      1.7  christos 	  /* A colon follow an address type.  */
   1371  1.9.2.1  perseant 	  need_comma = false;
   1372      1.7  christos 	}
   1373      1.1  christos       else
   1374      1.1  christos 	{
   1375      1.6  christos 	  if (operand->flags & ARC_OPERAND_TRUNCATE
   1376      1.6  christos 	      && !(operand->flags & ARC_OPERAND_ALIGNED32)
   1377      1.6  christos 	      && !(operand->flags & ARC_OPERAND_ALIGNED16)
   1378      1.8  christos 	      && value >= 0 && value <= 14)
   1379      1.8  christos 	    {
   1380      1.8  christos 	      /* Leave/Enter mnemonics.  */
   1381      1.8  christos 	      switch (value)
   1382      1.8  christos 		{
   1383      1.8  christos 		case 0:
   1384  1.9.2.1  perseant 		  need_comma = false;
   1385      1.8  christos 		  break;
   1386      1.8  christos 		case 1:
   1387  1.9.2.1  perseant 		  (*info->fprintf_styled_func) (info->stream,
   1388  1.9.2.1  perseant 						dis_style_register, "r13");
   1389      1.8  christos 		  break;
   1390      1.8  christos 		default:
   1391  1.9.2.1  perseant 		  (*info->fprintf_styled_func) (info->stream,
   1392  1.9.2.1  perseant 						dis_style_register, "r13");
   1393  1.9.2.1  perseant 		  (*info->fprintf_styled_func) (info->stream,
   1394  1.9.2.1  perseant 						dis_style_text, "-");
   1395  1.9.2.1  perseant 		  (*info->fprintf_styled_func) (info->stream,
   1396  1.9.2.1  perseant 						dis_style_register, "%s",
   1397  1.9.2.1  perseant 						regnames[13 + value - 1]);
   1398      1.8  christos 		  break;
   1399      1.8  christos 		}
   1400  1.9.2.1  perseant 	      rpcl = false;
   1401  1.9.2.1  perseant 	      rset = false;
   1402      1.8  christos 	    }
   1403      1.6  christos 	  else
   1404      1.1  christos 	    {
   1405      1.6  christos 	      const char *rname = get_auxreg (opcode, value, isa_mask);
   1406      1.6  christos 	      if (rname && open_braket)
   1407  1.9.2.1  perseant 		(*info->fprintf_styled_func) (info->stream, dis_style_register,
   1408  1.9.2.1  perseant 					      "%s", rname);
   1409      1.6  christos 	      else
   1410  1.9.2.1  perseant 		(*info->fprintf_styled_func) (info->stream, dis_style_immediate,
   1411  1.9.2.1  perseant 					      "%#x", value);
   1412      1.1  christos 	    }
   1413      1.1  christos 	}
   1414      1.7  christos 
   1415      1.7  christos       if (operand->flags & ARC_OPERAND_LIMM)
   1416      1.7  christos 	{
   1417      1.7  christos 	  arc_infop->operands[arc_infop->operands_count].kind
   1418      1.7  christos 	    = ARC_OPERAND_KIND_LIMM;
   1419      1.7  christos 	  /* It is not important to have exactly the LIMM indicator
   1420      1.7  christos 	     here.  */
   1421      1.7  christos 	  arc_infop->operands[arc_infop->operands_count].value = 63;
   1422      1.7  christos 	}
   1423      1.7  christos       else
   1424      1.7  christos 	{
   1425      1.7  christos 	  arc_infop->operands[arc_infop->operands_count].value = value;
   1426      1.7  christos 	  arc_infop->operands[arc_infop->operands_count].kind
   1427      1.7  christos 	    = (operand->flags & ARC_OPERAND_IR
   1428      1.7  christos 	       ? ARC_OPERAND_KIND_REG
   1429      1.7  christos 	       : ARC_OPERAND_KIND_SHIMM);
   1430      1.7  christos 	}
   1431      1.7  christos       arc_infop->operands_count ++;
   1432      1.1  christos     }
   1433      1.1  christos 
   1434      1.8  christos   /* Pretty print extra info for pc-relative operands.  */
   1435      1.8  christos   if (rpcl && rset)
   1436      1.8  christos     {
   1437      1.8  christos       if (info->flags & INSN_HAS_RELOC)
   1438      1.8  christos 	/* If the instruction has a reloc associated with it, then the
   1439      1.8  christos 	   offset field in the instruction will actually be the addend
   1440      1.8  christos 	   for the reloc.  (We are using REL type relocs).  In such
   1441      1.8  christos 	   cases, we can ignore the pc when computing addresses, since
   1442      1.8  christos 	   the addend is not currently pc-relative.  */
   1443      1.8  christos 	memaddr = 0;
   1444      1.8  christos 
   1445  1.9.2.1  perseant       (*info->fprintf_styled_func) (info->stream,
   1446  1.9.2.1  perseant 				    dis_style_comment_start, "\t;");
   1447      1.8  christos       (*info->print_address_func) ((memaddr & ~3) + vpcl, info);
   1448      1.8  christos     }
   1449      1.8  christos 
   1450      1.6  christos   return insn_len;
   1451      1.1  christos }
   1452      1.1  christos 
   1453      1.1  christos 
   1454      1.6  christos disassembler_ftype
   1455      1.6  christos arc_get_disassembler (bfd *abfd)
   1456      1.6  christos {
   1457      1.7  christos   /* BFD my be absent, if opcodes is invoked from the debugger that
   1458      1.7  christos      has connected to remote target and doesn't have an ELF file.  */
   1459      1.7  christos   if (abfd != NULL)
   1460      1.7  christos     {
   1461      1.7  christos       /* Read the extension insns and registers, if any.  */
   1462      1.7  christos       build_ARC_extmap (abfd);
   1463      1.6  christos #ifdef DEBUG
   1464      1.7  christos       dump_ARC_extmap ();
   1465      1.6  christos #endif
   1466      1.7  christos     }
   1467      1.1  christos 
   1468      1.6  christos   return print_insn_arc;
   1469      1.1  christos }
   1470      1.1  christos 
   1471  1.9.2.1  perseant /* Indices into option argument vector for options that do require
   1472  1.9.2.1  perseant    an argument.  Use ARC_OPTION_ARG_NONE for options that don't
   1473  1.9.2.1  perseant    expect an argument.  */
   1474  1.9.2.1  perseant typedef enum
   1475  1.9.2.1  perseant {
   1476  1.9.2.1  perseant   ARC_OPTION_ARG_NONE = -1,
   1477  1.9.2.1  perseant   ARC_OPTION_ARG_ARCH,
   1478  1.9.2.1  perseant   ARC_OPTION_ARG_SIZE
   1479  1.9.2.1  perseant } arc_option_arg_t;
   1480  1.9.2.1  perseant 
   1481  1.9.2.1  perseant /* Valid ARC disassembler options.  */
   1482  1.9.2.1  perseant static struct
   1483  1.9.2.1  perseant {
   1484  1.9.2.1  perseant   const char *name;
   1485  1.9.2.1  perseant   const char *description;
   1486  1.9.2.1  perseant   arc_option_arg_t arg;
   1487  1.9.2.1  perseant } arc_options[] =
   1488  1.9.2.1  perseant {
   1489  1.9.2.1  perseant   { "cpu=",       N_("Enforce the designated architecture while decoding."),
   1490  1.9.2.1  perseant 		  ARC_OPTION_ARG_ARCH },
   1491  1.9.2.1  perseant   { "dsp",	  N_("Recognize DSP instructions."),
   1492  1.9.2.1  perseant 		  ARC_OPTION_ARG_NONE },
   1493  1.9.2.1  perseant   { "spfp",	  N_("Recognize FPX SP instructions."),
   1494  1.9.2.1  perseant 		  ARC_OPTION_ARG_NONE },
   1495  1.9.2.1  perseant   { "dpfp",	  N_("Recognize FPX DP instructions."),
   1496  1.9.2.1  perseant 		  ARC_OPTION_ARG_NONE },
   1497  1.9.2.1  perseant   { "quarkse_em", N_("Recognize FPU QuarkSE-EM instructions."),
   1498  1.9.2.1  perseant 		  ARC_OPTION_ARG_NONE },
   1499  1.9.2.1  perseant   { "fpuda",	  N_("Recognize double assist FPU instructions."),
   1500  1.9.2.1  perseant 		  ARC_OPTION_ARG_NONE },
   1501  1.9.2.1  perseant   { "fpus",	  N_("Recognize single precision FPU instructions."),
   1502  1.9.2.1  perseant 		  ARC_OPTION_ARG_NONE },
   1503  1.9.2.1  perseant   { "fpud",	  N_("Recognize double precision FPU instructions."),
   1504  1.9.2.1  perseant 		  ARC_OPTION_ARG_NONE },
   1505  1.9.2.1  perseant   { "nps400",	  N_("Recognize NPS400 instructions."),
   1506  1.9.2.1  perseant 		  ARC_OPTION_ARG_NONE },
   1507  1.9.2.1  perseant   { "hex",	  N_("Use only hexadecimal number to print immediates."),
   1508  1.9.2.1  perseant 		  ARC_OPTION_ARG_NONE }
   1509  1.9.2.1  perseant };
   1510  1.9.2.1  perseant 
   1511  1.9.2.1  perseant /* Populate the structure for representing ARC's disassembly options.
   1512  1.9.2.1  perseant    Such a dynamic initialization is desired, because it makes the maintenance
   1513  1.9.2.1  perseant    easier and also gdb uses this to enable the "disassembler-option".  */
   1514  1.9.2.1  perseant 
   1515  1.9.2.1  perseant const disasm_options_and_args_t *
   1516  1.9.2.1  perseant disassembler_options_arc (void)
   1517  1.9.2.1  perseant {
   1518  1.9.2.1  perseant   static disasm_options_and_args_t *opts_and_args;
   1519  1.9.2.1  perseant 
   1520  1.9.2.1  perseant   if (opts_and_args == NULL)
   1521  1.9.2.1  perseant     {
   1522  1.9.2.1  perseant       disasm_option_arg_t *args;
   1523  1.9.2.1  perseant       disasm_options_t *opts;
   1524  1.9.2.1  perseant       size_t i;
   1525  1.9.2.1  perseant       const size_t nr_of_options = ARRAY_SIZE (arc_options);
   1526  1.9.2.1  perseant       /* There is a null element at the end of CPU_TYPES, therefore
   1527  1.9.2.1  perseant 	 NR_OF_CPUS is actually 1 more and that is desired here too.  */
   1528  1.9.2.1  perseant       const size_t nr_of_cpus = ARRAY_SIZE (cpu_types);
   1529  1.9.2.1  perseant 
   1530  1.9.2.1  perseant       opts_and_args = XNEW (disasm_options_and_args_t);
   1531  1.9.2.1  perseant       opts_and_args->args
   1532  1.9.2.1  perseant 	= XNEWVEC (disasm_option_arg_t, ARC_OPTION_ARG_SIZE + 1);
   1533  1.9.2.1  perseant       opts_and_args->options.name
   1534  1.9.2.1  perseant 	= XNEWVEC (const char *, nr_of_options + 1);
   1535  1.9.2.1  perseant       opts_and_args->options.description
   1536  1.9.2.1  perseant 	= XNEWVEC (const char *, nr_of_options + 1);
   1537  1.9.2.1  perseant       opts_and_args->options.arg
   1538  1.9.2.1  perseant 	= XNEWVEC (const disasm_option_arg_t *, nr_of_options + 1);
   1539  1.9.2.1  perseant 
   1540  1.9.2.1  perseant       /* Populate the arguments for "cpu=" option.  */
   1541  1.9.2.1  perseant       args = opts_and_args->args;
   1542  1.9.2.1  perseant       args[ARC_OPTION_ARG_ARCH].name = "ARCH";
   1543  1.9.2.1  perseant       args[ARC_OPTION_ARG_ARCH].values = XNEWVEC (const char *, nr_of_cpus);
   1544  1.9.2.1  perseant       for (i = 0; i < nr_of_cpus; ++i)
   1545  1.9.2.1  perseant 	args[ARC_OPTION_ARG_ARCH].values[i] = cpu_types[i].name;
   1546  1.9.2.1  perseant       args[ARC_OPTION_ARG_SIZE].name = NULL;
   1547  1.9.2.1  perseant       args[ARC_OPTION_ARG_SIZE].values = NULL;
   1548  1.9.2.1  perseant 
   1549  1.9.2.1  perseant       /* Populate the options.  */
   1550  1.9.2.1  perseant       opts = &opts_and_args->options;
   1551  1.9.2.1  perseant       for (i = 0; i < nr_of_options; ++i)
   1552  1.9.2.1  perseant 	{
   1553  1.9.2.1  perseant 	  opts->name[i] = arc_options[i].name;
   1554  1.9.2.1  perseant 	  opts->description[i] = arc_options[i].description;
   1555  1.9.2.1  perseant 	  if (arc_options[i].arg != ARC_OPTION_ARG_NONE)
   1556  1.9.2.1  perseant 	    opts->arg[i] = &args[arc_options[i].arg];
   1557  1.9.2.1  perseant 	  else
   1558  1.9.2.1  perseant 	    opts->arg[i] = NULL;
   1559  1.9.2.1  perseant 	}
   1560  1.9.2.1  perseant       opts->name[nr_of_options] = NULL;
   1561  1.9.2.1  perseant       opts->description[nr_of_options] = NULL;
   1562  1.9.2.1  perseant       opts->arg[nr_of_options] = NULL;
   1563  1.9.2.1  perseant     }
   1564  1.9.2.1  perseant 
   1565  1.9.2.1  perseant   return opts_and_args;
   1566  1.9.2.1  perseant }
   1567  1.9.2.1  perseant 
   1568  1.9.2.1  perseant 
   1569      1.6  christos void
   1570      1.6  christos print_arc_disassembler_options (FILE *stream)
   1571      1.1  christos {
   1572  1.9.2.1  perseant   const disasm_options_and_args_t *opts_and_args;
   1573  1.9.2.1  perseant   const disasm_option_arg_t *args;
   1574  1.9.2.1  perseant   const disasm_options_t *opts;
   1575  1.9.2.1  perseant   size_t i, j;
   1576  1.9.2.1  perseant   size_t max_len = 0;
   1577      1.8  christos 
   1578  1.9.2.1  perseant   opts_and_args = disassembler_options_arc ();
   1579  1.9.2.1  perseant   opts = &opts_and_args->options;
   1580  1.9.2.1  perseant   args = opts_and_args->args;
   1581      1.6  christos 
   1582  1.9.2.1  perseant   fprintf (stream, _("\nThe following ARC specific disassembler options are"
   1583  1.9.2.1  perseant 		     " supported for use \nwith the -M switch (multiple"
   1584  1.9.2.1  perseant 		     " options should be separated by commas):\n"));
   1585  1.9.2.1  perseant 
   1586  1.9.2.1  perseant   /* Find the maximum length for printing options (and their arg name).  */
   1587  1.9.2.1  perseant   for (i = 0; opts->name[i] != NULL; ++i)
   1588      1.8  christos     {
   1589  1.9.2.1  perseant       size_t len = strlen (opts->name[i]);
   1590  1.9.2.1  perseant       len += (opts->arg[i]) ? strlen (opts->arg[i]->name) : 0;
   1591  1.9.2.1  perseant       max_len = (len > max_len) ? len : max_len;
   1592  1.9.2.1  perseant     }
   1593  1.9.2.1  perseant 
   1594  1.9.2.1  perseant   /* Print the options, their arg and description, if any.  */
   1595  1.9.2.1  perseant   for (i = 0, ++max_len; opts->name[i] != NULL; ++i)
   1596  1.9.2.1  perseant     {
   1597  1.9.2.1  perseant       fprintf (stream, "  %s", opts->name[i]);
   1598  1.9.2.1  perseant       if (opts->arg[i] != NULL)
   1599  1.9.2.1  perseant 	fprintf (stream, "%s", opts->arg[i]->name);
   1600  1.9.2.1  perseant       if (opts->description[i] != NULL)
   1601  1.9.2.1  perseant 	{
   1602  1.9.2.1  perseant 	  size_t len = strlen (opts->name[i]);
   1603  1.9.2.1  perseant 	  len += (opts->arg[i]) ? strlen (opts->arg[i]->name) : 0;
   1604  1.9.2.1  perseant 	  fprintf (stream,
   1605  1.9.2.1  perseant 		   "%*c %s", (int) (max_len - len), ' ', opts->description[i]);
   1606  1.9.2.1  perseant 	}
   1607  1.9.2.1  perseant       fprintf (stream, _("\n"));
   1608  1.9.2.1  perseant     }
   1609  1.9.2.1  perseant 
   1610  1.9.2.1  perseant   /* Print the possible values of an argument.  */
   1611  1.9.2.1  perseant   for (i = 0; args[i].name != NULL; ++i)
   1612  1.9.2.1  perseant     {
   1613  1.9.2.1  perseant       size_t len = 3;
   1614  1.9.2.1  perseant       if (args[i].values == NULL)
   1615  1.9.2.1  perseant 	continue;
   1616  1.9.2.1  perseant       fprintf (stream, _("\n\
   1617  1.9.2.1  perseant   For the options above, the following values are supported for \"%s\":\n   "),
   1618  1.9.2.1  perseant 	       args[i].name);
   1619  1.9.2.1  perseant       for (j = 0; args[i].values[j] != NULL; ++j)
   1620  1.9.2.1  perseant 	{
   1621  1.9.2.1  perseant 	  fprintf (stream, " %s", args[i].values[j]);
   1622  1.9.2.1  perseant 	  len += strlen (args[i].values[j]) + 1;
   1623  1.9.2.1  perseant 	  /* reset line if printed too long.  */
   1624  1.9.2.1  perseant 	  if (len >= 78)
   1625  1.9.2.1  perseant 	    {
   1626  1.9.2.1  perseant 	      fprintf (stream, _("\n   "));
   1627  1.9.2.1  perseant 	      len = 3;
   1628  1.9.2.1  perseant 	    }
   1629  1.9.2.1  perseant 	}
   1630  1.9.2.1  perseant       fprintf (stream, _("\n"));
   1631  1.9.2.1  perseant     }
   1632  1.9.2.1  perseant 
   1633  1.9.2.1  perseant   fprintf (stream, _("\n"));
   1634      1.1  christos }
   1635      1.1  christos 
   1636      1.7  christos void arc_insn_decode (bfd_vma addr,
   1637      1.7  christos 		      struct disassemble_info *info,
   1638      1.7  christos 		      disassembler_ftype disasm_func,
   1639      1.7  christos 		      struct arc_instruction *insn)
   1640      1.7  christos {
   1641      1.7  christos   const struct arc_opcode *opcode;
   1642      1.7  christos   struct arc_disassemble_info *arc_infop;
   1643      1.7  christos 
   1644      1.7  christos   /* Ensure that insn would be in the reset state.  */
   1645      1.7  christos   memset (insn, 0, sizeof (struct arc_instruction));
   1646      1.7  christos 
   1647      1.7  christos   /* There was an error when disassembling, for example memory read error.  */
   1648      1.7  christos   if (disasm_func (addr, info) < 0)
   1649      1.7  christos     {
   1650  1.9.2.1  perseant       insn->valid = false;
   1651      1.7  christos       return;
   1652      1.7  christos     }
   1653      1.7  christos 
   1654      1.7  christos   assert (info->private_data != NULL);
   1655      1.7  christos   arc_infop = info->private_data;
   1656      1.7  christos 
   1657      1.7  christos   insn->length  = arc_infop->insn_len;;
   1658      1.7  christos   insn->address = addr;
   1659      1.7  christos 
   1660      1.7  christos   /* Quick exit if memory at this address is not an instruction.  */
   1661      1.7  christos   if (info->insn_type == dis_noninsn)
   1662      1.7  christos     {
   1663  1.9.2.1  perseant       insn->valid = false;
   1664      1.7  christos       return;
   1665      1.7  christos     }
   1666      1.7  christos 
   1667  1.9.2.1  perseant   insn->valid = true;
   1668      1.7  christos 
   1669      1.7  christos   opcode = (const struct arc_opcode *) arc_infop->opcode;
   1670      1.7  christos   insn->insn_class = opcode->insn_class;
   1671      1.7  christos   insn->limm_value = arc_infop->limm;
   1672      1.7  christos   insn->limm_p     = arc_infop->limm_p;
   1673      1.7  christos 
   1674      1.7  christos   insn->is_control_flow = (info->insn_type == dis_branch
   1675      1.7  christos 			   || info->insn_type == dis_condbranch
   1676      1.7  christos 			   || info->insn_type == dis_jsr
   1677      1.7  christos 			   || info->insn_type == dis_condjsr);
   1678      1.7  christos 
   1679      1.7  christos   insn->has_delay_slot = info->branch_delay_insns;
   1680      1.7  christos   insn->writeback_mode
   1681      1.7  christos     = (enum arc_ldst_writeback_mode) arc_infop->writeback_mode;
   1682      1.7  christos   insn->data_size_mode = info->data_size;
   1683      1.7  christos   insn->condition_code = arc_infop->condition_code;
   1684      1.7  christos   memcpy (insn->operands, arc_infop->operands,
   1685      1.7  christos 	  sizeof (struct arc_insn_operand) * MAX_INSN_ARGS);
   1686      1.7  christos   insn->operands_count = arc_infop->operands_count;
   1687      1.7  christos }
   1688      1.1  christos 
   1689      1.6  christos /* Local variables:
   1690      1.6  christos    eval: (c-set-style "gnu")
   1691      1.6  christos    indent-tabs-mode: t
   1692      1.6  christos    End:  */
   1693