ChangeLog rotatation and copyright year update
[deliverable/binutils-gdb.git] / opcodes / arc-dis.c
index 9868ae73756ad82d063ddb444b7e8b60220aa13f..92f69da76a17f7d81889077734f14e87920fa703 100644 (file)
 /* Instruction printing code for the ARC.
-   Copyright (C) 1994, 1995 Free Software Foundation, Inc. 
+   Copyright (C) 1994-2015 Free Software Foundation, Inc.
    Contributed by Doug Evans (dje@cygnus.com).
 
-This program is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2 of the License, or
-(at your option) any later version.
+   This file is part of libopcodes.
 
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
+   This library is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3, or (at your option)
+   any later version.
 
-You should have received a copy of the GNU General Public License
-along with this program; if not, write to the Free Software
-Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+   It is distributed in the hope that it will be useful, but WITHOUT
+   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+   or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
+   License for more details.
 
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+   MA 02110-1301, USA.  */
+
+#include "sysdep.h"
+#include "libiberty.h"
 #include "dis-asm.h"
 #include "opcode/arc.h"
-#include "libelf.h"
+#include "elf-bfd.h"
 #include "elf/arc.h"
+#include "opintl.h"
 
-static int print_insn_arc_base_little PARAMS ((bfd_vma, disassemble_info *));
-static int print_insn_arc_host_little PARAMS ((bfd_vma, disassemble_info *));
-static int print_insn_arc_graphics_little PARAMS ((bfd_vma, disassemble_info *));
-static int print_insn_arc_audio_little PARAMS ((bfd_vma, disassemble_info *));
-static int print_insn_arc_base_big PARAMS ((bfd_vma, disassemble_info *));
-static int print_insn_arc_host_big PARAMS ((bfd_vma, disassemble_info *));
-static int print_insn_arc_graphics_big PARAMS ((bfd_vma, disassemble_info *));
-static int print_insn_arc_audio_big PARAMS ((bfd_vma, disassemble_info *));
+#include <stdarg.h>
+#include "arc-dis.h"
+#include "arc-ext.h"
 
-static int print_insn PARAMS ((bfd_vma, disassemble_info *, int, int));
+#ifndef dbg
+#define dbg (0)
+#endif
 
-/* Print one instruction from PC on INFO->STREAM.
-   Return the size of the instruction (4 or 8 for the ARC). */
+/* Classification of the opcodes for the decoder to print 
+   the instructions.  */
 
-static int
-print_insn (pc, info, mach, big_p)
-     bfd_vma pc;
-     disassemble_info *info;
-     int mach;
-     int big_p;
+typedef enum
 {
-  const struct arc_opcode *opcode,*opcode_end;
-  bfd_byte buffer[4];
-  void *stream = info->stream;
-  fprintf_ftype func = info->fprintf_func;
-  int status;
-  /* First element is insn, second element is limm (if present).  */
-  arc_insn insn[2];
-  int got_limm_p = 0;
-  static int initialized = 0;
-  static int current_mach = 0;
+  CLASS_A4_ARITH,           
+  CLASS_A4_OP3_GENERAL,
+  CLASS_A4_FLAG,
+  /* All branches other than JC.  */
+  CLASS_A4_BRANCH,
+  CLASS_A4_JC ,
+  /* All loads other than immediate 
+     indexed loads.  */
+  CLASS_A4_LD0,
+  CLASS_A4_LD1,
+  CLASS_A4_ST,
+  CLASS_A4_SR,
+  /* All single operand instructions.  */
+  CLASS_A4_OP3_SUBOPC3F,
+  CLASS_A4_LR
+} a4_decoding_class;
+
+#define BIT(word,n)    ((word) & (1 << n))
+#define BITS(word,s,e)  (((word) >> s) & ((1 << (e + 1 - s)) - 1))
+#define OPCODE(word)   (BITS ((word), 27, 31))
+#define FIELDA(word)   (BITS ((word), 21, 26))
+#define FIELDB(word)   (BITS ((word), 15, 20))
+#define FIELDC(word)   (BITS ((word),  9, 14))
+
+/* FIELD D is signed.  */
+#define FIELDD(word)   ((BITS ((word), 0, 8) ^ 0x100) - 0x100)
+
+#define PUT_NEXT_WORD_IN(a)                                            \
+  do                                                                   \
+    {                                                                  \
+      if (is_limm == 1 && !NEXT_WORD (1))                              \
+        mwerror (state, _("Illegal limm reference in last instruction!\n")); \
+      a = state->words[1];                                             \
+    }                                                                  \
+  while (0)
+
+#define CHECK_FLAG_COND_NULLIFY()                              \
+  do                                                           \
+    {                                                          \
+      if (is_shimm == 0)                                       \
+        {                                                      \
+          flag = BIT (state->words[0], 8);                     \
+          state->nullifyMode = BITS (state->words[0], 5, 6);   \
+          cond = BITS (state->words[0], 0, 4);                 \
+        }                                                      \
+    }                                                          \
+  while (0)
+
+#define CHECK_COND()                           \
+  do                                           \
+    {                                          \
+      if (is_shimm == 0)                       \
+        cond = BITS (state->words[0], 0, 4);   \
+    }                                          \
+  while (0)
+
+#define CHECK_FIELD(field)                     \
+  do                                           \
+    {                                          \
+      if (field == 62)                         \
+        {                                      \
+          is_limm++;                           \
+         field##isReg = 0;                     \
+         PUT_NEXT_WORD_IN (field);             \
+         limm_value = field;                   \
+       }                                       \
+      else if (field > 60)                     \
+        {                                      \
+         field##isReg = 0;                     \
+         is_shimm++;                           \
+         flag = (field == 61);                 \
+         field = FIELDD (state->words[0]);     \
+       }                                       \
+    }                                          \
+  while (0)
+
+#define CHECK_FIELD_A()                                \
+  do                                           \
+    {                                          \
+      fieldA = FIELDA (state->words[0]);       \
+      if (fieldA > 60)                         \
+        {                                      \
+         fieldAisReg = 0;                      \
+         fieldA = 0;                           \
+       }                                       \
+    }                                          \
+  while (0)
+
+#define CHECK_FIELD_B()                                \
+  do                                           \
+    {                                          \
+      fieldB = FIELDB (state->words[0]);       \
+      CHECK_FIELD (fieldB);                    \
+    }                                          \
+  while (0)
+
+#define CHECK_FIELD_C()                                \
+  do                                           \
+    {                                          \
+      fieldC = FIELDC (state->words[0]);       \
+      CHECK_FIELD (fieldC);                    \
+    }                                          \
+  while (0)
+
+#define IS_SMALL(x)                 (((field##x) < 256) && ((field##x) > -257))
+#define IS_REG(x)                    (field##x##isReg)
+#define WRITE_FORMAT_LB_Rx_RB(x)     WRITE_FORMAT (x, "[","]","","")
+#define WRITE_FORMAT_x_COMMA_LB(x)   WRITE_FORMAT (x, "",",[","",",[")
+#define WRITE_FORMAT_COMMA_x_RB(x)   WRITE_FORMAT (x, ",","]",",","]")
+#define WRITE_FORMAT_x_RB(x)         WRITE_FORMAT (x, "","]","","]")
+#define WRITE_FORMAT_COMMA_x(x)      WRITE_FORMAT (x, ",","",",","")
+#define WRITE_FORMAT_x_COMMA(x)      WRITE_FORMAT (x, "",",","",",")
+#define WRITE_FORMAT_x(x)            WRITE_FORMAT (x, "","","","")
+#define WRITE_FORMAT(x,cb1,ca1,cb,ca) strcat (formatString,            \
+                                    (IS_REG (x) ? cb1"%r"ca1 :         \
+                                     usesAuxReg ? cb"%a"ca :           \
+                                     IS_SMALL (x) ? cb"%d"ca : cb"%h"ca))
+#define WRITE_FORMAT_RB()      strcat (formatString, "]")
+#define WRITE_COMMENT(str)     (state->comm[state->commNum++] = (str))
+#define WRITE_NOP_COMMENT()    if (!fieldAisReg && !flag) WRITE_COMMENT ("nop");
+
+#define NEXT_WORD(x)   (offset += 4, state->words[x])
 
-  if (!initialized || mach != current_mach)
+#define add_target(x)  (state->targets[state->tcnt++] = (x))
+
+static char comment_prefix[] = "\t; ";
+
+static const char *
+core_reg_name (struct arcDisState * state, int val)
+{
+  if (state->coreRegName)
+    return (*state->coreRegName)(state->_this, val);
+  return 0;
+}
+
+static const char *
+aux_reg_name (struct arcDisState * state, int val)
+{
+  if (state->auxRegName)
+    return (*state->auxRegName)(state->_this, val);
+  return 0;
+}
+
+static const char *
+cond_code_name (struct arcDisState * state, int val)
+{
+  if (state->condCodeName)
+    return (*state->condCodeName)(state->_this, val);
+  return 0;
+}
+
+static const char *
+instruction_name (struct arcDisState * state,
+                 int    op1,
+                 int    op2,
+                 int *  flags)
+{
+  if (state->instName)
+    return (*state->instName)(state->_this, op1, op2, flags);
+  return 0;
+}
+
+static void
+mwerror (struct arcDisState * state, const char * msg)
+{
+  if (state->err != 0)
+    (*state->err)(state->_this, (msg));
+}
+
+static const char *
+post_address (struct arcDisState * state, int addr)
+{
+  static char id[3 * ARRAY_SIZE (state->addresses)];
+  int j, i = state->acnt;
+
+  if (i < ((int) ARRAY_SIZE (state->addresses)))
     {
-      initialized = 1;
-      current_mach = arc_get_opcode_mach (mach, big_p);
-      arc_opcode_init_tables (current_mach);
+      state->addresses[i] = addr;
+      ++state->acnt;
+      j = i*3;
+      id[j+0] = '@';
+      id[j+1] = '0'+i;
+      id[j+2] = 0;
+
+      return id + j;
     }
+  return "";
+}
 
-  status = (*info->read_memory_func) (pc, buffer, 4, info);
-  if (status != 0)
+static void
+arc_sprintf (struct arcDisState *state, char *buf, const char *format, ...)
+{
+  char *bp;
+  const char *p;
+  int size, leading_zero, regMap[2];
+  va_list ap;
+
+  va_start (ap, format);
+
+  bp = buf;
+  *bp = 0;
+  p = format;
+  regMap[0] = 0;
+  regMap[1] = 0;
+
+  while (1)
+    switch (*p++)
+      {
+      case 0:
+       goto DOCOMM; /* (return)  */
+      default:
+       *bp++ = p[-1];
+       break;
+      case '%':
+       size = 0;
+       leading_zero = 0;
+      RETRY: ;
+       switch (*p++)
+         {
+         case '0':
+         case '1':
+         case '2':
+         case '3':
+         case '4':
+         case '5':
+         case '6':
+         case '7':
+         case '8':
+         case '9':
+           {
+             /* size.  */
+             size = p[-1] - '0';
+             if (size == 0)
+               leading_zero = 1; /* e.g. %08x  */
+             while (*p >= '0' && *p <= '9')
+               {
+                 size = size * 10 + *p - '0';
+                 p++;
+               }
+             goto RETRY;
+           }
+#define inc_bp() bp = bp + strlen (bp)
+
+         case 'h':
+           {
+             unsigned u = va_arg (ap, int);
+
+             /* Hex.  We can change the format to 0x%08x in
+                one place, here, if we wish.
+                We add underscores for easy reading.  */
+             if (u > 65536)
+               sprintf (bp, "0x%x_%04x", u >> 16, u & 0xffff);
+             else
+               sprintf (bp, "0x%x", u);
+             inc_bp ();
+           }
+           break;
+         case 'X': case 'x':
+           {
+             int val = va_arg (ap, int);
+
+             if (size != 0)
+               if (leading_zero)
+                 sprintf (bp, "%0*x", size, val);
+               else
+                 sprintf (bp, "%*x", size, val);
+             else
+               sprintf (bp, "%x", val);
+             inc_bp ();
+           }
+           break;
+         case 'd':
+           {
+             int val = va_arg (ap, int);
+
+             if (size != 0)
+               sprintf (bp, "%*d", size, val);
+             else
+               sprintf (bp, "%d", val);
+             inc_bp ();
+           }
+           break;
+         case 'r':
+           {
+             /* Register.  */
+             int val = va_arg (ap, int);
+
+#define REG2NAME(num, name) case num: sprintf (bp, ""name); \
+  regMap[(num < 32) ? 0 : 1] |= 1 << (num - ((num < 32) ? 0 : 32)); break;
+
+             switch (val)
+               {
+                 REG2NAME (26, "gp");
+                 REG2NAME (27, "fp");
+                 REG2NAME (28, "sp");
+                 REG2NAME (29, "ilink1");
+                 REG2NAME (30, "ilink2");
+                 REG2NAME (31, "blink");
+                 REG2NAME (60, "lp_count");
+               default:
+                 {
+                   const char * ext;
+
+                   ext = core_reg_name (state, val);
+                   if (ext)
+                     sprintf (bp, "%s", ext);
+                   else
+                     sprintf (bp,"r%d",val);
+                 }
+                 break;
+               }
+             inc_bp ();
+           } break;
+
+         case 'a':
+           {
+             /* Aux Register.  */
+             int val = va_arg (ap, int);
+
+#define AUXREG2NAME(num, name) case num: sprintf (bp,name); break;
+
+             switch (val)
+               {
+                 AUXREG2NAME (0x0, "status");
+                 AUXREG2NAME (0x1, "semaphore");
+                 AUXREG2NAME (0x2, "lp_start");
+                 AUXREG2NAME (0x3, "lp_end");
+                 AUXREG2NAME (0x4, "identity");
+                 AUXREG2NAME (0x5, "debug");
+               default:
+                 {
+                   const char *ext;
+
+                   ext = aux_reg_name (state, val);
+                   if (ext)
+                     sprintf (bp, "%s", ext);
+                   else
+                     arc_sprintf (state, bp, "%h", val);
+                 }
+                 break;
+               }
+             inc_bp ();
+           }
+           break;
+
+         case 's':
+           {
+             sprintf (bp, "%s", va_arg (ap, char *));
+             inc_bp ();
+           }
+           break;
+
+         default:
+           fprintf (stderr, "?? format %c\n", p[-1]);
+           break;
+         }
+      }
+
+ DOCOMM: *bp = 0;
+  va_end (ap);
+}
+
+static void
+write_comments_(struct arcDisState * state,
+               int shimm,
+               int is_limm,
+               long limm_value)
+{
+  if (state->commentBuffer != 0)
     {
-      (*info->memory_error_func) (status, pc, info);
-      return -1;
+      int i;
+
+      if (is_limm)
+       {
+         const char *name = post_address (state, limm_value + shimm);
+
+         if (*name != 0)
+           WRITE_COMMENT (name);
+       }
+      for (i = 0; i < state->commNum; i++)
+       {
+         if (i == 0)
+           strcpy (state->commentBuffer, comment_prefix);
+         else
+           strcat (state->commentBuffer, ", ");
+         strcat (state->commentBuffer, state->comm[i]);
+       }
     }
-  if (big_p)
-    insn[0] = bfd_getb32 (buffer);
-  else
-    insn[0] = bfd_getl32 (buffer);
+}
+
+#define write_comments2(x) write_comments_ (state, x, is_limm, limm_value)
+#define write_comments()   write_comments2 (0)
+
+static const char *condName[] =
+{
+  /* 0..15.  */
+  ""   , "z"  , "nz" , "p"  , "n"  , "c"  , "nc" , "v"  ,
+  "nv" , "gt" , "ge" , "lt" , "le" , "hi" , "ls" , "pnz"
+};
+
+static void
+write_instr_name_(struct arcDisState * state,
+                 const char * instrName,
+                 int cond,
+                 int condCodeIsPartOfName,
+                 int flag,
+                 int signExtend,
+                 int addrWriteBack,
+                 int directMem)
+{
+  strcpy (state->instrBuffer, instrName);
+
+  if (cond > 0)
+    {
+      const char *cc = 0;
+
+      if (!condCodeIsPartOfName)
+       strcat (state->instrBuffer, ".");
+
+      if (cond < 16)
+       cc = condName[cond];
+      else
+       cc = cond_code_name (state, cond);
+
+      if (!cc)
+       cc = "???";
+
+      strcat (state->instrBuffer, cc);
+    }
+
+  if (flag)
+    strcat (state->instrBuffer, ".f");
+
+  switch (state->nullifyMode)
+    {
+    case BR_exec_always:
+      strcat (state->instrBuffer, ".d");
+      break;
+    case BR_exec_when_jump:
+      strcat (state->instrBuffer, ".jd");
+      break;
+    }
+
+  if (signExtend)
+    strcat (state->instrBuffer, ".x");
+
+  if (addrWriteBack)
+    strcat (state->instrBuffer, ".a");
+
+  if (directMem)
+    strcat (state->instrBuffer, ".di");
+}
+
+#define write_instr_name()                                             \
+  do                                                                   \
+    {                                                                  \
+      write_instr_name_(state, instrName,cond, condCodeIsPartOfName,   \
+                       flag, signExtend, addrWriteBack, directMem);    \
+      formatString[0] = '\0';                                          \
+    }                                                                  \
+  while (0)
+
+enum
+{
+  op_LD0 = 0, op_LD1 = 1, op_ST  = 2, op_3   = 3,
+  op_BC  = 4, op_BLC = 5, op_LPC = 6, op_JC  = 7,
+  op_ADD = 8, op_ADC = 9, op_SUB = 10, op_SBC = 11,
+  op_AND = 12, op_OR  = 13, op_BIC = 14, op_XOR = 15
+};
+
+extern disassemble_info tm_print_insn_info;
+
+static int
+dsmOneArcInst (bfd_vma addr, struct arcDisState * state)
+{
+  int condCodeIsPartOfName = 0;
+  a4_decoding_class decodingClass;
+  const char * instrName;
+  int repeatsOp = 0;
+  int fieldAisReg = 1;
+  int fieldBisReg = 1;
+  int fieldCisReg = 1;
+  int fieldA;
+  int fieldB;
+  int fieldC = 0;
+  int flag = 0;
+  int cond = 0;
+  int is_shimm = 0;
+  int is_limm = 0;
+  long limm_value = 0;
+  int signExtend = 0;
+  int addrWriteBack = 0;
+  int directMem = 0;
+  int is_linked = 0;
+  int offset = 0;
+  int usesAuxReg = 0;
+  int flags;
+  int ignoreFirstOpd;
+  char formatString[60];
 
-  (*func) (stream, "%08lx\t", insn[0]);
+  state->instructionLen = 4;
+  state->nullifyMode = BR_exec_when_no_jump;
+  state->opWidth = 12;
+  state->isBranch = 0;
 
-  opcode_end = arc_opcodes + arc_opcodes_count;
-  for (opcode = arc_opcodes; opcode < opcode_end; opcode++)
+  state->_mem_load = 0;
+  state->_ea_present = 0;
+  state->_load_len = 0;
+  state->ea_reg1 = no_reg;
+  state->ea_reg2 = no_reg;
+  state->_offset = 0;
+
+  if (! NEXT_WORD (0))
+    return 0;
+
+  state->_opcode = OPCODE (state->words[0]);
+  instrName = 0;
+  decodingClass = CLASS_A4_ARITH; /* default!  */
+  repeatsOp = 0;
+  condCodeIsPartOfName=0;
+  state->commNum = 0;
+  state->tcnt = 0;
+  state->acnt = 0;
+  state->flow = noflow;
+  ignoreFirstOpd = 0;
+
+  if (state->commentBuffer)
+    state->commentBuffer[0] = '\0';
+
+  switch (state->_opcode)
     {
-      char *syn;
-      int mods,invalid;
-      long value;
-      const struct arc_operand *operand;
-      const struct arc_operand_value *opval;
-
-      /* Basic bit mask must be correct.  */
-      if ((insn[0] & opcode->mask) != opcode->value)
-       continue;
-
-      /* Supported by this cpu?  */
-      if (! arc_opcode_supported (opcode))
-       continue;
-
-      /* Make two passes over the operands.  First see if any of them
-        have extraction functions, and, if they do, make sure the
-        instruction is valid.  */
-
-      arc_opcode_init_extract ();
-      invalid = 0;
-
-      /* ??? Granted, this is slower than the `ppc' way.  Maybe when this is
-        done it'll be clear what the right way to do this is.  */
-      /* Instructions like "add.f r0,r1,1" are tricky because the ".f" gets
-        printed first, but we don't know how to print it until we've processed
-        the regs.  Since we're scanning all the args before printing the insn
-        anyways, it's actually quite easy.  */
-
-      for (syn = opcode->syntax; *syn; ++syn)
+    case op_LD0:
+      switch (BITS (state->words[0],1,2))
        {
-         if (*syn != '%' || *++syn == '%')
-           continue;
-         mods = 0;
-         while (ARC_MOD_P (arc_operands[arc_operand_map[*syn]].flags))
-           {
-             mods |= arc_operands[arc_operand_map[*syn]].flags & ARC_MOD_BITS;
-             ++syn;
-           }
-         operand = arc_operands + arc_operand_map[*syn];
-         if (operand->extract)
-           (*operand->extract) (insn, operand, mods,
-                                (const struct arc_operand_value **) NULL,
-                                &invalid);
+       case 0:
+         instrName = "ld";
+         state->_load_len = 4;
+         break;
+       case 1:
+         instrName = "ldb";
+         state->_load_len = 1;
+         break;
+       case 2:
+         instrName = "ldw";
+         state->_load_len = 2;
+         break;
+       default:
+         instrName = "??? (0[3])";
+         state->flow = invalid_instr;
+         break;
        }
-      if (invalid)
-       continue;
-
-      /* The instruction is valid.  */
+      decodingClass = CLASS_A4_LD0;
+      break;
 
-      /* If we have an insn with a limm, fetch it now.  Scanning the insns
-        twice lets us do this.  */
-      if (arc_opcode_limm_p (NULL))
+    case op_LD1:
+      if (BIT (state->words[0],13))
        {
-         status = (*info->read_memory_func) (pc + 4, buffer, 4, info);
-         if (status != 0)
+         instrName = "lr";
+         decodingClass = CLASS_A4_LR;
+       }
+      else
+       {
+         switch (BITS (state->words[0], 10, 11))
            {
-             (*info->memory_error_func) (status, pc, info);
-             return -1;
+           case 0:
+             instrName = "ld";
+             state->_load_len = 4;
+             break;
+           case 1:
+             instrName = "ldb";
+             state->_load_len = 1;
+             break;
+           case 2:
+             instrName = "ldw";
+             state->_load_len = 2;
+             break;
+           default:
+             instrName = "??? (1[3])";
+             state->flow = invalid_instr;
+             break;
            }
-         if (big_p)
-           insn[1] = bfd_getb32 (buffer);
-         else
-           insn[1] = bfd_getl32 (buffer);
-         got_limm_p = 1;
+         decodingClass = CLASS_A4_LD1;
        }
+      break;
 
-      for (syn = opcode->syntax; *syn; ++syn)
+    case op_ST:
+      if (BIT (state->words[0], 25))
+       {
+         instrName = "sr";
+         decodingClass = CLASS_A4_SR;
+       }
+      else
        {
-         if (*syn != '%' || *++syn == '%')
+         switch (BITS (state->words[0], 22, 23))
            {
-             (*func) (stream, "%c", *syn);
-             continue;
+           case 0:
+             instrName = "st";
+             break;
+           case 1:
+             instrName = "stb";
+             break;
+           case 2:
+             instrName = "stw";
+             break;
+           default:
+             instrName = "??? (2[3])";
+             state->flow = invalid_instr;
+             break;
            }
+         decodingClass = CLASS_A4_ST;
+       }
+      break;
+
+    case op_3:
+      decodingClass = CLASS_A4_OP3_GENERAL;  /* default for opcode 3...  */
+      switch (FIELDC (state->words[0]))
+       {
+       case  0:
+         instrName = "flag";
+         decodingClass = CLASS_A4_FLAG;
+         break;
+       case  1:
+         instrName = "asr";
+         break;
+       case  2:
+         instrName = "lsr";
+         break;
+       case  3:
+         instrName = "ror";
+         break;
+       case  4:
+         instrName = "rrc";
+         break;
+       case  5:
+         instrName = "sexb";
+         break;
+       case  6:
+         instrName = "sexw";
+         break;
+       case  7:
+         instrName = "extb";
+         break;
+       case  8:
+         instrName = "extw";
+         break;
+       case  0x3f:
+         {
+           decodingClass = CLASS_A4_OP3_SUBOPC3F;
+           switch (FIELDD (state->words[0]))
+             {
+             case 0:
+               instrName = "brk";
+               break;
+             case 1:
+               instrName = "sleep";
+               break;
+             case 2:
+               instrName = "swi";
+               break;
+             default:
+               instrName = "???";
+               state->flow=invalid_instr;
+               break;
+             }
+         }
+         break;
 
-         /* We have an operand.  Fetch any special modifiers.  */
-         mods = 0;
-         while (ARC_MOD_P (arc_operands[arc_operand_map[*syn]].flags))
+         /* ARC Extension Library Instructions
+            NOTE: We assume that extension codes are these instrs.  */
+       default:
+         instrName = instruction_name (state,
+                                       state->_opcode,
+                                       FIELDC (state->words[0]),
+                                       &flags);
+         if (!instrName)
            {
-             mods |= arc_operands[arc_operand_map[*syn]].flags & ARC_MOD_BITS;
-             ++syn;
+             instrName = "???";
+             state->flow = invalid_instr;
            }
-         operand = arc_operands + arc_operand_map[*syn];
+         if (flags & IGNORE_FIRST_OPD)
+           ignoreFirstOpd = 1;
+         break;
+       }
+      break;
 
-         /* Extract the value from the instruction.  */
-         opval = NULL;
-         if (operand->extract)
+    case op_BC:
+      instrName = "b";
+    case op_BLC:
+      if (!instrName)
+       instrName = "bl";
+    case op_LPC:
+      if (!instrName)
+       instrName = "lp";
+    case op_JC:
+      if (!instrName)
+       {
+         if (BITS (state->words[0],9,9))
            {
-             value = (*operand->extract) (insn, operand, mods,
-                                          &opval, (int *) NULL);
+             instrName = "jl";
+             is_linked = 1;
            }
          else
            {
-             value = (insn[0] >> operand->shift) & ((1 << operand->bits) - 1);
-             if ((operand->flags & ARC_OPERAND_SIGNED)
-                 && (value & (1 << (operand->bits - 1))))
-               value -= 1 << operand->bits;
-
-             /* If this is a suffix operand, set `opval'.  */
-             if (operand->flags & ARC_OPERAND_SUFFIX)
-               opval = arc_opcode_lookup_suffix (operand, value);
+             instrName = "j";
+             is_linked = 0;
            }
+       }
+      condCodeIsPartOfName = 1;
+      decodingClass = ((state->_opcode == op_JC) ? CLASS_A4_JC : CLASS_A4_BRANCH );
+      state->isBranch = 1;
+      break;
+
+    case op_ADD:
+    case op_ADC:
+    case op_AND:
+      repeatsOp = (FIELDC (state->words[0]) == FIELDB (state->words[0]));
+
+      switch (state->_opcode)
+       {
+       case op_ADD:
+         instrName = (repeatsOp ? "asl" : "add");
+         break;
+       case op_ADC:
+         instrName = (repeatsOp ? "rlc" : "adc");
+         break;
+       case op_AND:
+         instrName = (repeatsOp ? "mov" : "and");
+         break;
+       }
+      break;
+
+    case op_SUB: instrName = "sub";
+      break;
+    case op_SBC: instrName = "sbc";
+      break;
+    case op_OR:  instrName = "or";
+      break;
+    case op_BIC: instrName = "bic";
+      break;
+
+    case op_XOR:
+      if (state->words[0] == 0x7fffffff)
+       {
+         /* NOP encoded as xor -1, -1, -1.   */
+         instrName = "nop";
+         decodingClass = CLASS_A4_OP3_SUBOPC3F;
+       }
+      else
+       instrName = "xor";
+      break;
+
+    default:
+      instrName = instruction_name (state,state->_opcode,0,&flags);
+      /* if (instrName) printf("FLAGS=0x%x\n", flags);  */
+      if (!instrName)
+       {
+         instrName = "???";
+         state->flow=invalid_instr;
+       }
+      if (flags & IGNORE_FIRST_OPD)
+       ignoreFirstOpd = 1;
+      break;
+    }
+
+  fieldAisReg = fieldBisReg = fieldCisReg = 1; /* Assume regs for now.  */
+  flag = cond = is_shimm = is_limm = 0;
+  state->nullifyMode = BR_exec_when_no_jump;   /* 0  */
+  signExtend = addrWriteBack = directMem = 0;
+  usesAuxReg = 0;
+
+  switch (decodingClass)
+    {
+    case CLASS_A4_ARITH:
+      CHECK_FIELD_A ();
+      CHECK_FIELD_B ();
+      if (!repeatsOp)
+       CHECK_FIELD_C ();
+      CHECK_FLAG_COND_NULLIFY ();
+
+      write_instr_name ();
+      if (!ignoreFirstOpd)
+       {
+         WRITE_FORMAT_x (A);
+         WRITE_FORMAT_COMMA_x (B);
+         if (!repeatsOp)
+           WRITE_FORMAT_COMMA_x (C);
+         WRITE_NOP_COMMENT ();
+         arc_sprintf (state, state->operandBuffer, formatString,
+                     fieldA, fieldB, fieldC);
+       }
+      else
+       {
+         WRITE_FORMAT_x (B);
+         if (!repeatsOp)
+           WRITE_FORMAT_COMMA_x (C);
+         arc_sprintf (state, state->operandBuffer, formatString,
+                     fieldB, fieldC);
+       }
+      write_comments ();
+      break;
 
-         /* Print the operand as directed by the flags.  */
-         if (operand->flags & ARC_OPERAND_FAKE)
-           ; /* nothing to do (??? at least not yet) */
-         else if (operand->flags & ARC_OPERAND_SUFFIX)
+    case CLASS_A4_OP3_GENERAL:
+      CHECK_FIELD_A ();
+      CHECK_FIELD_B ();
+      CHECK_FLAG_COND_NULLIFY ();
+
+      write_instr_name ();
+      if (!ignoreFirstOpd)
+       {
+         WRITE_FORMAT_x (A);
+         WRITE_FORMAT_COMMA_x (B);
+         WRITE_NOP_COMMENT ();
+         arc_sprintf (state, state->operandBuffer, formatString,
+                     fieldA, fieldB);
+       }
+      else
+       {
+         WRITE_FORMAT_x (B);
+         arc_sprintf (state, state->operandBuffer, formatString, fieldB);
+       }
+      write_comments ();
+      break;
+
+    case CLASS_A4_FLAG:
+      CHECK_FIELD_B ();
+      CHECK_FLAG_COND_NULLIFY ();
+      flag = 0; /* This is the FLAG instruction -- it's redundant.  */
+
+      write_instr_name ();
+      WRITE_FORMAT_x (B);
+      arc_sprintf (state, state->operandBuffer, formatString, fieldB);
+      write_comments ();
+      break;
+
+    case CLASS_A4_BRANCH:
+      fieldA = BITS (state->words[0],7,26) << 2;
+      fieldA = (fieldA << 10) >> 10; /* Make it signed.  */
+      fieldA += addr + 4;
+      CHECK_FLAG_COND_NULLIFY ();
+      flag = 0;
+
+      write_instr_name ();
+      /* This address could be a label we know. Convert it.  */
+      if (state->_opcode != op_LPC /* LP  */)
+       {
+         add_target (fieldA); /* For debugger.  */
+         state->flow = state->_opcode == op_BLC /* BL  */
+           ? direct_call
+           : direct_jump;
+         /* indirect calls are achieved by "lr blink,[status];
+            lr dest<- func addr; j [dest]"  */
+       }
+
+      strcat (formatString, "%s"); /* Address/label name.  */
+      arc_sprintf (state, state->operandBuffer, formatString,
+                 post_address (state, fieldA));
+      write_comments ();
+      break;
+
+    case CLASS_A4_JC:
+      /* For op_JC -- jump to address specified.
+        Also covers jump and link--bit 9 of the instr. word
+        selects whether linked, thus "is_linked" is set above.  */
+      fieldA = 0;
+      CHECK_FIELD_B ();
+      CHECK_FLAG_COND_NULLIFY ();
+
+      if (!fieldBisReg)
+       {
+         fieldAisReg = 0;
+         fieldA = (fieldB >> 25) & 0x7F; /* Flags.  */
+         fieldB = (fieldB & 0xFFFFFF) << 2;
+         state->flow = is_linked ? direct_call : direct_jump;
+         add_target (fieldB);
+         /* Screwy JLcc requires .jd mode to execute correctly
+            but we pretend it is .nd (no delay slot).  */
+         if (is_linked && state->nullifyMode == BR_exec_when_jump)
+           state->nullifyMode = BR_exec_when_no_jump;
+       }
+      else
+       {
+         state->flow = is_linked ? indirect_call : indirect_jump;
+         /* We should also treat this as indirect call if NOT linked
+            but the preceding instruction was a "lr blink,[status]"
+            and we have a delay slot with "add blink,blink,2".
+            For now we can't detect such.  */
+         state->register_for_indirect_jump = fieldB;
+       }
+
+      write_instr_name ();
+      strcat (formatString,
+             IS_REG (B) ? "[%r]" : "%s"); /* Address/label name.  */
+      if (fieldA != 0)
+       {
+         fieldAisReg = 0;
+         WRITE_FORMAT_COMMA_x (A);
+       }
+      if (IS_REG (B))
+       arc_sprintf (state, state->operandBuffer, formatString, fieldB, fieldA);
+      else
+       arc_sprintf (state, state->operandBuffer, formatString,
+                   post_address (state, fieldB), fieldA);
+      write_comments ();
+      break;
+
+    case CLASS_A4_LD0:
+      /* LD instruction.
+        B and C can be regs, or one (both?) can be limm.  */
+      CHECK_FIELD_A ();
+      CHECK_FIELD_B ();
+      CHECK_FIELD_C ();
+      if (dbg)
+       printf ("5:b reg %d %d c reg %d %d  \n",
+               fieldBisReg,fieldB,fieldCisReg,fieldC);
+      state->_offset = 0;
+      state->_ea_present = 1;
+      if (fieldBisReg)
+       state->ea_reg1 = fieldB;
+      else
+       state->_offset += fieldB;
+      if (fieldCisReg)
+       state->ea_reg2 = fieldC;
+      else
+       state->_offset += fieldC;
+      state->_mem_load = 1;
+
+      directMem     = BIT (state->words[0], 5);
+      addrWriteBack = BIT (state->words[0], 3);
+      signExtend    = BIT (state->words[0], 0);
+
+      write_instr_name ();
+      WRITE_FORMAT_x_COMMA_LB(A);
+      if (fieldBisReg || fieldB != 0)
+       WRITE_FORMAT_x_COMMA (B);
+      else
+       fieldB = fieldC;
+
+      WRITE_FORMAT_x_RB (C);
+      arc_sprintf (state, state->operandBuffer, formatString,
+                 fieldA, fieldB, fieldC);
+      write_comments ();
+      break;
+
+    case CLASS_A4_LD1:
+      /* LD instruction.  */
+      CHECK_FIELD_B ();
+      CHECK_FIELD_A ();
+      fieldC = FIELDD (state->words[0]);
+
+      if (dbg)
+       printf ("6:b reg %d %d c 0x%x  \n",
+               fieldBisReg, fieldB, fieldC);
+      state->_ea_present = 1;
+      state->_offset = fieldC;
+      state->_mem_load = 1;
+      if (fieldBisReg)
+       state->ea_reg1 = fieldB;
+      /* Field B is either a shimm (same as fieldC) or limm (different!)
+        Say ea is not present, so only one of us will do the name lookup.  */
+      else
+       state->_offset += fieldB, state->_ea_present = 0;
+
+      directMem     = BIT (state->words[0],14);
+      addrWriteBack = BIT (state->words[0],12);
+      signExtend    = BIT (state->words[0],9);
+
+      write_instr_name ();
+      WRITE_FORMAT_x_COMMA_LB (A);
+      if (!fieldBisReg)
+       {
+         fieldB = state->_offset;
+         WRITE_FORMAT_x_RB (B);
+       }
+      else
+       {
+         WRITE_FORMAT_x (B);
+         if (fieldC != 0 && !BIT (state->words[0],13))
            {
-             /* Default suffixes aren't printed.  Fortunately, they all have
-                zero values.  Also, zero values for boolean suffixes are
-                represented by the absence of text.  */
+             fieldCisReg = 0;
+             WRITE_FORMAT_COMMA_x_RB (C);
+           }
+         else
+           WRITE_FORMAT_RB ();
+       }
+      arc_sprintf (state, state->operandBuffer, formatString,
+                 fieldA, fieldB, fieldC);
+      write_comments ();
+      break;
 
-             if (value != 0)
-               {
-                 /* ??? OPVAL should have a value.  If it doesn't just cope
-                    as we want disassembly to be reasonably robust.
-                    Also remember that several condition code values (16-31)
-                    aren't defined yet.  For these cases just print the
-                    number suitably decorated.  */
-                 if (opval)
-                   (*func) (stream, "%s%s",
-                            mods & ARC_MOD_DOT ? "." : "",
-                            opval->name);
-                 else
-                   (*func) (stream, "%s%c%d",
-                            mods & ARC_MOD_DOT ? "." : "",
-                            operand->fmt, value);
-               }
+    case CLASS_A4_ST:
+      /* ST instruction.  */
+      CHECK_FIELD_B();
+      CHECK_FIELD_C();
+      fieldA = FIELDD(state->words[0]); /* shimm  */
+
+      /* [B,A offset]  */
+      if (dbg) printf("7:b reg %d %x off %x\n",
+                     fieldBisReg,fieldB,fieldA);
+      state->_ea_present = 1;
+      state->_offset = fieldA;
+      if (fieldBisReg)
+       state->ea_reg1 = fieldB;
+      /* Field B is either a shimm (same as fieldA) or limm (different!)
+        Say ea is not present, so only one of us will do the name lookup.
+        (for is_limm we do the name translation here).  */
+      else
+       state->_offset += fieldB, state->_ea_present = 0;
+
+      directMem     = BIT (state->words[0], 26);
+      addrWriteBack = BIT (state->words[0], 24);
+
+      write_instr_name ();
+      WRITE_FORMAT_x_COMMA_LB(C);
+
+      if (!fieldBisReg)
+       {
+         fieldB = state->_offset;
+         WRITE_FORMAT_x_RB (B);
+       }
+      else
+       {
+         WRITE_FORMAT_x (B);
+         if (fieldBisReg && fieldA != 0)
+           {
+             fieldAisReg = 0;
+             WRITE_FORMAT_COMMA_x_RB(A);
            }
-         else if (operand->flags & ARC_OPERAND_RELATIVE_BRANCH)
-           (*info->print_address_func) (pc + 4 + value, info);
-         /* ??? Not all cases of this are currently caught.  */
-         else if (operand->flags & ARC_OPERAND_ABSOLUTE_BRANCH)
-           (*info->print_address_func) ((bfd_vma) value & 0xffffffff, info);
-         else if (operand->flags & ARC_OPERAND_ADDRESS)
-           (*info->print_address_func) ((bfd_vma) value & 0xffffffff, info);
-         else if (opval)
-           /* Note that this case catches both normal and auxiliary regs.  */
-           (*func) (stream, "%s", opval->name);
          else
-           (*func) (stream, "%ld", value);
+           WRITE_FORMAT_RB();
        }
+      arc_sprintf (state, state->operandBuffer, formatString,
+                 fieldC, fieldB, fieldA);
+      write_comments2 (fieldA);
+      break;
 
-      /* We have found and printed an instruction; return.  */
-      return got_limm_p ? 8 : 4;
-    }
+    case CLASS_A4_SR:
+      /* SR instruction  */
+      CHECK_FIELD_B();
+      CHECK_FIELD_C();
 
-  (*func) (stream, "*unknown*");
-  return 4;
-}
+      write_instr_name ();
+      WRITE_FORMAT_x_COMMA_LB(C);
+      /* Try to print B as an aux reg if it is not a core reg.  */
+      usesAuxReg = 1;
+      WRITE_FORMAT_x (B);
+      WRITE_FORMAT_RB ();
+      arc_sprintf (state, state->operandBuffer, formatString, fieldC, fieldB);
+      write_comments ();
+      break;
 
-/* Given MACH, one of bfd_mach_arc_xxx, return the print_insn function to use.
-   This does things a non-standard way (the "standard" way would be to copy
-   this code into disassemble.c).  Since there are more than a couple of
-   variants, hiding all this crud here seems cleaner.  */
+    case CLASS_A4_OP3_SUBOPC3F:
+      write_instr_name ();
+      state->operandBuffer[0] = '\0';
+      break;
 
-disassembler_ftype
-arc_get_disassembler (mach, big_p)
-     int mach;
-     int big_p;
-{
-  switch (mach)
-    {
-    case bfd_mach_arc_base:
-      return big_p ? print_insn_arc_base_big : print_insn_arc_base_little;
-    case bfd_mach_arc_host:
-      return big_p ? print_insn_arc_host_big : print_insn_arc_host_little;
-    case bfd_mach_arc_graphics:
-      return big_p ? print_insn_arc_graphics_big : print_insn_arc_graphics_little;
-    case bfd_mach_arc_audio:
-      return big_p ? print_insn_arc_audio_big : print_insn_arc_audio_little;
+    case CLASS_A4_LR:
+      /* LR instruction */
+      CHECK_FIELD_A ();
+      CHECK_FIELD_B ();
+
+      write_instr_name ();
+      WRITE_FORMAT_x_COMMA_LB (A);
+      /* Try to print B as an aux reg if it is not a core reg. */
+      usesAuxReg = 1;
+      WRITE_FORMAT_x (B);
+      WRITE_FORMAT_RB ();
+      arc_sprintf (state, state->operandBuffer, formatString, fieldA, fieldB);
+      write_comments ();
+      break;
+
+    default:
+      mwerror (state, "Bad decoding class in ARC disassembler");
+      break;
     }
-  return print_insn_arc_base_little;
-}
 
-static int
-print_insn_arc_base_little (pc, info)
-     bfd_vma pc;
-     disassemble_info *info;
-{
-  return print_insn (pc, info, bfd_mach_arc_base, 0);
+  state->_cond = cond;
+  return state->instructionLen = offset;
 }
 
-static int
-print_insn_arc_host_little (pc, info)
-     bfd_vma pc;
-     disassemble_info *info;
-{
-  return print_insn (pc, info, bfd_mach_arc_host, 0);
-}
 
-static int
-print_insn_arc_graphics_little (pc, info)
-     bfd_vma pc;
-     disassemble_info *info;
+/* Returns the name the user specified core extension register.  */
+
+static const char *
+_coreRegName(void * arg ATTRIBUTE_UNUSED, int regval)
 {
-  return print_insn (pc, info, bfd_mach_arc_graphics, 0);
+  return arcExtMap_coreRegName (regval);
 }
 
-static int
-print_insn_arc_audio_little (pc, info)
-     bfd_vma pc;
-     disassemble_info *info;
+/* Returns the name the user specified AUX extension register.  */
+
+static const char *
+_auxRegName(void *_this ATTRIBUTE_UNUSED, int regval)
 {
-  return print_insn (pc, info, bfd_mach_arc_audio, 0);
+  return arcExtMap_auxRegName(regval);
 }
 
-static int
-print_insn_arc_base_big (pc, info)
-     bfd_vma pc;
-     disassemble_info *info;
+/* Returns the name the user specified condition code name.  */
+
+static const char *
+_condCodeName(void *_this ATTRIBUTE_UNUSED, int regval)
 {
-  return print_insn (pc, info, bfd_mach_arc_base, 1);
+  return arcExtMap_condCodeName(regval);
 }
 
-static int
-print_insn_arc_host_big (pc, info)
-     bfd_vma pc;
-     disassemble_info *info;
+/* Returns the name the user specified extension instruction.  */
+
+static const char *
+_instName (void *_this ATTRIBUTE_UNUSED, int majop, int minop, int *flags)
 {
-  return print_insn (pc, info, bfd_mach_arc_host, 1);
+  return arcExtMap_instName(majop, minop, flags);
 }
 
+/* Decode an instruction returning the size of the instruction
+   in bytes or zero if unrecognized.  */
+
 static int
-print_insn_arc_graphics_big (pc, info)
-     bfd_vma pc;
-     disassemble_info *info;
+decodeInstr (bfd_vma            address, /* Address of this instruction.  */
+            disassemble_info * info)
 {
-  return print_insn (pc, info, bfd_mach_arc_graphics, 1);
+  int status;
+  bfd_byte buffer[4];
+  struct arcDisState s;                /* ARC Disassembler state.  */
+  void *stream = info->stream;         /* Output stream.  */
+  fprintf_ftype func = info->fprintf_func;
+
+  memset (&s, 0, sizeof(struct arcDisState));
+
+  /* read first instruction  */
+  status = (*info->read_memory_func) (address, buffer, 4, info);
+  if (status != 0)
+    {
+      (*info->memory_error_func) (status, address, info);
+      return 0;
+    }
+  if (info->endian == BFD_ENDIAN_LITTLE)
+    s.words[0] = bfd_getl32(buffer);
+  else
+    s.words[0] = bfd_getb32(buffer);
+  /* Always read second word in case of limm.  */
+
+  /* We ignore the result since last insn may not have a limm.  */
+  status = (*info->read_memory_func) (address + 4, buffer, 4, info);
+  if (info->endian == BFD_ENDIAN_LITTLE)
+    s.words[1] = bfd_getl32(buffer);
+  else
+    s.words[1] = bfd_getb32(buffer);
+
+  s._this = &s;
+  s.coreRegName = _coreRegName;
+  s.auxRegName = _auxRegName;
+  s.condCodeName = _condCodeName;
+  s.instName = _instName;
+
+  /* Disassemble.  */
+  dsmOneArcInst (address, & s);
+
+  /* Display the disassembly instruction.  */
+  (*func) (stream, "%08lx ", s.words[0]);
+  (*func) (stream, "    ");
+  (*func) (stream, "%-10s ", s.instrBuffer);
+
+  if (__TRANSLATION_REQUIRED (s))
+    {
+      bfd_vma addr = s.addresses[s.operandBuffer[1] - '0'];
+
+      (*info->print_address_func) ((bfd_vma) addr, info);
+      (*func) (stream, "\n");
+    }
+  else
+    (*func) (stream, "%s",s.operandBuffer);
+
+  return s.instructionLen;
 }
 
-static int
-print_insn_arc_audio_big (pc, info)
-     bfd_vma pc;
-     disassemble_info *info;
+/* Return the print_insn function to use.
+   Side effect: load (possibly empty) extension section  */
+
+disassembler_ftype
+arc_get_disassembler (void *ptr)
 {
-  return print_insn (pc, info, bfd_mach_arc_audio, 1);
+  if (ptr)
+    build_ARC_extmap ((struct bfd *) ptr);
+  return decodeInstr;
 }
This page took 0.038616 seconds and 4 git commands to generate.