Back to index

cell-binutils  2.17cvs20070401
arc-dis.c
Go to the documentation of this file.
00001 /* Instruction printing code for the ARC.
00002    Copyright 1994, 1995, 1997, 1998, 2000, 2001, 2002, 2005
00003    Free Software Foundation, Inc.
00004    Contributed by Doug Evans (dje@cygnus.com).
00005 
00006    This program is free software; you can redistribute it and/or modify
00007    it under the terms of the GNU General Public License as published by
00008    the Free Software Foundation; either version 2 of the License, or
00009    (at your option) any later version.
00010 
00011    This program is distributed in the hope that it will be useful,
00012    but WITHOUT ANY WARRANTY; without even the implied warranty of
00013    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014    GNU General Public License for more details.
00015 
00016    You should have received a copy of the GNU General Public License
00017    along with this program; if not, write to the Free Software
00018    Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
00019    MA 02110-1301, USA.  */
00020 
00021 #include "ansidecl.h"
00022 #include "libiberty.h"
00023 #include "dis-asm.h"
00024 #include "opcode/arc.h"
00025 #include "elf-bfd.h"
00026 #include "elf/arc.h"
00027 #include <string.h>
00028 #include "opintl.h"
00029 
00030 #include <stdarg.h>
00031 #include "arc-dis.h"
00032 #include "arc-ext.h"
00033 
00034 #ifndef dbg
00035 #define dbg (0)
00036 #endif
00037 
00038 /* Classification of the opcodes for the decoder to print 
00039    the instructions.  */
00040 
00041 typedef enum
00042 {
00043   CLASS_A4_ARITH,         
00044   CLASS_A4_OP3_GENERAL,
00045   CLASS_A4_FLAG,
00046   /* All branches other than JC.  */
00047   CLASS_A4_BRANCH,
00048   CLASS_A4_JC ,
00049   /* All loads other than immediate 
00050      indexed loads.  */
00051   CLASS_A4_LD0,
00052   CLASS_A4_LD1,
00053   CLASS_A4_ST,
00054   CLASS_A4_SR,
00055   /* All single operand instructions.  */
00056   CLASS_A4_OP3_SUBOPC3F,
00057   CLASS_A4_LR
00058 } a4_decoding_class;
00059 
00060 #define BIT(word,n)  ((word) & (1 << n))
00061 #define BITS(word,s,e)  (((word) << (31 - e)) >> (s + (31 - e)))
00062 #define OPCODE(word) (BITS ((word), 27, 31))
00063 #define FIELDA(word) (BITS ((word), 21, 26))
00064 #define FIELDB(word) (BITS ((word), 15, 20))
00065 #define FIELDC(word) (BITS ((word),  9, 14))
00066 
00067 /* FIELD D is signed in all of its uses, so we make sure argument is
00068    treated as signed for bit shifting purposes:  */
00069 #define FIELDD(word) (BITS (((signed int)word), 0, 8))
00070 
00071 #define PUT_NEXT_WORD_IN(a)                                    \
00072   do                                                           \
00073     {                                                          \
00074       if (is_limm == 1 && !NEXT_WORD (1))                      \
00075         mwerror (state, _("Illegal limm reference in last instruction!\n")); \
00076       a = state->words[1];                                     \
00077     }                                                          \
00078   while (0)
00079 
00080 #define CHECK_FLAG_COND_NULLIFY()                       \
00081   do                                                    \
00082     {                                                   \
00083       if (is_shimm == 0)                                \
00084         {                                               \
00085           flag = BIT (state->words[0], 8);                     \
00086           state->nullifyMode = BITS (state->words[0], 5, 6);   \
00087           cond = BITS (state->words[0], 0, 4);                 \
00088         }                                               \
00089     }                                                   \
00090   while (0)
00091 
00092 #define CHECK_COND()                      \
00093   do                                      \
00094     {                                     \
00095       if (is_shimm == 0)                  \
00096         cond = BITS (state->words[0], 0, 4);     \
00097     }                                     \
00098   while (0)
00099 
00100 #define CHECK_FIELD(field)                \
00101   do                                      \
00102     {                                     \
00103       if (field == 62)                           \
00104         {                                 \
00105           is_limm++;                      \
00106          field##isReg = 0;                \
00107          PUT_NEXT_WORD_IN (field);        \
00108          limm_value = field;                     \
00109        }                                  \
00110       else if (field > 60)                \
00111         {                                 \
00112          field##isReg = 0;                \
00113          is_shimm++;                      \
00114          flag = (field == 61);                   \
00115          field = FIELDD (state->words[0]);       \
00116        }                                  \
00117     }                                     \
00118   while (0)
00119 
00120 #define CHECK_FIELD_A()                          \
00121   do                                      \
00122     {                                     \
00123       fieldA = FIELDA (state->words[0]);  \
00124       if (fieldA > 60)                           \
00125         {                                 \
00126          fieldAisReg = 0;                 \
00127          fieldA = 0;                      \
00128        }                                  \
00129     }                                     \
00130   while (0)
00131 
00132 #define CHECK_FIELD_B()                          \
00133   do                                      \
00134     {                                     \
00135       fieldB = FIELDB (state->words[0]);  \
00136       CHECK_FIELD (fieldB);               \
00137     }                                     \
00138   while (0)
00139 
00140 #define CHECK_FIELD_C()                          \
00141   do                                      \
00142     {                                     \
00143       fieldC = FIELDC (state->words[0]);  \
00144       CHECK_FIELD (fieldC);               \
00145     }                                     \
00146   while (0)
00147 
00148 #define IS_SMALL(x)                 (((field##x) < 256) && ((field##x) > -257))
00149 #define IS_REG(x)                    (field##x##isReg)
00150 #define WRITE_FORMAT_LB_Rx_RB(x)     WRITE_FORMAT (x, "[","]","","")
00151 #define WRITE_FORMAT_x_COMMA_LB(x)   WRITE_FORMAT (x, "",",[","",",[")
00152 #define WRITE_FORMAT_COMMA_x_RB(x)   WRITE_FORMAT (x, ",","]",",","]")
00153 #define WRITE_FORMAT_x_RB(x)         WRITE_FORMAT (x, "","]","","]")
00154 #define WRITE_FORMAT_COMMA_x(x)      WRITE_FORMAT (x, ",","",",","")
00155 #define WRITE_FORMAT_x_COMMA(x)      WRITE_FORMAT (x, "",",","",",")
00156 #define WRITE_FORMAT_x(x)            WRITE_FORMAT (x, "","","","")
00157 #define WRITE_FORMAT(x,cb1,ca1,cb,ca) strcat (formatString,           \
00158                                  (IS_REG (x) ? cb1"%r"ca1 :           \
00159                                   usesAuxReg ? cb"%a"ca :             \
00160                                   IS_SMALL (x) ? cb"%d"ca : cb"%h"ca))
00161 #define WRITE_FORMAT_RB()   strcat (formatString, "]")
00162 #define WRITE_COMMENT(str)  (state->comm[state->commNum++] = (str))
00163 #define WRITE_NOP_COMMENT() if (!fieldAisReg && !flag) WRITE_COMMENT ("nop");
00164 
00165 #define NEXT_WORD(x) (offset += 4, state->words[x])
00166 
00167 #define add_target(x)       (state->targets[state->tcnt++] = (x))
00168 
00169 static char comment_prefix[] = "\t; ";
00170 
00171 static const char *
00172 core_reg_name (struct arcDisState * state, int val)
00173 {
00174   if (state->coreRegName)
00175     return (*state->coreRegName)(state->_this, val);
00176   return 0;
00177 }
00178 
00179 static const char *
00180 aux_reg_name (struct arcDisState * state, int val)
00181 {
00182   if (state->auxRegName)
00183     return (*state->auxRegName)(state->_this, val);
00184   return 0;
00185 }
00186 
00187 static const char *
00188 cond_code_name (struct arcDisState * state, int val)
00189 {
00190   if (state->condCodeName)
00191     return (*state->condCodeName)(state->_this, val);
00192   return 0;
00193 }
00194 
00195 static const char *
00196 instruction_name (struct arcDisState * state,
00197                 int    op1,
00198                 int    op2,
00199                 int *  flags)
00200 {
00201   if (state->instName)
00202     return (*state->instName)(state->_this, op1, op2, flags);
00203   return 0;
00204 }
00205 
00206 static void
00207 mwerror (struct arcDisState * state, const char * msg)
00208 {
00209   if (state->err != 0)
00210     (*state->err)(state->_this, (msg));
00211 }
00212 
00213 static const char *
00214 post_address (struct arcDisState * state, int addr)
00215 {
00216   static char id[3 * ARRAY_SIZE (state->addresses)];
00217   int j, i = state->acnt;
00218 
00219   if (i < ((int) ARRAY_SIZE (state->addresses)))
00220     {
00221       state->addresses[i] = addr;
00222       ++state->acnt;
00223       j = i*3;
00224       id[j+0] = '@';
00225       id[j+1] = '0'+i;
00226       id[j+2] = 0;
00227 
00228       return id + j;
00229     }
00230   return "";
00231 }
00232 
00233 static void
00234 arc_sprintf (struct arcDisState *state, char *buf, const char *format, ...)
00235 {
00236   char *bp;
00237   const char *p;
00238   int size, leading_zero, regMap[2];
00239   long auxNum;
00240   va_list ap;
00241 
00242   va_start (ap, format);
00243 
00244   bp = buf;
00245   *bp = 0;
00246   p = format;
00247   auxNum = -1;
00248   regMap[0] = 0;
00249   regMap[1] = 0;
00250 
00251   while (1)
00252     switch (*p++)
00253       {
00254       case 0:
00255        goto DOCOMM; /* (return)  */
00256       default:
00257        *bp++ = p[-1];
00258        break;
00259       case '%':
00260        size = 0;
00261        leading_zero = 0;
00262       RETRY: ;
00263        switch (*p++)
00264          {
00265          case '0':
00266          case '1':
00267          case '2':
00268          case '3':
00269          case '4':
00270          case '5':
00271          case '6':
00272          case '7':
00273          case '8':
00274          case '9':
00275            {
00276              /* size.  */
00277              size = p[-1] - '0';
00278              if (size == 0)
00279               leading_zero = 1; /* e.g. %08x  */
00280              while (*p >= '0' && *p <= '9')
00281               {
00282                 size = size * 10 + *p - '0';
00283                 p++;
00284               }
00285              goto RETRY;
00286            }
00287 #define inc_bp() bp = bp + strlen (bp)
00288 
00289          case 'h':
00290            {
00291              unsigned u = va_arg (ap, int);
00292 
00293              /* Hex.  We can change the format to 0x%08x in
00294                one place, here, if we wish.
00295                We add underscores for easy reading.  */
00296              if (u > 65536)
00297               sprintf (bp, "0x%x_%04x", u >> 16, u & 0xffff);
00298              else
00299               sprintf (bp, "0x%x", u);
00300              inc_bp ();
00301            }
00302            break;
00303          case 'X': case 'x':
00304            {
00305              int val = va_arg (ap, int);
00306 
00307              if (size != 0)
00308               if (leading_zero)
00309                 sprintf (bp, "%0*x", size, val);
00310               else
00311                 sprintf (bp, "%*x", size, val);
00312              else
00313               sprintf (bp, "%x", val);
00314              inc_bp ();
00315            }
00316            break;
00317          case 'd':
00318            {
00319              int val = va_arg (ap, int);
00320 
00321              if (size != 0)
00322               sprintf (bp, "%*d", size, val);
00323              else
00324               sprintf (bp, "%d", val);
00325              inc_bp ();
00326            }
00327            break;
00328          case 'r':
00329            {
00330              /* Register.  */
00331              int val = va_arg (ap, int);
00332 
00333 #define REG2NAME(num, name) case num: sprintf (bp, ""name); \
00334   regMap[(num < 32) ? 0 : 1] |= 1 << (num - ((num < 32) ? 0 : 32)); break;
00335 
00336              switch (val)
00337               {
00338                 REG2NAME (26, "gp");
00339                 REG2NAME (27, "fp");
00340                 REG2NAME (28, "sp");
00341                 REG2NAME (29, "ilink1");
00342                 REG2NAME (30, "ilink2");
00343                 REG2NAME (31, "blink");
00344                 REG2NAME (60, "lp_count");
00345               default:
00346                 {
00347                   const char * ext;
00348 
00349                   ext = core_reg_name (state, val);
00350                   if (ext)
00351                     sprintf (bp, "%s", ext);
00352                   else
00353                     sprintf (bp,"r%d",val);
00354                 }
00355                 break;
00356               }
00357              inc_bp ();
00358            } break;
00359 
00360          case 'a':
00361            {
00362              /* Aux Register.  */
00363              int val = va_arg (ap, int);
00364 
00365 #define AUXREG2NAME(num, name) case num: sprintf (bp,name); break;
00366 
00367              switch (val)
00368               {
00369                 AUXREG2NAME (0x0, "status");
00370                 AUXREG2NAME (0x1, "semaphore");
00371                 AUXREG2NAME (0x2, "lp_start");
00372                 AUXREG2NAME (0x3, "lp_end");
00373                 AUXREG2NAME (0x4, "identity");
00374                 AUXREG2NAME (0x5, "debug");
00375               default:
00376                 {
00377                   const char *ext;
00378 
00379                   ext = aux_reg_name (state, val);
00380                   if (ext)
00381                     sprintf (bp, "%s", ext);
00382                   else
00383                     arc_sprintf (state, bp, "%h", val);
00384                 }
00385                 break;
00386               }
00387              inc_bp ();
00388            }
00389            break;
00390 
00391          case 's':
00392            {
00393              sprintf (bp, "%s", va_arg (ap, char *));
00394              inc_bp ();
00395            }
00396            break;
00397 
00398          default:
00399            fprintf (stderr, "?? format %c\n", p[-1]);
00400            break;
00401          }
00402       }
00403 
00404  DOCOMM: *bp = 0;
00405   va_end (ap);
00406 }
00407 
00408 static void
00409 write_comments_(struct arcDisState * state,
00410               int shimm,
00411               int is_limm,
00412               long limm_value)
00413 {
00414   if (state->commentBuffer != 0)
00415     {
00416       int i;
00417 
00418       if (is_limm)
00419        {
00420          const char *name = post_address (state, limm_value + shimm);
00421 
00422          if (*name != 0)
00423            WRITE_COMMENT (name);
00424        }
00425       for (i = 0; i < state->commNum; i++)
00426        {
00427          if (i == 0)
00428            strcpy (state->commentBuffer, comment_prefix);
00429          else
00430            strcat (state->commentBuffer, ", ");
00431          strncat (state->commentBuffer, state->comm[i],
00432                  sizeof (state->commentBuffer));
00433        }
00434     }
00435 }
00436 
00437 #define write_comments2(x) write_comments_ (state, x, is_limm, limm_value)
00438 #define write_comments()   write_comments2 (0)
00439 
00440 static const char *condName[] =
00441 {
00442   /* 0..15.  */
00443   ""   , "z"  , "nz" , "p"  , "n"  , "c"  , "nc" , "v"  ,
00444   "nv" , "gt" , "ge" , "lt" , "le" , "hi" , "ls" , "pnz"
00445 };
00446 
00447 static void
00448 write_instr_name_(struct arcDisState * state,
00449                 const char * instrName,
00450                 int cond,
00451                 int condCodeIsPartOfName,
00452                 int flag,
00453                 int signExtend,
00454                 int addrWriteBack,
00455                 int directMem)
00456 {
00457   strcpy (state->instrBuffer, instrName);
00458 
00459   if (cond > 0)
00460     {
00461       const char *cc = 0;
00462 
00463       if (!condCodeIsPartOfName)
00464        strcat (state->instrBuffer, ".");
00465 
00466       if (cond < 16)
00467        cc = condName[cond];
00468       else
00469        cc = cond_code_name (state, cond);
00470 
00471       if (!cc)
00472        cc = "???";
00473 
00474       strcat (state->instrBuffer, cc);
00475     }
00476 
00477   if (flag)
00478     strcat (state->instrBuffer, ".f");
00479 
00480   switch (state->nullifyMode)
00481     {
00482     case BR_exec_always:
00483       strcat (state->instrBuffer, ".d");
00484       break;
00485     case BR_exec_when_jump:
00486       strcat (state->instrBuffer, ".jd");
00487       break;
00488     }
00489 
00490   if (signExtend)
00491     strcat (state->instrBuffer, ".x");
00492 
00493   if (addrWriteBack)
00494     strcat (state->instrBuffer, ".a");
00495 
00496   if (directMem)
00497     strcat (state->instrBuffer, ".di");
00498 }
00499 
00500 #define write_instr_name()                                     \
00501   do                                                           \
00502     {                                                          \
00503       write_instr_name_(state, instrName,cond, condCodeIsPartOfName,  \
00504                      flag, signExtend, addrWriteBack, directMem);     \
00505       formatString[0] = '\0';                                         \
00506     }                                                          \
00507   while (0)
00508 
00509 enum
00510 {
00511   op_LD0 = 0, op_LD1 = 1, op_ST  = 2, op_3   = 3,
00512   op_BC  = 4, op_BLC = 5, op_LPC = 6, op_JC  = 7,
00513   op_ADD = 8, op_ADC = 9, op_SUB = 10, op_SBC = 11,
00514   op_AND = 12, op_OR  = 13, op_BIC = 14, op_XOR = 15
00515 };
00516 
00517 extern disassemble_info tm_print_insn_info;
00518 
00519 static int
00520 dsmOneArcInst (bfd_vma addr, struct arcDisState * state)
00521 {
00522   int condCodeIsPartOfName = 0;
00523   a4_decoding_class decodingClass;
00524   const char * instrName;
00525   int repeatsOp = 0;
00526   int fieldAisReg = 1;
00527   int fieldBisReg = 1;
00528   int fieldCisReg = 1;
00529   int fieldA;
00530   int fieldB;
00531   int fieldC = 0;
00532   int flag = 0;
00533   int cond = 0;
00534   int is_shimm = 0;
00535   int is_limm = 0;
00536   long limm_value = 0;
00537   int signExtend = 0;
00538   int addrWriteBack = 0;
00539   int directMem = 0;
00540   int is_linked = 0;
00541   int offset = 0;
00542   int usesAuxReg = 0;
00543   int flags;
00544   int ignoreFirstOpd;
00545   char formatString[60];
00546 
00547   state->instructionLen = 4;
00548   state->nullifyMode = BR_exec_when_no_jump;
00549   state->opWidth = 12;
00550   state->isBranch = 0;
00551 
00552   state->_mem_load = 0;
00553   state->_ea_present = 0;
00554   state->_load_len = 0;
00555   state->ea_reg1 = no_reg;
00556   state->ea_reg2 = no_reg;
00557   state->_offset = 0;
00558 
00559   if (! NEXT_WORD (0))
00560     return 0;
00561 
00562   state->_opcode = OPCODE (state->words[0]);
00563   instrName = 0;
00564   decodingClass = CLASS_A4_ARITH; /* default!  */
00565   repeatsOp = 0;
00566   condCodeIsPartOfName=0;
00567   state->commNum = 0;
00568   state->tcnt = 0;
00569   state->acnt = 0;
00570   state->flow = noflow;
00571   ignoreFirstOpd = 0;
00572 
00573   if (state->commentBuffer)
00574     state->commentBuffer[0] = '\0';
00575 
00576   switch (state->_opcode)
00577     {
00578     case op_LD0:
00579       switch (BITS (state->words[0],1,2))
00580        {
00581        case 0:
00582          instrName = "ld";
00583          state->_load_len = 4;
00584          break;
00585        case 1:
00586          instrName = "ldb";
00587          state->_load_len = 1;
00588          break;
00589        case 2:
00590          instrName = "ldw";
00591          state->_load_len = 2;
00592          break;
00593        default:
00594          instrName = "??? (0[3])";
00595          state->flow = invalid_instr;
00596          break;
00597        }
00598       decodingClass = CLASS_A4_LD0;
00599       break;
00600 
00601     case op_LD1:
00602       if (BIT (state->words[0],13))
00603        {
00604          instrName = "lr";
00605          decodingClass = CLASS_A4_LR;
00606        }
00607       else
00608        {
00609          switch (BITS (state->words[0], 10, 11))
00610            {
00611            case 0:
00612              instrName = "ld";
00613              state->_load_len = 4;
00614              break;
00615            case 1:
00616              instrName = "ldb";
00617              state->_load_len = 1;
00618              break;
00619            case 2:
00620              instrName = "ldw";
00621              state->_load_len = 2;
00622              break;
00623            default:
00624              instrName = "??? (1[3])";
00625              state->flow = invalid_instr;
00626              break;
00627            }
00628          decodingClass = CLASS_A4_LD1;
00629        }
00630       break;
00631 
00632     case op_ST:
00633       if (BIT (state->words[0], 25))
00634        {
00635          instrName = "sr";
00636          decodingClass = CLASS_A4_SR;
00637        }
00638       else
00639        {
00640          switch (BITS (state->words[0], 22, 23))
00641            {
00642            case 0:
00643              instrName = "st";
00644              break;
00645            case 1:
00646              instrName = "stb";
00647              break;
00648            case 2:
00649              instrName = "stw";
00650              break;
00651            default:
00652              instrName = "??? (2[3])";
00653              state->flow = invalid_instr;
00654              break;
00655            }
00656          decodingClass = CLASS_A4_ST;
00657        }
00658       break;
00659 
00660     case op_3:
00661       decodingClass = CLASS_A4_OP3_GENERAL;  /* default for opcode 3...  */
00662       switch (FIELDC (state->words[0]))
00663        {
00664        case  0:
00665          instrName = "flag";
00666          decodingClass = CLASS_A4_FLAG;
00667          break;
00668        case  1:
00669          instrName = "asr";
00670          break;
00671        case  2:
00672          instrName = "lsr";
00673          break;
00674        case  3:
00675          instrName = "ror";
00676          break;
00677        case  4:
00678          instrName = "rrc";
00679          break;
00680        case  5:
00681          instrName = "sexb";
00682          break;
00683        case  6:
00684          instrName = "sexw";
00685          break;
00686        case  7:
00687          instrName = "extb";
00688          break;
00689        case  8:
00690          instrName = "extw";
00691          break;
00692        case  0x3f:
00693          {
00694            decodingClass = CLASS_A4_OP3_SUBOPC3F;
00695            switch (FIELDD (state->words[0]))
00696              {
00697              case 0:
00698               instrName = "brk";
00699               break;
00700              case 1:
00701               instrName = "sleep";
00702               break;
00703              case 2:
00704               instrName = "swi";
00705               break;
00706              default:
00707               instrName = "???";
00708               state->flow=invalid_instr;
00709               break;
00710              }
00711          }
00712          break;
00713 
00714          /* ARC Extension Library Instructions
00715             NOTE: We assume that extension codes are these instrs.  */
00716        default:
00717          instrName = instruction_name (state,
00718                                    state->_opcode,
00719                                    FIELDC (state->words[0]),
00720                                    &flags);
00721          if (!instrName)
00722            {
00723              instrName = "???";
00724              state->flow = invalid_instr;
00725            }
00726          if (flags & IGNORE_FIRST_OPD)
00727            ignoreFirstOpd = 1;
00728          break;
00729        }
00730       break;
00731 
00732     case op_BC:
00733       instrName = "b";
00734     case op_BLC:
00735       if (!instrName)
00736        instrName = "bl";
00737     case op_LPC:
00738       if (!instrName)
00739        instrName = "lp";
00740     case op_JC:
00741       if (!instrName)
00742        {
00743          if (BITS (state->words[0],9,9))
00744            {
00745              instrName = "jl";
00746              is_linked = 1;
00747            }
00748          else
00749            {
00750              instrName = "j";
00751              is_linked = 0;
00752            }
00753        }
00754       condCodeIsPartOfName = 1;
00755       decodingClass = ((state->_opcode == op_JC) ? CLASS_A4_JC : CLASS_A4_BRANCH );
00756       state->isBranch = 1;
00757       break;
00758 
00759     case op_ADD:
00760     case op_ADC:
00761     case op_AND:
00762       repeatsOp = (FIELDC (state->words[0]) == FIELDB (state->words[0]));
00763 
00764       switch (state->_opcode)
00765        {
00766        case op_ADD:
00767          instrName = (repeatsOp ? "asl" : "add");
00768          break;
00769        case op_ADC:
00770          instrName = (repeatsOp ? "rlc" : "adc");
00771          break;
00772        case op_AND:
00773          instrName = (repeatsOp ? "mov" : "and");
00774          break;
00775        }
00776       break;
00777 
00778     case op_SUB: instrName = "sub";
00779       break;
00780     case op_SBC: instrName = "sbc";
00781       break;
00782     case op_OR:  instrName = "or";
00783       break;
00784     case op_BIC: instrName = "bic";
00785       break;
00786 
00787     case op_XOR:
00788       if (state->words[0] == 0x7fffffff)
00789        {
00790          /* NOP encoded as xor -1, -1, -1.   */
00791          instrName = "nop";
00792          decodingClass = CLASS_A4_OP3_SUBOPC3F;
00793        }
00794       else
00795        instrName = "xor";
00796       break;
00797 
00798     default:
00799       instrName = instruction_name (state,state->_opcode,0,&flags);
00800       /* if (instrName) printf("FLAGS=0x%x\n", flags);  */
00801       if (!instrName)
00802        {
00803          instrName = "???";
00804          state->flow=invalid_instr;
00805        }
00806       if (flags & IGNORE_FIRST_OPD)
00807        ignoreFirstOpd = 1;
00808       break;
00809     }
00810 
00811   fieldAisReg = fieldBisReg = fieldCisReg = 1; /* Assume regs for now.  */
00812   flag = cond = is_shimm = is_limm = 0;
00813   state->nullifyMode = BR_exec_when_no_jump;     /* 0  */
00814   signExtend = addrWriteBack = directMem = 0;
00815   usesAuxReg = 0;
00816 
00817   switch (decodingClass)
00818     {
00819     case CLASS_A4_ARITH:
00820       CHECK_FIELD_A ();
00821       CHECK_FIELD_B ();
00822       if (!repeatsOp)
00823        CHECK_FIELD_C ();
00824       CHECK_FLAG_COND_NULLIFY ();
00825 
00826       write_instr_name ();
00827       if (!ignoreFirstOpd)
00828        {
00829          WRITE_FORMAT_x (A);
00830          WRITE_FORMAT_COMMA_x (B);
00831          if (!repeatsOp)
00832            WRITE_FORMAT_COMMA_x (C);
00833          WRITE_NOP_COMMENT ();
00834          arc_sprintf (state, state->operandBuffer, formatString,
00835                     fieldA, fieldB, fieldC);
00836        }
00837       else
00838        {
00839          WRITE_FORMAT_x (B);
00840          if (!repeatsOp)
00841            WRITE_FORMAT_COMMA_x (C);
00842          arc_sprintf (state, state->operandBuffer, formatString,
00843                     fieldB, fieldC);
00844        }
00845       write_comments ();
00846       break;
00847 
00848     case CLASS_A4_OP3_GENERAL:
00849       CHECK_FIELD_A ();
00850       CHECK_FIELD_B ();
00851       CHECK_FLAG_COND_NULLIFY ();
00852 
00853       write_instr_name ();
00854       if (!ignoreFirstOpd)
00855        {
00856          WRITE_FORMAT_x (A);
00857          WRITE_FORMAT_COMMA_x (B);
00858          WRITE_NOP_COMMENT ();
00859          arc_sprintf (state, state->operandBuffer, formatString,
00860                     fieldA, fieldB);
00861        }
00862       else
00863        {
00864          WRITE_FORMAT_x (B);
00865          arc_sprintf (state, state->operandBuffer, formatString, fieldB);
00866        }
00867       write_comments ();
00868       break;
00869 
00870     case CLASS_A4_FLAG:
00871       CHECK_FIELD_B ();
00872       CHECK_FLAG_COND_NULLIFY ();
00873       flag = 0; /* This is the FLAG instruction -- it's redundant.  */
00874 
00875       write_instr_name ();
00876       WRITE_FORMAT_x (B);
00877       arc_sprintf (state, state->operandBuffer, formatString, fieldB);
00878       write_comments ();
00879       break;
00880 
00881     case CLASS_A4_BRANCH:
00882       fieldA = BITS (state->words[0],7,26) << 2;
00883       fieldA = (fieldA << 10) >> 10; /* Make it signed.  */
00884       fieldA += addr + 4;
00885       CHECK_FLAG_COND_NULLIFY ();
00886       flag = 0;
00887 
00888       write_instr_name ();
00889       /* This address could be a label we know. Convert it.  */
00890       if (state->_opcode != op_LPC /* LP  */)
00891        {
00892          add_target (fieldA); /* For debugger.  */
00893          state->flow = state->_opcode == op_BLC /* BL  */
00894            ? direct_call
00895            : direct_jump;
00896          /* indirect calls are achieved by "lr blink,[status];
00897             lr dest<- func addr; j [dest]"  */
00898        }
00899 
00900       strcat (formatString, "%s"); /* Address/label name.  */
00901       arc_sprintf (state, state->operandBuffer, formatString,
00902                 post_address (state, fieldA));
00903       write_comments ();
00904       break;
00905 
00906     case CLASS_A4_JC:
00907       /* For op_JC -- jump to address specified.
00908         Also covers jump and link--bit 9 of the instr. word
00909         selects whether linked, thus "is_linked" is set above.  */
00910       fieldA = 0;
00911       CHECK_FIELD_B ();
00912       CHECK_FLAG_COND_NULLIFY ();
00913 
00914       if (!fieldBisReg)
00915        {
00916          fieldAisReg = 0;
00917          fieldA = (fieldB >> 25) & 0x7F; /* Flags.  */
00918          fieldB = (fieldB & 0xFFFFFF) << 2;
00919          state->flow = is_linked ? direct_call : direct_jump;
00920          add_target (fieldB);
00921          /* Screwy JLcc requires .jd mode to execute correctly
00922             but we pretend it is .nd (no delay slot).  */
00923          if (is_linked && state->nullifyMode == BR_exec_when_jump)
00924            state->nullifyMode = BR_exec_when_no_jump;
00925        }
00926       else
00927        {
00928          state->flow = is_linked ? indirect_call : indirect_jump;
00929          /* We should also treat this as indirect call if NOT linked
00930             but the preceding instruction was a "lr blink,[status]"
00931             and we have a delay slot with "add blink,blink,2".
00932             For now we can't detect such.  */
00933          state->register_for_indirect_jump = fieldB;
00934        }
00935 
00936       write_instr_name ();
00937       strcat (formatString,
00938              IS_REG (B) ? "[%r]" : "%s"); /* Address/label name.  */
00939       if (fieldA != 0)
00940        {
00941          fieldAisReg = 0;
00942          WRITE_FORMAT_COMMA_x (A);
00943        }
00944       if (IS_REG (B))
00945        arc_sprintf (state, state->operandBuffer, formatString, fieldB, fieldA);
00946       else
00947        arc_sprintf (state, state->operandBuffer, formatString,
00948                   post_address (state, fieldB), fieldA);
00949       write_comments ();
00950       break;
00951 
00952     case CLASS_A4_LD0:
00953       /* LD instruction.
00954         B and C can be regs, or one (both?) can be limm.  */
00955       CHECK_FIELD_A ();
00956       CHECK_FIELD_B ();
00957       CHECK_FIELD_C ();
00958       if (dbg)
00959        printf ("5:b reg %d %d c reg %d %d  \n",
00960               fieldBisReg,fieldB,fieldCisReg,fieldC);
00961       state->_offset = 0;
00962       state->_ea_present = 1;
00963       if (fieldBisReg)
00964        state->ea_reg1 = fieldB;
00965       else
00966        state->_offset += fieldB;
00967       if (fieldCisReg)
00968        state->ea_reg2 = fieldC;
00969       else
00970        state->_offset += fieldC;
00971       state->_mem_load = 1;
00972 
00973       directMem     = BIT (state->words[0], 5);
00974       addrWriteBack = BIT (state->words[0], 3);
00975       signExtend    = BIT (state->words[0], 0);
00976 
00977       write_instr_name ();
00978       WRITE_FORMAT_x_COMMA_LB(A);
00979       if (fieldBisReg || fieldB != 0)
00980        WRITE_FORMAT_x_COMMA (B);
00981       else
00982        fieldB = fieldC;
00983 
00984       WRITE_FORMAT_x_RB (C);
00985       arc_sprintf (state, state->operandBuffer, formatString,
00986                 fieldA, fieldB, fieldC);
00987       write_comments ();
00988       break;
00989 
00990     case CLASS_A4_LD1:
00991       /* LD instruction.  */
00992       CHECK_FIELD_B ();
00993       CHECK_FIELD_A ();
00994       fieldC = FIELDD (state->words[0]);
00995 
00996       if (dbg)
00997        printf ("6:b reg %d %d c 0x%x  \n",
00998               fieldBisReg, fieldB, fieldC);
00999       state->_ea_present = 1;
01000       state->_offset = fieldC;
01001       state->_mem_load = 1;
01002       if (fieldBisReg)
01003        state->ea_reg1 = fieldB;
01004       /* Field B is either a shimm (same as fieldC) or limm (different!)
01005         Say ea is not present, so only one of us will do the name lookup.  */
01006       else
01007        state->_offset += fieldB, state->_ea_present = 0;
01008 
01009       directMem     = BIT (state->words[0],14);
01010       addrWriteBack = BIT (state->words[0],12);
01011       signExtend    = BIT (state->words[0],9);
01012 
01013       write_instr_name ();
01014       WRITE_FORMAT_x_COMMA_LB (A);
01015       if (!fieldBisReg)
01016        {
01017          fieldB = state->_offset;
01018          WRITE_FORMAT_x_RB (B);
01019        }
01020       else
01021        {
01022          WRITE_FORMAT_x (B);
01023          if (fieldC != 0 && !BIT (state->words[0],13))
01024            {
01025              fieldCisReg = 0;
01026              WRITE_FORMAT_COMMA_x_RB (C);
01027            }
01028          else
01029            WRITE_FORMAT_RB ();
01030        }
01031       arc_sprintf (state, state->operandBuffer, formatString,
01032                 fieldA, fieldB, fieldC);
01033       write_comments ();
01034       break;
01035 
01036     case CLASS_A4_ST:
01037       /* ST instruction.  */
01038       CHECK_FIELD_B();
01039       CHECK_FIELD_C();
01040       fieldA = FIELDD(state->words[0]); /* shimm  */
01041 
01042       /* [B,A offset]  */
01043       if (dbg) printf("7:b reg %d %x off %x\n",
01044                     fieldBisReg,fieldB,fieldA);
01045       state->_ea_present = 1;
01046       state->_offset = fieldA;
01047       if (fieldBisReg)
01048        state->ea_reg1 = fieldB;
01049       /* Field B is either a shimm (same as fieldA) or limm (different!)
01050         Say ea is not present, so only one of us will do the name lookup.
01051         (for is_limm we do the name translation here).  */
01052       else
01053        state->_offset += fieldB, state->_ea_present = 0;
01054 
01055       directMem     = BIT (state->words[0], 26);
01056       addrWriteBack = BIT (state->words[0], 24);
01057 
01058       write_instr_name ();
01059       WRITE_FORMAT_x_COMMA_LB(C);
01060 
01061       if (!fieldBisReg)
01062        {
01063          fieldB = state->_offset;
01064          WRITE_FORMAT_x_RB (B);
01065        }
01066       else
01067        {
01068          WRITE_FORMAT_x (B);
01069          if (fieldBisReg && fieldA != 0)
01070            {
01071              fieldAisReg = 0;
01072              WRITE_FORMAT_COMMA_x_RB(A);
01073            }
01074          else
01075            WRITE_FORMAT_RB();
01076        }
01077       arc_sprintf (state, state->operandBuffer, formatString,
01078                 fieldC, fieldB, fieldA);
01079       write_comments2 (fieldA);
01080       break;
01081 
01082     case CLASS_A4_SR:
01083       /* SR instruction  */
01084       CHECK_FIELD_B();
01085       CHECK_FIELD_C();
01086 
01087       write_instr_name ();
01088       WRITE_FORMAT_x_COMMA_LB(C);
01089       /* Try to print B as an aux reg if it is not a core reg.  */
01090       usesAuxReg = 1;
01091       WRITE_FORMAT_x (B);
01092       WRITE_FORMAT_RB ();
01093       arc_sprintf (state, state->operandBuffer, formatString, fieldC, fieldB);
01094       write_comments ();
01095       break;
01096 
01097     case CLASS_A4_OP3_SUBOPC3F:
01098       write_instr_name ();
01099       state->operandBuffer[0] = '\0';
01100       break;
01101 
01102     case CLASS_A4_LR:
01103       /* LR instruction */
01104       CHECK_FIELD_A ();
01105       CHECK_FIELD_B ();
01106 
01107       write_instr_name ();
01108       WRITE_FORMAT_x_COMMA_LB (A);
01109       /* Try to print B as an aux reg if it is not a core reg. */
01110       usesAuxReg = 1;
01111       WRITE_FORMAT_x (B);
01112       WRITE_FORMAT_RB ();
01113       arc_sprintf (state, state->operandBuffer, formatString, fieldA, fieldB);
01114       write_comments ();
01115       break;
01116 
01117     default:
01118       mwerror (state, "Bad decoding class in ARC disassembler");
01119       break;
01120     }
01121 
01122   state->_cond = cond;
01123   return state->instructionLen = offset;
01124 }
01125 
01126 
01127 /* Returns the name the user specified core extension register.  */
01128 
01129 static const char *
01130 _coreRegName(void * arg ATTRIBUTE_UNUSED, int regval)
01131 {
01132   return arcExtMap_coreRegName (regval);
01133 }
01134 
01135 /* Returns the name the user specified AUX extension register.  */
01136 
01137 static const char *
01138 _auxRegName(void *_this ATTRIBUTE_UNUSED, int regval)
01139 {
01140   return arcExtMap_auxRegName(regval);
01141 }
01142 
01143 /* Returns the name the user specified condition code name.  */
01144 
01145 static const char *
01146 _condCodeName(void *_this ATTRIBUTE_UNUSED, int regval)
01147 {
01148   return arcExtMap_condCodeName(regval);
01149 }
01150 
01151 /* Returns the name the user specified extension instruction.  */
01152 
01153 static const char *
01154 _instName (void *_this ATTRIBUTE_UNUSED, int majop, int minop, int *flags)
01155 {
01156   return arcExtMap_instName(majop, minop, flags);
01157 }
01158 
01159 /* Decode an instruction returning the size of the instruction
01160    in bytes or zero if unrecognized.  */
01161 
01162 static int
01163 decodeInstr (bfd_vma            address, /* Address of this instruction.  */
01164             disassemble_info * info)
01165 {
01166   int status;
01167   bfd_byte buffer[4];
01168   struct arcDisState s;            /* ARC Disassembler state.  */
01169   void *stream = info->stream;     /* Output stream.  */
01170   fprintf_ftype func = info->fprintf_func;
01171   int bytes;
01172 
01173   memset (&s, 0, sizeof(struct arcDisState));
01174 
01175   /* read first instruction  */
01176   status = (*info->read_memory_func) (address, buffer, 4, info);
01177   if (status != 0)
01178     {
01179       (*info->memory_error_func) (status, address, info);
01180       return 0;
01181     }
01182   if (info->endian == BFD_ENDIAN_LITTLE)
01183     s.words[0] = bfd_getl32(buffer);
01184   else
01185     s.words[0] = bfd_getb32(buffer);
01186   /* Always read second word in case of limm.  */
01187 
01188   /* We ignore the result since last insn may not have a limm.  */
01189   status = (*info->read_memory_func) (address + 4, buffer, 4, info);
01190   if (info->endian == BFD_ENDIAN_LITTLE)
01191     s.words[1] = bfd_getl32(buffer);
01192   else
01193     s.words[1] = bfd_getb32(buffer);
01194 
01195   s._this = &s;
01196   s.coreRegName = _coreRegName;
01197   s.auxRegName = _auxRegName;
01198   s.condCodeName = _condCodeName;
01199   s.instName = _instName;
01200 
01201   /* Disassemble.  */
01202   bytes = dsmOneArcInst (address, (void *)& s);
01203 
01204   /* Display the disassembly instruction.  */
01205   (*func) (stream, "%08lx ", s.words[0]);
01206   (*func) (stream, "    ");
01207   (*func) (stream, "%-10s ", s.instrBuffer);
01208 
01209   if (__TRANSLATION_REQUIRED (s))
01210     {
01211       bfd_vma addr = s.addresses[s.operandBuffer[1] - '0'];
01212 
01213       (*info->print_address_func) ((bfd_vma) addr, info);
01214       (*func) (stream, "\n");
01215     }
01216   else
01217     (*func) (stream, "%s",s.operandBuffer);
01218 
01219   return s.instructionLen;
01220 }
01221 
01222 /* Return the print_insn function to use.
01223    Side effect: load (possibly empty) extension section  */
01224 
01225 disassembler_ftype
01226 arc_get_disassembler (void *ptr)
01227 {
01228   if (ptr)
01229     build_ARC_extmap (ptr);
01230   return decodeInstr;
01231 }