/***************************************************************************

    am29ops.h
    Am29000 instructions

***************************************************************************/

/***************************************************************************
    DEFINES
***************************************************************************/

#define IFLAG_ILLEGAL				(1 << 0)
#define IFLAG_SUPERVISOR_ONLY		(1 << 1)
#define IFLAG_RA_PRESENT			(1 << 2)
#define IFLAG_RB_PRESENT			(1 << 3)
#define IFLAG_RC_PRESENT			(1 << 4)

#define IFLAG_SPR_ACCESS			(1 << 6)
#define IFLAG_MEMORY_ACCESS			(1 << 8)
#define IFLAG_CONTROL				(1 << 9)


#define GET_RA_VAL					(am29000->r[RA])
#define GET_RB_VAL					(am29000->r[RB])

#define RA							(get_abs_reg(am29000, am29000->exec_ir >>  8, am29000->ipa))
#define RB							(get_abs_reg(am29000, am29000->exec_ir >>  0, am29000->ipb))
#define RC							(get_abs_reg(am29000, am29000->exec_ir >> 16, am29000->ipc))

#define INST_SA						((am29000->exec_ir >> 8) & 0xff)
#define INST_VN						((am29000->exec_ir >> 16) & 0xff)
#define INST_M_BIT					(am29000->exec_ir & (1 << 24))
#define INST_CE_BIT					(am29000->exec_ir & (1 << 23))
#define INST_AS_BIT					(am29000->exec_ir & (1 << 22))
#define INST_PA_BIT					(am29000->exec_ir & (1 << 21))
#define INST_SB_BIT					(am29000->exec_ir & (1 << 20))
#define INST_UA_BIT					(am29000->exec_ir & (1 << 19))
#define INST_OPT_MASK				(7)
#define INST_OPT_SHIFT				(16)
#define INST_OPT_FIELD				(((am29000->exec_ir) >> INST_OPT_SHIFT) & INST_OPT_MASK)
#define INST_CNTL_MASK				(0x7f)
#define INST_CNTL_SHIFT				(16)

#define I8							(am29000->exec_ir & 0xff)
#define I16							(((am29000->exec_ir >> 8) & 0xff00) | (am29000->exec_ir & 0xff))
#define I16_ZEX						((UINT32)(I16))
#define I16_SEX						((INT32)(INT16)I16)
#define I16_OEX						(0xffff0000 | I16)

#define JMP_ZEX						(I16 << 2)
#define JMP_SEX						((INT32)(INT16)(((am29000->exec_ir >> 8) & 0xff00) | (am29000->exec_ir & 0xff)) << 2)

#define BOOLEAN_MASK				(1 << 31)
#define BOOLEAN_TRUE				(1 << 31)
#define BOOLEAN_FALSE				(0)

#define UNHANDLED_OP				fatalerror("Am29000: Unhandled inst %s at %x\n", __FUNCTION__, am29000->exec_pc);


/***************************************************************************
    STRUCTS
***************************************************************************/

typedef struct _op_info
{
	void (*opcode)(am29000_state *);
	UINT32 flags;
} op_info;


/***************************************************************************
    ALU FLAG CALCULATION
***************************************************************************/

#define SET_ALU_Z(r)			am29000->alu &= ~ALU_Z; \
								am29000->alu |= (r == 0) << ALU_Z_SHIFT;

#define SET_ALU_N(r)			am29000->alu &= ~ALU_N; \
								am29000->alu |= ((UINT32)r & 0x80000000) >> (31 - ALU_N_SHIFT);

#define CALC_C_ADD(r, a)		((UINT32)(r) < (UINT32)(a))

#define SET_ALU_C_ADD(r, a)		am29000->alu &= ~ALU_C; \
								am29000->alu |= CALC_C_ADD(r, a) << ALU_C_SHIFT;

#define CALC_C_SUB(a, b)		(!((UINT32)(a) < (UINT32)(b)))

#define SET_ALU_C_SUB(a, b)		am29000->alu &= ~ALU_C; \
								am29000->alu |= CALC_C_SUB(a, b) << ALU_C_SHIFT;

#define SET_ALU_V_ADD(r, a, b)	am29000->alu &= ~ALU_V; \
								am29000->alu |= (((INT32)(~((a) ^ (b)) & ((a) ^ (r))) < 0)) << ALU_V_SHIFT;

#define SET_ALU_V_SUB(r, a, b)	am29000->alu &= ~ALU_V; \
								am29000->alu |= ((INT32)(((a) ^ (b)) & ((a) ^ (r))) < 0) << ALU_V_SHIFT;

#define GET_CARRY				((am29000->alu >> ALU_C_SHIFT) & 1)



static UINT32 read_spr(am29000_state *am29000, UINT32 idx)
{
	UINT32 val = 0;

	switch (idx)
	{
		case SPR_VAB:	val = am29000->vab;		break;
		case SPR_OPS:	val = am29000->ops;		break;
		case SPR_CPS:	val = am29000->cps;		break;
		case SPR_CFG:	val = am29000->cfg;		break;
		case SPR_CHA:	val = am29000->cha;		break;
		case SPR_CHD:	val = am29000->chd;		break;
		case SPR_CHC:	val = am29000->chc;		break;
		case SPR_RBP:	val = am29000->rbp;		break;
		case SPR_TMC:	val = am29000->tmc;		break;
		case SPR_TMR:	val = am29000->tmr;		break;
		case SPR_PC0:	val = am29000->pc0;		break;
		case SPR_PC1:	val = am29000->pc1;		break;
		case SPR_PC2:	val = am29000->pc2;		break;
		case SPR_MMU:	val = am29000->mmu;		break;
		case SPR_LRU:	val = am29000->lru;		break;
		case SPR_IPC:	val = am29000->ipc;		break;
		case SPR_IPA:	val = am29000->ipa;		break;
		case SPR_IPB:	val = am29000->ipb;		break;
		case SPR_Q:		val = am29000->q;		break;
		case SPR_ALU:	val = am29000->alu;		break;
		case SPR_BP:	val = GET_ALU_BP;		break;
		case SPR_FC:	val = GET_ALU_FC;		break;
		case SPR_CR:	val = GET_CHC_CR;		break;
		case SPR_FPE:	val = am29000->fpe;		break;
		case SPR_INTE:	val = am29000->inte;	break;
		case SPR_FPS:	val = am29000->fps;		break;
		default:
			logerror("Unknown SPR read (%d)\n", idx);
	}

	return val;
}


static void write_spr(am29000_state *am29000, UINT32 idx, UINT32 val)
{
	switch (idx)
	{
		case SPR_VAB:	am29000->vab = val & (VAB_MASK << VAB_SHIFT);
						break;
		case SPR_OPS:	am29000->ops = val & (CPS_CA | CPS_IP | CPS_TE | CPS_TP | CPS_TU | CPS_FZ | CPS_LK | CPS_RE |
						CPS_WM | CPS_PD | CPS_PI | CPS_SM | (CPS_IM_MASK << CPS_IM_SHIFT) | CPS_DI | CPS_DA);
						break;
		case SPR_CPS:	am29000->cps = val & (CPS_CA | CPS_IP | CPS_TE | CPS_TP | CPS_TU | CPS_FZ | CPS_LK | CPS_RE |
						CPS_WM | CPS_PD | CPS_PI | CPS_SM | (CPS_IM_MASK << CPS_IM_SHIFT) | CPS_DI | CPS_DA);
						break;
		case SPR_CFG:	am29000->cfg = val & (CFG_DW | CFG_VF | CFG_RV | CFG_BO | CFG_CP | CFG_CD);
						am29000->cfg |= PROCESSOR_REL_FIELD << CFG_PRL_SHIFT;
						break;
		case SPR_CHA:	am29000->cha = val;
						break;
		case SPR_CHD:	am29000->chd = val;
						break;
		case SPR_CHC:	am29000->chc = val;
						break;
		case SPR_RBP:	am29000->rbp = val & RBP_MASK;
						break;
		case SPR_TMC:	am29000->tmc = val & TCV_MASK;
						break;
		case SPR_TMR:	am29000->tmr = val & (TMR_OV | TMR_IN | TMR_IE | TMR_TRV_MASK);
						break;
		case SPR_PC0:	am29000->pc0 = val & PC_MASK;
						break;
		case SPR_PC1:	am29000->pc1 = val & PC_MASK;
						break;
		case SPR_PC2:	am29000->pc2 = val & PC_MASK;
						break;
		case SPR_MMU:	am29000->mmu = val & ((MMU_PS_MASK << MMU_PS_SHIFT) | MMU_PID_MASK);
						break;
		case SPR_LRU:	am29000->lru = val & (LRU_MASK << LRU_SHIFT);
						break;
		case SPR_IPC:	am29000->ipc = val;// & IPX_MASK;
						break;
		case SPR_IPA:	am29000->ipa = val;// & IPX_MASK;
						break;
		case SPR_IPB:	am29000->ipb = val;// & IPX_MASK;
						break;
		case SPR_Q:		am29000->q = val;
						break;
		case SPR_ALU:	am29000->alu = val & (ALU_DF | ALU_V | ALU_N | ALU_Z | ALU_C | (ALU_BP_MASK << ALU_BP_SHIFT) | (ALU_FC_MASK << ALU_FC_SHIFT));
						break;
		case SPR_BP:	am29000->alu &= ~(ALU_BP_MASK << ALU_BP_SHIFT);
						am29000->alu |= (val & ALU_BP_MASK) << ALU_BP_SHIFT;
						break;
		case SPR_FC:	am29000->alu &= ~(ALU_FC_MASK << ALU_FC_SHIFT);
						am29000->alu |= (val & ALU_FC_MASK) << ALU_FC_SHIFT;
						break;
		case SPR_CR:	am29000->chc &= ~(CHC_CR_MASK << CHC_CR_SHIFT);
						am29000->chc |= (val & CHC_CR_MASK) << CHC_CR_SHIFT;
						break;
//      case SPR_FPE:
//      case SPR_INTE:
//      case SPR_FPS:
		default: logerror("Unhandled SPR write (%d)\n", idx);
	}
}


/***************************************************************************
    INSTRUCTIONS
***************************************************************************/

/***************************************************************************
    INTEGER ARITHMETIC
***************************************************************************/

static void ADD(am29000_state *am29000)
{
	UINT32 a = GET_RA_VAL;
	UINT32 b = INST_M_BIT ? I8: GET_RB_VAL;
	UINT32 r = a + b;

	if (!FREEZE_MODE)
	{
		SET_ALU_V_ADD(r, a, b);
		SET_ALU_Z(r);
		SET_ALU_N(r);
		SET_ALU_C_ADD(r, a);
	}

	am29000->r[RC] = r;
}

static void ADDS(am29000_state *am29000)
{
	UNHANDLED_OP;
}

static void ADDU(am29000_state *am29000)
{
	UNHANDLED_OP;
}

static void ADDC(am29000_state *am29000)
{
	UNHANDLED_OP;
}

static void ADDCS(am29000_state *am29000)
{
	UINT32 a = GET_RA_VAL;
	UINT32 b = INST_M_BIT ? I8: GET_RB_VAL;
	UINT32 r = a + b + GET_CARRY;

	if (!FREEZE_MODE)
	{
		UINT32 carry = GET_CARRY;
		UINT32 tmp = a + b;

		SET_ALU_V_ADD(r, a, b);
		SET_ALU_Z(r);
		SET_ALU_N(r);

		carry = CALC_C_ADD(tmp, a) || CALC_C_ADD(tmp + carry, carry);
		am29000->alu &= ~ALU_C;
		am29000->alu |= carry << ALU_C_SHIFT;
	}

	// TODO: Trap on signed overflow
	am29000->r[RC] = r;
}

static void ADDCU(am29000_state *am29000)
{
	UNHANDLED_OP;
}

static void SUB(am29000_state *am29000)
{
	UINT32 a = GET_RA_VAL;
	UINT32 b = INST_M_BIT ? I8 : GET_RB_VAL;
	UINT32 r = a - b;

	if (!FREEZE_MODE)
	{
		SET_ALU_V_SUB(r, a, b);
		SET_ALU_Z(r);
		SET_ALU_N(r);
		SET_ALU_C_SUB(a, b);
	}

	// TODO: Trap on unsigned overflow
	am29000->r[RC] = r;
}

static void SUBS(am29000_state *am29000)
{
	UINT32 a = GET_RA_VAL;
	UINT32 b = INST_M_BIT ? I8 : GET_RB_VAL;
	UINT32 r = a - b;

	if (!FREEZE_MODE)
	{
		SET_ALU_V_SUB(r, a, b);
		SET_ALU_Z(r);
		SET_ALU_N(r);
		SET_ALU_C_SUB(a, b);
	}

	if ((INT32)(((a) ^ (b)) & ((a) ^ (r))) < 0)
		SIGNAL_EXCEPTION(EXCEPTION_OUT_OF_RANGE);

	am29000->r[RC] = r;
}

static void SUBU(am29000_state *am29000)
{
	UNHANDLED_OP;
}

static void SUBC(am29000_state *am29000)
{
	UNHANDLED_OP;
}

static void SUBCS(am29000_state *am29000)
{
	UNHANDLED_OP;
}

static void SUBCU(am29000_state *am29000)
{
	UNHANDLED_OP;
}

static void SUBR(am29000_state *am29000)
{
	UINT32 a = GET_RA_VAL;
	UINT32 b = INST_M_BIT ? I8 : GET_RB_VAL;
	UINT32 r = b - a;

	if (!FREEZE_MODE)
	{
		SET_ALU_V_SUB(r, a, b);
		SET_ALU_Z(r);
		SET_ALU_N(r);
		SET_ALU_C_SUB(a, b);
	}

	am29000->r[RC] = r;
}

static void SUBRS(am29000_state *am29000)
{
	UNHANDLED_OP;
}

static void SUBRU(am29000_state *am29000)
{
	UNHANDLED_OP;
}

static void SUBRC(am29000_state *am29000)
{
	UINT32 a = GET_RA_VAL;
	UINT32 b = INST_M_BIT ? I8 : GET_RB_VAL;
	UINT32 r = b - a - 1 + GET_CARRY;

	if (!FREEZE_MODE)
	{
		SET_ALU_V_SUB(r, a, b);
		SET_ALU_Z(r);
		SET_ALU_N(r);
		SET_ALU_C_SUB(a, b);
	}

	am29000->r[RC] = r;
}

static void SUBRCS(am29000_state *am29000)
{
	UNHANDLED_OP;
}

static void SUBRCU(am29000_state *am29000)
{
	UNHANDLED_OP;
}

static void MULTIPLU(am29000_state *am29000)
{
	UNHANDLED_OP;
}

static void MULTIPLY(am29000_state *am29000)
{
	UNHANDLED_OP;
}

static void MUL(am29000_state *am29000)
{
	/* TODO: Zero/Neg flags ? */
	UINT32 a = GET_RA_VAL;
	UINT32 b = INST_M_BIT ? I8 : GET_RB_VAL;
	UINT32 r;
	UINT64 v;
	UINT32 sign;

	if (am29000->q & 1)
	{
		r = a + b;
		sign = (r >> 31) ^ (((INT32)(~((a) ^ (b)) & ((a) ^ (r))) < 0));
	}
	else
	{
		r = b;
		sign = b >> 31;
	}

	v = ((((UINT64)r << 32) | am29000->q) >> 1) | ((UINT64)sign << 63);
	am29000->q = v & 0xffffffff;

	am29000->r[RC] = v >> 32;
}

static void MULL(am29000_state *am29000)
{
	/* TODO: Zero/Neg flags ? */
	UINT32 a = GET_RA_VAL;
	UINT32 b = INST_M_BIT ? I8 : GET_RB_VAL;
	UINT32 r;
	UINT64 v;
	UINT32 sign;

	if (am29000->q & 1)
	{
		r = b - a;
		sign = (r >> 31) ^ ((INT32)(((a) ^ (b)) & ((a) ^ (r))) < 0);
	}
	else
	{
		r = b;
		sign = b >> 31;
	}

	v = ((((UINT64)r << 32) | am29000->q) >> 1) | ((UINT64)sign << 63);
	am29000->q = v & 0xffffffff;

	am29000->r[RC] = v >> 32;
}

static void MULU(am29000_state *am29000)
{
	/* TODO: Zero/Neg flags ? */
	UINT32 a = GET_RA_VAL;
	UINT32 b = INST_M_BIT ? I8 : GET_RB_VAL;
	UINT32 r;
	UINT64 v;
	UINT32 c;

	if (am29000->q & 1)
	{
		r = a + b;
		c = (UINT32)(r) < (UINT32)(a);
	}
	else
	{
		r = b;
		c = 0;
	}

	v = ((((UINT64)r << 32) | am29000->q) >> 1) | ((UINT64)c << 63);
	am29000->q = v & 0xffffffff;

	am29000->r[RC] = v >> 32;
}

static void DIVIDE(am29000_state *am29000)
{
	am29000->ipa = RA << IPX_SHIFT;
	am29000->ipb = RB << IPX_SHIFT;
	am29000->ipc = RC << IPX_SHIFT;

	SIGNAL_EXCEPTION(EXCEPTION_DIVIDE);
}

static void DIVIDU(am29000_state *am29000)
{
	UNHANDLED_OP;
}

static void DIV0(am29000_state *am29000)
{
	UINT32 b = INST_M_BIT ? I8: GET_RB_VAL;
	UINT64 v;

	if (!FREEZE_MODE)
	{
		am29000->alu |= ALU_DF;
		SET_ALU_N(b);
	}

	v = (((UINT64)b << 32) | am29000->q) << 1;

	am29000->q = v & 0xffffffff;

	am29000->r[RC] = v >> 32;
}

static void DIV(am29000_state *am29000)
{
	UINT32 a = GET_RA_VAL;
	UINT32 b = INST_M_BIT ? I8: GET_RB_VAL;
	UINT32 c;
	UINT32 r;
	UINT64 r64;
	UINT32 df;

	if (am29000->alu & ALU_DF)
	{
		r = a - b;
		c = !((UINT32)(a) < (UINT32)(b));
	}
	else
	{
		r = a + b;
		c = (UINT32)(r) < (UINT32)(a);
	}


	df = (~(c ^ (am29000->alu >> ALU_DF_SHIFT) ^ (am29000->alu >> ALU_N_SHIFT)) & 1);

	if (!FREEZE_MODE)
	{
		am29000->alu &= ~ALU_DF;
		am29000->alu |= df << ALU_DF_SHIFT;
		SET_ALU_N(r);
	}

	r64 = ((((UINT64)r << 32) | am29000->q) << 1) | df;
	am29000->q = r64 & 0xffffffff;

	am29000->r[RC] = r64 >> 32;
}

static void DIVL(am29000_state *am29000)
{
	UINT32 a = GET_RA_VAL;
	UINT32 b = INST_M_BIT ? I8: GET_RB_VAL;
	UINT32 c;
	UINT32 r;
	UINT32 df;

	if (am29000->alu & ALU_DF)
	{
		r = a - b;
		c = !((UINT32)(a) < (UINT32)(b));
	}
	else
	{
		r = a + b;
		c = (UINT32)(r) < (UINT32)(a);
	}

	df = (~(c ^ (am29000->alu >> ALU_DF_SHIFT) ^ (am29000->alu >> ALU_N_SHIFT)) & 1);

	if (!FREEZE_MODE)
	{
		am29000->alu &= ~ALU_DF;
		am29000->alu |= df << ALU_DF_SHIFT;
		SET_ALU_N(r);
	}

	am29000->q = (am29000->q << 1) | df;
	am29000->r[RC] = r;
}

static void DIVREM(am29000_state *am29000)
{
	UINT32 a = GET_RA_VAL;
	UINT32 b = INST_M_BIT ? I8: GET_RB_VAL;

	if (am29000->alu & ALU_DF)
		am29000->r[RC] = a;
	else
		am29000->r[RC] = a + b;
}


/***************************************************************************
    COMPARE
***************************************************************************/

static void CPEQ(am29000_state *am29000)
{
	UINT32 a = GET_RA_VAL;
	UINT32 b = INST_M_BIT ? I8: GET_RB_VAL;
	UINT32 r = a == b ? BOOLEAN_TRUE : BOOLEAN_FALSE;

	am29000->r[RC] = r;
}

static void CPNEQ(am29000_state *am29000)
{
	UINT32 a = GET_RA_VAL;
	UINT32 b = INST_M_BIT ? I8: GET_RB_VAL;
	UINT32 r = a != b ? BOOLEAN_TRUE : BOOLEAN_FALSE;

	am29000->r[RC] = r;
}

static void CPLT(am29000_state *am29000)
{
	UINT32 a = GET_RA_VAL;
	UINT32 b = INST_M_BIT ? I8: GET_RB_VAL;
	UINT32 r = (INT32)a < (INT32)b ? BOOLEAN_TRUE : BOOLEAN_FALSE;

	am29000->r[RC] = r;
}

static void CPLTU(am29000_state *am29000)
{
	UINT32 a = GET_RA_VAL;
	UINT32 b = INST_M_BIT ? I8: GET_RB_VAL;
	UINT32 r = (UINT32)a < (UINT32)b ? BOOLEAN_TRUE : BOOLEAN_FALSE;

	am29000->r[RC] = r;
}

static void CPLE(am29000_state *am29000)
{
	UINT32 a = GET_RA_VAL;
	UINT32 b = INST_M_BIT ? I8: GET_RB_VAL;
	UINT32 r = (INT32)a <= (INT32)b ? BOOLEAN_TRUE : BOOLEAN_FALSE;

	am29000->r[RC] = r;
}

static void CPLEU(am29000_state *am29000)
{
	UINT32 a = GET_RA_VAL;
	UINT32 b = INST_M_BIT ? I8: GET_RB_VAL;
	UINT32 r = (UINT32)a <= (UINT32)b ? BOOLEAN_TRUE : BOOLEAN_FALSE;

	am29000->r[RC] = r;
}

static void CPGT(am29000_state *am29000)
{
	UINT32 a = GET_RA_VAL;
	UINT32 b = INST_M_BIT ? I8: GET_RB_VAL;
	UINT32 r = (INT32)a > (INT32)b ? BOOLEAN_TRUE : BOOLEAN_FALSE;

	am29000->r[RC] = r;
}

static void CPGTU(am29000_state *am29000)
{
	UINT32 a = GET_RA_VAL;
	UINT32 b = INST_M_BIT ? I8: GET_RB_VAL;
	UINT32 r = (UINT32)a > (UINT32)b ? BOOLEAN_TRUE : BOOLEAN_FALSE;

	am29000->r[RC] = r;
}

static void CPGE(am29000_state *am29000)
{
	UINT32 a = GET_RA_VAL;
	UINT32 b = INST_M_BIT ? I8: GET_RB_VAL;
	UINT32 r = (INT32)a >= (INT32)b ? BOOLEAN_TRUE : BOOLEAN_FALSE;

	am29000->r[RC] = r;
}

static void CPGEU(am29000_state *am29000)
{
	UINT32 a = GET_RA_VAL;
	UINT32 b = INST_M_BIT ? I8: GET_RB_VAL;
	UINT32 r = (UINT32)a >= (UINT32)b ? BOOLEAN_TRUE : BOOLEAN_FALSE;

	am29000->r[RC] = r;
}

static void CPBYTE(am29000_state *am29000)
{
	UINT32 a = GET_RA_VAL;
	UINT32 b = INST_M_BIT ? I8 : GET_RB_VAL;
	UINT32 r =
			((a & 0xff000000) == (b & 0xff000000)) ||
			((a & 0x00ff0000) == (b & 0x00ff0000)) ||
			((a & 0x0000ff00) == (b & 0x0000ff00)) ||
			((a & 0x000000ff) == (b & 0x000000ff))
			? BOOLEAN_TRUE : BOOLEAN_FALSE;

	am29000->r[RC] = r;
}

static void ASEQ(am29000_state *am29000)
{
	if (USER_MODE && INST_VN < 64)
		SIGNAL_EXCEPTION(EXCEPTION_PROTECTION_VIOLATION);
	else if (!(GET_RA_VAL == GET_RB_VAL))
		SIGNAL_EXCEPTION(INST_VN);
}

static void ASNEQ(am29000_state *am29000)
{
	if (USER_MODE && INST_VN < 64)
		SIGNAL_EXCEPTION(EXCEPTION_PROTECTION_VIOLATION);
	else if (!(GET_RA_VAL != GET_RB_VAL))
		SIGNAL_EXCEPTION(INST_VN);
}

static void ASLT(am29000_state *am29000)
{
	if (USER_MODE && INST_VN < 64)
		SIGNAL_EXCEPTION(EXCEPTION_PROTECTION_VIOLATION);
	else if (!((INT32)GET_RA_VAL < (INT32)GET_RB_VAL))
		SIGNAL_EXCEPTION(INST_VN);
}

static void ASLTU(am29000_state *am29000)
{
	if (USER_MODE && INST_VN < 64)
		SIGNAL_EXCEPTION(EXCEPTION_PROTECTION_VIOLATION);
	else if (!((UINT32)GET_RA_VAL < (UINT32)GET_RB_VAL))
		SIGNAL_EXCEPTION(INST_VN);
}

static void ASLE(am29000_state *am29000)
{
	if (USER_MODE && INST_VN < 64)
		SIGNAL_EXCEPTION(EXCEPTION_PROTECTION_VIOLATION);
	else if (!((INT32)GET_RA_VAL <= (INT32)GET_RB_VAL))
		SIGNAL_EXCEPTION(INST_VN);
}

static void ASLEU(am29000_state *am29000)
{
	if (USER_MODE && INST_VN < 64)
		SIGNAL_EXCEPTION(EXCEPTION_PROTECTION_VIOLATION);
	else if (!((UINT32)GET_RA_VAL <= (UINT32)GET_RB_VAL))
		SIGNAL_EXCEPTION(INST_VN);
}

static void ASGT(am29000_state *am29000)
{
	if (USER_MODE && INST_VN < 64)
		SIGNAL_EXCEPTION(EXCEPTION_PROTECTION_VIOLATION);
	else if (!((INT32)GET_RA_VAL > (INT32)GET_RB_VAL))
		SIGNAL_EXCEPTION(INST_VN);
}

static void ASGTU(am29000_state *am29000)
{
	if (USER_MODE && INST_VN < 64)
		SIGNAL_EXCEPTION(EXCEPTION_PROTECTION_VIOLATION);
	else if (!((UINT32)GET_RA_VAL > (UINT32)GET_RB_VAL))
		SIGNAL_EXCEPTION(INST_VN);
}

static void ASGE(am29000_state *am29000)
{
	if (USER_MODE && INST_VN < 64)
		SIGNAL_EXCEPTION(EXCEPTION_PROTECTION_VIOLATION);
	else if (!((INT32)GET_RA_VAL >= (INT32)GET_RB_VAL))
		SIGNAL_EXCEPTION(INST_VN);
}

static void ASGEU(am29000_state *am29000)
{
	if (USER_MODE && INST_VN < 64)
		SIGNAL_EXCEPTION(EXCEPTION_PROTECTION_VIOLATION);
	else if (!((UINT32)GET_RA_VAL >= (UINT32)GET_RB_VAL))
		SIGNAL_EXCEPTION(INST_VN);
}


/***************************************************************************
    LOGICAL
***************************************************************************/

static void AND(am29000_state *am29000)
{
	UINT32 a = GET_RA_VAL;
	UINT32 b = INST_M_BIT ? I8: GET_RB_VAL;
	UINT32 r = a & b;

	if (!FREEZE_MODE)
	{
		SET_ALU_Z(r);
		SET_ALU_N(r);
	}

	am29000->r[RC] = r;
}

static void ANDN(am29000_state *am29000)
{
	UINT32 a = GET_RA_VAL;
	UINT32 b = INST_M_BIT ? I8: GET_RB_VAL;
	UINT32 r = a & ~b;

	if (!FREEZE_MODE)
	{
		SET_ALU_Z(r);
		SET_ALU_N(r);
	}

	am29000->r[RC] = r;
}

static void NAND(am29000_state *am29000)
{
	UINT32 a = GET_RA_VAL;
	UINT32 b = INST_M_BIT ? I8: GET_RB_VAL;
	UINT32 r = ~(a & b);

	if (!FREEZE_MODE)
	{
		SET_ALU_Z(r);
		SET_ALU_N(r);
	}

	am29000->r[RC] = r;
}

static void OR(am29000_state *am29000)
{
	UINT32 a = GET_RA_VAL;
	UINT32 b = INST_M_BIT ? I8: GET_RB_VAL;
	UINT32 r = a | b;

	if (!FREEZE_MODE)
	{
		SET_ALU_Z(r);
		SET_ALU_N(r);
	}

	am29000->r[RC] = r;
}

static void NOR(am29000_state *am29000)
{
	UINT32 a = GET_RA_VAL;
	UINT32 b = INST_M_BIT ? I8: GET_RB_VAL;
	UINT32 r = ~(a | b);

	if (!FREEZE_MODE)
	{
		SET_ALU_Z(r);
		SET_ALU_N(r);
	}

	am29000->r[RC] = r;
}

static void XOR(am29000_state *am29000)
{
	UINT32 a = GET_RA_VAL;
	UINT32 b = INST_M_BIT ? I8: GET_RB_VAL;
	UINT32 r = a ^ b;

	if (!FREEZE_MODE)
	{
		SET_ALU_Z(r);
		SET_ALU_N(r);
	}

	am29000->r[RC] = r;
}

static void XNOR(am29000_state *am29000)
{
	UINT32 a = GET_RA_VAL;
	UINT32 b = INST_M_BIT ? I8: GET_RB_VAL;
	UINT32 r = ~(a ^ b);

	if (!FREEZE_MODE)
	{
		SET_ALU_Z(r);
		SET_ALU_N(r);
	}

	am29000->r[RC] = r;
}


/***************************************************************************
    SHIFT
***************************************************************************/

static void SLL(am29000_state *am29000)
{
	UINT32 a = GET_RA_VAL;
	UINT32 b = (INST_M_BIT ? I8: GET_RB_VAL) & 0x1f;
	UINT32 r = a << b;

	am29000->r[RC] = r;
}

static void SRL(am29000_state *am29000)
{
	UINT32 a = GET_RA_VAL;
	UINT32 b = (INST_M_BIT ? I8: GET_RB_VAL) & 0x1f;
	UINT32 r = a >> b;

	am29000->r[RC] = r;
}

static void SRA(am29000_state *am29000)
{
	INT32 a = GET_RA_VAL;
	UINT32 b = (INST_M_BIT ? I8: GET_RB_VAL) & 0x1f;
	UINT32 r = a >> b;

	am29000->r[RC] = r;
}

static void EXTRACT(am29000_state *am29000)
{
	INT32 a = GET_RA_VAL;
	UINT32 b = (INST_M_BIT ? I8: GET_RB_VAL);
	UINT64 r;

	r = (((UINT64)a << 32) | b) << GET_ALU_FC;

	am29000->r[RC] = r >> 32;
}


/***************************************************************************
    DATA MOVEMENT
***************************************************************************/

static void LOAD(am29000_state *am29000)
{
	UINT32 addr = INST_M_BIT ? I8: GET_RB_VAL;
	UINT32 r;

	if (INST_UA_BIT)
		fatalerror("Am29000: UA bit set on LOAD\n");

	if (INST_CE_BIT)
	{
		logerror("Am29000: Attempting a co-processor LOAD!\n");
		r = 0;
	}
	else
	{
		if (!INST_PA_BIT && !(am29000->cps & CPS_PD))
		{
			fatalerror("Am29000: Address translation on LOAD\n");
		}
		else
		{
			if (USER_MODE)
			{
				SIGNAL_EXCEPTION(EXCEPTION_PROTECTION_VIOLATION);
				return;
			}

			r = am29000->data->read_dword(addr);
		}
	}

//  if (opt & 2)
//      logerror("Am29000: Half word LOAD\n");

	if (!FREEZE_MODE)
	{
		am29000->chc = ((am29000->exec_ir << 8) & 0xff) |
						CHC_LS |
						RA << CHC_TR_SHIFT |
						CHC_CV;

		am29000->cha = addr;
		am29000->chd = r;

		if (!(am29000->cfg & CFG_DW) && (am29000->exec_ir & INST_SB_BIT))
			SET_ALU_BP(addr & 3);
	}

	am29000->r[RA] = r;

	if (am29000->cfg & CFG_DW)
		logerror("DW ON A STORE");
}

static void LOADL(am29000_state *am29000)
{
	UNHANDLED_OP;
}

static void LOADSET(am29000_state *am29000)
{
	UNHANDLED_OP;
}

static void LOADM(am29000_state *am29000)
{
	UINT32 addr = INST_M_BIT ? I8: GET_RB_VAL;
	UINT32 r;

	if (INST_UA_BIT)
		fatalerror("Am29000: UA bit set on LOAD\n");

	if (INST_CE_BIT)
	{
		logerror("Am29000: Attempting a co-processor LOAD!\n");
		r = 0;
	}
	else
	{
		if (!INST_PA_BIT && !(am29000->cps & CPS_PD))
		{
			fatalerror("Am29000: Address translation on LOAD\n");
		}
		else
		{
			if (USER_MODE)
			{
				SIGNAL_EXCEPTION(EXCEPTION_PROTECTION_VIOLATION);
				return;
			}

			r = am29000->data->read_dword(addr);
		}
	}

	if (!FREEZE_MODE)
	{
		// TODO
		am29000->chc &= (CHC_CR_MASK << CHC_CR_SHIFT);
		am29000->chc |= ((am29000->exec_ir << 8) & 0xff) |
						RA << CHC_TR_SHIFT |
						CHC_CV;

		am29000->cha = addr;
		am29000->chd = r; // ?????

		if (!(am29000->cfg & CFG_DW) && (am29000->exec_ir & INST_SB_BIT))
			SET_ALU_BP(addr & 3);
	}

	r = RA;

	{
		int cnt;
		for (cnt = 0; cnt <= GET_CHC_CR; ++cnt)
		{
			am29000->r[r] = am29000->data->read_dword(addr);

//          SET_CHC_CR(cnt - 1);
			addr += 4;

			if (++r == 256)
				r = 128;
		}
	}
}

static void STORE(am29000_state *am29000)
{
	UINT32 addr = INST_M_BIT ? I8: GET_RB_VAL;
//  UINT32 r;

	if (INST_UA_BIT)
		fatalerror("Am29000: UA bit set on LOAD\n");

	if (INST_CE_BIT)
	{
		logerror("Am29000: Attempting a co-processor LOAD!\n");
//      r = 0;
	}
	else
	{
		if (!INST_PA_BIT && !(am29000->cps & CPS_PD))
		{
			fatalerror("Am29000: Address translation on LOAD\n");
		}
		else
		{
			if (USER_MODE)
			{
				SIGNAL_EXCEPTION(EXCEPTION_PROTECTION_VIOLATION);
				return;
			}

		}
	}

	am29000->data->write_dword(addr, am29000->r[RA]);

	if (!FREEZE_MODE)
	{
		am29000->chc = ((am29000->exec_ir << 8) & 0xff) |
						RA << CHC_TR_SHIFT |
						CHC_CV;

		am29000->cha = addr;

		if (!(am29000->cfg & CFG_DW) && (am29000->exec_ir & INST_SB_BIT))
			SET_ALU_BP(addr & 3);
	}

	if (am29000->cfg & CFG_DW)
		logerror("DW ON A STORE");
}

static void STOREL(am29000_state *am29000)
{
	UNHANDLED_OP;
}

static void STOREM(am29000_state *am29000)
{
	UINT32 addr = INST_M_BIT ? I8: GET_RB_VAL;
	UINT32 r;

	if (INST_UA_BIT)
		fatalerror("Am29000: UA bit set on LOAD\n");

	if (INST_CE_BIT)
	{
		logerror("Am29000: Attempting a co-processor LOAD!\n");
		r = 0;
	}
	else
	{
		if (!INST_PA_BIT && !(am29000->cps & CPS_PD))
		{
			fatalerror("Am29000: Address translation on LOAD\n");
		}
		else
		{
			if (USER_MODE)
			{
				SIGNAL_EXCEPTION(EXCEPTION_PROTECTION_VIOLATION);
				return;
			}

		}
	}

	if (!FREEZE_MODE)
	{
		// TODO
		am29000->chc &= (CHC_CR_MASK << CHC_CR_SHIFT);
		am29000->chc |= ((am29000->exec_ir << 8) & 0xff) |
						RA << CHC_TR_SHIFT |
						CHC_CV;

		am29000->cha = addr;

		if (!(am29000->cfg & CFG_DW) && (am29000->exec_ir & INST_SB_BIT))
			SET_ALU_BP(addr & 3);
	}

	r = RA;

	{
		int cnt;
		for (cnt = 0; cnt <= GET_CHC_CR; ++cnt)
		{
			am29000->data->write_dword(addr, am29000->r[r]);

//          SET_CHC_CR(cnt - 1);
			addr += 4;

			if (++r == 256)
				r = 128;
		}
	}
}

static void EXBYTE(am29000_state *am29000)
{
	UINT32 a = GET_RA_VAL;
	UINT32 b = INST_M_BIT ? I8: GET_RB_VAL;
	UINT32 bp = GET_ALU_BP;
	UINT8 srcbyte;
	UINT32 r;

	if (am29000->cfg & CFG_BO)
		srcbyte = a >> 8 * bp;
	else
		srcbyte = a >> (8 * (3 - bp));

	r = (b & 0xffffff00) | srcbyte;

	am29000->r[RC] = r;
}

static void EXHW(am29000_state *am29000)
{
	UINT32 a = GET_RA_VAL;
	UINT32 b = INST_M_BIT ? I8: GET_RB_VAL;
	UINT32 wp = ((am29000->alu >> ALU_BP_SHIFT) & ALU_BP_MASK) >> 1;
	UINT16 srcword;
	UINT32 r;

	if (am29000->cfg & CFG_BO)
		srcword = a >> 16 * wp;
	else
		srcword = a >> (16 * (1 - wp));

	r = (b & 0xffff0000) | srcword;

	am29000->r[RC] = r;
}

static void EXHWS(am29000_state *am29000)
{
	UINT32 a = GET_RA_VAL;
	UINT32 wp = ((am29000->alu >> ALU_BP_SHIFT) & ALU_BP_MASK) >> 1;
	UINT16 srcword;
	UINT32 r;

	if (am29000->cfg & CFG_BO)
		srcword = a >> 16 * wp;
	else
		srcword = a >> (16 * (1 - wp));

	r = (INT32)(INT16)srcword;

	am29000->r[RC] = r;
}

static void INBYTE(am29000_state *am29000)
{
	UINT32 a = GET_RA_VAL;
	UINT32 b = INST_M_BIT ? I8: GET_RB_VAL;
	UINT32 bp = GET_ALU_BP;
	UINT8 shift = (am29000->cfg & CFG_BO) ? 8 * bp : (8 * (3 - bp));
	UINT32 r;

	r = (a & ~(0xff << shift)) | ((b & 0xff) << shift);

	am29000->r[RC] = r;
}

static void INHW(am29000_state *am29000)
{
	UINT32 a = GET_RA_VAL;
	UINT32 b = INST_M_BIT ? I8: GET_RB_VAL;
	UINT32 wp = ((am29000->alu >> ALU_BP_SHIFT) & ALU_BP_MASK) >> 1;
	UINT32 shift = (am29000->cfg & CFG_BO) ? 16 * wp : (16 * (1 - wp));
	UINT32 r;

	r = (a & ~(0xffff << shift)) | ((b & 0xffff) << shift);

	am29000->r[RC] = r;
}

static void MFSR(am29000_state *am29000)
{
	am29000->r[RC] = read_spr(am29000, INST_SA);
}

static void MFTLB(am29000_state *am29000)
{
	am29000->r[RC] = am29000->tlb[GET_RA_VAL & 0x7f];
}

static void MTSR(am29000_state *am29000)
{
	write_spr(am29000, INST_SA, GET_RB_VAL);
}

static void MTSRIM(am29000_state *am29000)
{
	write_spr(am29000, INST_SA, I16_ZEX);
}

static void MTTLB(am29000_state *am29000)
{
	am29000->tlb[GET_RA_VAL & 0x7f] = GET_RB_VAL;
}


/***************************************************************************
    CONSTANT
***************************************************************************/

static void CONST(am29000_state *am29000)
{
	am29000->r[RA] = I16_ZEX;
}

static void CONSTH(am29000_state *am29000)
{
	am29000->r[RA] = (I16 << 16) | GET_RA_VAL;
}

static void CONSTN(am29000_state *am29000)
{
	am29000->r[RA] = I16_OEX;
}


/***************************************************************************
    BRANCH INSTRUCTIONS
***************************************************************************/

static void CALL(am29000_state *am29000)
{
	UINT32 ret = am29000->next_pc;

	if (INST_M_BIT)
		am29000->next_pc = JMP_ZEX;
	else
		am29000->next_pc = am29000->exec_pc + JMP_SEX;

	am29000->r[RA] = ret;
am29000->next_pl_flags |= PFLAG_JUMP;
}

static void CALLI(am29000_state *am29000)
{
	UINT32 ret = am29000->next_pc;
	am29000->next_pc = GET_RB_VAL;
	am29000->r[RA] = ret;
	am29000->next_pl_flags |= PFLAG_JUMP;
}

static void JMP(am29000_state *am29000)
{
	if (INST_M_BIT)
		am29000->next_pc = JMP_ZEX;
	else
		am29000->next_pc = am29000->exec_pc + JMP_SEX;

	am29000->next_pl_flags |= PFLAG_JUMP;
}

static void JMPI(am29000_state *am29000)
{
	am29000->next_pc = GET_RB_VAL;

	am29000->next_pl_flags |= PFLAG_JUMP;
}

static void JMPT(am29000_state *am29000)
{
	if ((GET_RA_VAL & BOOLEAN_MASK) == BOOLEAN_TRUE)
	{
		if (INST_M_BIT)
			am29000->next_pc = JMP_ZEX;
		else
			am29000->next_pc = am29000->exec_pc + JMP_SEX;

		am29000->next_pl_flags |= PFLAG_JUMP;
	}
}

static void JMPTI(am29000_state *am29000)
{
	if ((GET_RA_VAL & BOOLEAN_MASK) == BOOLEAN_TRUE)
	{
		am29000->next_pc = GET_RB_VAL;
		am29000->next_pl_flags |= PFLAG_JUMP;
	}
}

static void JMPF(am29000_state *am29000)
{
	if ((GET_RA_VAL & BOOLEAN_MASK) == BOOLEAN_FALSE)
	{
		if (INST_M_BIT)
			am29000->next_pc = JMP_ZEX;
		else
			am29000->next_pc = am29000->exec_pc + JMP_SEX;

		am29000->next_pl_flags |= PFLAG_JUMP;
	}
}

static void JMPFI(am29000_state *am29000)
{
	if ((GET_RA_VAL & BOOLEAN_MASK) == BOOLEAN_FALSE)
	{
		am29000->next_pc = GET_RB_VAL;
		am29000->next_pl_flags |= PFLAG_JUMP;
	}
}

static void JMPFDEC(am29000_state *am29000)
{
	UINT32 a = GET_RA_VAL;

	if ((a & BOOLEAN_MASK) == BOOLEAN_FALSE)
	{
		if (INST_M_BIT)
			am29000->next_pc = JMP_ZEX;
		else
			am29000->next_pc = am29000->exec_pc + JMP_SEX;

		am29000->next_pl_flags |= PFLAG_JUMP;
	}

	am29000->r[RA] = a - 1;
}


/***************************************************************************
    MISCELLANEOUS INSTRUCTIONS
***************************************************************************/

static void CLZ(am29000_state *am29000)
{
	UINT32 b = INST_M_BIT ? I8: GET_RB_VAL;

	am29000->r[RC] = count_leading_zeros(b);
}

static void SETIP(am29000_state *am29000)
{
	am29000->ipa = RA << IPX_SHIFT;
	am29000->ipb = RB << IPX_SHIFT;
	am29000->ipc = RC << IPX_SHIFT;
}

static void EMULATE(am29000_state *am29000)
{
	UNHANDLED_OP;
}

static void INV(am29000_state *am29000)
{
	/* Nothing to do yet */
}

static void IRET(am29000_state *am29000)
{
	am29000->iret_pc = am29000->pc0;
	am29000->next_pc = am29000->pc1;
	am29000->cps = am29000->ops;
	am29000->next_pl_flags = PFLAG_IRET;
}

static void IRETINV(am29000_state *am29000)
{
	UNHANDLED_OP;
}

static void HALT(am29000_state *am29000)
{
	UNHANDLED_OP;
}


static void ILLEGAL(am29000_state *am29000)
{
	fatalerror("Am29000: Executed illegal instruction - this should never happen! %x (%x)\n", am29000->pc2, am29000->exec_pc);
}



/***************************************************************************
    UNHANDLED
***************************************************************************/

static void CONVERT(am29000_state *am29000)
{
	UNHANDLED_OP;
}

static void SQRT(am29000_state *am29000)
{
	UNHANDLED_OP;
}

static void CLASS(am29000_state *am29000)
{
	UNHANDLED_OP;
}

static void MULTM(am29000_state *am29000)
{
	UNHANDLED_OP;
}

static void MULTMU(am29000_state *am29000)
{
	UNHANDLED_OP;
}


const op_info op_table[256] =
{
	{ ILLEGAL,  IFLAG_ILLEGAL                                                      },
	{ CONSTN,   IFLAG_RA_PRESENT                                                   },
	{ CONSTH,   IFLAG_RA_PRESENT                                                   },
	{ CONST,    IFLAG_RA_PRESENT                                                   },
	{ MTSRIM,   0                                                                  },
	{ ILLEGAL,  IFLAG_ILLEGAL                                                      },
	{ LOADL,    0                                                                  },
	{ LOADL,    0                                                                  },
	{ CLZ,      IFLAG_RC_PRESENT | IFLAG_RB_PRESENT                                },
	{ CLZ,      IFLAG_RC_PRESENT                                                   },
	{ EXBYTE,   IFLAG_RC_PRESENT | IFLAG_RB_PRESENT | IFLAG_RA_PRESENT             },
	{ EXBYTE,   IFLAG_RC_PRESENT | IFLAG_RA_PRESENT                                },
	{ INBYTE,   IFLAG_RC_PRESENT | IFLAG_RB_PRESENT | IFLAG_RA_PRESENT             },
	{ INBYTE,   IFLAG_RC_PRESENT | IFLAG_RA_PRESENT                                },
	{ STOREL,   0                                                                  },
	{ STOREL,   0                                                                  },
	{ ADDS,     0                                                                  },
	{ ADDS,     0                                                                  },
	{ ADDU,     0                                                                  },
	{ ADDU,     0                                                                  },
	{ ADD,      IFLAG_RC_PRESENT | IFLAG_RB_PRESENT | IFLAG_RA_PRESENT             },
	{ ADD,      IFLAG_RC_PRESENT | IFLAG_RA_PRESENT                                },
	{ LOAD,     IFLAG_RA_PRESENT | IFLAG_RB_PRESENT                                },
	{ LOAD,     IFLAG_RA_PRESENT                                                   },
	{ ADDCS,    IFLAG_RC_PRESENT | IFLAG_RB_PRESENT | IFLAG_RA_PRESENT             },
	{ ADDCS,    IFLAG_RC_PRESENT | IFLAG_RA_PRESENT                                },
	{ ADDCU,    0                                                                  },
	{ ADDCU,    0                                                                  },
	{ ADDC,     0                                                                  },
	{ ADDC,     0                                                                  },
	{ STORE,    IFLAG_RA_PRESENT | IFLAG_RB_PRESENT                                },
	{ STORE,    IFLAG_RA_PRESENT                                                   },
	{ SUBS,     IFLAG_RC_PRESENT | IFLAG_RB_PRESENT | IFLAG_RA_PRESENT             },
	{ SUBS,     IFLAG_RC_PRESENT | IFLAG_RA_PRESENT                                },
	{ SUBU,     0                                                                  },
	{ SUBU,     0                                                                  },
	{ SUB,      IFLAG_RC_PRESENT | IFLAG_RB_PRESENT | IFLAG_RA_PRESENT             },
	{ SUB,      IFLAG_RC_PRESENT | IFLAG_RA_PRESENT                                },
	{ LOADSET,  0                                                                  },
	{ LOADSET,  0                                                                  },
	{ SUBCS,    0                                                                  },
	{ SUBCS,    0                                                                  },
	{ SUBCU,    0                                                                  },
	{ SUBCU,    0                                                                  },
	{ SUBC,     0                                                                  },
	{ SUBC,     0                                                                  },
	{ CPBYTE,   IFLAG_RC_PRESENT | IFLAG_RB_PRESENT | IFLAG_RA_PRESENT             },
	{ CPBYTE,   IFLAG_RC_PRESENT | IFLAG_RA_PRESENT                                },
	{ SUBRS,    0                                                                  },
	{ SUBRS,    0                                                                  },
	{ SUBRU,    0                                                                  },
	{ SUBRU,    0                                                                  },
	{ SUBR,     IFLAG_RC_PRESENT | IFLAG_RB_PRESENT | IFLAG_RA_PRESENT             },
	{ SUBR,     IFLAG_RC_PRESENT | IFLAG_RA_PRESENT                                },
	{ LOADM,    IFLAG_RA_PRESENT | IFLAG_RB_PRESENT                                },
	{ LOADM,    IFLAG_RA_PRESENT                                                   },
	{ SUBRCS,   0                                                                  },
	{ SUBRCS,   0                                                                  },
	{ SUBRCU,   0                                                                  },
	{ SUBRCU,   0                                                                  },
	{ SUBRC,    IFLAG_RC_PRESENT | IFLAG_RB_PRESENT | IFLAG_RA_PRESENT             },
	{ SUBRC,    IFLAG_RC_PRESENT | IFLAG_RA_PRESENT                                },
	{ STOREM,   IFLAG_RA_PRESENT | IFLAG_RB_PRESENT                                },
	{ STOREM,   IFLAG_RA_PRESENT                                                   },
	{ CPLT,     IFLAG_RC_PRESENT | IFLAG_RB_PRESENT | IFLAG_RA_PRESENT             },
	{ CPLT,     IFLAG_RC_PRESENT | IFLAG_RA_PRESENT                                },
	{ CPLTU,    IFLAG_RC_PRESENT | IFLAG_RB_PRESENT | IFLAG_RA_PRESENT             },
	{ CPLTU,    IFLAG_RC_PRESENT | IFLAG_RA_PRESENT                                },
	{ CPLE,     IFLAG_RC_PRESENT | IFLAG_RB_PRESENT | IFLAG_RA_PRESENT             },
	{ CPLE,     IFLAG_RC_PRESENT | IFLAG_RA_PRESENT                                },
	{ CPLEU,    IFLAG_RC_PRESENT | IFLAG_RB_PRESENT | IFLAG_RA_PRESENT             },
	{ CPLEU,    IFLAG_RC_PRESENT | IFLAG_RA_PRESENT                                },
	{ CPGT,     IFLAG_RC_PRESENT | IFLAG_RB_PRESENT | IFLAG_RA_PRESENT             },
	{ CPGT,     IFLAG_RC_PRESENT | IFLAG_RA_PRESENT                                },
	{ CPGTU,    IFLAG_RC_PRESENT | IFLAG_RB_PRESENT | IFLAG_RA_PRESENT             },
	{ CPGTU,    IFLAG_RC_PRESENT | IFLAG_RA_PRESENT                                },
	{ CPGE,     IFLAG_RC_PRESENT | IFLAG_RB_PRESENT | IFLAG_RA_PRESENT             },
	{ CPGE,     IFLAG_RC_PRESENT | IFLAG_RA_PRESENT                                },
	{ CPGEU,    IFLAG_RC_PRESENT | IFLAG_RB_PRESENT | IFLAG_RA_PRESENT             },
	{ CPGEU,    IFLAG_RC_PRESENT | IFLAG_RA_PRESENT                                },
	{ ASLT,     IFLAG_RA_PRESENT | IFLAG_RB_PRESENT                                },
	{ ASLT,     IFLAG_RA_PRESENT                                                   },
	{ ASLTU,    IFLAG_RA_PRESENT | IFLAG_RB_PRESENT                                },
	{ ASLTU,    IFLAG_RA_PRESENT                                                   },
	{ ASLE,     IFLAG_RA_PRESENT | IFLAG_RB_PRESENT                                },
	{ ASLE,     IFLAG_RA_PRESENT                                                   },
	{ ASLEU,    IFLAG_RA_PRESENT | IFLAG_RB_PRESENT                                },
	{ ASLEU,    IFLAG_RA_PRESENT                                                   },
	{ ASGT,     IFLAG_RA_PRESENT | IFLAG_RB_PRESENT                                },
	{ ASGT,     IFLAG_RA_PRESENT                                                   },
	{ ASGTU,    IFLAG_RA_PRESENT | IFLAG_RB_PRESENT                                },
	{ ASGTU,    IFLAG_RA_PRESENT                                                   },
	{ ASGE,     IFLAG_RA_PRESENT | IFLAG_RB_PRESENT                                },
	{ ASGE,     IFLAG_RA_PRESENT                                                   },
	{ ASGEU,    IFLAG_RA_PRESENT | IFLAG_RB_PRESENT                                },
	{ ASGEU,    IFLAG_RA_PRESENT                                                   },
	{ CPEQ,     IFLAG_RC_PRESENT | IFLAG_RB_PRESENT | IFLAG_RA_PRESENT             },
	{ CPEQ,     IFLAG_RC_PRESENT | IFLAG_RA_PRESENT                                },
	{ CPNEQ,    IFLAG_RC_PRESENT | IFLAG_RB_PRESENT | IFLAG_RA_PRESENT             },
	{ CPNEQ,    IFLAG_RC_PRESENT | IFLAG_RA_PRESENT                                },
	{ MUL,      IFLAG_RC_PRESENT | IFLAG_RA_PRESENT | IFLAG_RB_PRESENT             },
	{ MUL,      IFLAG_RC_PRESENT | IFLAG_RA_PRESENT                                },
	{ MULL,     IFLAG_RC_PRESENT | IFLAG_RA_PRESENT | IFLAG_RB_PRESENT             },
	{ MULL,     IFLAG_RC_PRESENT | IFLAG_RA_PRESENT                                },
	{ DIV0,     IFLAG_RC_PRESENT | IFLAG_RB_PRESENT                                },
	{ DIV0,     IFLAG_RC_PRESENT                                                   },
	{ DIV,      IFLAG_RC_PRESENT | IFLAG_RA_PRESENT | IFLAG_RB_PRESENT             },
	{ DIV,      IFLAG_RC_PRESENT | IFLAG_RA_PRESENT                                },
	{ DIVL,     IFLAG_RC_PRESENT | IFLAG_RA_PRESENT | IFLAG_RB_PRESENT             },
	{ DIVL,     IFLAG_RC_PRESENT | IFLAG_RA_PRESENT                                },
	{ DIVREM,   IFLAG_RC_PRESENT | IFLAG_RA_PRESENT | IFLAG_RB_PRESENT             },
	{ DIVREM,   IFLAG_RC_PRESENT | IFLAG_RA_PRESENT                                },
	{ ASEQ,     IFLAG_RA_PRESENT | IFLAG_RB_PRESENT                                },
	{ ASEQ,     IFLAG_RA_PRESENT                                                   },
	{ ASNEQ,    IFLAG_RA_PRESENT | IFLAG_RB_PRESENT                                },
	{ ASNEQ,    IFLAG_RA_PRESENT                                                   },
	{ MULU,     IFLAG_RC_PRESENT | IFLAG_RA_PRESENT | IFLAG_RB_PRESENT             },
	{ MULU,     IFLAG_RC_PRESENT | IFLAG_RA_PRESENT                                },
	{ ILLEGAL,  IFLAG_ILLEGAL                                                      },
	{ ILLEGAL,  IFLAG_ILLEGAL                                                      },
	{ INHW,     IFLAG_RC_PRESENT | IFLAG_RB_PRESENT | IFLAG_RA_PRESENT             },
	{ INHW,     IFLAG_RC_PRESENT | IFLAG_RA_PRESENT                                },
	{ EXTRACT,  IFLAG_RC_PRESENT | IFLAG_RB_PRESENT | IFLAG_RA_PRESENT             },
	{ EXTRACT,  IFLAG_RC_PRESENT | IFLAG_RA_PRESENT                                },
	{ EXHW,     IFLAG_RC_PRESENT | IFLAG_RB_PRESENT | IFLAG_RA_PRESENT             },
	{ EXHW,     IFLAG_RC_PRESENT | IFLAG_RA_PRESENT                                },
	{ EXHWS,    IFLAG_RC_PRESENT | IFLAG_RA_PRESENT                                },
	{ ILLEGAL,  IFLAG_ILLEGAL                                                      },
	{ SLL,      IFLAG_RC_PRESENT | IFLAG_RB_PRESENT | IFLAG_RA_PRESENT             },
	{ SLL,      IFLAG_RC_PRESENT | IFLAG_RA_PRESENT                                },
	{ SRL,      IFLAG_RC_PRESENT | IFLAG_RB_PRESENT | IFLAG_RA_PRESENT             },
	{ SRL,      IFLAG_RC_PRESENT | IFLAG_RA_PRESENT                                },
	{ ILLEGAL,  IFLAG_ILLEGAL                                                      },
	{ ILLEGAL,  IFLAG_ILLEGAL                                                      },
	{ SRA,      IFLAG_RC_PRESENT | IFLAG_RB_PRESENT | IFLAG_RA_PRESENT             },
	{ SRA,      IFLAG_RC_PRESENT | IFLAG_RA_PRESENT                                },
	{ IRET,     IFLAG_SUPERVISOR_ONLY                                              },
	{ HALT,     IFLAG_SUPERVISOR_ONLY                                              },
	{ ILLEGAL,  IFLAG_ILLEGAL                                                      },
	{ ILLEGAL,  IFLAG_ILLEGAL                                                      },
	{ IRETINV,  IFLAG_SUPERVISOR_ONLY                                              },
	{ ILLEGAL,  IFLAG_ILLEGAL                                                      },
	{ ILLEGAL,  IFLAG_ILLEGAL                                                      },
	{ ILLEGAL,  IFLAG_ILLEGAL                                                      },
	{ AND,      IFLAG_RC_PRESENT | IFLAG_RB_PRESENT | IFLAG_RA_PRESENT             },
	{ AND,      IFLAG_RC_PRESENT | IFLAG_RA_PRESENT                                },
	{ OR,       IFLAG_RC_PRESENT | IFLAG_RB_PRESENT | IFLAG_RA_PRESENT             },
	{ OR,       IFLAG_RC_PRESENT | IFLAG_RA_PRESENT                                },
	{ XOR,      IFLAG_RC_PRESENT | IFLAG_RB_PRESENT | IFLAG_RA_PRESENT             },
	{ XOR,      IFLAG_RC_PRESENT | IFLAG_RA_PRESENT                                },
	{ XNOR,     IFLAG_RC_PRESENT | IFLAG_RB_PRESENT | IFLAG_RA_PRESENT             },
	{ XNOR,     IFLAG_RC_PRESENT | IFLAG_RA_PRESENT                                },
	{ NOR,      IFLAG_RC_PRESENT | IFLAG_RB_PRESENT | IFLAG_RA_PRESENT             },
	{ NOR,      IFLAG_RC_PRESENT | IFLAG_RA_PRESENT                                },
	{ NAND,     IFLAG_RC_PRESENT | IFLAG_RB_PRESENT | IFLAG_RA_PRESENT             },
	{ NAND,     IFLAG_RC_PRESENT | IFLAG_RA_PRESENT                                },
	{ ANDN,     IFLAG_RC_PRESENT | IFLAG_RB_PRESENT | IFLAG_RA_PRESENT             },
	{ ANDN,     IFLAG_RC_PRESENT | IFLAG_RA_PRESENT                                },
	{ SETIP,    IFLAG_RA_PRESENT | IFLAG_RB_PRESENT | IFLAG_RC_PRESENT             },
	{ INV,      IFLAG_SUPERVISOR_ONLY                                              },
	{ JMP,      0                                                                  },
	{ JMP,      0                                                                  },
	{ ILLEGAL,  IFLAG_ILLEGAL                                                      },
	{ ILLEGAL,  IFLAG_ILLEGAL                                                      },
	{ JMPF,     IFLAG_RA_PRESENT                                                   },
	{ JMPF,     IFLAG_RA_PRESENT                                                   },
	{ ILLEGAL,  IFLAG_ILLEGAL                                                      },
	{ ILLEGAL,  IFLAG_ILLEGAL                                                      },
	{ CALL,     IFLAG_RA_PRESENT                                                   },
	{ CALL,     IFLAG_RA_PRESENT                                                   },
	{ ILLEGAL,  IFLAG_ILLEGAL                                                      },
	{ ILLEGAL,  IFLAG_ILLEGAL                                                      },
	{ JMPT,     IFLAG_RA_PRESENT                                                   },
	{ JMPT,     IFLAG_RA_PRESENT                                                   },
	{ ILLEGAL,  IFLAG_ILLEGAL                                                      },
	{ ILLEGAL,  IFLAG_ILLEGAL                                                      },
	{ ILLEGAL,  IFLAG_ILLEGAL                                                      },
	{ ILLEGAL,  IFLAG_ILLEGAL                                                      },
	{ ILLEGAL,  IFLAG_ILLEGAL                                                      },
	{ ILLEGAL,  IFLAG_ILLEGAL                                                      },
	{ JMPFDEC,  IFLAG_RA_PRESENT                                                   },
	{ JMPFDEC,  IFLAG_RA_PRESENT                                                   },
	{ MFTLB,    IFLAG_SUPERVISOR_ONLY | IFLAG_RC_PRESENT | IFLAG_RA_PRESENT        },
	{ ILLEGAL,  IFLAG_ILLEGAL                                                      },
	{ ILLEGAL,  IFLAG_ILLEGAL                                                      },
	{ ILLEGAL,  IFLAG_ILLEGAL                                                      },
	{ ILLEGAL,  IFLAG_ILLEGAL                                                      },
	{ ILLEGAL,  IFLAG_ILLEGAL                                                      },
	{ ILLEGAL,  IFLAG_ILLEGAL                                                      },
	{ ILLEGAL,  IFLAG_ILLEGAL                                                      },
	{ MTTLB,    IFLAG_SUPERVISOR_ONLY | IFLAG_RA_PRESENT | IFLAG_RB_PRESENT        },
	{ ILLEGAL,  IFLAG_ILLEGAL                                                      },
	{ JMPI,     IFLAG_RB_PRESENT                                                   },
	{ ILLEGAL,  IFLAG_ILLEGAL                                                      },
	{ ILLEGAL,  IFLAG_ILLEGAL                                                      },
	{ ILLEGAL,  IFLAG_ILLEGAL                                                      },
	{ JMPFI,    IFLAG_RA_PRESENT | IFLAG_RB_PRESENT                                },
	{ ILLEGAL,  IFLAG_ILLEGAL                                                      },
	{ MFSR,     IFLAG_RC_PRESENT                                                   },
	{ ILLEGAL,  IFLAG_ILLEGAL                                                      },
	{ CALLI,    IFLAG_RA_PRESENT | IFLAG_RB_PRESENT                                },
	{ ILLEGAL,  IFLAG_ILLEGAL                                                      },
	{ ILLEGAL,  IFLAG_ILLEGAL                                                      },
	{ ILLEGAL,  IFLAG_ILLEGAL                                                      },
	{ JMPTI,    IFLAG_RA_PRESENT | IFLAG_RB_PRESENT                                },
	{ ILLEGAL,  IFLAG_ILLEGAL                                                      },
	{ MTSR,     IFLAG_RB_PRESENT                                                   },
	{ ILLEGAL,  IFLAG_ILLEGAL                                                      },
	{ ILLEGAL,  IFLAG_ILLEGAL                                                      },
	{ ILLEGAL,  IFLAG_ILLEGAL                                                      },
	{ ILLEGAL,  IFLAG_ILLEGAL                                                      },
	{ ILLEGAL,  IFLAG_ILLEGAL                                                      },
	{ ILLEGAL,  IFLAG_ILLEGAL                                                      },
	{ ILLEGAL,  IFLAG_ILLEGAL                                                      },
	{ ILLEGAL,  IFLAG_ILLEGAL                                                      },
	{ EMULATE,  0                                                                  },
	{ ILLEGAL,  IFLAG_ILLEGAL                                                      },
	{ ILLEGAL,  IFLAG_ILLEGAL                                                      },
	{ ILLEGAL,  IFLAG_ILLEGAL                                                      },
	{ ILLEGAL,  IFLAG_ILLEGAL                                                      },
	{ ILLEGAL,  IFLAG_ILLEGAL                                                      },
	{ ILLEGAL,  IFLAG_ILLEGAL                                                      },
	{ MULTM,    0                                                                  },
	{ MULTMU,   0                                                                  },
	{ MULTIPLY, 0                                                                  },
	{ DIVIDE,   0                                                                  },
	{ MULTIPLU, 0                                                                  },
	{ DIVIDU,   0                                                                  },
	{ CONVERT,  0                                                                  },
	{ SQRT,     0                                                                  },
	{ CLASS,    0                                                                  },
	{ ILLEGAL,  IFLAG_ILLEGAL                                                      },
	{ ILLEGAL,  IFLAG_ILLEGAL                                                      },
	{ ILLEGAL,  IFLAG_ILLEGAL                                                      },
	// FEQ
	// DEQ
	// TODO! etc
};
