138889Sjdp/* Instruction printing code for the ARC.
2218822Sdim   Copyright 1994, 1995, 1997, 1998, 2000, 2001, 2002, 2005
385815Sobrien   Free Software Foundation, Inc.
438889Sjdp   Contributed by Doug Evans (dje@cygnus.com).
538889Sjdp
685815Sobrien   This program is free software; you can redistribute it and/or modify
785815Sobrien   it under the terms of the GNU General Public License as published by
885815Sobrien   the Free Software Foundation; either version 2 of the License, or
985815Sobrien   (at your option) any later version.
1038889Sjdp
1185815Sobrien   This program is distributed in the hope that it will be useful,
1285815Sobrien   but WITHOUT ANY WARRANTY; without even the implied warranty of
1385815Sobrien   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1485815Sobrien   GNU General Public License for more details.
1538889Sjdp
1685815Sobrien   You should have received a copy of the GNU General Public License
1785815Sobrien   along with this program; if not, write to the Free Software
18218822Sdim   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
19218822Sdim   MA 02110-1301, USA.  */
2038889Sjdp
21104834Sobrien#include "ansidecl.h"
22104834Sobrien#include "libiberty.h"
2338889Sjdp#include "dis-asm.h"
2438889Sjdp#include "opcode/arc.h"
2538889Sjdp#include "elf-bfd.h"
2638889Sjdp#include "elf/arc.h"
2785815Sobrien#include <string.h>
2860484Sobrien#include "opintl.h"
2938889Sjdp
3085815Sobrien#include <stdarg.h>
3185815Sobrien#include "arc-dis.h"
3285815Sobrien#include "arc-ext.h"
3338889Sjdp
3485815Sobrien#ifndef dbg
3585815Sobrien#define dbg (0)
3685815Sobrien#endif
3738889Sjdp
38218822Sdim/* Classification of the opcodes for the decoder to print
39218822Sdim   the instructions.  */
40218822Sdim
41218822Sdimtypedef enum
42218822Sdim{
43218822Sdim  CLASS_A4_ARITH,
44218822Sdim  CLASS_A4_OP3_GENERAL,
45218822Sdim  CLASS_A4_FLAG,
46218822Sdim  /* All branches other than JC.  */
47218822Sdim  CLASS_A4_BRANCH,
48218822Sdim  CLASS_A4_JC ,
49218822Sdim  /* All loads other than immediate
50218822Sdim     indexed loads.  */
51218822Sdim  CLASS_A4_LD0,
52218822Sdim  CLASS_A4_LD1,
53218822Sdim  CLASS_A4_ST,
54218822Sdim  CLASS_A4_SR,
55218822Sdim  /* All single operand instructions.  */
56218822Sdim  CLASS_A4_OP3_SUBOPC3F,
57218822Sdim  CLASS_A4_LR
58218822Sdim} a4_decoding_class;
59218822Sdim
6089857Sobrien#define BIT(word,n)	((word) & (1 << n))
6189857Sobrien#define BITS(word,s,e)  (((word) << (31 - e)) >> (s + (31 - e)))
6289857Sobrien#define OPCODE(word)	(BITS ((word), 27, 31))
6389857Sobrien#define FIELDA(word)	(BITS ((word), 21, 26))
6489857Sobrien#define FIELDB(word)	(BITS ((word), 15, 20))
6589857Sobrien#define FIELDC(word)	(BITS ((word),  9, 14))
6638889Sjdp
6785815Sobrien/* FIELD D is signed in all of its uses, so we make sure argument is
6885815Sobrien   treated as signed for bit shifting purposes:  */
6989857Sobrien#define FIELDD(word)	(BITS (((signed int)word), 0, 8))
7085815Sobrien
7189857Sobrien#define PUT_NEXT_WORD_IN(a)						\
7289857Sobrien  do									\
7389857Sobrien    {									\
7489857Sobrien      if (is_limm == 1 && !NEXT_WORD (1))				\
7589857Sobrien        mwerror (state, _("Illegal limm reference in last instruction!\n")); \
7689857Sobrien      a = state->words[1];						\
7789857Sobrien    }									\
7885815Sobrien  while (0)
7985815Sobrien
8085815Sobrien#define CHECK_FLAG_COND_NULLIFY()				\
8185815Sobrien  do								\
8285815Sobrien    {								\
8385815Sobrien      if (is_shimm == 0)					\
8485815Sobrien        {							\
8585815Sobrien          flag = BIT (state->words[0], 8);			\
8685815Sobrien          state->nullifyMode = BITS (state->words[0], 5, 6);	\
8785815Sobrien          cond = BITS (state->words[0], 0, 4);			\
8885815Sobrien        }							\
8985815Sobrien    }								\
9085815Sobrien  while (0)
9185815Sobrien
9285815Sobrien#define CHECK_COND()				\
9385815Sobrien  do						\
9485815Sobrien    {						\
9585815Sobrien      if (is_shimm == 0)			\
9685815Sobrien        cond = BITS (state->words[0], 0, 4);	\
9785815Sobrien    }						\
9885815Sobrien  while (0)
9985815Sobrien
10085815Sobrien#define CHECK_FIELD(field)			\
10185815Sobrien  do						\
10285815Sobrien    {						\
10385815Sobrien      if (field == 62)				\
10485815Sobrien        {					\
10585815Sobrien          is_limm++;				\
10685815Sobrien	  field##isReg = 0;			\
10785815Sobrien	  PUT_NEXT_WORD_IN (field);		\
10885815Sobrien	  limm_value = field;			\
10985815Sobrien	}					\
11085815Sobrien      else if (field > 60)			\
11185815Sobrien        {					\
11285815Sobrien	  field##isReg = 0;			\
11385815Sobrien	  is_shimm++;				\
11485815Sobrien	  flag = (field == 61);			\
11585815Sobrien	  field = FIELDD (state->words[0]);	\
11685815Sobrien	}					\
11785815Sobrien    }						\
11885815Sobrien  while (0)
11985815Sobrien
12085815Sobrien#define CHECK_FIELD_A()				\
12185815Sobrien  do						\
12285815Sobrien    {						\
12389857Sobrien      fieldA = FIELDA (state->words[0]);	\
12485815Sobrien      if (fieldA > 60)				\
12585815Sobrien        {					\
12685815Sobrien	  fieldAisReg = 0;			\
12785815Sobrien	  fieldA = 0;				\
12885815Sobrien	}					\
12985815Sobrien    }						\
13085815Sobrien  while (0)
13185815Sobrien
13285815Sobrien#define CHECK_FIELD_B()				\
13385815Sobrien  do						\
13485815Sobrien    {						\
13585815Sobrien      fieldB = FIELDB (state->words[0]);	\
13685815Sobrien      CHECK_FIELD (fieldB);			\
13785815Sobrien    }						\
13885815Sobrien  while (0)
13985815Sobrien
14085815Sobrien#define CHECK_FIELD_C()				\
14185815Sobrien  do						\
14285815Sobrien    {						\
14385815Sobrien      fieldC = FIELDC (state->words[0]);	\
14485815Sobrien      CHECK_FIELD (fieldC);			\
14585815Sobrien    }						\
14685815Sobrien  while (0)
14785815Sobrien
148218822Sdim#define IS_SMALL(x)                 (((field##x) < 256) && ((field##x) > -257))
149218822Sdim#define IS_REG(x)                    (field##x##isReg)
150218822Sdim#define WRITE_FORMAT_LB_Rx_RB(x)     WRITE_FORMAT (x, "[","]","","")
151218822Sdim#define WRITE_FORMAT_x_COMMA_LB(x)   WRITE_FORMAT (x, "",",[","",",[")
152218822Sdim#define WRITE_FORMAT_COMMA_x_RB(x)   WRITE_FORMAT (x, ",","]",",","]")
153218822Sdim#define WRITE_FORMAT_x_RB(x)         WRITE_FORMAT (x, "","]","","]")
154218822Sdim#define WRITE_FORMAT_COMMA_x(x)      WRITE_FORMAT (x, ",","",",","")
155218822Sdim#define WRITE_FORMAT_x_COMMA(x)      WRITE_FORMAT (x, "",",","",",")
156218822Sdim#define WRITE_FORMAT_x(x)            WRITE_FORMAT (x, "","","","")
15785815Sobrien#define WRITE_FORMAT(x,cb1,ca1,cb,ca) strcat (formatString,		\
15885815Sobrien				     (IS_REG (x) ? cb1"%r"ca1 :		\
15985815Sobrien				      usesAuxReg ? cb"%a"ca :		\
16085815Sobrien				      IS_SMALL (x) ? cb"%d"ca : cb"%h"ca))
16189857Sobrien#define WRITE_FORMAT_RB()	strcat (formatString, "]")
16285815Sobrien#define WRITE_COMMENT(str)	(state->comm[state->commNum++] = (str))
16389857Sobrien#define WRITE_NOP_COMMENT()	if (!fieldAisReg && !flag) WRITE_COMMENT ("nop");
16485815Sobrien
16589857Sobrien#define NEXT_WORD(x)	(offset += 4, state->words[x])
16685815Sobrien
16789857Sobrien#define add_target(x)	(state->targets[state->tcnt++] = (x))
16885815Sobrien
16985815Sobrienstatic char comment_prefix[] = "\t; ";
17085815Sobrien
17185815Sobrienstatic const char *
172218822Sdimcore_reg_name (struct arcDisState * state, int val)
17338889Sjdp{
17485815Sobrien  if (state->coreRegName)
17585815Sobrien    return (*state->coreRegName)(state->_this, val);
17685815Sobrien  return 0;
17785815Sobrien}
17838889Sjdp
17985815Sobrienstatic const char *
180218822Sdimaux_reg_name (struct arcDisState * state, int val)
18185815Sobrien{
18285815Sobrien  if (state->auxRegName)
18385815Sobrien    return (*state->auxRegName)(state->_this, val);
18485815Sobrien  return 0;
18585815Sobrien}
18685815Sobrien
18785815Sobrienstatic const char *
188218822Sdimcond_code_name (struct arcDisState * state, int val)
18985815Sobrien{
19085815Sobrien  if (state->condCodeName)
19185815Sobrien    return (*state->condCodeName)(state->_this, val);
19285815Sobrien  return 0;
19385815Sobrien}
19485815Sobrien
19585815Sobrienstatic const char *
196218822Sdiminstruction_name (struct arcDisState * state,
197218822Sdim		  int    op1,
198218822Sdim		  int    op2,
199218822Sdim		  int *  flags)
20085815Sobrien{
20185815Sobrien  if (state->instName)
20285815Sobrien    return (*state->instName)(state->_this, op1, op2, flags);
20385815Sobrien  return 0;
20485815Sobrien}
20585815Sobrien
20685815Sobrienstatic void
207218822Sdimmwerror (struct arcDisState * state, const char * msg)
20885815Sobrien{
20985815Sobrien  if (state->err != 0)
21085815Sobrien    (*state->err)(state->_this, (msg));
21185815Sobrien}
21285815Sobrien
21385815Sobrienstatic const char *
214218822Sdimpost_address (struct arcDisState * state, int addr)
21585815Sobrien{
21685815Sobrien  static char id[3 * ARRAY_SIZE (state->addresses)];
21785815Sobrien  int j, i = state->acnt;
21885815Sobrien
21985815Sobrien  if (i < ((int) ARRAY_SIZE (state->addresses)))
22038889Sjdp    {
22185815Sobrien      state->addresses[i] = addr;
22285815Sobrien      ++state->acnt;
22385815Sobrien      j = i*3;
22485815Sobrien      id[j+0] = '@';
22585815Sobrien      id[j+1] = '0'+i;
22685815Sobrien      id[j+2] = 0;
22789857Sobrien
22885815Sobrien      return id + j;
22938889Sjdp    }
23085815Sobrien  return "";
23185815Sobrien}
23238889Sjdp
23389857Sobrienstatic void
234218822Sdimarc_sprintf (struct arcDisState *state, char *buf, const char *format, ...)
23585815Sobrien{
23689857Sobrien  char *bp;
23785815Sobrien  const char *p;
23885815Sobrien  int size, leading_zero, regMap[2];
23985815Sobrien  long auxNum;
240218822Sdim  va_list ap;
24189857Sobrien
242218822Sdim  va_start (ap, format);
24389857Sobrien
24489857Sobrien  bp = buf;
24585815Sobrien  *bp = 0;
24685815Sobrien  p = format;
24785815Sobrien  auxNum = -1;
24885815Sobrien  regMap[0] = 0;
24985815Sobrien  regMap[1] = 0;
25089857Sobrien
25189857Sobrien  while (1)
25285815Sobrien    switch (*p++)
25385815Sobrien      {
25489857Sobrien      case 0:
25589857Sobrien	goto DOCOMM; /* (return)  */
25689857Sobrien      default:
25789857Sobrien	*bp++ = p[-1];
25885815Sobrien	break;
25985815Sobrien      case '%':
26085815Sobrien	size = 0;
26185815Sobrien	leading_zero = 0;
26285815Sobrien      RETRY: ;
26389857Sobrien	switch (*p++)
26485815Sobrien	  {
26585815Sobrien	  case '0':
26685815Sobrien	  case '1':
26785815Sobrien	  case '2':
26885815Sobrien	  case '3':
26985815Sobrien	  case '4':
27085815Sobrien	  case '5':
27185815Sobrien	  case '6':
27285815Sobrien	  case '7':
27385815Sobrien	  case '8':
27485815Sobrien	  case '9':
27585815Sobrien	    {
27685815Sobrien	      /* size.  */
27785815Sobrien	      size = p[-1] - '0';
27885815Sobrien	      if (size == 0)
27985815Sobrien		leading_zero = 1; /* e.g. %08x  */
28085815Sobrien	      while (*p >= '0' && *p <= '9')
28185815Sobrien		{
28285815Sobrien		  size = size * 10 + *p - '0';
28385815Sobrien		  p++;
28485815Sobrien		}
28585815Sobrien	      goto RETRY;
28685815Sobrien	    }
28785815Sobrien#define inc_bp() bp = bp + strlen (bp)
28885815Sobrien
28989857Sobrien	  case 'h':
29085815Sobrien	    {
29185815Sobrien	      unsigned u = va_arg (ap, int);
29285815Sobrien
29385815Sobrien	      /* Hex.  We can change the format to 0x%08x in
29485815Sobrien		 one place, here, if we wish.
29585815Sobrien		 We add underscores for easy reading.  */
29689857Sobrien	      if (u > 65536)
29785815Sobrien		sprintf (bp, "0x%x_%04x", u >> 16, u & 0xffff);
29889857Sobrien	      else
29985815Sobrien		sprintf (bp, "0x%x", u);
30085815Sobrien	      inc_bp ();
30189857Sobrien	    }
30285815Sobrien	    break;
30389857Sobrien	  case 'X': case 'x':
30485815Sobrien	    {
30585815Sobrien	      int val = va_arg (ap, int);
30685815Sobrien
30789857Sobrien	      if (size != 0)
30885815Sobrien		if (leading_zero)
30985815Sobrien		  sprintf (bp, "%0*x", size, val);
31085815Sobrien		else
31185815Sobrien		  sprintf (bp, "%*x", size, val);
31285815Sobrien	      else
31385815Sobrien		sprintf (bp, "%x", val);
31485815Sobrien	      inc_bp ();
31585815Sobrien	    }
31685815Sobrien	    break;
31789857Sobrien	  case 'd':
31885815Sobrien	    {
31985815Sobrien	      int val = va_arg (ap, int);
32089857Sobrien
32185815Sobrien	      if (size != 0)
32285815Sobrien		sprintf (bp, "%*d", size, val);
32385815Sobrien	      else
32485815Sobrien		sprintf (bp, "%d", val);
32585815Sobrien	      inc_bp ();
32685815Sobrien	    }
32785815Sobrien	    break;
32889857Sobrien	  case 'r':
32985815Sobrien	    {
33085815Sobrien	      /* Register.  */
33185815Sobrien	      int val = va_arg (ap, int);
33289857Sobrien
33385815Sobrien#define REG2NAME(num, name) case num: sprintf (bp, ""name); \
33485815Sobrien  regMap[(num < 32) ? 0 : 1] |= 1 << (num - ((num < 32) ? 0 : 32)); break;
33589857Sobrien
33689857Sobrien	      switch (val)
33785815Sobrien		{
33885815Sobrien		  REG2NAME (26, "gp");
33985815Sobrien		  REG2NAME (27, "fp");
34085815Sobrien		  REG2NAME (28, "sp");
34185815Sobrien		  REG2NAME (29, "ilink1");
34285815Sobrien		  REG2NAME (30, "ilink2");
34385815Sobrien		  REG2NAME (31, "blink");
34485815Sobrien		  REG2NAME (60, "lp_count");
34585815Sobrien		default:
34685815Sobrien		  {
34785815Sobrien		    const char * ext;
34885815Sobrien
34985815Sobrien		    ext = core_reg_name (state, val);
35085815Sobrien		    if (ext)
35185815Sobrien		      sprintf (bp, "%s", ext);
35285815Sobrien		    else
35385815Sobrien		      sprintf (bp,"r%d",val);
35485815Sobrien		  }
35585815Sobrien		  break;
35685815Sobrien		}
35785815Sobrien	      inc_bp ();
35885815Sobrien	    } break;
35989857Sobrien
36089857Sobrien	  case 'a':
36185815Sobrien	    {
36285815Sobrien	      /* Aux Register.  */
36385815Sobrien	      int val = va_arg (ap, int);
36485815Sobrien
36585815Sobrien#define AUXREG2NAME(num, name) case num: sprintf (bp,name); break;
36685815Sobrien
36789857Sobrien	      switch (val)
36885815Sobrien		{
36985815Sobrien		  AUXREG2NAME (0x0, "status");
37085815Sobrien		  AUXREG2NAME (0x1, "semaphore");
37185815Sobrien		  AUXREG2NAME (0x2, "lp_start");
37285815Sobrien		  AUXREG2NAME (0x3, "lp_end");
37385815Sobrien		  AUXREG2NAME (0x4, "identity");
37485815Sobrien		  AUXREG2NAME (0x5, "debug");
37585815Sobrien		default:
37685815Sobrien		  {
37785815Sobrien		    const char *ext;
37885815Sobrien
37985815Sobrien		    ext = aux_reg_name (state, val);
38085815Sobrien		    if (ext)
38185815Sobrien		      sprintf (bp, "%s", ext);
38285815Sobrien		    else
383218822Sdim		      arc_sprintf (state, bp, "%h", val);
38485815Sobrien		  }
38585815Sobrien		  break;
38685815Sobrien		}
38785815Sobrien	      inc_bp ();
38885815Sobrien	    }
38985815Sobrien	    break;
39089857Sobrien
39189857Sobrien	  case 's':
39285815Sobrien	    {
39385815Sobrien	      sprintf (bp, "%s", va_arg (ap, char *));
39485815Sobrien	      inc_bp ();
39585815Sobrien	    }
39685815Sobrien	    break;
39789857Sobrien
39885815Sobrien	  default:
39985815Sobrien	    fprintf (stderr, "?? format %c\n", p[-1]);
40085815Sobrien	    break;
40185815Sobrien	  }
40285815Sobrien      }
40385815Sobrien
40485815Sobrien DOCOMM: *bp = 0;
405218822Sdim  va_end (ap);
40685815Sobrien}
40785815Sobrien
40889857Sobrienstatic void
409218822Sdimwrite_comments_(struct arcDisState * state,
410218822Sdim		int shimm,
411218822Sdim		int is_limm,
412218822Sdim		long limm_value)
41385815Sobrien{
41489857Sobrien  if (state->commentBuffer != 0)
41538889Sjdp    {
41685815Sobrien      int i;
41785815Sobrien
41889857Sobrien      if (is_limm)
41985815Sobrien	{
42085815Sobrien	  const char *name = post_address (state, limm_value + shimm);
42185815Sobrien
42285815Sobrien	  if (*name != 0)
42385815Sobrien	    WRITE_COMMENT (name);
42485815Sobrien	}
42589857Sobrien      for (i = 0; i < state->commNum; i++)
42685815Sobrien	{
42785815Sobrien	  if (i == 0)
42885815Sobrien	    strcpy (state->commentBuffer, comment_prefix);
42985815Sobrien	  else
43089857Sobrien	    strcat (state->commentBuffer, ", ");
43189857Sobrien	  strncat (state->commentBuffer, state->comm[i],
43289857Sobrien		   sizeof (state->commentBuffer));
43385815Sobrien	}
43438889Sjdp    }
43585815Sobrien}
43638889Sjdp
437218822Sdim#define write_comments2(x) write_comments_ (state, x, is_limm, limm_value)
438218822Sdim#define write_comments()   write_comments2 (0)
43938889Sjdp
440218822Sdimstatic const char *condName[] =
441218822Sdim{
44285815Sobrien  /* 0..15.  */
44389857Sobrien  ""   , "z"  , "nz" , "p"  , "n"  , "c"  , "nc" , "v"  ,
44485815Sobrien  "nv" , "gt" , "ge" , "lt" , "le" , "hi" , "ls" , "pnz"
44585815Sobrien};
44638889Sjdp
44789857Sobrienstatic void
448218822Sdimwrite_instr_name_(struct arcDisState * state,
449218822Sdim		  const char * instrName,
450218822Sdim		  int cond,
451218822Sdim		  int condCodeIsPartOfName,
452218822Sdim		  int flag,
453218822Sdim		  int signExtend,
454218822Sdim		  int addrWriteBack,
455218822Sdim		  int directMem)
45685815Sobrien{
45785815Sobrien  strcpy (state->instrBuffer, instrName);
45885815Sobrien
45989857Sobrien  if (cond > 0)
46038889Sjdp    {
46185815Sobrien      const char *cc = 0;
46238889Sjdp
46385815Sobrien      if (!condCodeIsPartOfName)
46485815Sobrien	strcat (state->instrBuffer, ".");
46538889Sjdp
46685815Sobrien      if (cond < 16)
46785815Sobrien	cc = condName[cond];
46885815Sobrien      else
46985815Sobrien	cc = cond_code_name (state, cond);
47038889Sjdp
47185815Sobrien      if (!cc)
47285815Sobrien	cc = "???";
47338889Sjdp
47485815Sobrien      strcat (state->instrBuffer, cc);
47585815Sobrien    }
47638889Sjdp
47785815Sobrien  if (flag)
47885815Sobrien    strcat (state->instrBuffer, ".f");
47938889Sjdp
48089857Sobrien  switch (state->nullifyMode)
48185815Sobrien    {
48285815Sobrien    case BR_exec_always:
48385815Sobrien      strcat (state->instrBuffer, ".d");
48485815Sobrien      break;
48585815Sobrien    case BR_exec_when_jump:
48685815Sobrien      strcat (state->instrBuffer, ".jd");
48785815Sobrien      break;
48885815Sobrien    }
48938889Sjdp
49085815Sobrien  if (signExtend)
49185815Sobrien    strcat (state->instrBuffer, ".x");
49238889Sjdp
49385815Sobrien  if (addrWriteBack)
49485815Sobrien    strcat (state->instrBuffer, ".a");
49538889Sjdp
49685815Sobrien  if (directMem)
49785815Sobrien    strcat (state->instrBuffer, ".di");
49885815Sobrien}
49985815Sobrien
50085815Sobrien#define write_instr_name()						\
50185815Sobrien  do									\
50285815Sobrien    {									\
50385815Sobrien      write_instr_name_(state, instrName,cond, condCodeIsPartOfName,	\
50485815Sobrien			flag, signExtend, addrWriteBack, directMem);	\
50585815Sobrien      formatString[0] = '\0';						\
50685815Sobrien    }									\
50785815Sobrien  while (0)
50885815Sobrien
509218822Sdimenum
510218822Sdim{
51189857Sobrien  op_LD0 = 0, op_LD1 = 1, op_ST  = 2, op_3   = 3,
51285815Sobrien  op_BC  = 4, op_BLC = 5, op_LPC = 6, op_JC  = 7,
51389857Sobrien  op_ADD = 8, op_ADC = 9, op_SUB = 10, op_SBC = 11,
51485815Sobrien  op_AND = 12, op_OR  = 13, op_BIC = 14, op_XOR = 15
51585815Sobrien};
51685815Sobrien
51785815Sobrienextern disassemble_info tm_print_insn_info;
51885815Sobrien
51989857Sobrienstatic int
520218822SdimdsmOneArcInst (bfd_vma addr, struct arcDisState * state)
52185815Sobrien{
52285815Sobrien  int condCodeIsPartOfName = 0;
523218822Sdim  a4_decoding_class decodingClass;
52485815Sobrien  const char * instrName;
52585815Sobrien  int repeatsOp = 0;
52685815Sobrien  int fieldAisReg = 1;
52785815Sobrien  int fieldBisReg = 1;
52885815Sobrien  int fieldCisReg = 1;
52985815Sobrien  int fieldA;
53085815Sobrien  int fieldB;
53185815Sobrien  int fieldC = 0;
53285815Sobrien  int flag = 0;
53385815Sobrien  int cond = 0;
53485815Sobrien  int is_shimm = 0;
53585815Sobrien  int is_limm = 0;
53685815Sobrien  long limm_value = 0;
53785815Sobrien  int signExtend = 0;
53885815Sobrien  int addrWriteBack = 0;
53985815Sobrien  int directMem = 0;
54085815Sobrien  int is_linked = 0;
54185815Sobrien  int offset = 0;
54285815Sobrien  int usesAuxReg = 0;
54385815Sobrien  int flags;
54485815Sobrien  int ignoreFirstOpd;
54585815Sobrien  char formatString[60];
54689857Sobrien
54785815Sobrien  state->instructionLen = 4;
54885815Sobrien  state->nullifyMode = BR_exec_when_no_jump;
54985815Sobrien  state->opWidth = 12;
55085815Sobrien  state->isBranch = 0;
55189857Sobrien
55285815Sobrien  state->_mem_load = 0;
55385815Sobrien  state->_ea_present = 0;
55485815Sobrien  state->_load_len = 0;
55585815Sobrien  state->ea_reg1 = no_reg;
55685815Sobrien  state->ea_reg2 = no_reg;
55785815Sobrien  state->_offset = 0;
55889857Sobrien
55985815Sobrien  if (! NEXT_WORD (0))
56085815Sobrien    return 0;
56189857Sobrien
56285815Sobrien  state->_opcode = OPCODE (state->words[0]);
56385815Sobrien  instrName = 0;
564218822Sdim  decodingClass = CLASS_A4_ARITH; /* default!  */
56585815Sobrien  repeatsOp = 0;
56685815Sobrien  condCodeIsPartOfName=0;
56785815Sobrien  state->commNum = 0;
56885815Sobrien  state->tcnt = 0;
56985815Sobrien  state->acnt = 0;
57085815Sobrien  state->flow = noflow;
57185815Sobrien  ignoreFirstOpd = 0;
57285815Sobrien
57385815Sobrien  if (state->commentBuffer)
57485815Sobrien    state->commentBuffer[0] = '\0';
57585815Sobrien
57689857Sobrien  switch (state->_opcode)
57785815Sobrien    {
57889857Sobrien    case op_LD0:
57989857Sobrien      switch (BITS (state->words[0],1,2))
58038889Sjdp	{
58185815Sobrien	case 0:
58285815Sobrien	  instrName = "ld";
58385815Sobrien	  state->_load_len = 4;
58485815Sobrien	  break;
58585815Sobrien	case 1:
58685815Sobrien	  instrName = "ldb";
58785815Sobrien	  state->_load_len = 1;
58885815Sobrien	  break;
58985815Sobrien	case 2:
59085815Sobrien	  instrName = "ldw";
59185815Sobrien	  state->_load_len = 2;
59285815Sobrien	  break;
59385815Sobrien	default:
59489857Sobrien	  instrName = "??? (0[3])";
59585815Sobrien	  state->flow = invalid_instr;
59685815Sobrien	  break;
59785815Sobrien	}
598218822Sdim      decodingClass = CLASS_A4_LD0;
59985815Sobrien      break;
60089857Sobrien
60189857Sobrien    case op_LD1:
60289857Sobrien      if (BIT (state->words[0],13))
60385815Sobrien	{
60489857Sobrien	  instrName = "lr";
605218822Sdim	  decodingClass = CLASS_A4_LR;
60685815Sobrien	}
60789857Sobrien      else
60885815Sobrien	{
609218822Sdim	  switch (BITS (state->words[0], 10, 11))
61038889Sjdp	    {
61185815Sobrien	    case 0:
61285815Sobrien	      instrName = "ld";
61385815Sobrien	      state->_load_len = 4;
61485815Sobrien	      break;
61585815Sobrien	    case 1:
61685815Sobrien	      instrName = "ldb";
61785815Sobrien	      state->_load_len = 1;
61885815Sobrien	      break;
61985815Sobrien	    case 2:
62085815Sobrien	      instrName = "ldw";
62185815Sobrien	      state->_load_len = 2;
62285815Sobrien	      break;
62385815Sobrien	    default:
62489857Sobrien	      instrName = "??? (1[3])";
62585815Sobrien	      state->flow = invalid_instr;
62685815Sobrien	      break;
62738889Sjdp	    }
628218822Sdim	  decodingClass = CLASS_A4_LD1;
62938889Sjdp	}
63085815Sobrien      break;
63189857Sobrien
63285815Sobrien    case op_ST:
633218822Sdim      if (BIT (state->words[0], 25))
63438889Sjdp	{
63585815Sobrien	  instrName = "sr";
636218822Sdim	  decodingClass = CLASS_A4_SR;
63785815Sobrien	}
63889857Sobrien      else
63985815Sobrien	{
640218822Sdim	  switch (BITS (state->words[0], 22, 23))
64138889Sjdp	    {
64285815Sobrien	    case 0:
64385815Sobrien	      instrName = "st";
64485815Sobrien	      break;
64585815Sobrien	    case 1:
64685815Sobrien	      instrName = "stb";
64785815Sobrien	      break;
64885815Sobrien	    case 2:
64985815Sobrien	      instrName = "stw";
65085815Sobrien	      break;
65185815Sobrien	    default:
65289857Sobrien	      instrName = "??? (2[3])";
65385815Sobrien	      state->flow = invalid_instr;
65485815Sobrien	      break;
65538889Sjdp	    }
656218822Sdim	  decodingClass = CLASS_A4_ST;
65785815Sobrien	}
65885815Sobrien      break;
65989857Sobrien
66085815Sobrien    case op_3:
661218822Sdim      decodingClass = CLASS_A4_OP3_GENERAL;  /* default for opcode 3...  */
66289857Sobrien      switch (FIELDC (state->words[0]))
66385815Sobrien	{
66485815Sobrien	case  0:
66589857Sobrien	  instrName = "flag";
666218822Sdim	  decodingClass = CLASS_A4_FLAG;
66785815Sobrien	  break;
66885815Sobrien	case  1:
66985815Sobrien	  instrName = "asr";
67085815Sobrien	  break;
67185815Sobrien	case  2:
67285815Sobrien	  instrName = "lsr";
67385815Sobrien	  break;
67485815Sobrien	case  3:
67585815Sobrien	  instrName = "ror";
67685815Sobrien	  break;
67785815Sobrien	case  4:
67885815Sobrien	  instrName = "rrc";
67985815Sobrien	  break;
68085815Sobrien	case  5:
68185815Sobrien	  instrName = "sexb";
68285815Sobrien	  break;
68385815Sobrien	case  6:
68485815Sobrien	  instrName = "sexw";
68585815Sobrien	  break;
68685815Sobrien	case  7:
68785815Sobrien	  instrName = "extb";
68885815Sobrien	  break;
68985815Sobrien	case  8:
69085815Sobrien	  instrName = "extw";
69185815Sobrien	  break;
69289857Sobrien	case  0x3f:
69385815Sobrien	  {
694218822Sdim	    decodingClass = CLASS_A4_OP3_SUBOPC3F;
695218822Sdim	    switch (FIELDD (state->words[0]))
69685815Sobrien	      {
69785815Sobrien	      case 0:
69885815Sobrien		instrName = "brk";
69985815Sobrien		break;
70085815Sobrien	      case 1:
70185815Sobrien		instrName = "sleep";
70285815Sobrien		break;
70385815Sobrien	      case 2:
70485815Sobrien		instrName = "swi";
70585815Sobrien		break;
70685815Sobrien	      default:
70785815Sobrien		instrName = "???";
70885815Sobrien		state->flow=invalid_instr;
70985815Sobrien		break;
71085815Sobrien	      }
71185815Sobrien	  }
71285815Sobrien	  break;
71389857Sobrien
71485815Sobrien	  /* ARC Extension Library Instructions
71585815Sobrien	     NOTE: We assume that extension codes are these instrs.  */
71685815Sobrien	default:
71785815Sobrien	  instrName = instruction_name (state,
71885815Sobrien					state->_opcode,
71985815Sobrien					FIELDC (state->words[0]),
72089857Sobrien					&flags);
72185815Sobrien	  if (!instrName)
72238889Sjdp	    {
72385815Sobrien	      instrName = "???";
72485815Sobrien	      state->flow = invalid_instr;
72538889Sjdp	    }
72685815Sobrien	  if (flags & IGNORE_FIRST_OPD)
72785815Sobrien	    ignoreFirstOpd = 1;
72885815Sobrien	  break;
72985815Sobrien	}
73085815Sobrien      break;
73138889Sjdp
73285815Sobrien    case op_BC:
73389857Sobrien      instrName = "b";
73485815Sobrien    case op_BLC:
73585815Sobrien      if (!instrName)
73689857Sobrien	instrName = "bl";
73785815Sobrien    case op_LPC:
73885815Sobrien      if (!instrName)
73989857Sobrien	instrName = "lp";
74085815Sobrien    case op_JC:
74185815Sobrien      if (!instrName)
74285815Sobrien	{
74389857Sobrien	  if (BITS (state->words[0],9,9))
74438889Sjdp	    {
74589857Sobrien	      instrName = "jl";
74685815Sobrien	      is_linked = 1;
74738889Sjdp	    }
74889857Sobrien	  else
74938889Sjdp	    {
75089857Sobrien	      instrName = "j";
75185815Sobrien	      is_linked = 0;
75238889Sjdp	    }
75385815Sobrien	}
75485815Sobrien      condCodeIsPartOfName = 1;
755218822Sdim      decodingClass = ((state->_opcode == op_JC) ? CLASS_A4_JC : CLASS_A4_BRANCH );
75685815Sobrien      state->isBranch = 1;
75785815Sobrien      break;
75889857Sobrien
75985815Sobrien    case op_ADD:
76085815Sobrien    case op_ADC:
76185815Sobrien    case op_AND:
76285815Sobrien      repeatsOp = (FIELDC (state->words[0]) == FIELDB (state->words[0]));
76338889Sjdp
76489857Sobrien      switch (state->_opcode)
76585815Sobrien	{
76685815Sobrien	case op_ADD:
76785815Sobrien	  instrName = (repeatsOp ? "asl" : "add");
76885815Sobrien	  break;
76985815Sobrien	case op_ADC:
77085815Sobrien	  instrName = (repeatsOp ? "rlc" : "adc");
77185815Sobrien	  break;
77285815Sobrien	case op_AND:
77385815Sobrien	  instrName = (repeatsOp ? "mov" : "and");
77485815Sobrien	  break;
77585815Sobrien	}
77685815Sobrien      break;
77789857Sobrien
77885815Sobrien    case op_SUB: instrName = "sub";
77985815Sobrien      break;
78085815Sobrien    case op_SBC: instrName = "sbc";
78185815Sobrien      break;
78285815Sobrien    case op_OR:  instrName = "or";
78385815Sobrien      break;
78485815Sobrien    case op_BIC: instrName = "bic";
78585815Sobrien      break;
78685815Sobrien
78785815Sobrien    case op_XOR:
78885815Sobrien      if (state->words[0] == 0x7fffffff)
78985815Sobrien	{
790218822Sdim	  /* NOP encoded as xor -1, -1, -1.   */
79185815Sobrien	  instrName = "nop";
792218822Sdim	  decodingClass = CLASS_A4_OP3_SUBOPC3F;
79385815Sobrien	}
79489857Sobrien      else
79585815Sobrien	instrName = "xor";
79685815Sobrien      break;
79789857Sobrien
79885815Sobrien    default:
79985815Sobrien      instrName = instruction_name (state,state->_opcode,0,&flags);
80085815Sobrien      /* if (instrName) printf("FLAGS=0x%x\n", flags);  */
80185815Sobrien      if (!instrName)
80285815Sobrien	{
80385815Sobrien	  instrName = "???";
80485815Sobrien	  state->flow=invalid_instr;
80585815Sobrien	}
80685815Sobrien      if (flags & IGNORE_FIRST_OPD)
80785815Sobrien	ignoreFirstOpd = 1;
80885815Sobrien      break;
80985815Sobrien    }
81089857Sobrien
81185815Sobrien  fieldAisReg = fieldBisReg = fieldCisReg = 1; /* Assume regs for now.  */
81285815Sobrien  flag = cond = is_shimm = is_limm = 0;
81385815Sobrien  state->nullifyMode = BR_exec_when_no_jump;	/* 0  */
81485815Sobrien  signExtend = addrWriteBack = directMem = 0;
81585815Sobrien  usesAuxReg = 0;
81689857Sobrien
81789857Sobrien  switch (decodingClass)
81885815Sobrien    {
819218822Sdim    case CLASS_A4_ARITH:
82085815Sobrien      CHECK_FIELD_A ();
82185815Sobrien      CHECK_FIELD_B ();
82285815Sobrien      if (!repeatsOp)
82385815Sobrien	CHECK_FIELD_C ();
82485815Sobrien      CHECK_FLAG_COND_NULLIFY ();
82589857Sobrien
82685815Sobrien      write_instr_name ();
82789857Sobrien      if (!ignoreFirstOpd)
82885815Sobrien	{
82985815Sobrien	  WRITE_FORMAT_x (A);
83085815Sobrien	  WRITE_FORMAT_COMMA_x (B);
83185815Sobrien	  if (!repeatsOp)
83285815Sobrien	    WRITE_FORMAT_COMMA_x (C);
83385815Sobrien	  WRITE_NOP_COMMENT ();
834218822Sdim	  arc_sprintf (state, state->operandBuffer, formatString,
83589857Sobrien		      fieldA, fieldB, fieldC);
83685815Sobrien	}
83789857Sobrien      else
83885815Sobrien	{
83985815Sobrien	  WRITE_FORMAT_x (B);
84085815Sobrien	  if (!repeatsOp)
84185815Sobrien	    WRITE_FORMAT_COMMA_x (C);
842218822Sdim	  arc_sprintf (state, state->operandBuffer, formatString,
84389857Sobrien		      fieldB, fieldC);
84485815Sobrien	}
84585815Sobrien      write_comments ();
84685815Sobrien      break;
84789857Sobrien
848218822Sdim    case CLASS_A4_OP3_GENERAL:
84985815Sobrien      CHECK_FIELD_A ();
85085815Sobrien      CHECK_FIELD_B ();
85185815Sobrien      CHECK_FLAG_COND_NULLIFY ();
85289857Sobrien
85385815Sobrien      write_instr_name ();
85489857Sobrien      if (!ignoreFirstOpd)
85585815Sobrien	{
85685815Sobrien	  WRITE_FORMAT_x (A);
85785815Sobrien	  WRITE_FORMAT_COMMA_x (B);
85885815Sobrien	  WRITE_NOP_COMMENT ();
859218822Sdim	  arc_sprintf (state, state->operandBuffer, formatString,
86089857Sobrien		      fieldA, fieldB);
86185815Sobrien	}
86289857Sobrien      else
86385815Sobrien	{
86485815Sobrien	  WRITE_FORMAT_x (B);
865218822Sdim	  arc_sprintf (state, state->operandBuffer, formatString, fieldB);
86685815Sobrien	}
86785815Sobrien      write_comments ();
86885815Sobrien      break;
86989857Sobrien
870218822Sdim    case CLASS_A4_FLAG:
87185815Sobrien      CHECK_FIELD_B ();
87285815Sobrien      CHECK_FLAG_COND_NULLIFY ();
873218822Sdim      flag = 0; /* This is the FLAG instruction -- it's redundant.  */
87489857Sobrien
87585815Sobrien      write_instr_name ();
87685815Sobrien      WRITE_FORMAT_x (B);
877218822Sdim      arc_sprintf (state, state->operandBuffer, formatString, fieldB);
87885815Sobrien      write_comments ();
87985815Sobrien      break;
88089857Sobrien
881218822Sdim    case CLASS_A4_BRANCH:
88285815Sobrien      fieldA = BITS (state->words[0],7,26) << 2;
883218822Sdim      fieldA = (fieldA << 10) >> 10; /* Make it signed.  */
88485815Sobrien      fieldA += addr + 4;
88585815Sobrien      CHECK_FLAG_COND_NULLIFY ();
88685815Sobrien      flag = 0;
88789857Sobrien
88885815Sobrien      write_instr_name ();
88985815Sobrien      /* This address could be a label we know. Convert it.  */
89089857Sobrien      if (state->_opcode != op_LPC /* LP  */)
89185815Sobrien	{
89289857Sobrien	  add_target (fieldA); /* For debugger.  */
89389857Sobrien	  state->flow = state->_opcode == op_BLC /* BL  */
89489857Sobrien	    ? direct_call
89589857Sobrien	    : direct_jump;
89689857Sobrien	  /* indirect calls are achieved by "lr blink,[status];
89789857Sobrien	     lr dest<- func addr; j [dest]"  */
89889857Sobrien	}
89989857Sobrien
900218822Sdim      strcat (formatString, "%s"); /* Address/label name.  */
901218822Sdim      arc_sprintf (state, state->operandBuffer, formatString,
90289857Sobrien		  post_address (state, fieldA));
90385815Sobrien      write_comments ();
90485815Sobrien      break;
90589857Sobrien
906218822Sdim    case CLASS_A4_JC:
90785815Sobrien      /* For op_JC -- jump to address specified.
90885815Sobrien	 Also covers jump and link--bit 9 of the instr. word
90985815Sobrien	 selects whether linked, thus "is_linked" is set above.  */
91085815Sobrien      fieldA = 0;
91185815Sobrien      CHECK_FIELD_B ();
91285815Sobrien      CHECK_FLAG_COND_NULLIFY ();
91389857Sobrien
91489857Sobrien      if (!fieldBisReg)
91585815Sobrien	{
91685815Sobrien	  fieldAisReg = 0;
917218822Sdim	  fieldA = (fieldB >> 25) & 0x7F; /* Flags.  */
91885815Sobrien	  fieldB = (fieldB & 0xFFFFFF) << 2;
91985815Sobrien	  state->flow = is_linked ? direct_call : direct_jump;
92085815Sobrien	  add_target (fieldB);
921218822Sdim	  /* Screwy JLcc requires .jd mode to execute correctly
922218822Sdim	     but we pretend it is .nd (no delay slot).  */
92385815Sobrien	  if (is_linked && state->nullifyMode == BR_exec_when_jump)
92485815Sobrien	    state->nullifyMode = BR_exec_when_no_jump;
92585815Sobrien	}
92689857Sobrien      else
92785815Sobrien	{
92885815Sobrien	  state->flow = is_linked ? indirect_call : indirect_jump;
92985815Sobrien	  /* We should also treat this as indirect call if NOT linked
930218822Sdim	     but the preceding instruction was a "lr blink,[status]"
931218822Sdim	     and we have a delay slot with "add blink,blink,2".
932218822Sdim	     For now we can't detect such.  */
93385815Sobrien	  state->register_for_indirect_jump = fieldB;
93485815Sobrien	}
93589857Sobrien
93685815Sobrien      write_instr_name ();
93789857Sobrien      strcat (formatString,
938218822Sdim	      IS_REG (B) ? "[%r]" : "%s"); /* Address/label name.  */
93989857Sobrien      if (fieldA != 0)
94085815Sobrien	{
94185815Sobrien	  fieldAisReg = 0;
94285815Sobrien	  WRITE_FORMAT_COMMA_x (A);
94385815Sobrien	}
94485815Sobrien      if (IS_REG (B))
945218822Sdim	arc_sprintf (state, state->operandBuffer, formatString, fieldB, fieldA);
94685815Sobrien      else
947218822Sdim	arc_sprintf (state, state->operandBuffer, formatString,
94885815Sobrien		    post_address (state, fieldB), fieldA);
94985815Sobrien      write_comments ();
95085815Sobrien      break;
95189857Sobrien
952218822Sdim    case CLASS_A4_LD0:
95385815Sobrien      /* LD instruction.
95485815Sobrien	 B and C can be regs, or one (both?) can be limm.  */
95585815Sobrien      CHECK_FIELD_A ();
95685815Sobrien      CHECK_FIELD_B ();
95785815Sobrien      CHECK_FIELD_C ();
95885815Sobrien      if (dbg)
95985815Sobrien	printf ("5:b reg %d %d c reg %d %d  \n",
96085815Sobrien		fieldBisReg,fieldB,fieldCisReg,fieldC);
96185815Sobrien      state->_offset = 0;
96285815Sobrien      state->_ea_present = 1;
96385815Sobrien      if (fieldBisReg)
96485815Sobrien	state->ea_reg1 = fieldB;
96585815Sobrien      else
96685815Sobrien	state->_offset += fieldB;
96785815Sobrien      if (fieldCisReg)
96885815Sobrien	state->ea_reg2 = fieldC;
96985815Sobrien      else
97085815Sobrien	state->_offset += fieldC;
97185815Sobrien      state->_mem_load = 1;
97289857Sobrien
973218822Sdim      directMem     = BIT (state->words[0], 5);
974218822Sdim      addrWriteBack = BIT (state->words[0], 3);
975218822Sdim      signExtend    = BIT (state->words[0], 0);
97689857Sobrien
97785815Sobrien      write_instr_name ();
97885815Sobrien      WRITE_FORMAT_x_COMMA_LB(A);
97985815Sobrien      if (fieldBisReg || fieldB != 0)
98085815Sobrien	WRITE_FORMAT_x_COMMA (B);
98185815Sobrien      else
98285815Sobrien	fieldB = fieldC;
98389857Sobrien
98485815Sobrien      WRITE_FORMAT_x_RB (C);
985218822Sdim      arc_sprintf (state, state->operandBuffer, formatString,
98689857Sobrien		  fieldA, fieldB, fieldC);
98785815Sobrien      write_comments ();
98885815Sobrien      break;
98989857Sobrien
990218822Sdim    case CLASS_A4_LD1:
99185815Sobrien      /* LD instruction.  */
99285815Sobrien      CHECK_FIELD_B ();
99385815Sobrien      CHECK_FIELD_A ();
99485815Sobrien      fieldC = FIELDD (state->words[0]);
99589857Sobrien
99685815Sobrien      if (dbg)
99785815Sobrien	printf ("6:b reg %d %d c 0x%x  \n",
99885815Sobrien		fieldBisReg, fieldB, fieldC);
99985815Sobrien      state->_ea_present = 1;
100085815Sobrien      state->_offset = fieldC;
100185815Sobrien      state->_mem_load = 1;
100285815Sobrien      if (fieldBisReg)
100385815Sobrien	state->ea_reg1 = fieldB;
1004218822Sdim      /* Field B is either a shimm (same as fieldC) or limm (different!)
100585815Sobrien	 Say ea is not present, so only one of us will do the name lookup.  */
100685815Sobrien      else
100785815Sobrien	state->_offset += fieldB, state->_ea_present = 0;
100889857Sobrien
100985815Sobrien      directMem     = BIT (state->words[0],14);
101085815Sobrien      addrWriteBack = BIT (state->words[0],12);
101185815Sobrien      signExtend    = BIT (state->words[0],9);
101289857Sobrien
101385815Sobrien      write_instr_name ();
101485815Sobrien      WRITE_FORMAT_x_COMMA_LB (A);
101589857Sobrien      if (!fieldBisReg)
101685815Sobrien	{
101785815Sobrien	  fieldB = state->_offset;
101885815Sobrien	  WRITE_FORMAT_x_RB (B);
101985815Sobrien	}
102089857Sobrien      else
102185815Sobrien	{
102285815Sobrien	  WRITE_FORMAT_x (B);
102389857Sobrien	  if (fieldC != 0 && !BIT (state->words[0],13))
102438889Sjdp	    {
102585815Sobrien	      fieldCisReg = 0;
102685815Sobrien	      WRITE_FORMAT_COMMA_x_RB (C);
102738889Sjdp	    }
102838889Sjdp	  else
102985815Sobrien	    WRITE_FORMAT_RB ();
103038889Sjdp	}
1031218822Sdim      arc_sprintf (state, state->operandBuffer, formatString,
103289857Sobrien		  fieldA, fieldB, fieldC);
103385815Sobrien      write_comments ();
103485815Sobrien      break;
103589857Sobrien
1036218822Sdim    case CLASS_A4_ST:
103785815Sobrien      /* ST instruction.  */
103885815Sobrien      CHECK_FIELD_B();
103985815Sobrien      CHECK_FIELD_C();
104085815Sobrien      fieldA = FIELDD(state->words[0]); /* shimm  */
104189857Sobrien
104285815Sobrien      /* [B,A offset]  */
104385815Sobrien      if (dbg) printf("7:b reg %d %x off %x\n",
104489857Sobrien		      fieldBisReg,fieldB,fieldA);
104585815Sobrien      state->_ea_present = 1;
104685815Sobrien      state->_offset = fieldA;
104785815Sobrien      if (fieldBisReg)
104885815Sobrien	state->ea_reg1 = fieldB;
1049218822Sdim      /* Field B is either a shimm (same as fieldA) or limm (different!)
105085815Sobrien	 Say ea is not present, so only one of us will do the name lookup.
105185815Sobrien	 (for is_limm we do the name translation here).  */
105289857Sobrien      else
105385815Sobrien	state->_offset += fieldB, state->_ea_present = 0;
105489857Sobrien
1055218822Sdim      directMem     = BIT (state->words[0], 26);
1056218822Sdim      addrWriteBack = BIT (state->words[0], 24);
105789857Sobrien
1058218822Sdim      write_instr_name ();
105985815Sobrien      WRITE_FORMAT_x_COMMA_LB(C);
106089857Sobrien
106189857Sobrien      if (!fieldBisReg)
106285815Sobrien	{
106385815Sobrien	  fieldB = state->_offset;
1064218822Sdim	  WRITE_FORMAT_x_RB (B);
106585815Sobrien	}
106689857Sobrien      else
106785815Sobrien	{
1068218822Sdim	  WRITE_FORMAT_x (B);
106989857Sobrien	  if (fieldBisReg && fieldA != 0)
107085815Sobrien	    {
107185815Sobrien	      fieldAisReg = 0;
107285815Sobrien	      WRITE_FORMAT_COMMA_x_RB(A);
107385815Sobrien	    }
107485815Sobrien	  else
107585815Sobrien	    WRITE_FORMAT_RB();
107685815Sobrien	}
1077218822Sdim      arc_sprintf (state, state->operandBuffer, formatString,
107889857Sobrien		  fieldC, fieldB, fieldA);
1079218822Sdim      write_comments2 (fieldA);
108085815Sobrien      break;
1081218822Sdim
1082218822Sdim    case CLASS_A4_SR:
108385815Sobrien      /* SR instruction  */
108485815Sobrien      CHECK_FIELD_B();
108585815Sobrien      CHECK_FIELD_C();
108689857Sobrien
1087218822Sdim      write_instr_name ();
108885815Sobrien      WRITE_FORMAT_x_COMMA_LB(C);
108985815Sobrien      /* Try to print B as an aux reg if it is not a core reg.  */
109085815Sobrien      usesAuxReg = 1;
1091218822Sdim      WRITE_FORMAT_x (B);
1092218822Sdim      WRITE_FORMAT_RB ();
1093218822Sdim      arc_sprintf (state, state->operandBuffer, formatString, fieldC, fieldB);
1094218822Sdim      write_comments ();
109585815Sobrien      break;
109689857Sobrien
1097218822Sdim    case CLASS_A4_OP3_SUBOPC3F:
1098218822Sdim      write_instr_name ();
109985815Sobrien      state->operandBuffer[0] = '\0';
110085815Sobrien      break;
110189857Sobrien
1102218822Sdim    case CLASS_A4_LR:
110385815Sobrien      /* LR instruction */
1104218822Sdim      CHECK_FIELD_A ();
1105218822Sdim      CHECK_FIELD_B ();
110689857Sobrien
1107218822Sdim      write_instr_name ();
1108218822Sdim      WRITE_FORMAT_x_COMMA_LB (A);
110985815Sobrien      /* Try to print B as an aux reg if it is not a core reg. */
111085815Sobrien      usesAuxReg = 1;
1111218822Sdim      WRITE_FORMAT_x (B);
1112218822Sdim      WRITE_FORMAT_RB ();
1113218822Sdim      arc_sprintf (state, state->operandBuffer, formatString, fieldA, fieldB);
1114218822Sdim      write_comments ();
111585815Sobrien      break;
111689857Sobrien
111785815Sobrien    default:
111885815Sobrien      mwerror (state, "Bad decoding class in ARC disassembler");
111985815Sobrien      break;
112038889Sjdp    }
112189857Sobrien
112285815Sobrien  state->_cond = cond;
112385815Sobrien  return state->instructionLen = offset;
112485815Sobrien}
112538889Sjdp
112685815Sobrien
112785815Sobrien/* Returns the name the user specified core extension register.  */
1128218822Sdim
112985815Sobrienstatic const char *
1130218822Sdim_coreRegName(void * arg ATTRIBUTE_UNUSED, int regval)
113185815Sobrien{
113285815Sobrien  return arcExtMap_coreRegName (regval);
113338889Sjdp}
113438889Sjdp
113585815Sobrien/* Returns the name the user specified AUX extension register.  */
1136218822Sdim
113785815Sobrienstatic const char *
113885815Sobrien_auxRegName(void *_this ATTRIBUTE_UNUSED, int regval)
113985815Sobrien{
114089857Sobrien  return arcExtMap_auxRegName(regval);
114185815Sobrien}
114238889Sjdp
1143218822Sdim/* Returns the name the user specified condition code name.  */
114485815Sobrien
114585815Sobrienstatic const char *
114685815Sobrien_condCodeName(void *_this ATTRIBUTE_UNUSED, int regval)
114738889Sjdp{
114889857Sobrien  return arcExtMap_condCodeName(regval);
114938889Sjdp}
115038889Sjdp
115185815Sobrien/* Returns the name the user specified extension instruction.  */
1152218822Sdim
115385815Sobrienstatic const char *
115485815Sobrien_instName (void *_this ATTRIBUTE_UNUSED, int majop, int minop, int *flags)
115538889Sjdp{
115689857Sobrien  return arcExtMap_instName(majop, minop, flags);
115738889Sjdp}
115838889Sjdp
115985815Sobrien/* Decode an instruction returning the size of the instruction
116085815Sobrien   in bytes or zero if unrecognized.  */
1161218822Sdim
116238889Sjdpstatic int
1163218822SdimdecodeInstr (bfd_vma            address, /* Address of this instruction.  */
1164218822Sdim	     disassemble_info * info)
116538889Sjdp{
116685815Sobrien  int status;
116785815Sobrien  bfd_byte buffer[4];
1168218822Sdim  struct arcDisState s;		/* ARC Disassembler state.  */
1169218822Sdim  void *stream = info->stream; 	/* Output stream.  */
117089857Sobrien  fprintf_ftype func = info->fprintf_func;
117185815Sobrien  int bytes;
117289857Sobrien
117385815Sobrien  memset (&s, 0, sizeof(struct arcDisState));
117489857Sobrien
117585815Sobrien  /* read first instruction  */
117685815Sobrien  status = (*info->read_memory_func) (address, buffer, 4, info);
117785815Sobrien  if (status != 0)
117885815Sobrien    {
117985815Sobrien      (*info->memory_error_func) (status, address, info);
118085815Sobrien      return 0;
118185815Sobrien    }
118285815Sobrien  if (info->endian == BFD_ENDIAN_LITTLE)
118385815Sobrien    s.words[0] = bfd_getl32(buffer);
118485815Sobrien  else
118585815Sobrien    s.words[0] = bfd_getb32(buffer);
1186218822Sdim  /* Always read second word in case of limm.  */
118785815Sobrien
1188218822Sdim  /* We ignore the result since last insn may not have a limm.  */
118985815Sobrien  status = (*info->read_memory_func) (address + 4, buffer, 4, info);
119085815Sobrien  if (info->endian == BFD_ENDIAN_LITTLE)
119185815Sobrien    s.words[1] = bfd_getl32(buffer);
119285815Sobrien  else
119385815Sobrien    s.words[1] = bfd_getb32(buffer);
119485815Sobrien
119585815Sobrien  s._this = &s;
119685815Sobrien  s.coreRegName = _coreRegName;
119785815Sobrien  s.auxRegName = _auxRegName;
119885815Sobrien  s.condCodeName = _condCodeName;
119985815Sobrien  s.instName = _instName;
120085815Sobrien
1201218822Sdim  /* Disassemble.  */
1202218822Sdim  bytes = dsmOneArcInst (address, (void *)& s);
120385815Sobrien
1204218822Sdim  /* Display the disassembly instruction.  */
1205218822Sdim  (*func) (stream, "%08lx ", s.words[0]);
120685815Sobrien  (*func) (stream, "    ");
120785815Sobrien  (*func) (stream, "%-10s ", s.instrBuffer);
120889857Sobrien
1209218822Sdim  if (__TRANSLATION_REQUIRED (s))
121085815Sobrien    {
121185815Sobrien      bfd_vma addr = s.addresses[s.operandBuffer[1] - '0'];
1212218822Sdim
121385815Sobrien      (*info->print_address_func) ((bfd_vma) addr, info);
121485815Sobrien      (*func) (stream, "\n");
121585815Sobrien    }
121685815Sobrien  else
121785815Sobrien    (*func) (stream, "%s",s.operandBuffer);
1218218822Sdim
121985815Sobrien  return s.instructionLen;
122038889Sjdp}
122185815Sobrien
122285815Sobrien/* Return the print_insn function to use.
122385815Sobrien   Side effect: load (possibly empty) extension section  */
122485815Sobrien
122585815Sobriendisassembler_ftype
122685815Sobrienarc_get_disassembler (void *ptr)
122785815Sobrien{
122885815Sobrien  if (ptr)
122985815Sobrien    build_ARC_extmap (ptr);
123085815Sobrien  return decodeInstr;
123185815Sobrien}
1232