/* 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 <ctype.h>
#include <stdarg.h>
#include <string.h>
#include <stdio.h>

#include <common_gnu/ansidecl.h>
#include <common_gnu/disas-asm.h>
#include "arc.h"
#include "arc-ext.h"
#include "arc-dis.h"
#include "arcompact-dis.h"
#include <common_gnu/elf-bfd.h>

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

#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))
#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) strcat(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))

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

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

#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;

	if (!buf) {
		return;
	}
	va_start(ap, format);
	bp = buf;
	*bp = 0;
	p = format;
	regMap[0] = 0;
	regMap[1] = 0;
	while (1) {
		if (!bp) { // this check is just to silence the compiler
			va_end(ap);
			return;
		}
		switch (*p++) {
		case 0: goto DOCOMM; /*(return) */
		default:
			*bp++ = p[-1];
			break;
		case '%':
			size = 0;
			leading_zero = 0;
		RETRY:;
			switch (*p++) {
			case '0':
			case '1':
			case '2':
			case '3':
			case '4':
			case '5':
			case '6':
			case '7':
			case '8':
			case '9': {
				/* size. */
				size = p[-1] - '0';
				if (size == 0) {
					leading_zero = 1; /* e.g. %08x */
				}
				while (*p >= '0' && *p <= '9') {
					size = size * 10 + *p - '0', p++;
				}
				goto RETRY;
			}
#define inc_bp() bp = bp + strlen(bp)

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

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

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

				inc_bp();
			} break;
			case 's': {
				sprintf(bp, "%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);

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

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

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

DOCOMM:
	*bp = 0;
	va_end(ap);
}

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);
	if (cond > 0) {
		int condlim = 0; /* condition code limit*/
		const char *cc = 0;
		if (!condCodeIsPartOfName) {
			strcat(state->instrBuffer, ".");
		}
		condlim = 18;
		if (cond < condlim) {
			cc = condName[cond];
		} else {
			cc = cond_code_name(state, cond);
		}
		if (!cc) {
			cc = "???";
		}
		strcat(state->instrBuffer, cc);
	}
	if (flag) {
		strcat(state->instrBuffer, ".f");
	}
	if (state->nullifyMode) {
		if (strstr(state->instrBuffer, ".d") == NULL) {
			strcat(state->instrBuffer, ".d");
		}
	}
	if (signExtend) {
		strcat(state->instrBuffer, ".x");
	}
	switch (addrWriteBack) {
	case 1: strcat(state->instrBuffer, ".a"); break;
	case 2: strcat(state->instrBuffer, ".ab"); break;
	case 3: strcat(state->instrBuffer, ".as"); break;
	}
	if (directMem) {
		strcat(state->instrBuffer, ".di");
	}
}

#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 = 0;

	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 = 0;

	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";
			// fallthrough
		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 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";
				// fallthrough
			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";
				}
				// fallthrough
			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]";
					// fallthrough
				case 5:
					if (!instrName) {
						instrName = "jne_s [blink]";
					}
					// fallthrough
				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();
		strcat(formatString,
			IS_REG(C) ? "[%r]" : "%s"); /* 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();
		}
		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 {
			strcat(formatString, "%*");
			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;

		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 {
			strcat(formatString, "%*");
			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 */

		/* [B,A offset] */
		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:
		/* BBIT0/BBIT1 Instruction */

		CHECK_FIELD_C();
		if (is_limm || BIT(state->words[0], 4)) {
			fieldCisReg = 0;
			FIELD_B();
		} else {
			CHECK_FIELD_B();
		}
		fieldAisReg = 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);
		strcat(formatString, ",%s"); /* 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;

		strcat(formatString, "%s"); /* 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
			/* Checking for bl unconditionally FIX For Bug #553 */
			if ((state->_opcode == op_BLC && BITS(state->words[0], 16, 17) == 2) || (state->_opcode == op_BC && (BIT(state->words[0], 16)))) {
				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]" */

		strcat(formatString, "%s"); /* 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]" */

		strcat(formatString, "%s"); /* 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 = 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);
		strcat(formatString, ",%s"); /* 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();
		strcat(formatString, "[%r]");
		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]);
		write_instr_name();
		strcat(formatString, "%d");
		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();
		strcat(formatString, "%r,%r,%r");
		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 != NULL;) {
		if (CONST_STRNEQ(p, "simd")) {
			enable_simd = 1;
		}
		if (CONST_STRNEQ(p, "insn-stream")) {
			enable_insn_stream = 1;
		}

		p = strchr(p, ',');

		if (p != NULL) {
			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[allOperandsSize + 1];

	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];
		(*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 */
		(*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 != NULL) && (operand[0] == '\0')) {
			*space = '\0';
			operand = space + 1;
		}

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

		if (__TRANSLATION_REQUIRED(s)) {
			bfd_vma addr;
			char *tmpBuffer;
			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) - 1);
				buf[sizeof(buf) - 1] = '\0';
				tmpBuffer = strtok(buf, "@");
				(*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 bytes; // s.instructionLen;
}

/*
 * 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];
		(*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 */
		(*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");
}
