arc-dis.c revision 89857
138889Sjdp/* Instruction printing code for the ARC.
285815Sobrien   Copyright 1994, 1995, 1997, 1998, 2000, 2001
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
1885815Sobrien   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
1938889Sjdp
2085815Sobrien#include <ansidecl.h>
2185815Sobrien#include <libiberty.h>
2238889Sjdp#include "dis-asm.h"
2338889Sjdp#include "opcode/arc.h"
2438889Sjdp#include "elf-bfd.h"
2538889Sjdp#include "elf/arc.h"
2685815Sobrien#include <string.h>
2760484Sobrien#include "opintl.h"
2838889Sjdp
2985815Sobrien#include <stdarg.h>
3085815Sobrien#include "arc-dis.h"
3185815Sobrien#include "arc-ext.h"
3238889Sjdp
3385815Sobrien#ifndef dbg
3485815Sobrien#define dbg (0)
3585815Sobrien#endif
3638889Sjdp
3789857Sobrien#define BIT(word,n)	((word) & (1 << n))
3889857Sobrien#define BITS(word,s,e)  (((word) << (31 - e)) >> (s + (31 - e)))
3989857Sobrien#define OPCODE(word)	(BITS ((word), 27, 31))
4089857Sobrien#define FIELDA(word)	(BITS ((word), 21, 26))
4189857Sobrien#define FIELDB(word)	(BITS ((word), 15, 20))
4289857Sobrien#define FIELDC(word)	(BITS ((word),  9, 14))
4338889Sjdp
4485815Sobrien/* FIELD D is signed in all of its uses, so we make sure argument is
4585815Sobrien   treated as signed for bit shifting purposes:  */
4689857Sobrien#define FIELDD(word)	(BITS (((signed int)word), 0, 8))
4785815Sobrien
4889857Sobrien#define PUT_NEXT_WORD_IN(a)						\
4989857Sobrien  do									\
5089857Sobrien    {									\
5189857Sobrien      if (is_limm == 1 && !NEXT_WORD (1))				\
5289857Sobrien        mwerror (state, _("Illegal limm reference in last instruction!\n")); \
5389857Sobrien      a = state->words[1];						\
5489857Sobrien    }									\
5585815Sobrien  while (0)
5685815Sobrien
5785815Sobrien#define CHECK_FLAG_COND_NULLIFY()				\
5885815Sobrien  do								\
5985815Sobrien    {								\
6085815Sobrien      if (is_shimm == 0)					\
6185815Sobrien        {							\
6285815Sobrien          flag = BIT (state->words[0], 8);			\
6385815Sobrien          state->nullifyMode = BITS (state->words[0], 5, 6);	\
6485815Sobrien          cond = BITS (state->words[0], 0, 4);			\
6585815Sobrien        }							\
6685815Sobrien    }								\
6785815Sobrien  while (0)
6885815Sobrien
6985815Sobrien#define CHECK_COND()				\
7085815Sobrien  do						\
7185815Sobrien    {						\
7285815Sobrien      if (is_shimm == 0)			\
7385815Sobrien        cond = BITS (state->words[0], 0, 4);	\
7485815Sobrien    }						\
7585815Sobrien  while (0)
7685815Sobrien
7785815Sobrien#define CHECK_FIELD(field)			\
7885815Sobrien  do						\
7985815Sobrien    {						\
8085815Sobrien      if (field == 62)				\
8185815Sobrien        {					\
8285815Sobrien          is_limm++;				\
8385815Sobrien	  field##isReg = 0;			\
8485815Sobrien	  PUT_NEXT_WORD_IN (field);		\
8585815Sobrien	  limm_value = field;			\
8685815Sobrien	}					\
8785815Sobrien      else if (field > 60)			\
8885815Sobrien        {					\
8985815Sobrien	  field##isReg = 0;			\
9085815Sobrien	  is_shimm++;				\
9185815Sobrien	  flag = (field == 61);			\
9285815Sobrien	  field = FIELDD (state->words[0]);	\
9385815Sobrien	}					\
9485815Sobrien    }						\
9585815Sobrien  while (0)
9685815Sobrien
9785815Sobrien#define CHECK_FIELD_A()				\
9885815Sobrien  do						\
9985815Sobrien    {						\
10089857Sobrien      fieldA = FIELDA (state->words[0]);	\
10185815Sobrien      if (fieldA > 60)				\
10285815Sobrien        {					\
10385815Sobrien	  fieldAisReg = 0;			\
10485815Sobrien	  fieldA = 0;				\
10585815Sobrien	}					\
10685815Sobrien    }						\
10785815Sobrien  while (0)
10885815Sobrien
10985815Sobrien#define CHECK_FIELD_B()				\
11085815Sobrien  do						\
11185815Sobrien    {						\
11285815Sobrien      fieldB = FIELDB (state->words[0]);	\
11385815Sobrien      CHECK_FIELD (fieldB);			\
11485815Sobrien    }						\
11585815Sobrien  while (0)
11685815Sobrien
11785815Sobrien#define CHECK_FIELD_C()				\
11885815Sobrien  do						\
11985815Sobrien    {						\
12085815Sobrien      fieldC = FIELDC (state->words[0]);	\
12185815Sobrien      CHECK_FIELD (fieldC);			\
12285815Sobrien    }						\
12385815Sobrien  while (0)
12485815Sobrien
12585815Sobrien#define IS_SMALL(x) (((field##x) < 256) && ((field##x) > -257))
12685815Sobrien#define IS_REG(x)   (field##x##isReg)
12785815Sobrien#define WRITE_FORMAT_LB_Rx_RB(x)     WRITE_FORMAT(x,"[","]","","")
12885815Sobrien#define WRITE_FORMAT_x_COMMA_LB(x)   WRITE_FORMAT(x,"",",[","",",[")
12985815Sobrien#define WRITE_FORMAT_COMMA_x_RB(x)   WRITE_FORMAT(x,",","]",",","]")
13085815Sobrien#define WRITE_FORMAT_x_RB(x)         WRITE_FORMAT(x,"","]","","]")
13185815Sobrien#define WRITE_FORMAT_COMMA_x(x)      WRITE_FORMAT(x,",","",",","")
13285815Sobrien#define WRITE_FORMAT_x_COMMA(x)      WRITE_FORMAT(x,"",",","",",")
13385815Sobrien#define WRITE_FORMAT_x(x)            WRITE_FORMAT(x,"","","","")
13485815Sobrien#define WRITE_FORMAT(x,cb1,ca1,cb,ca) strcat (formatString,		\
13585815Sobrien				     (IS_REG (x) ? cb1"%r"ca1 :		\
13685815Sobrien				      usesAuxReg ? cb"%a"ca :		\
13785815Sobrien				      IS_SMALL (x) ? cb"%d"ca : cb"%h"ca))
13889857Sobrien#define WRITE_FORMAT_RB()	strcat (formatString, "]")
13985815Sobrien#define WRITE_COMMENT(str)	(state->comm[state->commNum++] = (str))
14089857Sobrien#define WRITE_NOP_COMMENT()	if (!fieldAisReg && !flag) WRITE_COMMENT ("nop");
14185815Sobrien
14289857Sobrien#define NEXT_WORD(x)	(offset += 4, state->words[x])
14385815Sobrien
14489857Sobrien#define add_target(x)	(state->targets[state->tcnt++] = (x))
14585815Sobrien
14685815Sobrienstatic char comment_prefix[] = "\t; ";
14785815Sobrien
14889857Sobrienstatic const char *core_reg_name PARAMS ((struct arcDisState *, int));
14989857Sobrienstatic const char *aux_reg_name PARAMS ((struct arcDisState *, int));
15089857Sobrienstatic const char *cond_code_name PARAMS ((struct arcDisState *, int));
15189857Sobrienstatic const char *instruction_name
15289857Sobrien  PARAMS ((struct arcDisState *, int, int, int *));
15389857Sobrienstatic void mwerror PARAMS ((struct arcDisState *, const char *));
15489857Sobrienstatic const char *post_address PARAMS ((struct arcDisState *, int));
15589857Sobrienstatic void write_comments_
15689857Sobrien  PARAMS ((struct arcDisState *, int, int, long int));
15789857Sobrienstatic void write_instr_name_
15889857Sobrien  PARAMS ((struct arcDisState *, const char *, int, int, int, int, int, int));
15989857Sobrienstatic int dsmOneArcInst PARAMS ((bfd_vma, struct arcDisState *));
16089857Sobrienstatic const char *_coreRegName PARAMS ((void *, int));
16189857Sobrienstatic int decodeInstr PARAMS ((bfd_vma, disassemble_info *));
16289857Sobrien
16385815Sobrienstatic const char *
16485815Sobriencore_reg_name (state, val)
16585815Sobrien     struct arcDisState * state;
16689857Sobrien     int                  val;
16738889Sjdp{
16885815Sobrien  if (state->coreRegName)
16985815Sobrien    return (*state->coreRegName)(state->_this, val);
17085815Sobrien  return 0;
17185815Sobrien}
17238889Sjdp
17385815Sobrienstatic const char *
17485815Sobrienaux_reg_name (state, val)
17585815Sobrien     struct arcDisState * state;
17689857Sobrien     int                  val;
17785815Sobrien{
17885815Sobrien  if (state->auxRegName)
17985815Sobrien    return (*state->auxRegName)(state->_this, val);
18085815Sobrien  return 0;
18185815Sobrien}
18285815Sobrien
18385815Sobrienstatic const char *
18485815Sobriencond_code_name (state, val)
18585815Sobrien     struct arcDisState * state;
18689857Sobrien     int                  val;
18785815Sobrien{
18885815Sobrien  if (state->condCodeName)
18985815Sobrien    return (*state->condCodeName)(state->_this, val);
19085815Sobrien  return 0;
19185815Sobrien}
19285815Sobrien
19385815Sobrienstatic const char *
19485815Sobrieninstruction_name (state, op1, op2, flags)
19585815Sobrien     struct arcDisState * state;
19685815Sobrien     int    op1;
19785815Sobrien     int    op2;
19889857Sobrien     int *  flags;
19985815Sobrien{
20085815Sobrien  if (state->instName)
20185815Sobrien    return (*state->instName)(state->_this, op1, op2, flags);
20285815Sobrien  return 0;
20385815Sobrien}
20485815Sobrien
20585815Sobrienstatic void
20685815Sobrienmwerror (state, msg)
20785815Sobrien     struct arcDisState * state;
20889857Sobrien     const char * msg;
20985815Sobrien{
21085815Sobrien  if (state->err != 0)
21185815Sobrien    (*state->err)(state->_this, (msg));
21285815Sobrien}
21385815Sobrien
21485815Sobrienstatic const char *
21585815Sobrienpost_address (state, addr)
21685815Sobrien     struct arcDisState * state;
21789857Sobrien     int addr;
21885815Sobrien{
21985815Sobrien  static char id[3 * ARRAY_SIZE (state->addresses)];
22085815Sobrien  int j, i = state->acnt;
22185815Sobrien
22285815Sobrien  if (i < ((int) ARRAY_SIZE (state->addresses)))
22338889Sjdp    {
22485815Sobrien      state->addresses[i] = addr;
22585815Sobrien      ++state->acnt;
22685815Sobrien      j = i*3;
22785815Sobrien      id[j+0] = '@';
22885815Sobrien      id[j+1] = '0'+i;
22985815Sobrien      id[j+2] = 0;
23089857Sobrien
23185815Sobrien      return id + j;
23238889Sjdp    }
23385815Sobrien  return "";
23485815Sobrien}
23538889Sjdp
23689857Sobrienstatic void my_sprintf PARAMS ((struct arcDisState *, char *, const char *,
23789857Sobrien				...));
23889857Sobrien
23989857Sobrienstatic void
24089857Sobrienmy_sprintf VPARAMS ((struct arcDisState *state, char *buf, const char *format,
24189857Sobrien		     ...))
24285815Sobrien{
24389857Sobrien  char *bp;
24485815Sobrien  const char *p;
24585815Sobrien  int size, leading_zero, regMap[2];
24685815Sobrien  long auxNum;
24789857Sobrien
24889857Sobrien  VA_OPEN (ap, format);
24989857Sobrien  VA_FIXEDARG (ap, struct arcDisState *, state);
25089857Sobrien  VA_FIXEDARG (ap, char *, buf);
25189857Sobrien  VA_FIXEDARG (ap, const char *, format);
25289857Sobrien
25389857Sobrien  bp = buf;
25485815Sobrien  *bp = 0;
25585815Sobrien  p = format;
25685815Sobrien  auxNum = -1;
25785815Sobrien  regMap[0] = 0;
25885815Sobrien  regMap[1] = 0;
25989857Sobrien
26089857Sobrien  while (1)
26185815Sobrien    switch (*p++)
26285815Sobrien      {
26389857Sobrien      case 0:
26489857Sobrien	goto DOCOMM; /* (return)  */
26589857Sobrien      default:
26689857Sobrien	*bp++ = p[-1];
26785815Sobrien	break;
26885815Sobrien      case '%':
26985815Sobrien	size = 0;
27085815Sobrien	leading_zero = 0;
27185815Sobrien      RETRY: ;
27289857Sobrien	switch (*p++)
27385815Sobrien	  {
27485815Sobrien	  case '0':
27585815Sobrien	  case '1':
27685815Sobrien	  case '2':
27785815Sobrien	  case '3':
27885815Sobrien	  case '4':
27985815Sobrien	  case '5':
28085815Sobrien	  case '6':
28185815Sobrien	  case '7':
28285815Sobrien	  case '8':
28385815Sobrien	  case '9':
28485815Sobrien	    {
28585815Sobrien	      /* size.  */
28685815Sobrien	      size = p[-1] - '0';
28785815Sobrien	      if (size == 0)
28885815Sobrien		leading_zero = 1; /* e.g. %08x  */
28985815Sobrien	      while (*p >= '0' && *p <= '9')
29085815Sobrien		{
29185815Sobrien		  size = size * 10 + *p - '0';
29285815Sobrien		  p++;
29385815Sobrien		}
29485815Sobrien	      goto RETRY;
29585815Sobrien	    }
29685815Sobrien#define inc_bp() bp = bp + strlen (bp)
29785815Sobrien
29889857Sobrien	  case 'h':
29985815Sobrien	    {
30085815Sobrien	      unsigned u = va_arg (ap, int);
30185815Sobrien
30285815Sobrien	      /* Hex.  We can change the format to 0x%08x in
30385815Sobrien		 one place, here, if we wish.
30485815Sobrien		 We add underscores for easy reading.  */
30589857Sobrien	      if (u > 65536)
30685815Sobrien		sprintf (bp, "0x%x_%04x", u >> 16, u & 0xffff);
30789857Sobrien	      else
30885815Sobrien		sprintf (bp, "0x%x", u);
30985815Sobrien	      inc_bp ();
31089857Sobrien	    }
31185815Sobrien	    break;
31289857Sobrien	  case 'X': case 'x':
31385815Sobrien	    {
31485815Sobrien	      int val = va_arg (ap, int);
31585815Sobrien
31689857Sobrien	      if (size != 0)
31785815Sobrien		if (leading_zero)
31885815Sobrien		  sprintf (bp, "%0*x", size, val);
31985815Sobrien		else
32085815Sobrien		  sprintf (bp, "%*x", size, val);
32185815Sobrien	      else
32285815Sobrien		sprintf (bp, "%x", val);
32385815Sobrien	      inc_bp ();
32485815Sobrien	    }
32585815Sobrien	    break;
32689857Sobrien	  case 'd':
32785815Sobrien	    {
32885815Sobrien	      int val = va_arg (ap, int);
32989857Sobrien
33085815Sobrien	      if (size != 0)
33185815Sobrien		sprintf (bp, "%*d", size, val);
33285815Sobrien	      else
33385815Sobrien		sprintf (bp, "%d", val);
33485815Sobrien	      inc_bp ();
33585815Sobrien	    }
33685815Sobrien	    break;
33789857Sobrien	  case 'r':
33885815Sobrien	    {
33985815Sobrien	      /* Register.  */
34085815Sobrien	      int val = va_arg (ap, int);
34189857Sobrien
34285815Sobrien#define REG2NAME(num, name) case num: sprintf (bp, ""name); \
34385815Sobrien  regMap[(num < 32) ? 0 : 1] |= 1 << (num - ((num < 32) ? 0 : 32)); break;
34489857Sobrien
34589857Sobrien	      switch (val)
34685815Sobrien		{
34785815Sobrien		  REG2NAME (26, "gp");
34885815Sobrien		  REG2NAME (27, "fp");
34985815Sobrien		  REG2NAME (28, "sp");
35085815Sobrien		  REG2NAME (29, "ilink1");
35185815Sobrien		  REG2NAME (30, "ilink2");
35285815Sobrien		  REG2NAME (31, "blink");
35385815Sobrien		  REG2NAME (60, "lp_count");
35485815Sobrien		default:
35585815Sobrien		  {
35685815Sobrien		    const char * ext;
35785815Sobrien
35885815Sobrien		    ext = core_reg_name (state, val);
35985815Sobrien		    if (ext)
36085815Sobrien		      sprintf (bp, "%s", ext);
36185815Sobrien		    else
36285815Sobrien		      sprintf (bp,"r%d",val);
36385815Sobrien		  }
36485815Sobrien		  break;
36585815Sobrien		}
36685815Sobrien	      inc_bp ();
36785815Sobrien	    } break;
36889857Sobrien
36989857Sobrien	  case 'a':
37085815Sobrien	    {
37185815Sobrien	      /* Aux Register.  */
37285815Sobrien	      int val = va_arg (ap, int);
37385815Sobrien
37485815Sobrien#define AUXREG2NAME(num, name) case num: sprintf (bp,name); break;
37585815Sobrien
37689857Sobrien	      switch (val)
37785815Sobrien		{
37885815Sobrien		  AUXREG2NAME (0x0, "status");
37985815Sobrien		  AUXREG2NAME (0x1, "semaphore");
38085815Sobrien		  AUXREG2NAME (0x2, "lp_start");
38185815Sobrien		  AUXREG2NAME (0x3, "lp_end");
38285815Sobrien		  AUXREG2NAME (0x4, "identity");
38385815Sobrien		  AUXREG2NAME (0x5, "debug");
38485815Sobrien		default:
38585815Sobrien		  {
38685815Sobrien		    const char *ext;
38785815Sobrien
38885815Sobrien		    ext = aux_reg_name (state, val);
38985815Sobrien		    if (ext)
39085815Sobrien		      sprintf (bp, "%s", ext);
39185815Sobrien		    else
39285815Sobrien		      my_sprintf (state, bp, "%h", val);
39385815Sobrien		  }
39485815Sobrien		  break;
39585815Sobrien		}
39685815Sobrien	      inc_bp ();
39785815Sobrien	    }
39885815Sobrien	    break;
39989857Sobrien
40089857Sobrien	  case 's':
40185815Sobrien	    {
40285815Sobrien	      sprintf (bp, "%s", va_arg (ap, char *));
40385815Sobrien	      inc_bp ();
40485815Sobrien	    }
40585815Sobrien	    break;
40689857Sobrien
40785815Sobrien	  default:
40885815Sobrien	    fprintf (stderr, "?? format %c\n", p[-1]);
40985815Sobrien	    break;
41085815Sobrien	  }
41185815Sobrien      }
41285815Sobrien
41385815Sobrien DOCOMM: *bp = 0;
41489857Sobrien  VA_CLOSE (ap);
41585815Sobrien}
41685815Sobrien
41789857Sobrienstatic void
41885815Sobrienwrite_comments_(state, shimm, is_limm, limm_value)
41985815Sobrien     struct arcDisState * state;
42085815Sobrien     int shimm;
42185815Sobrien     int is_limm;
42285815Sobrien     long limm_value;
42385815Sobrien{
42489857Sobrien  if (state->commentBuffer != 0)
42538889Sjdp    {
42685815Sobrien      int i;
42785815Sobrien
42889857Sobrien      if (is_limm)
42985815Sobrien	{
43085815Sobrien	  const char *name = post_address (state, limm_value + shimm);
43185815Sobrien
43285815Sobrien	  if (*name != 0)
43385815Sobrien	    WRITE_COMMENT (name);
43485815Sobrien	}
43589857Sobrien      for (i = 0; i < state->commNum; i++)
43685815Sobrien	{
43785815Sobrien	  if (i == 0)
43885815Sobrien	    strcpy (state->commentBuffer, comment_prefix);
43985815Sobrien	  else
44089857Sobrien	    strcat (state->commentBuffer, ", ");
44189857Sobrien	  strncat (state->commentBuffer, state->comm[i],
44289857Sobrien		   sizeof (state->commentBuffer));
44385815Sobrien	}
44438889Sjdp    }
44585815Sobrien}
44638889Sjdp
44785815Sobrien#define write_comments2(x) write_comments_(state, x, is_limm, limm_value)
44885815Sobrien#define write_comments() write_comments2(0)
44938889Sjdp
45085815Sobrienstatic const char *condName[] = {
45185815Sobrien  /* 0..15.  */
45289857Sobrien  ""   , "z"  , "nz" , "p"  , "n"  , "c"  , "nc" , "v"  ,
45385815Sobrien  "nv" , "gt" , "ge" , "lt" , "le" , "hi" , "ls" , "pnz"
45485815Sobrien};
45538889Sjdp
45689857Sobrienstatic void
45785815Sobrienwrite_instr_name_(state, instrName, cond, condCodeIsPartOfName, flag, signExtend, addrWriteBack, directMem)
45885815Sobrien     struct arcDisState * state;
45985815Sobrien     const char * instrName;
46085815Sobrien     int cond;
46185815Sobrien     int condCodeIsPartOfName;
46285815Sobrien     int flag;
46385815Sobrien     int signExtend;
46485815Sobrien     int addrWriteBack;
46585815Sobrien     int directMem;
46685815Sobrien{
46785815Sobrien  strcpy (state->instrBuffer, instrName);
46885815Sobrien
46989857Sobrien  if (cond > 0)
47038889Sjdp    {
47185815Sobrien      const char *cc = 0;
47238889Sjdp
47385815Sobrien      if (!condCodeIsPartOfName)
47485815Sobrien	strcat (state->instrBuffer, ".");
47538889Sjdp
47685815Sobrien      if (cond < 16)
47785815Sobrien	cc = condName[cond];
47885815Sobrien      else
47985815Sobrien	cc = cond_code_name (state, cond);
48038889Sjdp
48185815Sobrien      if (!cc)
48285815Sobrien	cc = "???";
48338889Sjdp
48485815Sobrien      strcat (state->instrBuffer, cc);
48585815Sobrien    }
48638889Sjdp
48785815Sobrien  if (flag)
48885815Sobrien    strcat (state->instrBuffer, ".f");
48938889Sjdp
49089857Sobrien  switch (state->nullifyMode)
49185815Sobrien    {
49285815Sobrien    case BR_exec_always:
49385815Sobrien      strcat (state->instrBuffer, ".d");
49485815Sobrien      break;
49585815Sobrien    case BR_exec_when_jump:
49685815Sobrien      strcat (state->instrBuffer, ".jd");
49785815Sobrien      break;
49885815Sobrien    }
49938889Sjdp
50085815Sobrien  if (signExtend)
50185815Sobrien    strcat (state->instrBuffer, ".x");
50238889Sjdp
50385815Sobrien  if (addrWriteBack)
50485815Sobrien    strcat (state->instrBuffer, ".a");
50538889Sjdp
50685815Sobrien  if (directMem)
50785815Sobrien    strcat (state->instrBuffer, ".di");
50885815Sobrien}
50985815Sobrien
51085815Sobrien#define write_instr_name()						\
51185815Sobrien  do									\
51285815Sobrien    {									\
51385815Sobrien      write_instr_name_(state, instrName,cond, condCodeIsPartOfName,	\
51485815Sobrien			flag, signExtend, addrWriteBack, directMem);	\
51585815Sobrien      formatString[0] = '\0';						\
51685815Sobrien    }									\
51785815Sobrien  while (0)
51885815Sobrien
51989857Sobrienenum {
52089857Sobrien  op_LD0 = 0, op_LD1 = 1, op_ST  = 2, op_3   = 3,
52185815Sobrien  op_BC  = 4, op_BLC = 5, op_LPC = 6, op_JC  = 7,
52289857Sobrien  op_ADD = 8, op_ADC = 9, op_SUB = 10, op_SBC = 11,
52385815Sobrien  op_AND = 12, op_OR  = 13, op_BIC = 14, op_XOR = 15
52485815Sobrien};
52585815Sobrien
52685815Sobrienextern disassemble_info tm_print_insn_info;
52785815Sobrien
52889857Sobrienstatic int
52985815SobriendsmOneArcInst (addr, state)
53085815Sobrien     bfd_vma              addr;
53185815Sobrien     struct arcDisState * state;
53285815Sobrien{
53385815Sobrien  int condCodeIsPartOfName = 0;
53485815Sobrien  int decodingClass;
53585815Sobrien  const char * instrName;
53685815Sobrien  int repeatsOp = 0;
53785815Sobrien  int fieldAisReg = 1;
53885815Sobrien  int fieldBisReg = 1;
53985815Sobrien  int fieldCisReg = 1;
54085815Sobrien  int fieldA;
54185815Sobrien  int fieldB;
54285815Sobrien  int fieldC = 0;
54385815Sobrien  int flag = 0;
54485815Sobrien  int cond = 0;
54585815Sobrien  int is_shimm = 0;
54685815Sobrien  int is_limm = 0;
54785815Sobrien  long limm_value = 0;
54885815Sobrien  int signExtend = 0;
54985815Sobrien  int addrWriteBack = 0;
55085815Sobrien  int directMem = 0;
55185815Sobrien  int is_linked = 0;
55285815Sobrien  int offset = 0;
55385815Sobrien  int usesAuxReg = 0;
55485815Sobrien  int flags;
55585815Sobrien  int ignoreFirstOpd;
55685815Sobrien  char formatString[60];
55789857Sobrien
55885815Sobrien  state->instructionLen = 4;
55985815Sobrien  state->nullifyMode = BR_exec_when_no_jump;
56085815Sobrien  state->opWidth = 12;
56185815Sobrien  state->isBranch = 0;
56289857Sobrien
56385815Sobrien  state->_mem_load = 0;
56485815Sobrien  state->_ea_present = 0;
56585815Sobrien  state->_load_len = 0;
56685815Sobrien  state->ea_reg1 = no_reg;
56785815Sobrien  state->ea_reg2 = no_reg;
56885815Sobrien  state->_offset = 0;
56989857Sobrien
57085815Sobrien  if (! NEXT_WORD (0))
57185815Sobrien    return 0;
57289857Sobrien
57385815Sobrien  state->_opcode = OPCODE (state->words[0]);
57485815Sobrien  instrName = 0;
57585815Sobrien  decodingClass = 0; /* default!  */
57685815Sobrien  repeatsOp = 0;
57785815Sobrien  condCodeIsPartOfName=0;
57885815Sobrien  state->commNum = 0;
57985815Sobrien  state->tcnt = 0;
58085815Sobrien  state->acnt = 0;
58185815Sobrien  state->flow = noflow;
58285815Sobrien  ignoreFirstOpd = 0;
58385815Sobrien
58485815Sobrien  if (state->commentBuffer)
58585815Sobrien    state->commentBuffer[0] = '\0';
58685815Sobrien
58789857Sobrien  switch (state->_opcode)
58885815Sobrien    {
58989857Sobrien    case op_LD0:
59089857Sobrien      switch (BITS (state->words[0],1,2))
59138889Sjdp	{
59285815Sobrien	case 0:
59385815Sobrien	  instrName = "ld";
59485815Sobrien	  state->_load_len = 4;
59585815Sobrien	  break;
59685815Sobrien	case 1:
59785815Sobrien	  instrName = "ldb";
59885815Sobrien	  state->_load_len = 1;
59985815Sobrien	  break;
60085815Sobrien	case 2:
60185815Sobrien	  instrName = "ldw";
60285815Sobrien	  state->_load_len = 2;
60385815Sobrien	  break;
60485815Sobrien	default:
60589857Sobrien	  instrName = "??? (0[3])";
60685815Sobrien	  state->flow = invalid_instr;
60785815Sobrien	  break;
60885815Sobrien	}
60989857Sobrien      decodingClass = 5;
61085815Sobrien      break;
61189857Sobrien
61289857Sobrien    case op_LD1:
61389857Sobrien      if (BIT (state->words[0],13))
61485815Sobrien	{
61589857Sobrien	  instrName = "lr";
61685815Sobrien	  decodingClass = 10;
61785815Sobrien	}
61889857Sobrien      else
61985815Sobrien	{
62089857Sobrien	  switch (BITS (state->words[0],10,11))
62138889Sjdp	    {
62285815Sobrien	    case 0:
62385815Sobrien	      instrName = "ld";
62485815Sobrien	      state->_load_len = 4;
62585815Sobrien	      break;
62685815Sobrien	    case 1:
62785815Sobrien	      instrName = "ldb";
62885815Sobrien	      state->_load_len = 1;
62985815Sobrien	      break;
63085815Sobrien	    case 2:
63185815Sobrien	      instrName = "ldw";
63285815Sobrien	      state->_load_len = 2;
63385815Sobrien	      break;
63485815Sobrien	    default:
63589857Sobrien	      instrName = "??? (1[3])";
63685815Sobrien	      state->flow = invalid_instr;
63785815Sobrien	      break;
63838889Sjdp	    }
63985815Sobrien	  decodingClass = 6;
64038889Sjdp	}
64185815Sobrien      break;
64289857Sobrien
64385815Sobrien    case op_ST:
64489857Sobrien      if (BIT (state->words[0],25))
64538889Sjdp	{
64685815Sobrien	  instrName = "sr";
64785815Sobrien	  decodingClass = 8;
64885815Sobrien	}
64989857Sobrien      else
65085815Sobrien	{
65189857Sobrien	  switch (BITS (state->words[0],22,23))
65238889Sjdp	    {
65385815Sobrien	    case 0:
65485815Sobrien	      instrName = "st";
65585815Sobrien	      break;
65685815Sobrien	    case 1:
65785815Sobrien	      instrName = "stb";
65885815Sobrien	      break;
65985815Sobrien	    case 2:
66085815Sobrien	      instrName = "stw";
66185815Sobrien	      break;
66285815Sobrien	    default:
66389857Sobrien	      instrName = "??? (2[3])";
66485815Sobrien	      state->flow = invalid_instr;
66585815Sobrien	      break;
66638889Sjdp	    }
66785815Sobrien	  decodingClass = 7;
66885815Sobrien	}
66985815Sobrien      break;
67089857Sobrien
67185815Sobrien    case op_3:
67285815Sobrien      decodingClass = 1;  /* default for opcode 3...  */
67389857Sobrien      switch (FIELDC (state->words[0]))
67485815Sobrien	{
67585815Sobrien	case  0:
67689857Sobrien	  instrName = "flag";
67785815Sobrien	  decodingClass = 2;
67885815Sobrien	  break;
67985815Sobrien	case  1:
68085815Sobrien	  instrName = "asr";
68185815Sobrien	  break;
68285815Sobrien	case  2:
68385815Sobrien	  instrName = "lsr";
68485815Sobrien	  break;
68585815Sobrien	case  3:
68685815Sobrien	  instrName = "ror";
68785815Sobrien	  break;
68885815Sobrien	case  4:
68985815Sobrien	  instrName = "rrc";
69085815Sobrien	  break;
69185815Sobrien	case  5:
69285815Sobrien	  instrName = "sexb";
69385815Sobrien	  break;
69485815Sobrien	case  6:
69585815Sobrien	  instrName = "sexw";
69685815Sobrien	  break;
69785815Sobrien	case  7:
69885815Sobrien	  instrName = "extb";
69985815Sobrien	  break;
70085815Sobrien	case  8:
70185815Sobrien	  instrName = "extw";
70285815Sobrien	  break;
70389857Sobrien	case  0x3f:
70485815Sobrien	  {
70585815Sobrien	    decodingClass = 9;
70689857Sobrien	    switch( FIELDD (state->words[0]) )
70785815Sobrien	      {
70885815Sobrien	      case 0:
70985815Sobrien		instrName = "brk";
71085815Sobrien		break;
71185815Sobrien	      case 1:
71285815Sobrien		instrName = "sleep";
71385815Sobrien		break;
71485815Sobrien	      case 2:
71585815Sobrien		instrName = "swi";
71685815Sobrien		break;
71785815Sobrien	      default:
71885815Sobrien		instrName = "???";
71985815Sobrien		state->flow=invalid_instr;
72085815Sobrien		break;
72185815Sobrien	      }
72285815Sobrien	  }
72385815Sobrien	  break;
72489857Sobrien
72585815Sobrien	  /* ARC Extension Library Instructions
72685815Sobrien	     NOTE: We assume that extension codes are these instrs.  */
72785815Sobrien	default:
72885815Sobrien	  instrName = instruction_name (state,
72985815Sobrien					state->_opcode,
73085815Sobrien					FIELDC (state->words[0]),
73189857Sobrien					&flags);
73285815Sobrien	  if (!instrName)
73338889Sjdp	    {
73485815Sobrien	      instrName = "???";
73585815Sobrien	      state->flow = invalid_instr;
73638889Sjdp	    }
73785815Sobrien	  if (flags & IGNORE_FIRST_OPD)
73885815Sobrien	    ignoreFirstOpd = 1;
73985815Sobrien	  break;
74085815Sobrien	}
74185815Sobrien      break;
74238889Sjdp
74385815Sobrien    case op_BC:
74489857Sobrien      instrName = "b";
74585815Sobrien    case op_BLC:
74685815Sobrien      if (!instrName)
74789857Sobrien	instrName = "bl";
74885815Sobrien    case op_LPC:
74985815Sobrien      if (!instrName)
75089857Sobrien	instrName = "lp";
75185815Sobrien    case op_JC:
75285815Sobrien      if (!instrName)
75385815Sobrien	{
75489857Sobrien	  if (BITS (state->words[0],9,9))
75538889Sjdp	    {
75689857Sobrien	      instrName = "jl";
75785815Sobrien	      is_linked = 1;
75838889Sjdp	    }
75989857Sobrien	  else
76038889Sjdp	    {
76189857Sobrien	      instrName = "j";
76285815Sobrien	      is_linked = 0;
76338889Sjdp	    }
76485815Sobrien	}
76585815Sobrien      condCodeIsPartOfName = 1;
76685815Sobrien      decodingClass = ((state->_opcode == op_JC) ? 4 : 3);
76785815Sobrien      state->isBranch = 1;
76885815Sobrien      break;
76989857Sobrien
77085815Sobrien    case op_ADD:
77185815Sobrien    case op_ADC:
77285815Sobrien    case op_AND:
77385815Sobrien      repeatsOp = (FIELDC (state->words[0]) == FIELDB (state->words[0]));
77485815Sobrien      decodingClass = 0;
77538889Sjdp
77689857Sobrien      switch (state->_opcode)
77785815Sobrien	{
77885815Sobrien	case op_ADD:
77985815Sobrien	  instrName = (repeatsOp ? "asl" : "add");
78085815Sobrien	  break;
78185815Sobrien	case op_ADC:
78285815Sobrien	  instrName = (repeatsOp ? "rlc" : "adc");
78385815Sobrien	  break;
78485815Sobrien	case op_AND:
78585815Sobrien	  instrName = (repeatsOp ? "mov" : "and");
78685815Sobrien	  break;
78785815Sobrien	}
78885815Sobrien      break;
78989857Sobrien
79085815Sobrien    case op_SUB: instrName = "sub";
79185815Sobrien      break;
79285815Sobrien    case op_SBC: instrName = "sbc";
79385815Sobrien      break;
79485815Sobrien    case op_OR:  instrName = "or";
79585815Sobrien      break;
79685815Sobrien    case op_BIC: instrName = "bic";
79785815Sobrien      break;
79885815Sobrien
79985815Sobrien    case op_XOR:
80085815Sobrien      if (state->words[0] == 0x7fffffff)
80185815Sobrien	{
80285815Sobrien	  /* nop encoded as xor -1, -1, -1  */
80385815Sobrien	  instrName = "nop";
80485815Sobrien	  decodingClass = 9;
80585815Sobrien	}
80689857Sobrien      else
80785815Sobrien	instrName = "xor";
80885815Sobrien      break;
80989857Sobrien
81085815Sobrien    default:
81185815Sobrien      instrName = instruction_name (state,state->_opcode,0,&flags);
81285815Sobrien      /* if (instrName) printf("FLAGS=0x%x\n", flags);  */
81385815Sobrien      if (!instrName)
81485815Sobrien	{
81585815Sobrien	  instrName = "???";
81685815Sobrien	  state->flow=invalid_instr;
81785815Sobrien	}
81885815Sobrien      if (flags & IGNORE_FIRST_OPD)
81985815Sobrien	ignoreFirstOpd = 1;
82085815Sobrien      break;
82185815Sobrien    }
82289857Sobrien
82385815Sobrien  fieldAisReg = fieldBisReg = fieldCisReg = 1; /* Assume regs for now.  */
82485815Sobrien  flag = cond = is_shimm = is_limm = 0;
82585815Sobrien  state->nullifyMode = BR_exec_when_no_jump;	/* 0  */
82685815Sobrien  signExtend = addrWriteBack = directMem = 0;
82785815Sobrien  usesAuxReg = 0;
82889857Sobrien
82989857Sobrien  switch (decodingClass)
83085815Sobrien    {
83185815Sobrien    case 0:
83285815Sobrien      CHECK_FIELD_A ();
83385815Sobrien      CHECK_FIELD_B ();
83485815Sobrien      if (!repeatsOp)
83585815Sobrien	CHECK_FIELD_C ();
83685815Sobrien      CHECK_FLAG_COND_NULLIFY ();
83789857Sobrien
83885815Sobrien      write_instr_name ();
83989857Sobrien      if (!ignoreFirstOpd)
84085815Sobrien	{
84185815Sobrien	  WRITE_FORMAT_x (A);
84285815Sobrien	  WRITE_FORMAT_COMMA_x (B);
84385815Sobrien	  if (!repeatsOp)
84485815Sobrien	    WRITE_FORMAT_COMMA_x (C);
84585815Sobrien	  WRITE_NOP_COMMENT ();
84689857Sobrien	  my_sprintf (state, state->operandBuffer, formatString,
84789857Sobrien		      fieldA, fieldB, fieldC);
84885815Sobrien	}
84989857Sobrien      else
85085815Sobrien	{
85185815Sobrien	  WRITE_FORMAT_x (B);
85285815Sobrien	  if (!repeatsOp)
85385815Sobrien	    WRITE_FORMAT_COMMA_x (C);
85489857Sobrien	  my_sprintf (state, state->operandBuffer, formatString,
85589857Sobrien		      fieldB, fieldC);
85685815Sobrien	}
85785815Sobrien      write_comments ();
85885815Sobrien      break;
85989857Sobrien
86085815Sobrien    case 1:
86185815Sobrien      CHECK_FIELD_A ();
86285815Sobrien      CHECK_FIELD_B ();
86385815Sobrien      CHECK_FLAG_COND_NULLIFY ();
86489857Sobrien
86585815Sobrien      write_instr_name ();
86689857Sobrien      if (!ignoreFirstOpd)
86785815Sobrien	{
86885815Sobrien	  WRITE_FORMAT_x (A);
86985815Sobrien	  WRITE_FORMAT_COMMA_x (B);
87085815Sobrien	  WRITE_NOP_COMMENT ();
87189857Sobrien	  my_sprintf (state, state->operandBuffer, formatString,
87289857Sobrien		      fieldA, fieldB);
87385815Sobrien	}
87489857Sobrien      else
87585815Sobrien	{
87685815Sobrien	  WRITE_FORMAT_x (B);
87789857Sobrien	  my_sprintf (state, state->operandBuffer, formatString, fieldB);
87885815Sobrien	}
87985815Sobrien      write_comments ();
88085815Sobrien      break;
88189857Sobrien
88285815Sobrien    case 2:
88385815Sobrien      CHECK_FIELD_B ();
88485815Sobrien      CHECK_FLAG_COND_NULLIFY ();
88585815Sobrien      flag = 0; /* this is the FLAG instruction -- it's redundant  */
88689857Sobrien
88785815Sobrien      write_instr_name ();
88885815Sobrien      WRITE_FORMAT_x (B);
88985815Sobrien      my_sprintf (state, state->operandBuffer, formatString, fieldB);
89085815Sobrien      write_comments ();
89185815Sobrien      break;
89289857Sobrien
89385815Sobrien    case 3:
89485815Sobrien      fieldA = BITS (state->words[0],7,26) << 2;
89585815Sobrien      fieldA = (fieldA << 10) >> 10; /* make it signed  */
89685815Sobrien      fieldA += addr + 4;
89785815Sobrien      CHECK_FLAG_COND_NULLIFY ();
89885815Sobrien      flag = 0;
89989857Sobrien
90085815Sobrien      write_instr_name ();
90185815Sobrien      /* This address could be a label we know. Convert it.  */
90289857Sobrien      if (state->_opcode != op_LPC /* LP  */)
90385815Sobrien	{
90489857Sobrien	  add_target (fieldA); /* For debugger.  */
90589857Sobrien	  state->flow = state->_opcode == op_BLC /* BL  */
90689857Sobrien	    ? direct_call
90789857Sobrien	    : direct_jump;
90889857Sobrien	  /* indirect calls are achieved by "lr blink,[status];
90989857Sobrien	     lr dest<- func addr; j [dest]"  */
91089857Sobrien	}
91189857Sobrien
91285815Sobrien      strcat (formatString, "%s"); /* address/label name */
91389857Sobrien      my_sprintf (state, state->operandBuffer, formatString,
91489857Sobrien		  post_address (state, fieldA));
91585815Sobrien      write_comments ();
91685815Sobrien      break;
91789857Sobrien
91885815Sobrien    case 4:
91985815Sobrien      /* For op_JC -- jump to address specified.
92085815Sobrien	 Also covers jump and link--bit 9 of the instr. word
92185815Sobrien	 selects whether linked, thus "is_linked" is set above.  */
92285815Sobrien      fieldA = 0;
92385815Sobrien      CHECK_FIELD_B ();
92485815Sobrien      CHECK_FLAG_COND_NULLIFY ();
92589857Sobrien
92689857Sobrien      if (!fieldBisReg)
92785815Sobrien	{
92885815Sobrien	  fieldAisReg = 0;
92985815Sobrien	  fieldA = (fieldB >> 25) & 0x7F; /* flags */
93085815Sobrien	  fieldB = (fieldB & 0xFFFFFF) << 2;
93185815Sobrien	  state->flow = is_linked ? direct_call : direct_jump;
93285815Sobrien	  add_target (fieldB);
93385815Sobrien	  /* screwy JLcc requires .jd mode to execute correctly
93485815Sobrien	   * but we pretend it is .nd (no delay slot).  */
93585815Sobrien	  if (is_linked && state->nullifyMode == BR_exec_when_jump)
93685815Sobrien	    state->nullifyMode = BR_exec_when_no_jump;
93785815Sobrien	}
93889857Sobrien      else
93985815Sobrien	{
94085815Sobrien	  state->flow = is_linked ? indirect_call : indirect_jump;
94185815Sobrien	  /* We should also treat this as indirect call if NOT linked
94285815Sobrien	   * but the preceding instruction was a "lr blink,[status]"
94385815Sobrien	   * and we have a delay slot with "add blink,blink,2".
94485815Sobrien	   * For now we can't detect such.  */
94585815Sobrien	  state->register_for_indirect_jump = fieldB;
94685815Sobrien	}
94789857Sobrien
94885815Sobrien      write_instr_name ();
94989857Sobrien      strcat (formatString,
95085815Sobrien	      IS_REG (B) ? "[%r]" : "%s"); /* address/label name  */
95189857Sobrien      if (fieldA != 0)
95285815Sobrien	{
95385815Sobrien	  fieldAisReg = 0;
95485815Sobrien	  WRITE_FORMAT_COMMA_x (A);
95585815Sobrien	}
95685815Sobrien      if (IS_REG (B))
95785815Sobrien	my_sprintf (state, state->operandBuffer, formatString, fieldB, fieldA);
95885815Sobrien      else
95989857Sobrien	my_sprintf (state, state->operandBuffer, formatString,
96085815Sobrien		    post_address (state, fieldB), fieldA);
96185815Sobrien      write_comments ();
96285815Sobrien      break;
96389857Sobrien
96485815Sobrien    case 5:
96585815Sobrien      /* LD instruction.
96685815Sobrien	 B and C can be regs, or one (both?) can be limm.  */
96785815Sobrien      CHECK_FIELD_A ();
96885815Sobrien      CHECK_FIELD_B ();
96985815Sobrien      CHECK_FIELD_C ();
97085815Sobrien      if (dbg)
97185815Sobrien	printf ("5:b reg %d %d c reg %d %d  \n",
97285815Sobrien		fieldBisReg,fieldB,fieldCisReg,fieldC);
97385815Sobrien      state->_offset = 0;
97485815Sobrien      state->_ea_present = 1;
97585815Sobrien      if (fieldBisReg)
97685815Sobrien	state->ea_reg1 = fieldB;
97785815Sobrien      else
97885815Sobrien	state->_offset += fieldB;
97985815Sobrien      if (fieldCisReg)
98085815Sobrien	state->ea_reg2 = fieldC;
98185815Sobrien      else
98285815Sobrien	state->_offset += fieldC;
98385815Sobrien      state->_mem_load = 1;
98489857Sobrien
98585815Sobrien      directMem     = BIT (state->words[0],5);
98685815Sobrien      addrWriteBack = BIT (state->words[0],3);
98785815Sobrien      signExtend    = BIT (state->words[0],0);
98889857Sobrien
98985815Sobrien      write_instr_name ();
99085815Sobrien      WRITE_FORMAT_x_COMMA_LB(A);
99185815Sobrien      if (fieldBisReg || fieldB != 0)
99285815Sobrien	WRITE_FORMAT_x_COMMA (B);
99385815Sobrien      else
99485815Sobrien	fieldB = fieldC;
99589857Sobrien
99685815Sobrien      WRITE_FORMAT_x_RB (C);
99789857Sobrien      my_sprintf (state, state->operandBuffer, formatString,
99889857Sobrien		  fieldA, fieldB, fieldC);
99985815Sobrien      write_comments ();
100085815Sobrien      break;
100189857Sobrien
100285815Sobrien    case 6:
100385815Sobrien      /* LD instruction.  */
100485815Sobrien      CHECK_FIELD_B ();
100585815Sobrien      CHECK_FIELD_A ();
100685815Sobrien      fieldC = FIELDD (state->words[0]);
100789857Sobrien
100885815Sobrien      if (dbg)
100985815Sobrien	printf ("6:b reg %d %d c 0x%x  \n",
101085815Sobrien		fieldBisReg, fieldB, fieldC);
101185815Sobrien      state->_ea_present = 1;
101285815Sobrien      state->_offset = fieldC;
101385815Sobrien      state->_mem_load = 1;
101485815Sobrien      if (fieldBisReg)
101585815Sobrien	state->ea_reg1 = fieldB;
101685815Sobrien      /* field B is either a shimm (same as fieldC) or limm (different!)
101785815Sobrien	 Say ea is not present, so only one of us will do the name lookup.  */
101885815Sobrien      else
101985815Sobrien	state->_offset += fieldB, state->_ea_present = 0;
102089857Sobrien
102185815Sobrien      directMem     = BIT (state->words[0],14);
102285815Sobrien      addrWriteBack = BIT (state->words[0],12);
102385815Sobrien      signExtend    = BIT (state->words[0],9);
102489857Sobrien
102585815Sobrien      write_instr_name ();
102685815Sobrien      WRITE_FORMAT_x_COMMA_LB (A);
102789857Sobrien      if (!fieldBisReg)
102885815Sobrien	{
102985815Sobrien	  fieldB = state->_offset;
103085815Sobrien	  WRITE_FORMAT_x_RB (B);
103185815Sobrien	}
103289857Sobrien      else
103385815Sobrien	{
103485815Sobrien	  WRITE_FORMAT_x (B);
103589857Sobrien	  if (fieldC != 0 && !BIT (state->words[0],13))
103638889Sjdp	    {
103785815Sobrien	      fieldCisReg = 0;
103885815Sobrien	      WRITE_FORMAT_COMMA_x_RB (C);
103938889Sjdp	    }
104038889Sjdp	  else
104185815Sobrien	    WRITE_FORMAT_RB ();
104238889Sjdp	}
104389857Sobrien      my_sprintf (state, state->operandBuffer, formatString,
104489857Sobrien		  fieldA, fieldB, fieldC);
104585815Sobrien      write_comments ();
104685815Sobrien      break;
104789857Sobrien
104885815Sobrien    case 7:
104985815Sobrien      /* ST instruction.  */
105085815Sobrien      CHECK_FIELD_B();
105185815Sobrien      CHECK_FIELD_C();
105285815Sobrien      fieldA = FIELDD(state->words[0]); /* shimm  */
105389857Sobrien
105485815Sobrien      /* [B,A offset]  */
105585815Sobrien      if (dbg) printf("7:b reg %d %x off %x\n",
105689857Sobrien		      fieldBisReg,fieldB,fieldA);
105785815Sobrien      state->_ea_present = 1;
105885815Sobrien      state->_offset = fieldA;
105985815Sobrien      if (fieldBisReg)
106085815Sobrien	state->ea_reg1 = fieldB;
106189857Sobrien      /* field B is either a shimm (same as fieldA) or limm (different!)
106285815Sobrien	 Say ea is not present, so only one of us will do the name lookup.
106385815Sobrien	 (for is_limm we do the name translation here).  */
106489857Sobrien      else
106585815Sobrien	state->_offset += fieldB, state->_ea_present = 0;
106689857Sobrien
106785815Sobrien      directMem     = BIT(state->words[0],26);
106885815Sobrien      addrWriteBack = BIT(state->words[0],24);
106989857Sobrien
107085815Sobrien      write_instr_name();
107185815Sobrien      WRITE_FORMAT_x_COMMA_LB(C);
107289857Sobrien
107389857Sobrien      if (!fieldBisReg)
107485815Sobrien	{
107585815Sobrien	  fieldB = state->_offset;
107685815Sobrien	  WRITE_FORMAT_x_RB(B);
107785815Sobrien	}
107889857Sobrien      else
107985815Sobrien	{
108085815Sobrien	  WRITE_FORMAT_x(B);
108189857Sobrien	  if (fieldBisReg && fieldA != 0)
108285815Sobrien	    {
108385815Sobrien	      fieldAisReg = 0;
108485815Sobrien	      WRITE_FORMAT_COMMA_x_RB(A);
108585815Sobrien	    }
108685815Sobrien	  else
108785815Sobrien	    WRITE_FORMAT_RB();
108885815Sobrien	}
108989857Sobrien      my_sprintf (state, state->operandBuffer, formatString,
109089857Sobrien		  fieldC, fieldB, fieldA);
109185815Sobrien      write_comments2(fieldA);
109285815Sobrien      break;
109385815Sobrien    case 8:
109485815Sobrien      /* SR instruction  */
109585815Sobrien      CHECK_FIELD_B();
109685815Sobrien      CHECK_FIELD_C();
109789857Sobrien
109885815Sobrien      write_instr_name();
109985815Sobrien      WRITE_FORMAT_x_COMMA_LB(C);
110085815Sobrien      /* Try to print B as an aux reg if it is not a core reg.  */
110185815Sobrien      usesAuxReg = 1;
110285815Sobrien      WRITE_FORMAT_x(B);
110385815Sobrien      WRITE_FORMAT_RB();
110485815Sobrien      my_sprintf (state, state->operandBuffer, formatString, fieldC, fieldB);
110585815Sobrien      write_comments();
110685815Sobrien      break;
110789857Sobrien
110885815Sobrien    case 9:
110985815Sobrien      write_instr_name();
111085815Sobrien      state->operandBuffer[0] = '\0';
111185815Sobrien      break;
111289857Sobrien
111385815Sobrien    case 10:
111485815Sobrien      /* LR instruction */
111585815Sobrien      CHECK_FIELD_A();
111685815Sobrien      CHECK_FIELD_B();
111789857Sobrien
111885815Sobrien      write_instr_name();
111985815Sobrien      WRITE_FORMAT_x_COMMA_LB(A);
112085815Sobrien      /* Try to print B as an aux reg if it is not a core reg. */
112185815Sobrien      usesAuxReg = 1;
112285815Sobrien      WRITE_FORMAT_x(B);
112385815Sobrien      WRITE_FORMAT_RB();
112485815Sobrien      my_sprintf (state, state->operandBuffer, formatString, fieldA, fieldB);
112585815Sobrien      write_comments();
112685815Sobrien      break;
112789857Sobrien
112885815Sobrien    case 11:
112985815Sobrien      CHECK_COND();
113085815Sobrien      write_instr_name();
113185815Sobrien      state->operandBuffer[0] = '\0';
113285815Sobrien      break;
113389857Sobrien
113485815Sobrien    default:
113585815Sobrien      mwerror (state, "Bad decoding class in ARC disassembler");
113685815Sobrien      break;
113738889Sjdp    }
113889857Sobrien
113985815Sobrien  state->_cond = cond;
114085815Sobrien  return state->instructionLen = offset;
114185815Sobrien}
114238889Sjdp
114385815Sobrien
114485815Sobrien/* Returns the name the user specified core extension register.  */
114585815Sobrienstatic const char *
114685815Sobrien_coreRegName(arg, regval)
114785815Sobrien     void * arg ATTRIBUTE_UNUSED;
114885815Sobrien     int regval;
114985815Sobrien{
115085815Sobrien  return arcExtMap_coreRegName (regval);
115138889Sjdp}
115238889Sjdp
115385815Sobrien/* Returns the name the user specified AUX extension register.  */
115485815Sobrienstatic const char *
115585815Sobrien_auxRegName(void *_this ATTRIBUTE_UNUSED, int regval)
115685815Sobrien{
115789857Sobrien  return arcExtMap_auxRegName(regval);
115885815Sobrien}
115938889Sjdp
116085815Sobrien
116185815Sobrien/* Returns the name the user specified condition code name.  */
116285815Sobrienstatic const char *
116385815Sobrien_condCodeName(void *_this ATTRIBUTE_UNUSED, int regval)
116438889Sjdp{
116589857Sobrien  return arcExtMap_condCodeName(regval);
116638889Sjdp}
116738889Sjdp
116885815Sobrien/* Returns the name the user specified extension instruction.  */
116985815Sobrienstatic const char *
117085815Sobrien_instName (void *_this ATTRIBUTE_UNUSED, int majop, int minop, int *flags)
117138889Sjdp{
117289857Sobrien  return arcExtMap_instName(majop, minop, flags);
117338889Sjdp}
117438889Sjdp
117585815Sobrien/* Decode an instruction returning the size of the instruction
117685815Sobrien   in bytes or zero if unrecognized.  */
117738889Sjdpstatic int
117885815SobriendecodeInstr (address, info)
117985815Sobrien     bfd_vma            address; /* Address of this instruction.  */
118085815Sobrien     disassemble_info * info;
118138889Sjdp{
118285815Sobrien  int status;
118385815Sobrien  bfd_byte buffer[4];
118485815Sobrien  struct arcDisState s;	/* ARC Disassembler state  */
118585815Sobrien  void *stream = info->stream; /* output stream  */
118689857Sobrien  fprintf_ftype func = info->fprintf_func;
118785815Sobrien  int bytes;
118889857Sobrien
118985815Sobrien  memset (&s, 0, sizeof(struct arcDisState));
119089857Sobrien
119185815Sobrien  /* read first instruction  */
119285815Sobrien  status = (*info->read_memory_func) (address, buffer, 4, info);
119385815Sobrien  if (status != 0)
119485815Sobrien    {
119585815Sobrien      (*info->memory_error_func) (status, address, info);
119685815Sobrien      return 0;
119785815Sobrien    }
119885815Sobrien  if (info->endian == BFD_ENDIAN_LITTLE)
119985815Sobrien    s.words[0] = bfd_getl32(buffer);
120085815Sobrien  else
120185815Sobrien    s.words[0] = bfd_getb32(buffer);
120285815Sobrien  /* always read second word in case of limm  */
120385815Sobrien
120485815Sobrien  /* we ignore the result since last insn may not have a limm  */
120585815Sobrien  status = (*info->read_memory_func) (address + 4, buffer, 4, info);
120685815Sobrien  if (info->endian == BFD_ENDIAN_LITTLE)
120785815Sobrien    s.words[1] = bfd_getl32(buffer);
120885815Sobrien  else
120985815Sobrien    s.words[1] = bfd_getb32(buffer);
121085815Sobrien
121185815Sobrien  s._this = &s;
121285815Sobrien  s.coreRegName = _coreRegName;
121385815Sobrien  s.auxRegName = _auxRegName;
121485815Sobrien  s.condCodeName = _condCodeName;
121585815Sobrien  s.instName = _instName;
121685815Sobrien
121785815Sobrien  /* disassemble  */
121885815Sobrien  bytes = dsmOneArcInst(address, (void *)&s);
121985815Sobrien
122085815Sobrien  /* display the disassembly instruction  */
122185815Sobrien  (*func) (stream, "%08x ", s.words[0]);
122285815Sobrien  (*func) (stream, "    ");
122389857Sobrien
122485815Sobrien  (*func) (stream, "%-10s ", s.instrBuffer);
122589857Sobrien
122685815Sobrien  if (__TRANSLATION_REQUIRED(s))
122785815Sobrien    {
122885815Sobrien      bfd_vma addr = s.addresses[s.operandBuffer[1] - '0'];
122985815Sobrien      (*info->print_address_func) ((bfd_vma) addr, info);
123085815Sobrien      (*func) (stream, "\n");
123185815Sobrien    }
123285815Sobrien  else
123385815Sobrien    (*func) (stream, "%s",s.operandBuffer);
123485815Sobrien  return s.instructionLen;
123538889Sjdp}
123685815Sobrien
123785815Sobrien/* Return the print_insn function to use.
123885815Sobrien   Side effect: load (possibly empty) extension section  */
123985815Sobrien
124085815Sobriendisassembler_ftype
124185815Sobrienarc_get_disassembler (void *ptr)
124285815Sobrien{
124385815Sobrien  if (ptr)
124485815Sobrien    build_ARC_extmap (ptr);
124585815Sobrien  return decodeInstr;
124685815Sobrien}
1247