/* Instruction printing code for the ARC.
   Copyright 1994, 1995, 1997, 1998, 2000, 2001, 2002, 2005, 2006, 2007, 2008, 2009
   Free Software Foundation, Inc.
   Contributed by Doug Evans (dje@cygnus.com).

   Copyright 2008-2012 Synopsys Inc.

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2 of the License, or
   (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
   MA 02110-1301, USA.  */


#include "../../../include/disas-asm.h"
#include "arc.h"
#include "arc-ext.h"
#include "arc-dis.h"
#include "arcompact-dis.h"
#include "../../../include/elf-bfd.h"
#include <r_types.h>
#include <r_util.h>
#include <stdarg.h>

/* Compatibility definitions for arcompact-dis.c */
#define E_ARC_MACH_A4     0
#define ARC_MACH_ARC7     7
#define AC_SYNTAX_3OP     1
#define AC_SYNTAX_2OP     2
#define AC_SYNTAX_1OP     3
#define AC_SYNTAX_NOP     4
#define AC_SYNTAX_SIMD    5

/* Functions from arc-ext that are needed */
const char *arc_aux_reg_name (int regnum);
const char *arcExtMap_instName (int opcode, int minor, int *flags);

static bfd_vma bfd_getm32(unsigned int);
static bfd_vma bfd_getm32_ac(unsigned int) ATTRIBUTE_UNUSED;


#ifndef dbg
#define dbg	(0)
#endif

#undef _NELEM
#define _NELEM(ary)	(sizeof (ary) / sizeof ((ary)[0]))

#define BIT(word,n)       ((word) & (1 << (n)))
/* START ARC LOCAL */
#define BITS(word,s,e)    (((word) << (sizeof (word)*8-1 - (e))) >> ((s)+(sizeof (word)*8-1 - (e))))
/* END ARC LOCAL */
#define OPCODE(word)      (BITS ((word), 27, 31))
/* Undef macros from arc.h to avoid redefinition warnings */
#undef FIELDA
#undef FIELDB
#undef FIELDC
#define FIELDA(word)      (BITS ((word), 0, 5))
#define FIELDb(word)      (BITS ((word), 24, 26))
#define FIELDB(word)      (BITS ((word), 12, 14))
#define FIELDC(word)      (BITS ((word), 6, 11))
#define OPCODE_AC(word)   (BITS ((word), 11, 15))
#define FIELDA_AC(word)   (BITS ((word), 0, 2))
#define FIELDB_AC(word)   (BITS ((word), 8, 10))
#define FIELDC_AC(word)   (BITS ((word), 5, 7))
#define FIELDU_AC(word)   (BITS ((word), 0, 4))

/*
 * FIELDS_AC is the 11-bit signed immediate value used for
 * GP-relative instructions.
 */
#define FIELDS_AC(word)   (BITS (((signed int) (word)), 0, 8))

/*
 * FIELDD is signed in all of its uses, so we make sure argument is
 * treated as signed for bit shifting purposes.
 */
#define FIELDD(word)      (BITS (((signed int) (word)), 16, 23))

/*
 * FIELDD9 is the 9-bit signed immediate value used for
 * load/store instructions.
 */
#define FIELDD9(word)     ((BITS(((signed int)(word)),15,15) << 8) | (BITS((word),16,23)))

/*
 * FIELDS is the 12-bit signed immediate value
 */
#define FIELDS(word)      ((BITS(((signed int)(word)),0,5) << 6) | (BITS((word),6,11)))

/*
 * FIELD S9 is the 9-bit signed immediate value used for
 * bbit0/bbit instruction
 */
#define FIELDS9(word)     (((BITS(((signed int)(word)),15,15) << 7) | (BITS((word),17,23))) << 1)
#define FIELDS9_FLAG(word)     (((BITS(((signed int)(word)),0,5) << 6) | (BITS((word),6,11))) )

#define PUT_NEXT_WORD_IN(a) {		\
	if (is_limm == 1 && !NEXT_WORD(1))       	\
	  mwerror(state, "Illegal limm reference in last instruction!\n"); \
	if (info->endian == BFD_ENDIAN_LITTLE) { \
		(a) = ((state->words[1] & 0xff00) | (state->words[1] & 0xff)) << 16; \
		(a) |= ((state->words[1] & 0xff0000) | (state->words[1] & 0xff000000)) >> 16;	\
	} \
	else { \
		(a) = state->words[1]; \
	} \
	}

#define CHECK_NULLIFY() do { \
	state->nullifyMode = BITS (state->words[0],5,5);	\
	} while (0)

#define CHECK_COND_NULLIFY() do {		\
	state->nullifyMode = BITS (state->words[0],5,5);	\
	cond = BITS(state->words[0],0,4);	\
	} while (0)

#define CHECK_FLAG_COND_NULLIFY() do{	\
	if (is_shimm == 0) {			\
	  flag = BIT(state->words[0],15);	\
	  state->nullifyMode = BITS(state->words[0],5,5); \
	  cond = BITS(state->words[0],0,4);	\
	}					\
	} while (0)

#define CHECK_FLAG_COND() {		\
	if (is_shimm == 0) {			\
	  flag = BIT(state->words[0],15);	\
	  cond = BITS(state->words[0],0,4);	\
	}					\
	}

#define CHECK_FLAG() {			\
	flag = BIT(state->words[0],15);	\
	}

#define CHECK_COND() {		                \
	if (is_shimm == 0) {			\
	  cond = BITS(state->words[0],0,4);	\
	}					\
	}

#define CHECK_FIELD(field) {			\
	if ((field) == 62) {			\
	  is_limm++;				\
	  field##isReg = 0;			\
	  PUT_NEXT_WORD_IN(field);		\
	}					\
	}

#define CHECK_FIELD_A() {			\
	fieldA = FIELDA(state->words[0]);	\
	if (fieldA == 62) {			\
	  fieldAisReg = 0;			\
	  fieldA = 0;				\
	}					\
	}

#define FIELD_B() {				\
	fieldB = (FIELDB(state->words[0]) << 3);\
	fieldB |= FIELDb(state->words[0]);	\
	if (fieldB == 62) {			\
	  fieldBisReg = 0;			\
	  fieldB = 0;				\
	}					\
	}

#define FIELD_C() {				\
	fieldC = FIELDC(state->words[0]);	\
	if (fieldC == 62) {  			\
	  fieldCisReg = 0; 			\
	}					\
	}
/********** Aurora SIMD ARC 8 - bit constant **********/
#define FIELD_U8() {                            \
                                                \
          fieldC  = BITS(state->words[0],15,16);\
          fieldC  = fieldC <<6;                 \
          fieldC |= FIELDC(state->words[0]);    \
          fieldCisReg = 0;                      \
        }

#define CHECK_FIELD_B() {			\
	fieldB = (FIELDB(state->words[0]) << 3);\
	fieldB |= FIELDb(state->words[0]);	\
	CHECK_FIELD(fieldB);			\
	}

#define CHECK_FIELD_C() {			\
	fieldC = FIELDC(state->words[0]);	\
	CHECK_FIELD(fieldC);			\
	}

#define FIELD_C_S() {				\
	fieldC_S = (FIELDC_S(state->words[0]) << 3);	\
	}

#define FIELD_B_S() {				\
	fieldB_S = (FIELDB_S(state->words[0]) << 3);	\
	}

#define CHECK_FIELD_H_AC() {			\
	fieldC = ((FIELDA_AC(state->words[0])) << 3);	\
	fieldC |= FIELDC_AC(state->words[0]);	\
	CHECK_FIELD(fieldC);			\
	}

#define FIELD_H_AC() {				\
	fieldC = ((FIELDA_AC(state->words[0])) << 3);	\
	fieldC |= FIELDC_AC(state->words[0]);	\
	if (fieldC > 60) {  			\
	  fieldCisReg = 0; 			\
	  fieldC = 0;				\
	}					\
	}

#define FIELD_C_AC() {				\
	fieldC = FIELDC_AC(state->words[0]);	\
	if (fieldC > 3) {  			\
	  fieldC += 8;  			\
	}				  	\
	}

#define FIELD_B_AC() {				\
	fieldB = FIELDB_AC(state->words[0]);	\
	if (fieldB > 3) {  			\
	  fieldB += 8; 				\
	}				  	\
	}

#define FIELD_A_AC() {				\
	fieldA = FIELDA_AC(state->words[0]);	\
	if (fieldA > 3) {  			\
	  fieldA += 8; 				\
	}				  	\
	}

#define IS_SMALL(x) (((field##x) < 256) && ((field##x) > -257))
#define IS_REG(x)   (field##x##isReg)
#define IS_SIMD_128_REG(x)  (usesSimdReg##x == 1)
#define IS_SIMD_16_REG(x)   (usesSimdReg##x == 2)
#define IS_SIMD_DATA_REG(x) (usesSimdReg##x == 3)
#define WRITE_FORMAT_LB_Rx_RB(x)     WRITE_FORMAT(x,"[","]","","")
#define WRITE_FORMAT_x_COMMA_LB(x)   WRITE_FORMAT(x,"",", [","",",[")
#define WRITE_FORMAT_COMMA_x_RB(x)   WRITE_FORMAT(x,", ","]",", ","]")
#define WRITE_FORMAT_x_RB(x)         WRITE_FORMAT(x,"","]","","]")
#define WRITE_FORMAT_COMMA_x(x)      WRITE_FORMAT(x,", ","",", ","")
#define WRITE_FORMAT_x_COMMA(x)      WRITE_FORMAT(x,"",", ","",", ")
#define WRITE_FORMAT_x(x)            WRITE_FORMAT(x,"","","","")
#define WRITE_FORMAT(x,cb1,ca1,cb,ca) strncat(formatString,              \
                                     (IS_SIMD_128_REG(x) ? cb1"%S"ca1:  \
                                      IS_SIMD_16_REG(x)  ? cb1"%I"ca1:  \
                                      IS_SIMD_DATA_REG(x)? cb1"%D"ca1:  \
                                      IS_REG(x)          ? cb1"%r"ca1:  \
                                      usesAuxReg         ?  cb"%a"ca :  \
                                      IS_SMALL(x) ? cb"%d"ca : cb"%h"ca), \
                                     sizeof(formatString) - strlen(formatString) - 1)

#define WRITE_FORMAT_LB() strncat(formatString, "[", sizeof(formatString) - strlen(formatString) - 1)
#define WRITE_FORMAT_RB() strncat(formatString, "]", sizeof(formatString) - strlen(formatString) - 1)
#define WRITE_COMMENT(str)	(state->comm[state->commNum++] = (str))
#define WRITE_NOP_COMMENT() if (!fieldAisReg && !flag) WRITE_COMMENT("nop");

#define NEXT_WORD(x) (offset += 4, state->words[x])

#define NEXT_WORD_AC(x) (offset += 2, state->words[x])

#define add_target(x) 	(state->targets[state->tcnt++] = (x))

static short int enable_simd = 0;
static short int enable_insn_stream = 0;


static const char *
core_reg_name(struct arcDisState *state, int val)
{
	if (state->coreRegName) {
		return (*state->coreRegName) (state->_this, val);
	}
	return 0;
}

static const char *
aux_reg_name(struct arcDisState *state, int val)
{
	if (state->auxRegName) {
		return (*state->auxRegName) (state->_this, val);
	}
	return 0;
}

static const char *
cond_code_name(struct arcDisState *state, int val)
{
	if (state->condCodeName) {
		return (*state->condCodeName) (state->_this, val);
	}
	return 0;
}

static const char *
instruction_name(struct arcDisState *state, int op1, int op2, int *flags)
{
	if (state->instName) {
		return (*state->instName) (state->_this, op1, op2, flags);
	}
	return 0;
}

static void
mwerror(struct arcDisState *state, const char *msg)
{
	if (state->err != 0) {
		(*state->err) (state->_this, (msg));
	}
}

static const char *
post_address(struct arcDisState *state, int addr)
{
  static char id[3*_NELEM(state->addresses)];
  unsigned int j, i = state->acnt;
  if (i < _NELEM(state->addresses)) {
    state->addresses[i] = addr;
    ++state->acnt;
    j = i*3;
    id[j+0] = '@';
    id[j+1] = '0'+i;
    id[j+2] = 0;
    return id+j;
  }
  return "";
}

static void
my_sprintf (struct arcDisState *state, char *buf, const char*format, ...)
{
  char *bp;
  const char *p;
  int size, leading_zero, regMap[2];
  va_list ap;
  /* Compute remaining buffer space to prevent overflows */
  size_t bufsize = sizeof (state->operandBuffer) - (buf - state->operandBuffer);
  char *bufend = buf + bufsize;

  va_start(ap,format);
  bp = buf;
  *bp = 0;
  p = format;
  regMap[0] = 0;
  regMap[1] = 0;
  while (1) {
	  switch (*p++) {
	  case 0: goto DOCOMM; /*(return) */
	  default:
		  if (bp < bufend - 1) {
			  *bp++ = p[-1];
		  }
		  break;
	  case '%':
		  size = 0;
		  leading_zero = 0;
	  RETRY:;
		  switch (*p++) {
		  case '0':
		  case '1':
		  case '2':
		  case '3':
		  case '4':
		  case '5':
		  case '6':
		  case '7':
		  case '8':
		  case '9': {
			  /* size. */
			  size = p[-1] - '0';
			  if (size == 0) {
				  leading_zero = 1; /* e.g. %08x */
			  }
			  while (*p >= '0' && *p <= '9') {
				  size = size * 10 + *p - '0', p++;
			  }
			  goto RETRY;
		  }
#define inc_bp() do { bp = bp+strlen(bp); if (bp >= bufend) { bp = bufend - 1; *bp = 0; goto DOCOMM; } } while(0)
#define REMAINING() ((size_t)(bufend > bp ? bufend - bp : 0))

	case 'h':
	  {
	    unsigned u = va_arg(ap,int);
	    /*
	     * Hex.  We can change the format to 0x%08x in
	     * one place, here, if we wish.
	     * We add underscores for easy reading.
	     */
#define CDT_DEBUG
	    if (u > 65536) {
#ifndef CDT_DEBUG
	      snprintf(bp,REMAINING(),"0x%x_%04x",u >> 16, u & 0xffff);
#else
	      snprintf(bp,REMAINING(),"0x%08x",u);
#endif // CDT_DEBUG
	    } else {
		    snprintf (bp, REMAINING(), "0x%x", u);
	    }
	    inc_bp();
	  }
	  break;
	case 'X': case 'x':
	  {
	    int val = va_arg(ap,int);
	    if (size != 0) {
		    if (leading_zero) {
			    snprintf (bp, REMAINING(), "0x%0*x", size, val);
		    } else {
			    snprintf (bp, REMAINING(), "%*x", size, val);
		    }
	    } else {
		    snprintf (bp, REMAINING(), "0x%x", val);
	    }
	    inc_bp();
	  }
	  break;
	case 'd':
	  {
	    int val = va_arg(ap,int);
	    if (size != 0) {
		    snprintf (bp, REMAINING(), "%*d", size, val);
	    } else {
		    snprintf (bp, REMAINING(), "%d", val);
	    }
	    inc_bp();
	  }
	  break;
	case 'r':
	  {
	    /* Register. */
	    int val = va_arg(ap,int);

#define REG2NAME(num, name) case num: snprintf(bp,REMAINING(),""name); \
			regMap[((num)<32)?0:1] |= 1<<((num)-(((num)<32)?0:32)); break;
	    switch (val)
	      {
		REG2NAME(26, "gp");
		REG2NAME(27, "fp");
		REG2NAME(28, "sp");
		REG2NAME(29, "ilink1");
		REG2NAME(30, "ilink2");
		REG2NAME(31, "blink");
		REG2NAME(60, "lp_count");
		REG2NAME(63, "pcl");
	      default:
		{
		  const char *ext;
		  ext = core_reg_name(state, val);
		  if (ext) {
			  snprintf (bp, REMAINING(), "%s", ext);
		  } else {
			  snprintf (bp, REMAINING(), "r%d", val);
		  }
		}break;
	      }
	    inc_bp();
	  } break;

	case 'a':
	  {
	  /* Aux Register. */
	    int val = va_arg(ap,int);
	    const char *ret;
	    ret = arc_aux_reg_name(val);
	    if (ret) {
		    snprintf (bp, REMAINING(), "%s", ret);
	    } else {
		    const char *ext;
		    ext = aux_reg_name (state, val);
		    if (ext) {
			    snprintf (bp, REMAINING(), "%s", ext);
		    } else {
			    my_sprintf (state, bp, "%h", val);
		    }
	      }

	    inc_bp();
	  }
	  break;
	case 's':
	  {
	    snprintf(bp,REMAINING(),"%s",va_arg(ap,char*));
	    inc_bp();
	  }
	  break;
	case '*':
	  {
#if 0
	    va_arg(ap,char*);
	    inc_bp();
	    break;
#elif 1 /* used for prefetch to skip an argument.  */
        va_arg(ap,int);
        break;
#else
	    extern void abort (void);

	    abort ();
#endif
	  }

	  /* SIMD operands follow*/
	case 'S':
	  {
	    int val = va_arg (ap,int);

	    snprintf (bp, REMAINING(), "vr%d",val);
	    inc_bp ();
	    break;
	  }
	case 'I':
	  {
	    int val = va_arg (ap,int);

	    snprintf (bp, REMAINING(), "i%d",val);
	    inc_bp ();
	    break;
	  }
	case 'D':
	  {
	    int val = va_arg (ap,int);

	    snprintf (bp, REMAINING(), "dr%d",val);
	    inc_bp ();
	    break;
	  }
	  /* SIMD operands end */
	default:
	  fprintf(stderr,"?? format %c\n",p[-1]);
	  break;
	}
	  }
  }

 DOCOMM:
  *bp = 0;
  va_end (ap);
#undef inc_bp
#undef REMAINING
#undef REG2NAME
}

static const char *condName[] =
{
  /* 0..15. */
  ""   , "z"  , "nz" , "p"  , "n"  , "c"  , "nc" , "v"  ,
  "nv" , "gt" , "ge" , "lt" , "le" , "hi" , "ls" , "pnz",
  "ss" , "sc"

};

static void
write_instr_name_(struct arcDisState *state,
		  const char *instrName,
		  int cond,
		  int condCodeIsPartOfName,
		  int flag,
		  int signExtend,
		  int addrWriteBack,
		  int directMem)
{
	if (!instrName) {
		return;
	}
	strncpy (state->instrBuffer, instrName, sizeof (state->instrBuffer) - 1);
	state->instrBuffer[sizeof (state->instrBuffer) - 1] = '\0';
	size_t bufsize = sizeof (state->instrBuffer);
	if (cond > 0) {
		int condlim = 0; /* condition code limit*/
		const char *cc = 0;
		if (!condCodeIsPartOfName) {
			strncat (state->instrBuffer, ".", bufsize - strlen (state->instrBuffer) - 1);
		}
		condlim = 18;
		if (cond < condlim) {
			cc = condName[cond];
		} else {
			cc = cond_code_name (state, cond);
		}
		if (!cc) {
			cc = "???";
		}
		strncat (state->instrBuffer, cc, bufsize - strlen (state->instrBuffer) - 1);
    }
    if (flag) {
	    strncat (state->instrBuffer, ".f", bufsize - strlen (state->instrBuffer) - 1);
    }
    if (state->nullifyMode) {
	    if (strstr (state->instrBuffer, ".d") == NULL) {
		    strncat (state->instrBuffer, ".d", bufsize - strlen (state->instrBuffer) - 1);
	    }
    }
    if (signExtend) {
	    strncat (state->instrBuffer, ".x", bufsize - strlen (state->instrBuffer) - 1);
    }
    switch (addrWriteBack) {
    case 1: strncat(state->instrBuffer, ".a", bufsize - strlen (state->instrBuffer) - 1); break;
    case 2: strncat(state->instrBuffer, ".ab", bufsize - strlen (state->instrBuffer) - 1); break;
    case 3: strncat(state->instrBuffer, ".as", bufsize - strlen (state->instrBuffer) - 1); break;
  }
  if (directMem) {
	  strncat (state->instrBuffer, ".di", bufsize - strlen (state->instrBuffer) - 1);
  }
}

#define write_instr_name()	{\
  write_instr_name_(state, instrName,cond, condCodeIsPartOfName, flag, signExtend, addrWriteBack, directMem); \
 formatString[0] = '\0'; \
}

enum
{
  op_BC = 0, op_BLC = 1, op_LD  = 2, op_ST = 3, op_MAJOR_4  = 4,
  /* START ARC LOCAL */
  op_MAJOR_5 = 5, op_MAJOR_6 = 6, op_SIMD=9,      op_LD_ADD = 12, op_ADD_SUB_SHIFT  = 13,
  /* END ARC LOCAL */
  op_ADD_MOV_CMP = 14, op_S = 15, op_LD_S = 16, op_LDB_S = 17,
  op_LDW_S = 18, op_LDWX_S  = 19, op_ST_S = 20, op_STB_S = 21,
  op_STW_S = 22, op_Su5     = 23, op_SP   = 24, op_GP    = 25, op_Pcl = 26,
  op_MOV_S = 27, op_ADD_CMP = 28, op_BR_S = 29, op_B_S   = 30, op_BL_S = 31
};

extern disassemble_info tm_print_insn_info;

/*
 * bfd_getm32 - To retrieve the upper 16-bits of the ARCtangent-A5
 *              basecase (32-bit) instruction
 */
static bfd_vma bfd_getm32(unsigned int data) {
	bfd_vma value = ((data & 0xff00) | (data & 0xff)) << 16;
	value |= ((data & 0xff0000) | (data & 0xff000000)) >> 16;
	return value;
}

/*
 * bfd_getm32_ac - To retrieve the upper 8-bits of the ARCompact
 *                 16-bit instruction
 */
static bfd_vma bfd_getm32_ac (unsigned int data) {
	bfd_vma value = (data & 0xff) << 8 | (data & 0xff00) >> 8;
	return value;
}

/*
 * sign_extend - Sign Extend the value
 *
 */
static int sign_extend(int value, int bits) {
	if (BIT (value, (bits - 1))) {
		value |= (0xffffffff << bits);
	}
	return value;
}

/* dsmOneArcInst - This module is used to identify the instruction
 *		   and to decode them based on the ARCtangent-A5
 *                 instruction set architecture.
 *                 First, the major opcode is computed. Based on the
 *		   major opcode and sub opcode, the instruction is
 * 		   identified. The appropriate decoding class is assigned
 *		   based on the instruction.Further subopcode 2 is used in
 *                 cases where decoding upto subopcode1 is not possible.
 *
 *		   The instruction is then decoded accordingly.
 */
static int
dsmOneArcInst (bfd_vma addr, struct arcDisState *state, disassemble_info * info)
{
  int subopcode, mul;
  int condCodeIsPartOfName = 0;
  int decodingClass;
  const char *instrName;
  int fieldAisReg = 1, fieldBisReg = 1, fieldCisReg = 1;
  int fieldA = 0, fieldB = 0, fieldC = 0;
  int flag = 0, cond = 0, is_shimm = 0, is_limm = 0;
  int signExtend = 0, addrWriteBack = 0, directMem = 0;
  int is_linked = 0;
  int offset = 0;
  int usesAuxReg = 0;
  int usesSimdRegA= 0, usesSimdRegB = 0, usesSimdRegC = 0,simd_scale_u8=-1;
  int flags = !E_ARC_MACH_A4;
  char formatString[60];

  state->nullifyMode = BR_exec_when_no_jump;
  state->isBranch = 0;

  state->_mem_load = 0;
  state->_ea_present = 0;
  state->_load_len = 0;
  state->ea_reg1 = no_reg;
  state->ea_reg2 = no_reg;
  state->_offset = 0;

  state->sourceType = ARC_UNDEFINED;

  /* ARCtangent-A5 basecase instruction and little-endian mode */
  if ((info->endian == BFD_ENDIAN_LITTLE) && (state->instructionLen == 4)) {
	  state->words[0] = bfd_getm32 (state->words[0]);
  }

  if (state->instructionLen == 4)
  {
	  if (!NEXT_WORD (0)) {
		  return 0;
	  }
	  /* Get the major opcode of the ARCtangent-A5 32-bit instruction. */
	  state->_opcode = OPCODE (state->words[0]);
  } else {
    /* ARCompact 16-bit instruction */
    if (!NEXT_WORD_AC (0)) {
	    return 0;
    }
    /* Get the major opcode of the ARCompact 16-bit instruction. */
    state->_opcode = OPCODE_AC(state->words[0]);
  }

  instrName = 0;
  decodingClass = 0; /* default! */
  mul = 0;
  condCodeIsPartOfName = 0;
  state->commNum = 0;
  state->tcnt = 0;
  state->acnt = 0;
  state->flow = noflow;

  /* Find the match for the opcode. Once the major opcode category is
   * identified, get the subopcode to determine the exact instruction.
   * Based on the instruction identified, select the decoding class.
   * If condition code is part of the instruction name, then set the
   * flag 'condCodeIsPartOfName'.
   * For branch, jump instructions set 'isBranch' (state->isBranch).
   */

  switch (state->_opcode)
  {
    case op_BC:
    /* Branch Conditionally */
      instrName = "b";
      decodingClass = 13;
      condCodeIsPartOfName = 1;
      state->isBranch = 1;
      break;

    case op_BLC:
    /* Branch and Link, Compare and Branch  */
      decodingClass = 9;
      state->isBranch = 1;
      switch (BITS(state->words[0],16,16))
      {
	case 0:
		if (!instrName) {
			instrName = "bl";
		}
		decodingClass = 13;
		condCodeIsPartOfName = 1;
		break;
	case 1:
	  switch (BITS(state->words[0],0,3))
	  {
	    case 0: instrName = "breq"; break;
	    case 1: instrName = "brne"; break;
	    case 2: instrName = "brlt"; break;
	    case 3: instrName = "brge"; break;
	    case 4: instrName = "brlo"; break;
	    case 5: instrName = "brhs"; break;
	    case 14: instrName = "bbit0"; break;
	    case 15: instrName = "bbit1"; break;
	    default:
	      instrName = "??? (0[3])";
	      state->flow = invalid_instr;
	      break;
	  }
	  break;
	default:
	  instrName = "??? (0[3])";
	  state->flow = invalid_instr;
	  break;
      }
      break;

    case op_LD:
    /* Load register with offset [major opcode 2]  */
      decodingClass = 6;
      switch (BITS(state->words[0],7,8))
      {
	case 0: instrName  = "ld";  state->_load_len = 4; break;
	case 1: instrName  = "ldb"; state->_load_len = 1; break;
	case 2: instrName  = "ldw"; state->_load_len = 2; break;
	default:
	  instrName = "??? (0[3])";
	  state->flow = invalid_instr;
	  break;
      }
      break;

    case op_ST:
    /* Store register with offset [major opcode 0x03] */
      decodingClass = 7;
      switch (BITS(state->words[0],1,2))
      {
	case 0: instrName = "st";  break;
	case 1: instrName = "stb"; break;
  	case 2: instrName = "stw"; break;
	default:
	  instrName = "??? (2[3])";
	  state->flow = invalid_instr;
	  break;
      }
      break;

    case op_MAJOR_4:
    /* ARC 32-bit basecase instructions with 3 Operands */
      decodingClass = 0;  /* Default for 3 operand instructions */
      subopcode = BITS(state->words[0],16,21);
      switch (subopcode)
      {
        case 0: instrName = "add";  break;
        case 1: instrName = "adc";  break;
        case 2: instrName = "sub";  break;
        case 3: instrName = "sbc";  break;
        case 4: instrName = "and";  break;
        case 5: instrName = "or";   break;
        case 6: instrName = "bic";  break;
        case 7: instrName = "xor";  break;
      case 8: instrName = "max";  break;
      case 9: instrName = "min";  break;
      case 10:
	{
	  if (state->words[0] == 0x264a7000)
	    {
	      instrName = "nop";
	      decodingClass = 26;
	    } else {
	      instrName = "mov";
	      decodingClass = 12;
	    }
	  break;
	}
      case 11: instrName = "tst"; decodingClass = 2; break;
      case 12: instrName = "cmp"; decodingClass = 2; break;
      case 13: instrName = "rcmp"; decodingClass = 2; break;
      case 14: instrName = "rsub"; break;
      case 15: instrName = "bset"; break;
      case 16: instrName = "bclr"; break;
      case 17: instrName = "btst"; decodingClass = 2; break;
      case 18: instrName = "bxor"; break;
      case 19: instrName = "bmsk"; break;
      case 20: instrName = "add1"; break;
      case 21: instrName = "add2"; break;
      case 22: instrName = "add3"; break;
      case 23: instrName = "sub1"; break;
      case 24: instrName = "sub2"; break;
      case 25: instrName = "sub3"; break;
      case 30: instrName = "mpyw"; break;
      case 31: instrName = "mpyuw"; break;
        case 32:
        case 33:
	  instrName = "j";
        case 34:
        case 35:
		if (!instrName) {
			instrName = "jl";
		}
		decodingClass = 4;
		condCodeIsPartOfName = 1;
		state->isBranch = 1;
		break;
        case 40:
	  instrName = "lp";
	  decodingClass = 11;
	  condCodeIsPartOfName = 1;
          state->isBranch = 1;
	  break;
        case 41: instrName = "flag"; decodingClass = 3; break;
        case 42: instrName = "lr"; decodingClass = 10;  break;
        case 43: instrName = "sr"; decodingClass =  8;  break;
        case 47:
	  decodingClass = 1;
          switch (BITS(state->words[0],0,5)) /* Checking based on Subopcode2 */
	  {
	  case 0: instrName = "asl";  break;
	  case 1: instrName = "asr";  break;
	  case 2: instrName = "lsr";  break;
	  case 3: instrName = "ror";  break;
	  case 4: instrName = "rrc";  break;
	  case 5: instrName = "sexb"; break;
	  case 6: instrName = "sexw"; break;
	  case 7: instrName = "extb"; break;
	  case 8: instrName = "extw"; break;
	  case 9: instrName = "abs";  break;
	  case 10: instrName = "not"; break;
	  case 11: instrName = "rlc"; break;
	  case 12:  instrName = "ex";


	    decodingClass = 34;
	    break; // ramana adds

	  /* START ARC LOCAL */
	  case 16: instrName = "llock"; decodingClass = 34; break;
	  case 17: instrName = "scond"; decodingClass = 34; break;
	  /* END ARC LOCAL */

	  case 63:
	    decodingClass = 26;
	    switch (BITS(state->words[0],24,26))
	      {
	      case 1 : instrName = "sleep"; decodingClass = 32; break;
	      case 2 :
		      if ((info->mach) == ARC_MACH_ARC7) {
			      instrName = "trap0";
		      } else {
			      instrName = "swi";
		      }
		      break;
	      case 3:

		      if (BITS (state->words[0], 22, 23) == 1) {
			      instrName = "sync";
		      }

		      break;
	      case 4 : instrName = "rtie" ; break;
	      case 5 : instrName = "brk"; break;
	      default:

		instrName = "???";
		state->flow=invalid_instr;
		break;
	      }
	    break;
	  }
	  break;
      }

      if (!instrName)
      {
        subopcode = BITS(state->words[0],17,21);
	decodingClass = 5;
	switch (subopcode)
    	{
	  case 24: instrName  = "ld";   state->_load_len = 4; break;
	  case 25: instrName  = "ldb";  state->_load_len = 1; break;
	  case 26: instrName  = "ldw";  state->_load_len = 2; break;
	  default:
	    instrName = "??? (0[3])";
	    state->flow = invalid_instr;
	    break;
	}
      }
      break;

    case op_MAJOR_5:
    /* ARC 32-bit extension instructions */
      decodingClass = 0;  /* Default for Major opcode 5 ... */
      subopcode = BITS(state->words[0],16,21);
      switch (subopcode)
      {
	case 0: instrName = "asl"; break;
	case 1: instrName = "lsr"; break;
	case 2: instrName = "asr"; break;
	case 3: instrName = "ror"; break;
	case 4: instrName = "mul64"; mul = 1; decodingClass = 2; break;
	case 5: instrName = "mulu64"; mul = 1; decodingClass = 2; break;

	  /* ARC A700 */
      case 6: instrName = "adds" ;break;

      case 7: instrName = "subs"; break;
      case 8: instrName = "divaw"; break;
      case 0xA: instrName = "asls"; break;
      case 0xB: instrName = "asrs"; break;
      case 0x28: instrName = "addsdw";break;
      case 0x29: instrName = "subsdw"; break;

      case 47:
	switch(BITS(state->words[0],0,5))
	  {
	  case 0: instrName = "swap"; decodingClass = 1; break;
	  case 1: instrName = "norm"; decodingClass = 1; break;
	    /* ARC A700 ARC_DSP Extensions */
	  case 2: instrName = "sat16"; decodingClass = 1; break;
	  case 3: instrName = "rnd16"; decodingClass = 1; break;
	  case 4: instrName = "abssw"; decodingClass = 1; break;
	  case 5: instrName = "abss"; decodingClass = 1; break;
	  case 6: instrName = "negsw"; decodingClass = 1; break;
	  case 7: instrName = "negs"; decodingClass = 1; break;

	  case 8: instrName = "normw"; decodingClass = 1; break;

	  /* START ARC LOCAL */
	  case 9: instrName = "swape"; decodingClass = 1; break;
	  /* END ARC LOCAL */

	  default:
	    instrName = "???";
	    state->flow =invalid_instr;
	    break;

	  }
	break;
      default:
	instrName = "??? (2[3])";
	state->flow = invalid_instr;
	break;
      }
    break;

  /* START ARC LOCAL */
  case op_MAJOR_6:
      decodingClass = 44;  /* Default for Major opcode 6 ... */
      subopcode = BITS(state->words[0],0,5);
      switch (subopcode)
        {
	case 26: /* 0x1a */ instrName = "rtsc"; break;
        default:
	  instrName = "??? (2[3])";
	  state->flow = invalid_instr;
	  break;
	}
    break;
  /* END ARC LOCAL */

    /* Aurora SIMD instruction support*/
  case op_SIMD:

    if (enable_simd)
      {
	decodingClass = 42;
	subopcode     = BITS(state->words[0], 17, 23);

	switch (subopcode)
	  {

	  case 68:
	    instrName = "vld32";
	    decodingClass = 37;
	    usesSimdRegA = 1;
	    usesSimdRegB = 2;
	    usesSimdRegC = 0;
	    simd_scale_u8 = 2;
	    break;

	  case 72:
	    instrName = "vld64";
	    decodingClass = 37;
	    usesSimdRegA  = 1;
	    usesSimdRegB  = 2;
	    usesSimdRegC  = 0;
	    simd_scale_u8 = 3;
	    break;

	  case 74:
	    instrName = "vld64w";
	    decodingClass = 37;
	    usesSimdRegA  = 1;
	    usesSimdRegB  = 2;
	    usesSimdRegC  = 0;
	    simd_scale_u8 = 3;
	    break;

	  case 70:
	    instrName = "vld32wl";
	    decodingClass = 37;
	    usesSimdRegA  = 1;
	    usesSimdRegB  = 2;
	    usesSimdRegC  = 0;
	    simd_scale_u8 = 2;
	    break;

	  case 66:
	    instrName = "vld32wh";
	    decodingClass = 37;
	    usesSimdRegA  = 1;
	    usesSimdRegB  = 2;
	    usesSimdRegC  = 0;
	    simd_scale_u8 = 2;
	    break;

	  case 76:
	    instrName = "vld128";
	    decodingClass = 37;
	    usesSimdRegA  = 1;
	    usesSimdRegB  = 2;
	    usesSimdRegC  = 0;
	    simd_scale_u8 = 4;
	    break;

	  case 78:
	    {
	      short  sub_subopcode = BITS(state->words[0], 15, 16);
	      switch (sub_subopcode)
		{
		case 0:
		  instrName = "vld128r";
		  decodingClass = 38;
		  usesSimdRegA  = 1;
		  usesSimdRegB  = usesSimdRegC = 0;
		  break;
		default:
		  instrName = "SIMD";
		  state->flow = invalid_instr;
		}
	    }
	    break;
	  case 71:
	    instrName = "vst16_0";
	    decodingClass = 37;
	    usesSimdRegA = 1;
	    usesSimdRegB = 2;
	    usesSimdRegC = 0;
	    simd_scale_u8 = 1;
	    break;

	  case 81:
	    instrName = "vst16_1";
	    decodingClass = 37;
	    usesSimdRegA = 1;
	    usesSimdRegB = 2;
	    usesSimdRegC = 0;
	    simd_scale_u8 = 1;
	    break;

	  case 67:
	    instrName = "vst16_2";
	    decodingClass = 37;
	    usesSimdRegA = 1;
	    usesSimdRegB = 2;
	    usesSimdRegC = 0;
	    simd_scale_u8 = 1;
	    break;

	  case 75:
	    instrName = "vst16_3";
	    decodingClass = 37;
	    usesSimdRegA = 1;
	    usesSimdRegB = 2;
	    usesSimdRegC = 0;
	    simd_scale_u8 = 1;
	    break;

	  case 83:
	    instrName = "vst16_4";
	    decodingClass = 37;
	    usesSimdRegA = 1;
	    usesSimdRegB = 2;
	    usesSimdRegC = 0;
	    simd_scale_u8 = 1;
	    break;

	  case 89:
	    instrName = "vst16_5";
	    decodingClass = 37;
	    usesSimdRegA = 1;
	    usesSimdRegB = 2;
	    usesSimdRegC = 0;
	    simd_scale_u8 = 1;
	    break;

	  case 91:
	    instrName = "vst16_6";
	    decodingClass = 37;
	    usesSimdRegA = 1;
	    usesSimdRegB = 2;
	    usesSimdRegC = 0;
	    simd_scale_u8 = 1;
	    break;

	  case 93:
	    instrName = "vst16_7";
	    decodingClass = 37;
	    usesSimdRegA = 1;
	    usesSimdRegB = 2;
	    usesSimdRegC = 0;
	    simd_scale_u8 = 1;
	    break;

	  case 69:
	    instrName = "vst32_0";
	    decodingClass = 37;
	    usesSimdRegA  = 1;
	    usesSimdRegB  = 2;
	    usesSimdRegC  = 0;
	    simd_scale_u8 = 2;
	    break;

	  case 82:
	    instrName = "vst32_2";
	    decodingClass = 37;
	    usesSimdRegA  = 1;
	    usesSimdRegB  = 2;
	    usesSimdRegC  = 0;
	    simd_scale_u8 = 2;
	    break;

	  case 86:
	    instrName = "vst32_4";
	    decodingClass = 37;
	    usesSimdRegA  = 1;
	    usesSimdRegB  = 2;
	    usesSimdRegC  = 0;
	    simd_scale_u8 = 2;
	    break;

	  case 88:
	    instrName = "vst32_6";
	    decodingClass = 37;
	    usesSimdRegA  = 1;
	    usesSimdRegB  = 2;
	    usesSimdRegC  = 0;
	    simd_scale_u8 = 2;
	    break;

	  case 73:
	    instrName = "vst64";
	    decodingClass = 37 ;
	    usesSimdRegA  = 1;
	    usesSimdRegB  = 2;
	    usesSimdRegC  = 0;
	    simd_scale_u8 = 3;
	    break;

	  case 77:
	    instrName = "vst128";
	    decodingClass = 37;
	    usesSimdRegA  = 1;
	    usesSimdRegB  = 2;
	    usesSimdRegC  = 0;
	    simd_scale_u8 = 4;
	    break;

	  case 79:
	    {
	      short sub_subopcode = BITS(state->words[0], 15, 16);
	      switch (sub_subopcode)
		{
		case 0:
		  instrName = "vst128r";
		  decodingClass = 38;
		  usesSimdRegA = 1;
		  usesSimdRegB = usesSimdRegC = 0;
		  break;

		default:
		  instrName = "SIMD";
		  state->flow = invalid_instr;
		}

	    }
	    break;
	  case 80:
	    instrName = "vmvw";
	    usesSimdRegA = usesSimdRegB = 1;
	    usesSimdRegC = 0;
	    decodingClass = 39;
	    break;

	  case 84:
	    instrName = "vmvzw";
	    decodingClass = 39;
	    usesSimdRegA = usesSimdRegB = 1;
	    usesSimdRegC = 0;
	    break;

	  case 90:
	    instrName = "vmovw";
	    decodingClass = 39;
	    usesSimdRegA  = 1;
	    usesSimdRegB  = usesSimdRegC = 0;
	    break;

	  case 94:
	    instrName = "vmovzw";
	    decodingClass = 39;
	    usesSimdRegA  = 1;
	    usesSimdRegB  = usesSimdRegC = 0;
	    break;

	  case 85:
	    instrName = "vmvaw";
	    decodingClass = 39;
	    usesSimdRegA  = usesSimdRegB = 1;
	    usesSimdRegC  = 0;
	    break;

	  case 95:
	    instrName = "vmovaw";
	    decodingClass = 39;
	    usesSimdRegA  = 1;
	    usesSimdRegB  = usesSimdRegC = 0;
	    break;

	  case 10:
	    {
	      short sub_subopcode = BITS(state->words[0], 15, 16);
	      switch (sub_subopcode)
		{
		case 0:
		  instrName = "vaddw"; decodingClass = 42;
		  usesSimdRegA = usesSimdRegB = usesSimdRegC = 1;
		  break;

		case 1:
		  instrName = "vaddaw"; decodingClass = 42;
		  usesSimdRegA = usesSimdRegB = usesSimdRegC = 1;
		  break;

		case 2:
		  instrName = "vbaddw"; decodingClass = 42;
		  usesSimdRegA = usesSimdRegB = 1;
		  usesSimdRegC = 0;
		  break;
		}
	      break;
	    }

	  case 11:
	    {
	      short sub_subopcode = BITS(state->words[0], 15, 16);
	      switch (sub_subopcode)
		{
		case 0:
		  instrName = "vsubw";
		  decodingClass = 42;
		  usesSimdRegA  = usesSimdRegB = usesSimdRegC = 1;
		  break;

		case 1:
		  instrName = "vsubaw";
		  decodingClass = 42;
		  usesSimdRegA  = usesSimdRegB = usesSimdRegC = 1;
		  break;

		case 2:
		  instrName = "vbsubw";
		  decodingClass = 42;
		  usesSimdRegA  = usesSimdRegB = 1;
		  usesSimdRegC  = 0;
		  break;
		}
	    }
	    break;

	  case 12:
	    {
	      short sub_subopcode = BITS(state->words[0], 15, 16);
	      switch (sub_subopcode)
		{
		case 0:
		  instrName = "vmulw";
		  decodingClass = 42;
		  usesSimdRegA  = usesSimdRegB = usesSimdRegC = 1;
		  break;

		case 1:
		  instrName = "vmulaw";
		  decodingClass = 42;
		  usesSimdRegA  = usesSimdRegB = usesSimdRegC = 1;
		  break;

		case 2:
		  instrName = "vbmulw";
		  decodingClass = 42;
		  usesSimdRegA  = usesSimdRegB = 1;
		  usesSimdRegC  = 0;
		  break;

		case 3:
		  instrName = "vbmulaw";
		  decodingClass = 42;
		  usesSimdRegA  = usesSimdRegB = 1;
		  usesSimdRegC  = 0;
		  break;
		}
	    }
	    break;

	  case 13:
	    {
	      short sub_subopcode = BITS(state->words[0], 15, 16);
	      switch (sub_subopcode)
		{
		case 0:
		  instrName = "vmulfw";
		  decodingClass = 42;
		  usesSimdRegA  = usesSimdRegB = usesSimdRegC = 1;
		  break;

		case 1:
		  instrName = "vmulfaw";
		  decodingClass = 42;
		  usesSimdRegA  = usesSimdRegB = usesSimdRegC = 1;
		  break;

		case 2:
		  instrName = "vbmulfw";
		  decodingClass = 42;
		  usesSimdRegA  = usesSimdRegB = 1;
		  usesSimdRegC  = 0;
		  break;
		}
	    }
	    break;

	  case 15:
	    {
	      short sub_subopcode = BITS(state->words[0], 15, 16);
	      switch (sub_subopcode)
		{
		case 0:
		  instrName = "vsummw";
		  decodingClass = 42;
		  usesSimdRegA = usesSimdRegB = usesSimdRegC = 1;
		  break;
		case 2:
		  instrName = "vbrsubw";
		  decodingClass = 42;
		  usesSimdRegA  = usesSimdRegB = 1;
		  usesSimdRegC  = 0;
		  break;
		}
	    }
	    break;

	  case 23:
	    {
	      short sub_subopcode = BITS(state->words[0], 15, 16);
	      switch (sub_subopcode)
		{
		case 0:
		  instrName = "vmr7w";
		  decodingClass = 42;
		  usesSimdRegA  = usesSimdRegB = usesSimdRegC = 1;
		  break;

		case 1:
		  instrName = "vmr7aw";
		  decodingClass = 42;
		  usesSimdRegA  = usesSimdRegB = usesSimdRegC = 1;
		  break;


		case 2:
		  switch (BITS(state->words[0], 0, 5))
		    {
		    case 0:
		      instrName = "vaddsuw";
		      decodingClass = 40;
		      usesSimdRegC  = usesSimdRegB = 1;
		      usesSimdRegA  = 0;
		      break;

		    case 1:
		      instrName = "vabsw";
		      decodingClass = 40;
		      usesSimdRegC  = usesSimdRegB = 1;
		      usesSimdRegA  = 0;
		      break;

		    case 2:
		      instrName = "vsignw";
		      decodingClass = 40;
		      usesSimdRegC  = usesSimdRegB = 1;
		      usesSimdRegA  = 0;
		      break;

		    case 3:
		      instrName = "vupbw";
		      decodingClass = 40;
		      usesSimdRegC  = usesSimdRegB = 1;
		      usesSimdRegA  = 0;
		      break;

		    case 4:
		      instrName = "vexch1";
		      decodingClass = 40;
		      usesSimdRegC  = usesSimdRegB = 1;
		      usesSimdRegA  = 0;
		      break;

		    case 5:
		      instrName = "vexch2";
		      decodingClass = 40;
		      usesSimdRegC  = usesSimdRegB = 1;
		      usesSimdRegA  = 0;
		      break;

		    case 6:
		      instrName = "vexch4";
		      decodingClass = 40;
		      usesSimdRegC  = usesSimdRegB = 1;
		      usesSimdRegA  = 0;
		      break;

		    case 7:
		      instrName = "vupsbw";
		      decodingClass = 40;
		      usesSimdRegC  = usesSimdRegB = 1;
		      usesSimdRegA  = 0;
		      break;

		    case 8:
		      instrName = "vdirun";
		      decodingClass = 40;
		      usesSimdRegC  = usesSimdRegB = usesSimdRegA = 0;
		      break;

		    case 9:
		      instrName = "vdorun";
		      decodingClass = 40;
		      usesSimdRegC  = usesSimdRegB = usesSimdRegA = 0;
		      break;

		    case 10:
		      instrName = "vdiwr";
		      decodingClass = 40;
		      usesSimdRegB  = 3;
		      usesSimdRegA  = usesSimdRegC = 0;
		      break;

		    case 11:
		      instrName = "vdowr";
		      decodingClass = 40;
		      usesSimdRegB  = 3;
		      usesSimdRegA  = usesSimdRegC = 0;
		      break;

		    case 12:
		      instrName = "vdird";
		      decodingClass = 40;
		      usesSimdRegB  = 1;
		      usesSimdRegC  = 3;
		      usesSimdRegA  = 0;
		      break;

		    case 13:
		      instrName = "vdord";
		      decodingClass = 40;
		      usesSimdRegB  = 1;
		      usesSimdRegC  = 3;
		      usesSimdRegA  = 0;
		      break;

		    case 63:
		      {
			switch (BITS(state->words[0], 24, 25))
			  {
			  case 0:
			    instrName = "vrec";
			    decodingClass = 43;
			    usesSimdRegC  = 0;
			    usesSimdRegB  = usesSimdRegA = 0;
			    break;

			  case 1:
			    instrName = "vrecrun";
			    decodingClass = 43;
			    usesSimdRegC  = 0;
			    usesSimdRegA  = usesSimdRegB = 0;
			    break;

			  case 2:
			    instrName = "vrun";
			    decodingClass = 43;
			    usesSimdRegC  = 0;
			    usesSimdRegB  = usesSimdRegA = 0;
			    break;

			  case 3:
			    instrName = "vendrec";
			    decodingClass = 43;
			    usesSimdRegC  = 0;
			    usesSimdRegB  = usesSimdRegA = 0;
			    break;
			  }
		      }
		      break;
		    }
		  break;

		case 3:
		  switch (BITS(state->words[0], 0, 2))
		    {
		    case 1:
		      instrName = "vabsaw";
		      decodingClass = 40;
		      usesSimdRegC  = usesSimdRegB = 1;
		      usesSimdRegA  = 0;
		      break;
		    case 3:
		      instrName = "vupbaw";
		      decodingClass = 40;
		      usesSimdRegC  = usesSimdRegB = 1;
		      usesSimdRegA  = 0;
		      break;
		    case 7:
		      instrName = "vupsbaw";
		      decodingClass = 40;
		      usesSimdRegC  = usesSimdRegB = 1;
		      usesSimdRegA  = 0;
		      break;
		    }
		  break;
		}
	    }
	    break;

	  case 16:
	    instrName = "vasrw";
	    decodingClass = 42;
	    usesSimdRegA  = usesSimdRegB = 1;
	    usesSimdRegC  = 2;
	    break;

	  case 48:
	    {
	      short sub_subopcode = BITS(state->words[0], 15, 16);
	      switch (sub_subopcode)
		{
		case 0:
		  instrName = "vasrwi";
		  decodingClass = 41;
		  usesSimdRegA  = usesSimdRegB = 1;
		  usesSimdRegC  = 0;
		  break;
		case 2:
		  instrName = "vasrrwi";
		  decodingClass = 41;
		  usesSimdRegA  = usesSimdRegB = 1;
		  usesSimdRegC  = 0;
		  break;
		}
	    }
	    break;

	  case 59:
	    instrName = "vasrsrwi";
	    decodingClass = 41;
	    usesSimdRegA  = usesSimdRegB = 1;
	    usesSimdRegC  = 0;
	    break;

	  case 18:
	    {
	      short sub_subopcode = BITS(state->words[0], 15, 16);
	      switch (sub_subopcode)
		{
		case 0:
		  instrName = "vmaxw";
		  usesSimdRegC = 1;
		  break;
		case 1:
		  instrName = "vmaxaw";
		  usesSimdRegC = 1;
		  break;
		case 2:
		  instrName = "vbmaxw";
		  usesSimdRegC = 0;
		  break;
		}
	      decodingClass = 42;
	      usesSimdRegA  = usesSimdRegB = 1;
	      break;
	    }

	  case 19:
	    {
	      short sub_subopcode = BITS(state->words[0], 15, 16);
	      switch (sub_subopcode)
		{
		case 0:
		  instrName = "vminw";
		  usesSimdRegC = 1;
		  break;
		case 1:
		  instrName = "vminaw";
		  usesSimdRegC = 0;
		  break;
		case 2:
		  instrName = "vbminw";
		  usesSimdRegC = 0;
		  break;
		}
	      decodingClass = 42;
	      usesSimdRegA  = usesSimdRegB = 1;
	      break;
	    }

	  case 14:
	    {
	      short sub_subopcode = BITS(state->words[0], 15, 16);
	      switch (sub_subopcode)
		{
		case 0:
		  instrName = "vdifw";
		  break;
		case 1:
		  instrName = "vdifaw";
		  break;
		case 2:
		  instrName = "vmrb";
		  break;
		}
	      decodingClass = 42;
	      usesSimdRegA  = usesSimdRegB = usesSimdRegC = 1;
	      break;
	    }

	  case 24:
	    {
	      short sub_subopcode = BITS(state->words[0], 15, 16);
	      switch (sub_subopcode)
		{
		case 0:
		  instrName = "vand";
		  decodingClass = 42;
		  usesSimdRegA = usesSimdRegB = usesSimdRegC = 1;
		  break;
		case 1:
		  instrName = "vandaw";
		  decodingClass = 42;
		  usesSimdRegA = usesSimdRegB = usesSimdRegC = 1;
		  break;
		}
	      break;
	    }

	  case 25:
	    {
	      short sub_subopcode = BITS(state->words[0], 15, 16);
	      switch (sub_subopcode)
		{
		case 0:
		  instrName = "vor";
		  decodingClass = 42;
		  usesSimdRegA  = usesSimdRegB = usesSimdRegC = 1;
		  break;
		}
	      break;
	    }

	  case 26:
	    {
	      short sub_subopcode = BITS(state->words[0], 15, 16);
	      switch (sub_subopcode)
		{
		case 0:
		  instrName = "vxor";
		  break;
		case 1:
		  instrName = "vxoraw";
		  break;
		}
	      decodingClass = 42;
	      usesSimdRegA  = usesSimdRegB = usesSimdRegC = 1;
	      break;
	    }

	  case 27:
	    {
	      short sub_subopcode = BITS(state->words[0], 15, 16);
	      switch (sub_subopcode)
		{
		case 0:
		  instrName = "vbic";
		  break;
		case 1:
		  instrName = "vbicaw";
		  break;
		}
	      decodingClass = 42;
	      usesSimdRegA  = usesSimdRegB = usesSimdRegC = 1;
	      break;
	    }

	  case 4:
	    {
	      short sub_subopcode = BITS(state->words[0], 15, 16);
	      switch (sub_subopcode)
		{
		case 0:
		  instrName = "vavb";
		  break;
		case 2:
		  instrName = "vavrb";
		  break;
		}
	      decodingClass = 42;
	      usesSimdRegA  = usesSimdRegB = usesSimdRegC = 1;
	      break;
	    }

	  case 28:
	    instrName = "veqw";
	    decodingClass = 42;
	    usesSimdRegA  = usesSimdRegB = usesSimdRegC = 1;
	    break;

	  case 29:
	    instrName = "vnew";
	    decodingClass = 42;
	    usesSimdRegA  = usesSimdRegB = usesSimdRegC = 1;
	    break;

	  case 30:
	    instrName = "vlew";
	    decodingClass = 42;
	    usesSimdRegA  = usesSimdRegB = usesSimdRegC = 1;
	    break;

	  case 31:
	    instrName = "vltw";
	    decodingClass = 42;
	    usesSimdRegA  = usesSimdRegB = usesSimdRegC = 1;
	    break;

	  case 49:
	    {
	      short sub_subopcode = BITS(state->words[0], 15, 16);
	      switch (sub_subopcode)
		{
		case 0:
		  instrName = "vasrpwbi";
		  decodingClass = 41;
		  usesSimdRegA  = usesSimdRegB = 1;
		  usesSimdRegC  = 0;
		  break;
		case 2:
		  instrName = "vasrrpwbi";
		  decodingClass = 41;
		  usesSimdRegA  = usesSimdRegB = 1;
		  usesSimdRegC  = 0;
		  break;
		}
	      break;
	    }

	  case 5:
	    {
	      short sub_subopcode = BITS(state->words[0], 15, 16);
	      switch (sub_subopcode)
		{
		case 0:
		  instrName = "vsr8";
		  decodingClass = 42;
		  usesSimdRegA  = usesSimdRegB = 1;
		  usesSimdRegC  = 2;
		  break;

		case 1:
		  instrName = "vsr8aw";
		  decodingClass = 42;
		  usesSimdRegA  = usesSimdRegB = 1;
		  usesSimdRegC  = 2;
		  break;
		}
	      break;
	    }

	  case 37:
	    {
	      short sub_subopcode = BITS(state->words[0], 15, 16);
	      switch (sub_subopcode)
		{
		case 0:
		  instrName = "vsr8i";
		  decodingClass = 41;
		  usesSimdRegA  = usesSimdRegB = 1;
		  usesSimdRegC  = 0;
		  break;

		case 1:
		  instrName = "vsr8awi";
		  decodingClass = 41;
		  usesSimdRegA  = usesSimdRegB = 1;
		  usesSimdRegC  = 0;
		  break;
		}
	      break;
	    }

	  case 20:
	  case 21:
	  case 22:
	    {
	      short subopcode2 = BITS(state->words[0], 15, 18);
	      switch (subopcode2)
		{
		case 0:
		  instrName = "vmr1w";
		  break;

		case 2:
		  instrName = "vmr2w";
		  break;

		case 4:
		  instrName = "vmr3w";
		  break;

		case 6:
		  instrName = "vmr4w";
		  break;

		case 8:
		  instrName = "vmr5w";
		  break;

		case 10:
		  instrName = "vmr6w";
		  break;

		case 1:
		  instrName = "vmr1aw";
		  break;

		case 3:
		  instrName = "vmr2aw";
		  break;

		case 5:
		  instrName = "vmr3aw";
		  break;

		case 7:
		  instrName = "vmr4aw";
		  break;

		case 9:
		  instrName = "vmr5aw";
		  break;

		case 11:
		  instrName = "vmr6aw";
		  break;

		}

	      decodingClass = 42;
	      usesSimdRegA  = usesSimdRegB = usesSimdRegC = 1;
	      break;
	    }


	  case 7:
	  case 6:
	    {
	      switch (BITS(state->words[0], 16, 19))
		{
		case 15:
		  instrName = "vh264ft";
		  break;
		case 14:
		  instrName = "vh264f";
		  break;
		case 13:
		  instrName = "vvc1ft";
		  break;
		case 12:
		  instrName = "vvc1f";
		  break;
		}
	      decodingClass = 42;
	      usesSimdRegA  = usesSimdRegB = usesSimdRegC = 1;
	      break;

	    }

	  case 92:
	    instrName = "vd6tapf";
	    decodingClass = 39;
	    usesSimdRegA  = usesSimdRegB = 1;
	    usesSimdRegC  = 0;
	    break;

	  case 55:
	    instrName = "vinti";
	    decodingClass = 43;
	    usesSimdRegA  = usesSimdRegB = usesSimdRegC = 0;
	    break;

	  default:
	    instrName = "SIMD";
	    state->flow = invalid_instr;
	    break;
	  }
      } else {
	instrName = "???_SIMD";
	state->flow = invalid_instr;
      }
	break;


    case op_LD_ADD:
    /* Load/Add resister-register */
      decodingClass = 15;  /* default for Major opcode 12 ... */
      switch(BITS(state->words[0],3,4))
	{
	case 0: instrName = "ld_s"; break;
	case 1: instrName = "ldb_s"; break;
	case 2: instrName = "ldw_s"; break;
	case 3: instrName = "add_s"; break;
        default:
	  instrName = "??? (2[3])";
	  state->flow = invalid_instr;
	  break;
	}
      break;

  case op_ADD_SUB_SHIFT:
    /* Add/sub/shift immediate */
    decodingClass = 16;  /* default for Major opcode 13 ... */
    switch(BITS(state->words[0],3,4))
      {
      case 0: instrName = "add_s"; break;
      case 1: instrName = "sub_s"; break;
      case 2: instrName = "asl_s"; break;
      case 3: instrName = "asr_s"; break;
      default:
	instrName = "??? (2[3])";
	state->flow = invalid_instr;
	break;
      }
    break;

    case op_ADD_MOV_CMP:
    /* One Dest/Source can be any of r0 - r63 */
      decodingClass = 17;  /* default for Major opcode 14 ... */
      switch(BITS(state->words[0],3,4))
      {
	case 0: instrName = "add_s"; break;
	case 1:
	case 3: instrName = "mov_s"; decodingClass = 18; break;
	case 2: instrName = "cmp_s"; decodingClass = 18; break;
        default:
	  instrName = "??? (2[3])";
	  state->flow = invalid_instr;
	  break;
      }
      break;

    case op_S:
    /* ARCompact 16-bit instructions, General ops/ single ops */
      decodingClass = 22;  /* default for Major opcode 15 ... */
      switch(BITS(state->words[0],0,4))
      {
	case 0:
	  decodingClass = 27;
          switch(BITS(state->words[0],5,7))
	  {
            case 0 : instrName = "j_s";
            case 2 :
		    if (!instrName) {
			    instrName = "jl_s";
		    }
		    state->isBranch = 1;
		    state->nullifyMode = BR_exec_when_no_jump;
		    break;
            case 1 :
		    if (!instrName) {
			    instrName = "j_s.d";
		    }
	    case 3 :
		    if (!instrName) {
			    instrName = "jl_s.d";
		    }
		    state->isBranch = 1;
		    state->nullifyMode = BR_exec_always;
		    break;
            case 6 : instrName = "sub_s.ne";
	             decodingClass = 35;
	             break;
            case 7 :
	      decodingClass = 26;
              switch(BITS(state->words[0],8,10))
	      {
              	case 0 : instrName = "nop_s"; break;

		  /* Unimplemented instruction reserved in ARC700 */
	        case 1: instrName = "unimp_s";break;


	        case 4: instrName = "jeq_s [blink]";
		case 5:
			if (!instrName) {
				instrName = "jne_s [blink]";
			}
		case 6:
			if (!instrName) {
				instrName = "j_s [blink]";
			}
			state->isBranch = 1;
			state->nullifyMode = BR_exec_when_no_jump;
			break;
		case 7:
			if (!instrName) {
				instrName = "j_s.d [blink]";
			}
			state->isBranch = 1;
			state->nullifyMode = BR_exec_always;
			break;
                default:
		  instrName = "??? (2[3])";
	      	  state->flow = invalid_instr;
		  break;
	      }
	      break;
            default:
	      instrName = "??? (2[3])";
	      state->flow = invalid_instr;
	      break;
	  }
	  break;
        case 2 : instrName = "sub_s"; break;
        case 4 : instrName = "and_s"; break;
        case 5 : instrName = "or_s"; break;
        case 6 : instrName = "bic_s"; break;
        case 7 : instrName = "xor_s"; break;
	case 11: instrName = "tst_s"; decodingClass = 14; break;
	case 12: instrName = "mul64_s"; mul = 1; decodingClass = 14; break;
	case 13: instrName = "sexb_s"; decodingClass = 14; break;
	case 14: instrName = "sexw_s"; decodingClass = 14; break;
	case 15: instrName = "extb_s"; decodingClass = 14; break;
	case 16: instrName = "extw_s"; decodingClass = 14; break;
	case 17: instrName = "abs_s"; decodingClass = 14; break;
	case 18: instrName = "not_s"; decodingClass = 14; break;
	case 19: instrName = "neg_s"; decodingClass = 14; break;
        case 20: instrName = "add1_s"; break;
        case 21: instrName = "add2_s"; break;
        case 22: instrName = "add3_s"; break;
        case 24: instrName = "asl_s"; break;
        case 25: instrName = "lsr_s"; break;
        case 26: instrName = "asr_s"; break;
        case 27: instrName = "asl_s"; decodingClass = 14; break;
        case 28: instrName = "asr_s"; decodingClass = 14; break;
        case 29: instrName = "lsr_s"; decodingClass = 14; break;
      case 30: instrName = "trap_s"; decodingClass = 33; break;
      case 31: instrName = "brk_s"; decodingClass = 26; break;

        default:
	  instrName = "??? (2[3])";
	  state->flow = invalid_instr;
	  break;
      }
      break;

       case op_LD_S:
    /* ARCompact 16-bit Load with offset, Major Opcode 0x10 */
      instrName = "ld_s";
      decodingClass = 28;
      break;

    case op_LDB_S:
    /* ARCompact 16-bit Load with offset, Major Opcode 0x11 */
      instrName = "ldb_s";
      decodingClass = 28;
      break;

    case op_LDW_S:
    /* ARCompact 16-bit Load with offset, Major Opcode 0x12 */
      instrName = "ldw_s";
      decodingClass = 28;
      break;

    case op_LDWX_S:
    /* ARCompact 16-bit Load with offset, Major Opcode 0x13 */
      instrName = "ldw_s.x";
      decodingClass = 28;
      break;

    case op_ST_S:
    /* ARCompact 16-bit Store with offset, Major Opcode 0x14 */
      instrName = "st_s";
      decodingClass = 28;
      break;

    case op_STB_S:
    /* ARCompact 16-bit Store with offset, Major Opcode 0x15 */
      instrName = "stb_s";
      decodingClass = 28;
      break;

    case op_STW_S:
    /* ARCompact 16-bit Store with offset, Major Opcode 0x16 */
      instrName = "stw_s";
      decodingClass = 28;
      break;

    case op_Su5:
    /* ARCompact 16-bit involving unsigned 5-bit immediate operand */
      decodingClass = 23;  /* default for major opcode 0x17 ... */
      switch (BITS(state->words[0],5,7))
      {
	case 0: instrName = "asl_s"; break;
	case 1: instrName = "lsr_s"; break;
	case 2: instrName = "asr_s"; break;
	case 3: instrName = "sub_s"; break;
	case 4: instrName = "bset_s"; break;
	case 5: instrName = "bclr_s"; break;
	case 6: instrName = "bmsk_s"; break;
	case 7: instrName = "btst_s"; decodingClass = 21; break;
      }
      break;

    case op_SP:
    /* ARCompact 16-bit Stack pointer-based instructions */
      decodingClass = 19;  /* default for Stack pointer-based insns ... */
      switch (BITS(state->words[0],5,7))
      {
        case 0: instrName = "ld_s"; break;
        case 1: instrName = "ldb_s"; break;
        case 2: instrName = "st_s"; break;
        case 3: instrName = "stb_s"; break;
        case 4: instrName = "add_s"; break;
        case 5:
		if (!BITS (state->words[0], 8, 8)) {
			instrName = "add_s";
		} else {
			instrName = "sub_s";
		}
		break;
        case 6: instrName = "pop_s"; decodingClass = 31; break;
        case 7: instrName = "push_s"; decodingClass = 31; break;
	default:
          instrName = "??? (2[3])";
          state->flow = invalid_instr;
	  break;
      }
    break;

    case op_GP:
    /* ARCompact 16-bit Gp-based ld/add (data aligned offset) */
      decodingClass = 20;  /* default for gp-relative insns ... */
      switch (BITS(state->words[0],9,10))
      {
        case 0: instrName = "ld_s"; break;
        case 1: instrName = "ldb_s"; break;
        case 2: instrName = "ldw_s"; break;
        case 3: instrName = "add_s"; break;
      }
      break;

    case op_Pcl:
    /* ARCompact 16-bit Pcl-based ld (32-bit aligned offset) */
      instrName = "ld_s";
      decodingClass = 29;
      break;

    case op_MOV_S:
    /* ARCompact 16-bit Move immediate */
      instrName = "mov_s";
      decodingClass = 30;
      break;

    case op_ADD_CMP:
    /* ARCompact 16-bit Add/compare immediate */
      decodingClass = 21;  /* default for major opcode 0x1c ... */
      if (BIT (state->words[0], 7)) {
	      instrName = "cmp_s";
      } else {
	      instrName = "add_s";
      }
      break;

    case op_BR_S:
    /* ARCompact 16-bit Branch conditionally on reg z/nz */
      decodingClass = 25; /* Default for BR_S instruction ... */
      if (BIT (state->words[0], 7)) {
	      instrName = "brne_s";
      } else {
	      instrName = "breq_s";
      }
      state->isBranch = 1;
      break;

    case op_B_S:
    /* ARCompact 16-bit Branch conditionally */
      decodingClass = 24; /* Default for B_S instruction ... */
      state->isBranch = 1;
      switch (BITS(state->words[0],9,10))
      {
	case 0: instrName = "b_s"; break;
	case 1: instrName = "beq_s"; break;
	case 2: instrName = "bne_s"; break;
	case 3:
          switch (BITS(state->words[0],6,8))
	  {
	    case 0: instrName = "bgt_s"; break;
	    case 1: instrName = "bge_s"; break;
	    case 2: instrName = "blt_s"; break;
	    case 3: instrName = "ble_s"; break;
	    case 4: instrName = "bhi_s"; break;
	    case 5: instrName = "bhs_s"; break;
	    case 6: instrName = "blo_s"; break;
	    case 7: instrName = "bls_s"; break;
	  }
	  break;
      }
      break;

    case op_BL_S:
    /* ARCompact 16-bit Branch and link unconditionally */
      decodingClass = 24; /* Default for B_S instruction ... */
      instrName = "bl_s";
      state->isBranch = 1;
      break;

    default:

      instrName = "???";
      state->flow=invalid_instr;
      break;
  }

  /* Maybe we should be checking for extension instructions over here
   * instead of all over this crazy switch case. */
  if (state->flow == invalid_instr)
    {
	  if (!((state->_opcode == op_SIMD) && enable_simd)) {
		  instrName = instruction_name (state, state->_opcode,
			  state->words[0],
			  &flags);
	  }

	  if (state->instructionLen == 2) {
		  switch (flags) {
		  case AC_SYNTAX_3OP:
			  decodingClass = 22;
			  break;
		  case AC_SYNTAX_2OP:
			  decodingClass = 14;
			  break;
		  case AC_SYNTAX_1OP:
			  decodingClass = 36;
			  break;
		  case AC_SYNTAX_NOP:
			  decodingClass = 26;
			  break;
		  default:
			  mwerror (state, "Invalid syntax class\n");
		  }
	} else {
/* Must do the above for this one too */
	  switch (flags)
	    {
	    case AC_SYNTAX_3OP:
	      decodingClass = 0;
	      break;
	    case AC_SYNTAX_2OP:
	      decodingClass = 1;
	      break;
	    case AC_SYNTAX_1OP:
	      decodingClass = 32;
	      break;
	    case AC_SYNTAX_NOP:
	      break;
	    case AC_SYNTAX_SIMD:
	      break;
	    default:
	      mwerror(state, "Invalid syntax class\n");
	    }
	}

      if (!instrName)
	{
	  instrName = "???";
	  state->flow=invalid_instr;
	}
    }

  fieldAisReg = fieldBisReg = fieldCisReg = 1; /* assume regs for now */
  flag = cond = is_shimm = is_limm = 0;
  state->nullifyMode = BR_exec_when_no_jump;	/* 0 */
  signExtend = addrWriteBack = directMem = 0;
  usesAuxReg = 0;

  /* The following module decodes the instruction */
  switch (decodingClass)
  {
    case 0:

      /* For ARCtangent 32-bit instructions with 3 operands */

      subopcode = BITS(state->words[0],22,23);
      switch (subopcode)
      {
	case 0:

          /* Either fieldB or fieldC or both can be a limm value;
	   * fieldA can be 0;
           */

          CHECK_FIELD_C();
     	  if (!is_limm)
	  {
	    /* If fieldC is not a limm, then fieldB may be a limm value */
            CHECK_FIELD_B();
	  } else {
            FIELD_B();
	    if (!fieldBisReg) {
		    fieldB = fieldC;
	    }
	  }
      	  CHECK_FIELD_A();
      	  CHECK_FLAG();
	  break;

	case 1:

          /* fieldB may ba a limm value
	   * fieldC is a shimm (unsigned 6-bit immediate)
	   * fieldA can be 0
           */

          CHECK_FIELD_B();
          FIELD_C();
	  fieldCisReg = 0;
          /* Say ea is not present, so only one of us will do the
	     name lookup. */
	  state->_offset += fieldB, state->_ea_present = 0;
      	  CHECK_FIELD_A();
      	  CHECK_FLAG();
	  break;

	case 2:

          /* fieldB may ba a limm value
	   * fieldC is a shimm (signed 12-bit immediate)
	   * fieldA can be 0
           */

	  fieldCisReg = 0;
          fieldC = FIELDS(state->words[0]);
          CHECK_FIELD_B();
          /* Say ea is not present, so only one of us will do the
	     name lookup. */
	  state->_offset += fieldB, state->_ea_present = 0;
	  if (is_limm) {
		  fieldAisReg = fieldA = 0;
	  } else {
		  fieldA = fieldB;
	  }
	  CHECK_FLAG();
	  break;

	case 3:

          /* fieldB may ba a limm value
	   * fieldC may be a limm or a shimm (unsigned 6-bit immediate)
	   * fieldA can be 0
	   * Conditional instructions
           */

          CHECK_FIELD_B();
	  /* fieldC is a shimm (unsigned 6-bit immediate) */
	  if (is_limm)
	  {
	    fieldAisReg = fieldA = 0;
            FIELD_C();
	    if (BIT (state->words[0], 5)) {
		    fieldCisReg = 0;
	    } else if (fieldC == 62) {
		    fieldCisReg = 0;
		    fieldC = fieldB;
	    }
	  } else {
	    fieldA = fieldB;
            if (BIT(state->words[0],5))
	    {
              FIELD_C();
              fieldCisReg = 0;
	    } else {
              CHECK_FIELD_C();
	    }
	  }
      	  CHECK_FLAG_COND();
	  break;
      }

      write_instr_name();
      WRITE_FORMAT_x(A);
      WRITE_FORMAT_COMMA_x(B);
      WRITE_FORMAT_COMMA_x(C);
      WRITE_NOP_COMMENT();
      my_sprintf(state, state->operandBuffer, formatString, fieldA, fieldB, fieldC);
      break;

    case 1:

      /* For ARCtangent 32-bit instructions with 2 operands */

      /* field C is either a register or limm (different!) */
      CHECK_FIELD_C();
      FIELD_B();
      CHECK_FLAG();

      if (BITS (state->words[0], 22, 23) == 1) {
	      fieldCisReg = 0;
      }
      if (fieldCisReg) {
	      state->ea_reg1 = fieldC;
	      /* field C is either a shimm (same as fieldC) or limm (different!) */
	      /* Say ea is not present, so only one of us will do the name lookup. */
      } else {
	      state->_offset += fieldB, state->_ea_present = 0;
      }

      write_instr_name();
      WRITE_FORMAT_x(B);
      WRITE_FORMAT_COMMA_x(C);
      WRITE_NOP_COMMENT();
      my_sprintf(state, state->operandBuffer, formatString, fieldB, fieldC);
      break;

    case 2:

      /* For BTST, CMP, MUL64, MULU64 instruction */

      /* field C is either a register or limm (different!) */
      subopcode =  BITS(state->words[0],22,23);
      if (subopcode == 0 || ((subopcode == 3) && (!BIT(state->words[0],5))))
      {
      	CHECK_FIELD_C();
	if (is_limm)
	{
	  FIELD_B();
	  if (!fieldBisReg) {
		  fieldB = fieldC;
	  }
	} else {
      	  CHECK_FIELD_B();
	}
      }
      else if (subopcode == 1 || ((subopcode == 3) && (BIT(state->words[0],5))))
      {
	FIELD_C();
	fieldCisReg = 0;
      	CHECK_FIELD_B();
      }
      else if (subopcode == 2)
      {
	FIELD_B();
	fieldC = FIELDS(state->words[0]);
	fieldCisReg = 0;
      }
      if (subopcode == 3)
	CHECK_COND();

      if (fieldCisReg) {
	      state->ea_reg1 = fieldC;
	      /* field C is either a shimm (same as fieldC) or limm (different!) */
	      /* Say ea is not present, so only one of us will do the name lookup. */
      } else {
	      state->_offset += fieldB, state->_ea_present = 0;
      }

      write_instr_name();
      if (mul)
      {
	/* For Multiply instructions, the first operand is 0 */
	WRITE_FORMAT_x(A);
	WRITE_FORMAT_COMMA_x(B);
        WRITE_FORMAT_COMMA_x(C);
        WRITE_NOP_COMMENT();
        my_sprintf(state, state->operandBuffer, formatString, 0, fieldB, fieldC);
      } else {
	WRITE_FORMAT_x(B);
        WRITE_FORMAT_COMMA_x(C);
        WRITE_NOP_COMMENT();
        my_sprintf(state, state->operandBuffer, formatString, fieldB, fieldC);
      }
      break;

    case 3:
      /*
       * For FLAG instruction
       */
      subopcode =  BITS(state->words[0],22,23);

      if (subopcode == 0 || ((subopcode == 3) && (!BIT(state->words[0],5))))
      {
        CHECK_FIELD_C();
      }
      else if (subopcode == 1 || ((subopcode == 3) && (BIT(state->words[0],5))))
      {
        FIELD_C();
	fieldCisReg = 0;
      }
      else if (subopcode == 2)
      {
	fieldC = FIELDS(state->words[0]);
	fieldCisReg = 0;
      }
      if (subopcode == 3)
        CHECK_COND();
      flag = 0;  /* this is the FLAG instruction -- it's redundant */

      write_instr_name();
      WRITE_FORMAT_x(C);
      my_sprintf(state, state->operandBuffer, formatString, fieldC);
      break;

    case 4:
      /*
       * For op_JC -- jump to address specified.
       *     Also covers jump and link--bit 9 of the instr. word
       *     selects whether linked, thus "is_linked" is set above.
       */
      subopcode =  BITS(state->words[0],22,23);
      if (subopcode == 0 || ((subopcode == 3) && (!BIT(state->words[0],5))))
      {
        CHECK_FIELD_C();
	/* ilink registers */
	if (fieldC == 29 || fieldC == 31)
      	  CHECK_FLAG();
      }
      else if (subopcode == 1 || ((subopcode == 3) && (BIT(state->words[0],5))))
      {
        FIELD_C();
	fieldCisReg = 0;
      }
      else if (subopcode == 2)
      {
	fieldC = FIELDS(state->words[0]);
	fieldCisReg = 0;
      }

      if (subopcode == 3)
        CHECK_COND();

      state->nullifyMode = BITS(state->words[0],16,16);

      if (!fieldCisReg)
	{
	  state->flow = is_linked ? direct_call : direct_jump;
	  add_target(fieldC);
	} else {
	  state->flow = is_linked ? indirect_call : indirect_jump;
	  /*
	   * We should also treat this as indirect call if NOT linked
	   * but the preceding instruction was a "lr blink,[status]"
	   * and we have a delay slot with "add blink,blink,2".
	   * For now we can't detect such.
	   */
	  state->register_for_indirect_jump = fieldC;
	}

      write_instr_name();
      strncat(formatString,
	     IS_REG(C)?"[%r]":"%s", sizeof(formatString) - strlen(formatString) - 1); /* address/label name */

      if (IS_REG (C)) {
	      my_sprintf (state, state->operandBuffer, formatString, fieldC);
      } else {
	      my_sprintf (state, state->operandBuffer, formatString,
		      post_address (state, fieldC));
      }
      break;

    case 5:
      /* LD instruction.  B and C can be regs, or one or both can be limm. */

      CHECK_FIELD_A();
      CHECK_FIELD_B();

      if (FIELDA(state->words[0]) == 62)
	{
	  instrName = "prefetch";
	}



      if (is_limm)
      {
        FIELD_C();
	if (!fieldCisReg) {
		fieldC = fieldB;
	}
      } else {
        CHECK_FIELD_C();
      }
      if (dbg) {
	      printf ("5:b reg %d %d c reg %d %d  \n",
		      fieldBisReg, fieldB, fieldCisReg, fieldC);
      }
      state->_offset = 0;
      state->_ea_present = 1;
      if (fieldBisReg) {
	      state->ea_reg1 = fieldB;
      } else {
	      state->_offset += fieldB;
      }
      if (fieldCisReg) {
	      state->ea_reg2 = fieldC;
      } else {
	      state->_offset += fieldC;
      }
      state->_mem_load = 1;

      directMem     = BIT(state->words[0],15);
      /* - We should display the instruction as decoded, not some censored
	   version of it
         - Scaled index is encoded as 'addrWriteBack', even though it isn't
	   actually doing a write back;  it is legitimate with a LIMM.  */
#if 0
      /* Check if address writeback is allowed before decoding the
	 address writeback field of a load instruction.*/
      if (fieldBisReg && (fieldB != 62))
#endif
        addrWriteBack = BITS(state->words[0],22,23);
      signExtend    = BIT(state->words[0],16);

      write_instr_name();

      /* Check for prefetch or ld 0,...*/
      if (IS_REG (A)) {
	      WRITE_FORMAT_x_COMMA_LB (A);
      } else {
	      strncat (formatString, "%*", sizeof(formatString) - strlen(formatString) - 1);
	      WRITE_FORMAT_LB ();
	}

	if (fieldBisReg || fieldB != 0) {
		WRITE_FORMAT_x (B);
	} else {
		fieldB = fieldC;
	}

	WRITE_FORMAT_COMMA_x_RB (C);
	my_sprintf (state, state->operandBuffer, formatString, fieldA, fieldB, fieldC);
	break;

    case 6:
      /* LD instruction. */
      CHECK_FIELD_B();
      CHECK_FIELD_A();
      /* Support for Prefetch */
      /* Fixme :: Check for A700 within this function */

      if (FIELDA(state->words[0]) == 62) {
	  instrName = "prefetch";
      }

      fieldC = FIELDD9(state->words[0]);
      fieldCisReg = 0;

#if 0
      if (dbg) {
	      eprintf ("6:b reg %d %d c 0x%x  \n",
		      fieldBisReg, fieldB, fieldC);
      }
#endif
      state->_ea_present = 1;
      state->_offset = fieldC;
      state->_mem_load = 1;
      if (fieldBisReg) {
	      state->ea_reg1 = fieldB;
	      /* field B is either a shimm (same as fieldC) or limm (different!) */
	      /* Say ea is not present, so only one of us will do the name lookup. */
      } else {
	      state->_offset += fieldB, state->_ea_present = 0;
      }

      directMem     = BIT(state->words[0],11);
      /* Check if address writeback is allowed before decoding the
	 address writeback field of a load instruction.*/
      if (fieldBisReg && (fieldB != 62)) {
	      addrWriteBack = BITS (state->words[0], 9, 10);
      }
      signExtend    = BIT(state->words[0],6);

      write_instr_name();
      if (IS_REG (A)) {
	      WRITE_FORMAT_x_COMMA_LB (A);
      } else {
	      strncat (formatString, "%*", sizeof(formatString) - strlen(formatString) - 1);
	      WRITE_FORMAT_LB ();
	}
      if (!fieldBisReg)
	{
	  fieldB = state->_offset;
	  WRITE_FORMAT_x_RB(B);
	} else {
	  WRITE_FORMAT_x(B);
	  WRITE_FORMAT_COMMA_x_RB(C);
	}
      my_sprintf(state, state->operandBuffer, formatString, fieldA, fieldB, fieldC);
      break;

    case 7:
      /* ST instruction. */
      CHECK_FIELD_B();
      CHECK_FIELD_C();
      state->source_operand.registerNum = fieldC;
      state->sourceType = fieldCisReg ? ARC_REGISTER : ARC_LIMM ;
      fieldA  = FIELDD9(state->words[0]); /* shimm */
      fieldAisReg = 0;

      /* [B,A offset] */
#if 0
      if (dbg) {
	      eprintf ("7:b reg %d %x off %x\n",
		      fieldBisReg, fieldB, fieldA);
      }
#endif
      state->_ea_present = 1;
      state->_offset = fieldA;
      if (fieldBisReg) {
	      state->ea_reg1 = fieldB;
      /*
       * field B is either a shimm (same as fieldA) or limm (different!)
       * Say ea is not present, so only one of us will do the name lookup.
       * (for is_limm we do the name translation here).
       */
      } else {
	      state->_offset += fieldB, state->_ea_present = 0;
      }

      directMem     = BIT(state->words[0],5);
      addrWriteBack = BITS(state->words[0],3,4);

      write_instr_name();
      WRITE_FORMAT_x_COMMA_LB(C);
      if (fieldA == 0)
      {
        WRITE_FORMAT_x_RB(B);
      } else {
	WRITE_FORMAT_x(B);
        fieldAisReg = 0;
        WRITE_FORMAT_COMMA_x_RB(A);
      }
      my_sprintf(state, state->operandBuffer, formatString, fieldC, fieldB, fieldA);
      break;

    case 8:
      /* SR instruction */
      CHECK_FIELD_B();
      switch (BITS(state->words[0],22,23))
      {
 	case 0:
          if (is_limm)
          {
       	    FIELD_C();
	    if (!fieldCisReg) {
		    fieldC = fieldB;
	    }
	  }
      	  else
	  {
	    CHECK_FIELD_C();
	  }
	  break;
	case 1:
	  FIELD_C();
	  fieldCisReg = 0;
	  break;
	case 2:
	  fieldC = FIELDS(state->words[0]);
	  fieldCisReg = 0;
	  break;
      }

      write_instr_name();
      WRITE_FORMAT_x_COMMA_LB(B);
      /* Try to print B as an aux reg if it is not a core reg. */
      usesAuxReg = 1;
      WRITE_FORMAT_x(C);
      WRITE_FORMAT_RB();
      my_sprintf(state, state->operandBuffer, formatString, fieldB, fieldC);
      break;

    case 9:
      /* ARC_BBIT0/ARC_BBIT1 Instruction */

      CHECK_FIELD_C();
      if (is_limm || BIT(state->words[0],4))
      {
	fieldCisReg = 0;
        FIELD_B();
      }
      else
      {
        CHECK_FIELD_B();
      }
      fieldAisReg = fieldA = 0;
      fieldA = FIELDS9(state->words[0]);
      fieldA += (addr & ~0x3);
      CHECK_NULLIFY();

      write_instr_name();

      add_target(fieldA);
      state->flow = state->_opcode == op_BLC ? direct_call : direct_jump;
      WRITE_FORMAT_x(B);
      WRITE_FORMAT_COMMA_x(C);
      strncat(formatString, ",%s", sizeof(formatString) - strlen(formatString) - 1); /* address/label name */
      WRITE_NOP_COMMENT();
      my_sprintf(state, state->operandBuffer, formatString, fieldB, fieldC, post_address(state, fieldA));
      break;

    case 10:
      /* LR instruction */
      CHECK_FIELD_B();
      switch (BITS(state->words[0],22,23))
      {
 	case 0:
	  CHECK_FIELD_C(); break;
	case 1:
	  FIELD_C();
	  fieldCisReg = 0;
	  break;
	case 2:
	  fieldC = FIELDS(state->words[0]);
	  fieldCisReg = 0;
	  break;
      }

      write_instr_name();
      WRITE_FORMAT_x_COMMA_LB(B);
      /* Try to print B as an aux reg if it is not a core reg. */
      usesAuxReg = 1;
      WRITE_FORMAT_x(C);
      WRITE_FORMAT_RB();
      my_sprintf(state, state->operandBuffer, formatString, fieldB, fieldC);
      break;

    case 11:
      /* lp instruction */

      if (BITS(state->words[0],22,23) == 3)
      {
        FIELD_C();
        CHECK_COND();
      }
      else
      {
	fieldC = FIELDS(state->words[0]);
      }

      fieldC = fieldC << 1;
      fieldC += (addr & ~0x3);

      write_instr_name();

      /* This address could be a label we know.  Convert it. */
      add_target(fieldC);
      state->flow = state->_opcode == op_BLC ? direct_call : direct_jump;

      fieldCisReg = 0;
      strncat(formatString, "%s", sizeof(formatString) - strlen(formatString) - 1); /* address/label name */
      my_sprintf(state, state->operandBuffer, formatString, post_address(state, fieldC));
      break;

    case 12:
      /* MOV instruction */
      FIELD_B();
      subopcode = BITS(state->words[0],22,23);
      if (subopcode == 0 || ((subopcode == 3) && (!BIT(state->words[0],5))))
      {
      	CHECK_FIELD_C();
      }
      else if (subopcode == 1 || ((subopcode == 3) && (BIT(state->words[0],5))))
      {
      	FIELD_C();
	fieldCisReg = 0;
      }
      else if (subopcode == 2)
      {
	fieldC = FIELDS(state->words[0]);
	fieldCisReg = 0;
      }
      if (subopcode == 3)
      {
        CHECK_FLAG_COND();
      }
      else
      {
        CHECK_FLAG();
      }

     write_instr_name();
     WRITE_FORMAT_x(B);
     WRITE_FORMAT_COMMA_x(C);
     WRITE_NOP_COMMENT();
     my_sprintf(state, state->operandBuffer, formatString, fieldB, fieldC);
     break;

    case 13:
    /* "B", "BL" instruction */

      fieldA = 0;
      if ((state->_opcode == op_BC  && (BIT(state->words[0],16))) ||
 	  (state->_opcode == op_BLC && (BIT(state->words[0],17))))
      {
	/* unconditional branch s25 or branch and link d25 */
        fieldA = (BITS(state->words[0],0,4)) << 10;
      }
      fieldA |= BITS(state->words[0],6,15);

      if (state->_opcode == op_BLC)
      {
	  /* Fix for Bug #553.  A bl unconditional has only 9 bits in the
	   * least order bits. */
	fieldA = fieldA << 9;
        fieldA |= BITS(state->words[0],18,26);
	fieldA = fieldA << 2;
      }
      else
      {
	fieldA = fieldA << 10;
        fieldA |= BITS(state->words[0],17,26);
	fieldA = fieldA << 1;
      }

      if ((state->_opcode == op_BC && (BIT (state->words[0], 16))) ||
	      (state->_opcode == op_BLC && (BIT (state->words[0], 17)))) {
	      /* unconditional branch s25 or branch and link d25 */
	      fieldA = sign_extend (fieldA, 25);
      } else {
	      /* conditional branch s21 or branch and link d21 */
	      fieldA = sign_extend (fieldA, 21);
      }

      fieldA += (addr & ~0x3);

      if (BIT (state->words[0], 16) && state->_opcode == op_BC) {
	      CHECK_NULLIFY ();
      } else if ((state->_opcode == op_BLC && BITS (state->words[0], 16, 17) == 2) || (state->_opcode == op_BC && (BIT (state->words[0], 16)))) {
	      /* Checking for bl unconditionally FIX For Bug #553 */
	      CHECK_NULLIFY ();
      } else {
	      CHECK_COND_NULLIFY ();
      }

      write_instr_name();
      /* This address could be a label we know.  Convert it. */
      add_target(fieldA); /* For debugger. */
      state->flow = state->_opcode == op_BLC /* BL */
          ? direct_call
          : direct_jump;
        /* indirect calls are achieved by "lr blink,[status]; */
        /*      lr dest<- func addr; j [dest]" */

      strncat(formatString, "%s", sizeof(formatString) - strlen(formatString) - 1); /* address/label name */
      my_sprintf(state, state->operandBuffer, formatString, post_address(state, fieldA));
      break;

    case 14:

      /* Extension Instructions */

      FIELD_C_AC();
      FIELD_B_AC();

      write_instr_name();
      if (mul)
      {
        fieldA = fieldAisReg = 0;
	WRITE_FORMAT_x(A);
        WRITE_FORMAT_COMMA_x(B);
      } else {
	      WRITE_FORMAT_x (B);
      }
      WRITE_FORMAT_COMMA_x(C);
      WRITE_NOP_COMMENT();
      if (mul) {
	      my_sprintf (state, state->operandBuffer, formatString, 0, fieldB, fieldC);
      } else {
	      my_sprintf (state, state->operandBuffer, formatString, fieldB, fieldC);
      }
      break;

    case 15:

      /* ARCompact 16-bit Load/Add resister-register */

      FIELD_C_AC();
      FIELD_B_AC();
      FIELD_A_AC();

      write_instr_name();

      if (BITS(state->words[0],3,4) != 3)
      {
        WRITE_FORMAT_x_COMMA_LB(A);
	WRITE_FORMAT_x(B);
	WRITE_FORMAT_COMMA_x_RB(C);
      }
      else
      {
        WRITE_FORMAT_x(A);
        WRITE_FORMAT_COMMA_x(B);
        WRITE_FORMAT_COMMA_x(C);
      }
      WRITE_NOP_COMMENT();
      my_sprintf(state, state->operandBuffer, formatString, fieldA, fieldB, fieldC);
      break;

    case 16:

    /* ARCompact 16-bit Add/Sub/Shift instructions */

      FIELD_C_AC();
      FIELD_B_AC();
      fieldA = FIELDA_AC(state->words[0]);
      fieldAisReg = 0;

      write_instr_name();
      WRITE_FORMAT_x(C);
      WRITE_FORMAT_COMMA_x(B);
      WRITE_FORMAT_COMMA_x(A);
      WRITE_NOP_COMMENT();
      my_sprintf(state, state->operandBuffer, formatString, fieldC, fieldB, fieldA);
      break;

    case 17:

      /* add_s instruction, one Dest/Source can be any of r0 - r63 */

      CHECK_FIELD_H_AC();
      FIELD_B_AC();

      write_instr_name();
      WRITE_FORMAT_x(B);
      WRITE_FORMAT_COMMA_x(B);
      WRITE_FORMAT_COMMA_x(C);
      WRITE_NOP_COMMENT();
      my_sprintf(state, state->operandBuffer, formatString, fieldB, fieldB, fieldC);
      break;

    case 18:

      /* mov_s/cmp_s instruction, one Dest/Source can be any of r0 - r63 */

      if ((BITS(state->words[0],3,4) == 1) || (BITS(state->words[0],3,4) == 2))
      {
      	CHECK_FIELD_H_AC();
      }
      else if (BITS(state->words[0],3,4) == 3)
      {
	FIELD_H_AC();
      }
      FIELD_B_AC();

      write_instr_name();
      if (BITS(state->words[0],3,4) == 3)
      {
        WRITE_FORMAT_x(C);
        WRITE_FORMAT_COMMA_x(B);
        WRITE_NOP_COMMENT();
        my_sprintf(state, state->operandBuffer, formatString, fieldC, fieldB);
      }
      else
      {
        WRITE_FORMAT_x(B);
        WRITE_FORMAT_COMMA_x(C);
        WRITE_NOP_COMMENT();
        my_sprintf(state, state->operandBuffer, formatString, fieldB, fieldC);
      }
      break;

    case 19:

      /* Stack pointer-based instructions [major opcode 0x18] */

      if (BITS (state->words[0], 5, 7) == 5) {
	      fieldA = 28;
      } else {
	      FIELD_B_AC ();
	      fieldA = fieldB;
      }
      fieldB = 28; /* Field B is the stack pointer register */
      fieldC = (FIELDU_AC(state->words[0])) << 2;
      fieldCisReg = 0;

      write_instr_name();

      switch (BITS(state->words[0],5,7))
      {
	case 0:
	case 1:
	case 2:
	case 3:
          WRITE_FORMAT_x_COMMA_LB(A);
	  WRITE_FORMAT_x(B);
	  WRITE_FORMAT_COMMA_x_RB(C);
	  break;
	case 4:
	case 5:
          WRITE_FORMAT_x(A);
          WRITE_FORMAT_COMMA_x(B);
          WRITE_FORMAT_COMMA_x(C);
	  break;
      }
      WRITE_NOP_COMMENT();
      my_sprintf(state, state->operandBuffer, formatString, fieldA, fieldB, fieldC);
      break;

    case 20:

      /* gp-relative instructions [major opcode 0x19] */

      fieldA = 0;
      fieldB = 26; /* Field B is the gp register */
      fieldC = FIELDS_AC(state->words[0]);
      switch (BITS(state->words[0],9,10))
      {
	case 0:
	case 3:
	  fieldC = fieldC << 2; break;
	case 2:
	  fieldC = fieldC << 1; break;
      }
      fieldCisReg = 0;

      write_instr_name();

      if (BITS(state->words[0],9,10) != 3)
      {
        WRITE_FORMAT_x_COMMA_LB(A);
	WRITE_FORMAT_x(B);
	WRITE_FORMAT_COMMA_x_RB(C);
      }
      else
      {
        WRITE_FORMAT_x(A);
        WRITE_FORMAT_COMMA_x(B);
        WRITE_FORMAT_COMMA_x(C);
      }
      WRITE_NOP_COMMENT();
      my_sprintf(state, state->operandBuffer, formatString, fieldA, fieldB, fieldC);
      break;

    case 21:

      /* add/cmp/btst instructions [major opcode 28] */

      FIELD_B_AC();
      if (state->_opcode == op_Su5) {
	      fieldC = (BITS (state->words[0], 0, 4));
      } else {
	      fieldC = (BITS (state->words[0], 0, 6));
      }
      fieldCisReg = 0;
      write_instr_name();

      if (!BIT(state->words[0],7))
      {
        WRITE_FORMAT_x(B);
        WRITE_FORMAT_COMMA_x(B);
        WRITE_FORMAT_COMMA_x(C);
        WRITE_NOP_COMMENT();
        my_sprintf(state, state->operandBuffer, formatString, fieldB, fieldB, fieldC);
      }
      else
      {
        WRITE_FORMAT_x(B);
        WRITE_FORMAT_COMMA_x(C);
        WRITE_NOP_COMMENT();
        my_sprintf(state, state->operandBuffer, formatString, fieldB, fieldC);
      }
      break;

    case 22:

      /* ARCompact 16-bit instructions, General ops/ single ops */

      FIELD_C_AC();
      FIELD_B_AC();

      write_instr_name();

      WRITE_FORMAT_x(B);
      WRITE_FORMAT_COMMA_x(B);
      WRITE_FORMAT_COMMA_x(C);
      WRITE_NOP_COMMENT();
      my_sprintf(state, state->operandBuffer, formatString, fieldB, fieldB, fieldC);
      break;

    case 23:

      /* Shift/subtract/bit immediate instructions [major opcode 23] */

      FIELD_B_AC();
      fieldC = FIELDU_AC(state->words[0]);
      fieldCisReg = 0;
      write_instr_name();
      WRITE_FORMAT_x(B);
      WRITE_FORMAT_COMMA_x(B);
      WRITE_FORMAT_COMMA_x(C);
      WRITE_NOP_COMMENT();
      my_sprintf(state, state->operandBuffer, formatString, fieldB, fieldB, fieldC);
      break;

    case 24:

      /* ARCompact 16-bit Branch conditionally */

      if (state->_opcode == op_BL_S)
      {
        fieldA = (BITS(state->words[0],0,10)) << 2;
	fieldA = sign_extend(fieldA, 13);
      }
      else if (BITS(state->words[0],9,10) != 3)
      {
        fieldA = (BITS(state->words[0],0,8)) << 1;
	fieldA = sign_extend(fieldA, 10);
      }
      else
      {
        fieldA = (BITS(state->words[0],0,5)) << 1;
	fieldA = sign_extend(fieldA, 7);
      }
      fieldA += (addr & ~0x3);

      write_instr_name();
      /* This address could be a label we know.  Convert it. */
      add_target(fieldA); /* For debugger. */
      state->flow = state->_opcode == op_BL_S /* BL */
          ? direct_call
          : direct_jump;
        /* indirect calls are achieved by "lr blink,[status]; */
        /*      lr dest<- func addr; j [dest]" */

      strncat(formatString, "%s", sizeof(formatString) - strlen(formatString) - 1); /* address/label name */
      my_sprintf(state, state->operandBuffer, formatString, post_address(state, fieldA));
      break;

    case 25:

      /* ARCompact 16-bit Branch conditionally on reg z/nz */

      FIELD_B_AC();
      fieldC = (BITS(state->words[0],0,6)) << 1;
      fieldC = sign_extend (fieldC, 8);

      fieldC += (addr & ~0x3);
      fieldA = fieldAisReg = fieldCisReg = 0;

      write_instr_name();
      /* This address could be a label we know.  Convert it. */
      add_target(fieldC); /* For debugger. */
      state->flow = direct_jump;

      WRITE_FORMAT_x(B);
      WRITE_FORMAT_COMMA_x(A);
      strncat(formatString, ",%s", sizeof(formatString) - strlen(formatString) - 1); /* address/label name */
      WRITE_NOP_COMMENT();
      my_sprintf(state, state->operandBuffer, formatString, fieldB, fieldA, post_address(state, fieldC));
      break;

    case 26:

      /* Zero operand Instructions */

      write_instr_name();
      state->operandBuffer[0] = '\0';
      break;

    case 27:

      /* j_s instruction */

      FIELD_B_AC();
      write_instr_name();
      strncat(formatString,"[%r]", sizeof(formatString) - strlen(formatString) - 1);
      my_sprintf(state, state->operandBuffer, formatString, fieldB);
      break;

    case 28:

      /* Load/Store with offset */

      FIELD_C_AC();
      FIELD_B_AC();
      switch (state->_opcode)
      {
	case op_LD_S :
	case op_ST_S :
      	  fieldA = (FIELDU_AC(state->words[0])) << 2;
	  break;
	case op_LDB_S :
	case op_STB_S :
      	  fieldA = (FIELDU_AC(state->words[0]));
	  break;
	case op_LDW_S :
	case op_LDWX_S :
	case op_STW_S :
      	  fieldA = (FIELDU_AC(state->words[0])) << 1;
	  break;
      }
      fieldAisReg = 0;

      write_instr_name();

      WRITE_FORMAT_x_COMMA_LB(C);
      WRITE_FORMAT_x(B);
      WRITE_FORMAT_COMMA_x(A);
      WRITE_FORMAT_RB();
      WRITE_NOP_COMMENT();
      my_sprintf(state, state->operandBuffer, formatString, fieldC, fieldB, fieldA);
      break;

    case 29:

      /* Load pc-relative */

      FIELD_B_AC();
      fieldC = 63;
      fieldA = (BITS(state->words[0],0,7)) << 2;
      fieldAisReg = 0;

      write_instr_name();

      WRITE_FORMAT_x(B);
      WRITE_FORMAT_COMMA_x(C);
      WRITE_FORMAT_COMMA_x(A);
      WRITE_NOP_COMMENT();
      my_sprintf(state, state->operandBuffer, formatString, fieldB, fieldC, fieldA);
      break;

    case 30:

      /* mov immediate */

      FIELD_B_AC();
      fieldC = (BITS(state->words[0],0,7));
      fieldCisReg = 0;

      write_instr_name();

      WRITE_FORMAT_x(B);
      WRITE_FORMAT_COMMA_x(C);
      WRITE_NOP_COMMENT();
      my_sprintf(state, state->operandBuffer, formatString, fieldB, fieldC);
      break;

    case 31:

      /* push/pop instructions */

      if (BITS(state->words[0],0,4) == 1)
      {
        FIELD_B_AC();
      } else if (BITS (state->words[0], 0, 4) == 17) {
	      fieldB = 31;
      }

      write_instr_name();

      WRITE_FORMAT_x(B);
      WRITE_NOP_COMMENT();
      my_sprintf(state, state->operandBuffer, formatString, fieldB);
      break;

    case 32:

      /* Single operand instruction */

      if (!BITS(state->words[0],22,23))
      {
        CHECK_FIELD_C();
      }
      else
      {
	FIELD_C();
	fieldCisReg = 0;
      }

      write_instr_name();

      if (!fieldC) {
	      state->operandBuffer[0] = '\0';
      } else {
	      WRITE_FORMAT_x (C);
	      WRITE_NOP_COMMENT ();
	      my_sprintf (state, state->operandBuffer, formatString, fieldC);
      }
      break;

  case 33:
    /* For trap_s and the class of instructions that have
       unsigned 6 bits in the fields B and C in A700 16 bit
       instructions */
    fieldC = FIELDC_AC(state->words[0]);
    fieldB = FIELDB_AC(state->words[0]);
    fieldCisReg = 0;
    fieldBisReg = 0;
    write_instr_name();
    strncat(formatString,"%d", sizeof(formatString) - strlen(formatString) - 1);
    my_sprintf(state,state->operandBuffer,formatString, ((fieldB << 3) | fieldC));
    break;

  case 34:
    /* For ex.di and its class of instructions within op_major_4
       This class is different from the normal set of instructions
       in op_major_4 because this uses bit 15 as .di and the second
       operand is actually a memory operand.
       This is of the class
       <op>.<di> b,[c] and <op>.<di> b,[limm]
    */


    /* field C is either a register or limm (different!) */

    CHECK_FIELD_C();
    FIELD_B();
    directMem = BIT(state->words[0],15);

    if (BITS (state->words[0], 22, 23) == 1) {
	    fieldCisReg = 0;
    }
    if (fieldCisReg) {
	    state->ea_reg1 = fieldC;
    }

    write_instr_name();
    WRITE_FORMAT_x_COMMA_LB(B);

    WRITE_FORMAT_x_RB(C);

    WRITE_NOP_COMMENT();
    my_sprintf(state, state->operandBuffer, formatString, fieldB, fieldC);
    break;

  case 35:

    /* sub_s.ne instruction */

    FIELD_B_AC();
    write_instr_name();
    strncat(formatString,"%r,%r,%r", sizeof(formatString) - strlen(formatString) - 1);
    my_sprintf(state, state->operandBuffer, formatString, fieldB, fieldB, fieldB);
    break;

  case 36:

    FIELD_B_AC();

    write_instr_name();

    WRITE_FORMAT_x(B);
    WRITE_NOP_COMMENT();
    my_sprintf(state, state->operandBuffer, formatString, fieldB);

    break;

  /* START ARC LOCAL */
  case 44:
      /* rtsc instruction */
      /* The source operand has no use.  */
      fieldB = fieldBisReg = 0;

      write_instr_name();
      WRITE_FORMAT_x(A);
      WRITE_FORMAT_COMMA_x(B);
      WRITE_NOP_COMMENT();
      my_sprintf(state, state->operandBuffer, formatString, fieldA,
		 fieldB);
      break;
  /* END ARC LOCAL */

    /*******SIMD instructions decoding follows*************/
  case 37:
  case 39:
  case 41:
    /*fieldA is vr register
      fieldB is I register
      fieldC is a constant
      %*,[%(,%<]
      or
      %*,%(,%<
      or
      %*,%(,%u
    */

    CHECK_FIELD_A();

    CHECK_FIELD_B();
    if (decodingClass == 41)
       {
	 FIELD_C();
       }
    else
      {
	FIELD_U8();

	if (simd_scale_u8 > 0) {
		fieldC = fieldC << simd_scale_u8;
	}
      }

    fieldCisReg = 0;

    write_instr_name();
    (decodingClass == 37 ? WRITE_FORMAT_x_COMMA_LB(A) :
                           WRITE_FORMAT_x_COMMA(A));
    WRITE_FORMAT_x_COMMA(B);
    (decodingClass == 37 ?  WRITE_FORMAT_x_RB(C):
                            WRITE_FORMAT_x(C));
    WRITE_NOP_COMMENT();
    my_sprintf(state,state->operandBuffer, formatString, fieldA, fieldB, fieldC);


    break;
  case 38:
    /* fieldA is a vr register
       fieldB is a ARC700 basecase register.
       %*,[%b]
    */
    CHECK_FIELD_A();
    CHECK_FIELD_B();

    write_instr_name();
    WRITE_FORMAT_x_COMMA_LB(A);
    WRITE_FORMAT_x_RB(B);
    WRITE_NOP_COMMENT();
    my_sprintf(state,state->operandBuffer, formatString, fieldA, fieldB);

    break;
  case 40:
    /* fieldB & fieldC are vr registers
       %(,%)
       or
       %B,%C
       or
       %(,%C
    */
    CHECK_FIELD_B();
    CHECK_FIELD_C();

    write_instr_name();
    WRITE_FORMAT_x(B);
    WRITE_FORMAT_COMMA_x(C);
    my_sprintf(state, state->operandBuffer, formatString, fieldB, fieldC);
    break;

  case 42:
    /* fieldA, fieldB, fieldC are all vr registers
       %*, %(, %) */
    CHECK_FIELD_A();
    CHECK_FIELD_B();
    FIELD_C();

    write_instr_name();
    WRITE_FORMAT_x(A);
    WRITE_FORMAT_COMMA_x(B);
    WRITE_FORMAT_COMMA_x(C);
    my_sprintf(state, state->operandBuffer, formatString, fieldA, fieldB, fieldC);
    break;

  case 43:
    /* Only fieldC is a register
     %C*/
    CHECK_FIELD_C();

    if (BITS (state->words[0], 17, 23) == 55) {
	    fieldCisReg = 0;
    }

    write_instr_name();
    WRITE_FORMAT_x(C);
    my_sprintf(state, state->operandBuffer, formatString, fieldC);
    break;

    /***************SIMD decoding ends*********************/
  default:
    mwerror(state, "Bad decoding class in ARC disassembler");
    break;
  }

  state->_cond = cond;
  return state->instructionLen = offset;
}


/*
 * _coreRegName - Returns the name the user specified core extension
 *                register.
 */
static const char *
_coreRegName
(
 void *_this ATTRIBUTE_UNUSED, /* C++ this pointer */
 int v                         /* Register value */
 )
{
  return arcExtMap_coreRegName(v);
}

/*
 * _auxRegName - Returns the name the user specified AUX extension
 *               register.
 */
static const char *
_auxRegName
( void *_this ATTRIBUTE_UNUSED, /* C++ this pointer */
  int v                         /* Register value */
  )
{
  return arcExtMap_auxRegName(v);
}


/*
 * _condCodeName - Returns the name the user specified condition code
 *                 name.
 */
static const char *
_condCodeName
(
 void *_this ATTRIBUTE_UNUSED, /* C++ this pointer */
 int v                         /* Register value */
 )
{
  return arcExtMap_condCodeName(v);
}


/*
 * _instName - Returns the name the user specified extension instruction.
 */
static const char *
_instName
(
 void *_this ATTRIBUTE_UNUSED, /* C++ this pointer */
 int op1,                      /* major opcode value */
 int op2,                      /* minor opcode value */
 int *flags                    /* instruction flags */
 )
{
  return arcExtMap_instName(op1, op2, flags);
}

static void
parse_disassembler_options (char *options)
{
  const char *p;
  for (p = options; p; )
    {
	  if (CONST_STRNEQ (p, "simd"))
	    {
	      enable_simd = 1;
	    }
	  if (CONST_STRNEQ (p, "insn-stream"))
	    {
		  enable_insn_stream = 1;
	    }

	  p = strchr (p, ',');

	  if (p) {
		  p++;
	  }
    }

}

/* ARCompact_decodeInstr - Decode an ARCompact instruction returning the
   size of the instruction in bytes or zero if unrecognized.  */
int
ARCompact_decodeInstr (bfd_vma           address,    /* Address of this instruction.  */
                       disassemble_info* info)
{
  int status;
  bfd_byte buffer[4];
  struct arcDisState s;	/* ARC Disassembler state */
  void *stream = info->stream; /* output stream */
  fprintf_ftype func = info->fprintf_func;
  int bytes;
  int lowbyte, highbyte;
  char buf[256];

  if (info->disassembler_options)
    {
      parse_disassembler_options (info->disassembler_options);

      /* To avoid repeated parsing of these options, we remove them here.  */
      info->disassembler_options = NULL;
    }

  lowbyte = ((info->endian == BFD_ENDIAN_LITTLE) ? 1 : 0);
  highbyte = ((info->endian == BFD_ENDIAN_LITTLE) ? 0 : 1);

  memset(&s, 0, sizeof (struct arcDisState));

  /* read first instruction */
  status = (*info->read_memory_func) (address, buffer, 2, info);

  if (status != 0)
    {
      (*info->memory_error_func) (status, address, info);
      return -1;
    }

  if (((buffer[lowbyte] & 0xf8) > 0x38) && ((buffer[lowbyte] & 0xf8) != 0x48))
  {
    s.instructionLen = 2;
    s.words[0] = (buffer[lowbyte] << 8) | buffer[highbyte];
    status = (*info->read_memory_func) (address + 2, buffer, 4, info);
    if (info->endian == BFD_ENDIAN_LITTLE) {
	    s.words[1] = bfd_getl32 (buffer);
    } else {
	    s.words[1] = bfd_getb32 (buffer);
    }
  }
  else
  {
    s.instructionLen = 4;
    status = (*info->read_memory_func) (address + 2, &buffer[2], 2, info);
    if (status != 0)
    {
      (*info->memory_error_func) (status, address + 2, info);
      return -1;
    }
    if (info->endian == BFD_ENDIAN_LITTLE) {
	    s.words[0] = bfd_getl32 (buffer);
    } else {
	    s.words[0] = bfd_getb32 (buffer);
    }

    /* always read second word in case of limm */
    /* we ignore the result since last insn may not have a limm */
    status = (*info->read_memory_func) (address + 4, buffer, 4, info);
    if (info->endian == BFD_ENDIAN_LITTLE) {
	    s.words[1] = bfd_getl32 (buffer);
    } else {
	    s.words[1] = bfd_getb32 (buffer);
    }
  }

  s._this = &s;
  s.coreRegName = _coreRegName;
  s.auxRegName = _auxRegName;
  s.condCodeName = _condCodeName;
  s.instName = _instName;

  /* disassemble */
  bytes = dsmOneArcInst(address, (void *)&s, info);

  /* display the disassembled instruction */
  {
    char* instr   = s.instrBuffer;
    char* operand = s.operandBuffer;
    char* space   = strchr(instr, ' ');

    if (enable_insn_stream)
      {
        /* Show instruction stream from MSB to LSB*/

	if (s.instructionLen == 2) {
		(*func) (stream, "    %04x ", (unsigned int)s.words[0]);
	} else {
		(*func) (stream, "%08x ", (unsigned int)s.words[0]);
	}

	(*func) (stream, "    ");
      }

    /* if the operand is actually in the instruction buffer */
    if ((space) && (operand[0] == '\0'))
      {
          *space  = '\0';
          operand = space + 1;
      }

    (*func) (stream, "%s ", instr);

    if (__TRANSLATION_REQUIRED(s))
      {
        bfd_vma addr;
        char *tmpBuffer;
	char *save_ptr = NULL;
        int i = 1;

        if (operand[0] != '@')
        {
          /* Branch instruction with 3 operands, Translation is required
             only for the third operand. Print the first 2 operands */
          strncpy(buf, operand, sizeof (buf));
          buf[sizeof (buf) - 1] = '\0';
          tmpBuffer = r_str_tok_r(buf, "@", &save_ptr);
          (*func) (stream, "%s", tmpBuffer);
          i = strlen(tmpBuffer) + 1;
        }

        addr = s.addresses[operand[i] - '0'];
        (*info->print_address_func) ((bfd_vma) addr, info);
        //(*func) (stream, "\n");
    } else {
	    (*func) (stream, "%s", operand);
    }
  }

  /* We print max bytes for instruction */
  info->bytes_per_line = 8;

  return s.instructionLen + bytes-bytes;
}

/*
 * This function is the same as decodeInstr except that this function
 * returns a struct arcDisState instead of the instruction length.
 *
 * This struct contains information useful to the debugger.
 */
struct arcDisState
arcAnalyzeInstr
(
 bfd_vma           address,		/* Address of this instruction */
 disassemble_info* info
 )
{
  int status;
  bfd_byte buffer[4];
  struct arcDisState s;	/* ARC Disassembler state */
  int bytes;
  int lowbyte, highbyte;

  lowbyte = ((info->endian == BFD_ENDIAN_LITTLE) ? 1 : 0);
  highbyte = ((info->endian == BFD_ENDIAN_LITTLE) ? 0 : 1);

  memset(&s, 0, sizeof (struct arcDisState));

  /* read first instruction */
  status = (*info->read_memory_func) (address, buffer, 2, info);

  if (status != 0)
    {
      (*info->memory_error_func) (status, address, info);
      s.instructionLen = -1;
      return s;
    }

  if (((buffer[lowbyte] & 0xf8) > 0x38) && ((buffer[lowbyte] & 0xf8) != 0x48))
  {
    s.instructionLen = 2;
    s.words[0] = (buffer[lowbyte] << 8) | buffer[highbyte];
    status = (*info->read_memory_func) (address + 2, buffer, 4, info);
    if (info->endian == BFD_ENDIAN_LITTLE) {
	    s.words[1] = bfd_getl32 (buffer);
    } else {
	    s.words[1] = bfd_getb32 (buffer);
    }
  }
  else
  {
    s.instructionLen = 4;
    status = (*info->read_memory_func) (address + 2, &buffer[2], 2, info);
    if (status != 0)
    {
      (*info->memory_error_func) (status, address + 2, info);
      s.instructionLen = -1;
      return s;
    }
    if (info->endian == BFD_ENDIAN_LITTLE) {
	    s.words[0] = bfd_getl32 (buffer);
    } else {
	    s.words[0] = bfd_getb32 (buffer);
    }

    /* always read second word in case of limm */
    /* we ignore the result since last insn may not have a limm */
    status = (*info->read_memory_func) (address + 4, buffer, 4, info);
    if (info->endian == BFD_ENDIAN_LITTLE) {
	    s.words[1] = bfd_getl32 (buffer);
    } else {
	    s.words[1] = bfd_getb32 (buffer);
    }
  }

  s._this = &s;
  s.coreRegName = _coreRegName;
  s.auxRegName = _auxRegName;
  s.condCodeName = _condCodeName;
  s.instName = _instName;

  /* disassemble */
  bytes = dsmOneArcInst(address, (void *)&s, info);
  /* We print max bytes for instruction */
  info->bytes_per_line = bytes;
  return s;
}


void
arc_print_disassembler_options (FILE *stream)
{
  fprintf (stream, "\n\
 ARC-specific disassembler options:\n\
 use with the -M switch, with options separated by commas\n\n");

  fprintf (stream, "  insn-stream    Show the instruction byte stream from most\n");
  fprintf (stream, "                 significant byte to least significant byte (excluding LIMM).\n");
  fprintf (stream, "                 This option is useful for viewing the actual encoding of instructions.\n");

  fprintf (stream, "  simd           Enable SIMD instructions disassembly.\n\n");
}
