/*===========================================================================
    ASTAT -- ALU/MAC status register
===========================================================================*/

/* flag definitions */
#define SSFLAG			0x80
#define MVFLAG			0x40
#define QFLAG			0x20
#define SFLAG			0x10
#define CFLAG			0x08
#define VFLAG			0x04
#define NFLAG			0x02
#define ZFLAG			0x01

/* extracts flags */
#define GET_SS			(adsp->astat & SSFLAG)
#define GET_MV			(adsp->astat & MVFLAG)
#define GET_Q			(adsp->astat &  QFLAG)
#define GET_S			(adsp->astat &  SFLAG)
#define GET_C			(adsp->astat &  CFLAG)
#define GET_V			(adsp->astat &  VFLAG)
#define GET_N			(adsp->astat &  NFLAG)
#define GET_Z			(adsp->astat &  ZFLAG)

/* clears flags */
#define CLR_SS			(adsp->astat &= ~SSFLAG)
#define CLR_MV			(adsp->astat &= ~MVFLAG)
#define CLR_Q			(adsp->astat &=  ~QFLAG)
#define CLR_S			(adsp->astat &=  ~SFLAG)
#define CLR_C			(adsp->astat &=  ~CFLAG)
#define CLR_V			(adsp->astat &=  ~VFLAG)
#define CLR_N			(adsp->astat &=  ~NFLAG)
#define CLR_Z			(adsp->astat &=  ~ZFLAG)

/* sets flags */
#define SET_SS			(adsp->astat |= SSFLAG)
#define SET_MV			(adsp->astat |= MVFLAG)
#define SET_Q			(adsp->astat |=  QFLAG)
#define SET_S			(adsp->astat |=  SFLAG)
#define SET_C			(adsp->astat |=  CFLAG)
#define SET_V			(adsp->astat |=  VFLAG)
#define SET_Z			(adsp->astat |=  ZFLAG)
#define SET_N			(adsp->astat |=  NFLAG)

/* flag clearing; must be done before setting */
#define CLR_FLAGS		(adsp->astat &= adsp->astat_clear)

/* compute flags */
#define CALC_Z(r)		(adsp->astat |= ((r & 0xffff) == 0))
#define CALC_N(r)		(adsp->astat |= (r >> 14) & 0x02)
#define CALC_V(s,d,r)	(adsp->astat |= ((s ^ d ^ r ^ (r >> 1)) >> 13) & 0x04)
#define CALC_C(r)		(adsp->astat |= (r >> 13) & 0x08)
#define CALC_C_SUB(r)	(adsp->astat |= (~r >> 13) & 0x08)
#define CALC_NZ(r) 		CLR_FLAGS; CALC_N(r); CALC_Z(r)
#define CALC_NZV(s,d,r) CLR_FLAGS; CALC_N(r); CALC_Z(r); CALC_V(s,d,r)
#define CALC_NZVC(s,d,r) CLR_FLAGS; CALC_N(r); CALC_Z(r); CALC_V(s,d,r); CALC_C(r)
#define CALC_NZVC_SUB(s,d,r) CLR_FLAGS; CALC_N(r); CALC_Z(r); CALC_V(s,d,r); CALC_C_SUB(r)

/* ADSP-218x constants */
static const INT32 constants[] =
{
	0x0001, 0xfffe, 0x0002, 0xfffd, 0x0004, 0xfffb, 0x0008, 0xfff7,
	0x0010, 0xffef, 0x0020, 0xffdf, 0x0040, 0xffbf, 0x0080, 0xff7f,
	0x0100, 0xfeff, 0x0200, 0xfdff, 0x0400, 0xfbff, 0x0800, 0xf7ff,
	0x1000, 0xefff, 0x2000, 0xdfff, 0x4000, 0xbfff, 0x8000, 0x7fff
};



/*===========================================================================
    MSTAT -- ALU/MAC control register
===========================================================================*/

/* flag definitions */
#define MSTAT_BANK		0x01			/* register bank select */
#define MSTAT_REVERSE	0x02			/* bit-reverse addressing enable (DAG1) */
#define MSTAT_STICKYV	0x04			/* sticky ALU overflow enable */
#define MSTAT_SATURATE	0x08			/* AR saturation mode enable */
#define MSTAT_INTEGER	0x10			/* MAC result placement; 0=fractional, 1=integer */
#define MSTAT_TIMER		0x20			/* timer enable */
#define MSTAT_GOMODE	0x40			/* go mode enable */

/* you must call this in order to change MSTAT */
INLINE void update_mstat(adsp2100_state *adsp)
{
	if ((adsp->mstat ^ adsp->mstat_prev) & MSTAT_BANK)
	{
		ADSPCORE temp = adsp->core;
		adsp->core = adsp->alt;
		adsp->alt = temp;
	}
	if ((adsp->mstat ^ adsp->mstat_prev) & MSTAT_TIMER)
		if (adsp->timer_fired != NULL)
			(*adsp->timer_fired)(adsp->device, (adsp->mstat & MSTAT_TIMER) != 0);
	if (adsp->mstat & MSTAT_STICKYV)
		adsp->astat_clear = ~(CFLAG | NFLAG | ZFLAG);
	else
		adsp->astat_clear = ~(CFLAG | VFLAG | NFLAG | ZFLAG);
	adsp->mstat_prev = adsp->mstat;
}


/*===========================================================================
    SSTAT -- stack status register
===========================================================================*/

/* flag definitions */
#define PC_EMPTY		0x01			/* PC stack empty */
#define PC_OVER			0x02			/* PC stack overflow */
#define COUNT_EMPTY		0x04			/* count stack empty */
#define COUNT_OVER		0x08			/* count stack overflow */
#define STATUS_EMPTY	0x10			/* status stack empty */
#define STATUS_OVER		0x20			/* status stack overflow */
#define LOOP_EMPTY		0x40			/* loop stack empty */
#define LOOP_OVER		0x80			/* loop stack overflow */



/*===========================================================================
    PC stack handlers
===========================================================================*/

INLINE UINT32 pc_stack_top(adsp2100_state *adsp)
{
	if (adsp->pc_sp > 0)
		return adsp->pc_stack[adsp->pc_sp - 1];
	else
		return adsp->pc_stack[0];
}

INLINE void set_pc_stack_top(adsp2100_state *adsp, UINT32 top)
{
	if (adsp->pc_sp > 0)
		adsp->pc_stack[adsp->pc_sp - 1] = top;
	else
		adsp->pc_stack[0] = top;
}

INLINE void pc_stack_push(adsp2100_state *adsp)
{
	if (adsp->pc_sp < PC_STACK_DEPTH)
	{
		adsp->pc_stack[adsp->pc_sp] = adsp->pc;
		adsp->pc_sp++;
		adsp->sstat &= ~PC_EMPTY;
	}
	else
		adsp->sstat |= PC_OVER;
}

INLINE void pc_stack_push_val(adsp2100_state *adsp, UINT32 val)
{
	if (adsp->pc_sp < PC_STACK_DEPTH)
	{
		adsp->pc_stack[adsp->pc_sp] = val;
		adsp->pc_sp++;
		adsp->sstat &= ~PC_EMPTY;
	}
	else
		adsp->sstat |= PC_OVER;
}

INLINE void pc_stack_pop(adsp2100_state *adsp)
{
	if (adsp->pc_sp > 0)
	{
		adsp->pc_sp--;
		if (adsp->pc_sp == 0)
			adsp->sstat |= PC_EMPTY;
	}
	adsp->pc = adsp->pc_stack[adsp->pc_sp];
}

INLINE UINT32 pc_stack_pop_val(adsp2100_state *adsp)
{
	if (adsp->pc_sp > 0)
	{
		adsp->pc_sp--;
		if (adsp->pc_sp == 0)
			adsp->sstat |= PC_EMPTY;
	}
	return adsp->pc_stack[adsp->pc_sp];
}


/*===========================================================================
    CNTR stack handlers
===========================================================================*/

INLINE UINT32 cntr_stack_top(adsp2100_state *adsp)
{
	if (adsp->cntr_sp > 0)
		return adsp->cntr_stack[adsp->cntr_sp - 1];
	else
		return adsp->cntr_stack[0];
}

INLINE void cntr_stack_push(adsp2100_state *adsp)
{
	if (adsp->cntr_sp < CNTR_STACK_DEPTH)
	{
		adsp->cntr_stack[adsp->cntr_sp] = adsp->cntr;
		adsp->cntr_sp++;
		adsp->sstat &= ~COUNT_EMPTY;
	}
	else
		adsp->sstat |= COUNT_OVER;
}

INLINE void cntr_stack_pop(adsp2100_state *adsp)
{
	if (adsp->cntr_sp > 0)
	{
		adsp->cntr_sp--;
		if (adsp->cntr_sp == 0)
			adsp->sstat |= COUNT_EMPTY;
	}
	adsp->cntr = adsp->cntr_stack[adsp->cntr_sp];
}


/*===========================================================================
    LOOP stack handlers
===========================================================================*/

INLINE UINT32 loop_stack_top(adsp2100_state *adsp)
{
	if (adsp->loop_sp > 0)
		return adsp->loop_stack[adsp->loop_sp - 1];
	else
		return adsp->loop_stack[0];
}

INLINE void loop_stack_push(adsp2100_state *adsp, UINT32 value)
{
	if (adsp->loop_sp < LOOP_STACK_DEPTH)
	{
		adsp->loop_stack[adsp->loop_sp] = value;
		adsp->loop_sp++;
		adsp->loop = value >> 4;
		adsp->loop_condition = value & 15;
		adsp->sstat &= ~LOOP_EMPTY;
	}
	else
		adsp->sstat |= LOOP_OVER;
}

INLINE void loop_stack_pop(adsp2100_state *adsp)
{
	if (adsp->loop_sp > 0)
	{
		adsp->loop_sp--;
		if (adsp->loop_sp == 0)
		{
			adsp->loop = 0xffff;
			adsp->loop_condition = 0;
			adsp->sstat |= LOOP_EMPTY;
		}
		else
		{
			adsp->loop = adsp->loop_stack[adsp->loop_sp -1] >> 4;
			adsp->loop_condition = adsp->loop_stack[adsp->loop_sp - 1] & 15;
		}
	}
}


/*===========================================================================
    STAT stack handlers
===========================================================================*/

INLINE void stat_stack_push(adsp2100_state *adsp)
{
	if (adsp->stat_sp < STAT_STACK_DEPTH)
	{
		adsp->stat_stack[adsp->stat_sp][0] = adsp->mstat;
		adsp->stat_stack[adsp->stat_sp][1] = adsp->imask;
		adsp->stat_stack[adsp->stat_sp][2] = adsp->astat;
		adsp->stat_sp++;
		adsp->sstat &= ~STATUS_EMPTY;
	}
	else
		adsp->sstat |= STATUS_OVER;
}

INLINE void stat_stack_pop(adsp2100_state *adsp)
{
	if (adsp->stat_sp > 0)
	{
		adsp->stat_sp--;
		if (adsp->stat_sp == 0)
			adsp->sstat |= STATUS_EMPTY;
	}
	adsp->mstat = adsp->stat_stack[adsp->stat_sp][0];
	update_mstat(adsp);
	adsp->imask = adsp->stat_stack[adsp->stat_sp][1];
	adsp->astat = adsp->stat_stack[adsp->stat_sp][2];
 	check_irqs(adsp);
}



/*===========================================================================
    condition code checking
===========================================================================*/

INLINE int CONDITION(adsp2100_state *adsp, int c)
{
	if (c != 14)
		return condition_table[((c) << 8) | adsp->astat];
	else if ((INT32)--adsp->cntr > 0)
		return 1;
	else
	{
		cntr_stack_pop(adsp);
		return 0;
	}
}



/*===========================================================================
    register writing
===========================================================================*/

INLINE void update_i(adsp2100_state *adsp, int which)
{
	adsp->base[which] = adsp->i[which] & adsp->lmask[which];
}

INLINE void update_l(adsp2100_state *adsp, int which)
{
	adsp->lmask[which] = mask_table[adsp->l[which] & 0x3fff];
	adsp->base[which] = adsp->i[which] & adsp->lmask[which];
}

static void wr_inval(adsp2100_state *adsp, INT32 val) { logerror( "ADSP %04x: Writing to an invalid register!\n", adsp->ppc ); }
static void wr_ax0(adsp2100_state *adsp, INT32 val)   { adsp->core.ax0.s = val; }
static void wr_ax1(adsp2100_state *adsp, INT32 val)   { adsp->core.ax1.s = val; }
static void wr_mx0(adsp2100_state *adsp, INT32 val)   { adsp->core.mx0.s = val; }
static void wr_mx1(adsp2100_state *adsp, INT32 val)   { adsp->core.mx1.s = val; }
static void wr_ay0(adsp2100_state *adsp, INT32 val)   { adsp->core.ay0.s = val; }
static void wr_ay1(adsp2100_state *adsp, INT32 val)   { adsp->core.ay1.s = val; }
static void wr_my0(adsp2100_state *adsp, INT32 val)   { adsp->core.my0.s = val; }
static void wr_my1(adsp2100_state *adsp, INT32 val)   { adsp->core.my1.s = val; }
static void wr_si(adsp2100_state *adsp, INT32 val)    { adsp->core.si.s = val; }
static void wr_se(adsp2100_state *adsp, INT32 val)    { adsp->core.se.s = (INT8)val; }
static void wr_ar(adsp2100_state *adsp, INT32 val)    { adsp->core.ar.s = val; }
static void wr_mr0(adsp2100_state *adsp, INT32 val)   { adsp->core.mr.mrx.mr0.s = val; }
static void wr_mr1(adsp2100_state *adsp, INT32 val)   { adsp->core.mr.mrx.mr1.s = val; adsp->core.mr.mrx.mr2.s = (INT16)val >> 15; }
static void wr_mr2(adsp2100_state *adsp, INT32 val)   { adsp->core.mr.mrx.mr2.s = (INT8)val; }
static void wr_sr0(adsp2100_state *adsp, INT32 val)   { adsp->core.sr.srx.sr0.s = val; }
static void wr_sr1(adsp2100_state *adsp, INT32 val)   { adsp->core.sr.srx.sr1.s = val; }
static void wr_i0(adsp2100_state *adsp, INT32 val)    { adsp->i[0] = val & 0x3fff; update_i(adsp, 0); }
static void wr_i1(adsp2100_state *adsp, INT32 val)    { adsp->i[1] = val & 0x3fff; update_i(adsp, 1); }
static void wr_i2(adsp2100_state *adsp, INT32 val)    { adsp->i[2] = val & 0x3fff; update_i(adsp, 2); }
static void wr_i3(adsp2100_state *adsp, INT32 val)    { adsp->i[3] = val & 0x3fff; update_i(adsp, 3); }
static void wr_i4(adsp2100_state *adsp, INT32 val)    { adsp->i[4] = val & 0x3fff; update_i(adsp, 4); }
static void wr_i5(adsp2100_state *adsp, INT32 val)    { adsp->i[5] = val & 0x3fff; update_i(adsp, 5); }
static void wr_i6(adsp2100_state *adsp, INT32 val)    { adsp->i[6] = val & 0x3fff; update_i(adsp, 6); }
static void wr_i7(adsp2100_state *adsp, INT32 val)    { adsp->i[7] = val & 0x3fff; update_i(adsp, 7); }
static void wr_m0(adsp2100_state *adsp, INT32 val)    { adsp->m[0] = (INT32)(val << 18) >> 18; }
static void wr_m1(adsp2100_state *adsp, INT32 val)    { adsp->m[1] = (INT32)(val << 18) >> 18; }
static void wr_m2(adsp2100_state *adsp, INT32 val)    { adsp->m[2] = (INT32)(val << 18) >> 18; }
static void wr_m3(adsp2100_state *adsp, INT32 val)    { adsp->m[3] = (INT32)(val << 18) >> 18; }
static void wr_m4(adsp2100_state *adsp, INT32 val)    { adsp->m[4] = (INT32)(val << 18) >> 18; }
static void wr_m5(adsp2100_state *adsp, INT32 val)    { adsp->m[5] = (INT32)(val << 18) >> 18; }
static void wr_m6(adsp2100_state *adsp, INT32 val)    { adsp->m[6] = (INT32)(val << 18) >> 18; }
static void wr_m7(adsp2100_state *adsp, INT32 val)    { adsp->m[7] = (INT32)(val << 18) >> 18; }
static void wr_l0(adsp2100_state *adsp, INT32 val)    { adsp->l[0] = val & 0x3fff; update_l(adsp, 0); }
static void wr_l1(adsp2100_state *adsp, INT32 val)    { adsp->l[1] = val & 0x3fff; update_l(adsp, 1); }
static void wr_l2(adsp2100_state *adsp, INT32 val)    { adsp->l[2] = val & 0x3fff; update_l(adsp, 2); }
static void wr_l3(adsp2100_state *adsp, INT32 val)    { adsp->l[3] = val & 0x3fff; update_l(adsp, 3); }
static void wr_l4(adsp2100_state *adsp, INT32 val)    { adsp->l[4] = val & 0x3fff; update_l(adsp, 4); }
static void wr_l5(adsp2100_state *adsp, INT32 val)    { adsp->l[5] = val & 0x3fff; update_l(adsp, 5); }
static void wr_l6(adsp2100_state *adsp, INT32 val)    { adsp->l[6] = val & 0x3fff; update_l(adsp, 6); }
static void wr_l7(adsp2100_state *adsp, INT32 val)    { adsp->l[7] = val & 0x3fff; update_l(adsp, 7); }
static void wr_astat(adsp2100_state *adsp, INT32 val) { adsp->astat = val & 0x00ff; }
static void wr_mstat(adsp2100_state *adsp, INT32 val) { adsp->mstat = val & adsp->mstat_mask; update_mstat(adsp); }
static void wr_imask(adsp2100_state *adsp, INT32 val) { adsp->imask = val & adsp->imask_mask; check_irqs(adsp); }
static void wr_icntl(adsp2100_state *adsp, INT32 val) { adsp->icntl = val & 0x001f; check_irqs(adsp); }
static void wr_cntr(adsp2100_state *adsp, INT32 val)  { cntr_stack_push(adsp); adsp->cntr = val & 0x3fff; }
static void wr_sb(adsp2100_state *adsp, INT32 val)    { adsp->core.sb.s = (INT32)(val << 27) >> 27; }
static void wr_px(adsp2100_state *adsp, INT32 val)    { adsp->px = val; }
static void wr_ifc(adsp2100_state *adsp, INT32 val)
{
	adsp->ifc = val;
	if (adsp->chip_type >= CHIP_TYPE_ADSP2181)
	{
		/* clear timer */
		if (val & 0x0002) adsp->irq_latch[ADSP2181_IRQ0] = 0;
		if (val & 0x0004) adsp->irq_latch[ADSP2181_IRQ1] = 0;
		/* clear BDMA */
		if (val & 0x0010) adsp->irq_latch[ADSP2181_IRQE] = 0;
		if (val & 0x0020) adsp->irq_latch[ADSP2181_SPORT0_RX] = 0;
		if (val & 0x0040) adsp->irq_latch[ADSP2181_SPORT0_TX] = 0;
		if (val & 0x0080) adsp->irq_latch[ADSP2181_IRQ2] = 0;
		/* force timer */
		if (val & 0x0200) adsp->irq_latch[ADSP2181_IRQ0] = 1;
		if (val & 0x0400) adsp->irq_latch[ADSP2181_IRQ1] = 1;
		/* force BDMA */
		if (val & 0x1000) adsp->irq_latch[ADSP2181_IRQE] = 1;
		if (val & 0x2000) adsp->irq_latch[ADSP2181_SPORT0_RX] = 1;
		if (val & 0x4000) adsp->irq_latch[ADSP2181_SPORT0_TX] = 1;
		if (val & 0x8000) adsp->irq_latch[ADSP2181_IRQ2] = 1;
	}
	else
	{
		/* clear timer */
		if (val & 0x002) adsp->irq_latch[ADSP2101_IRQ0] = 0;
		if (val & 0x004) adsp->irq_latch[ADSP2101_IRQ1] = 0;
		if (val & 0x008) adsp->irq_latch[ADSP2101_SPORT0_RX] = 0;
		if (val & 0x010) adsp->irq_latch[ADSP2101_SPORT0_TX] = 0;
		if (val & 0x020) adsp->irq_latch[ADSP2101_IRQ2] = 0;
		/* set timer */
		if (val & 0x080) adsp->irq_latch[ADSP2101_IRQ0] = 1;
		if (val & 0x100) adsp->irq_latch[ADSP2101_IRQ1] = 1;
		if (val & 0x200) adsp->irq_latch[ADSP2101_SPORT0_RX] = 1;
		if (val & 0x400) adsp->irq_latch[ADSP2101_SPORT0_TX] = 1;
		if (val & 0x800) adsp->irq_latch[ADSP2101_IRQ2] = 1;
	}
	check_irqs(adsp);
}
static void wr_tx0(adsp2100_state *adsp, INT32 val)	{ if (adsp->sport_tx_callback) (*adsp->sport_tx_callback)(adsp->device, 0, val); }
static void wr_tx1(adsp2100_state *adsp, INT32 val)	{ if (adsp->sport_tx_callback) (*adsp->sport_tx_callback)(adsp->device, 1, val); }
static void wr_owrctr(adsp2100_state *adsp, INT32 val) { adsp->cntr = val & 0x3fff; }
static void wr_topstack(adsp2100_state *adsp, INT32 val) { pc_stack_push_val(adsp, val & 0x3fff); }

#define WRITE_REG(adsp,grp,reg,val) ((*wr_reg[grp][reg])(adsp,val))

static void (*const wr_reg[4][16])(adsp2100_state*, INT32) =
{
	{
		wr_ax0, wr_ax1, wr_mx0, wr_mx1, wr_ay0, wr_ay1, wr_my0, wr_my1,
		wr_si, wr_se, wr_ar, wr_mr0, wr_mr1, wr_mr2, wr_sr0, wr_sr1
	},
	{
		wr_i0, wr_i1, wr_i2, wr_i3, wr_m0, wr_m1, wr_m2, wr_m3,
		wr_l0, wr_l1, wr_l2, wr_l3, wr_inval, wr_inval, wr_inval, wr_inval
	},
	{
		wr_i4, wr_i5, wr_i6, wr_i7, wr_m4, wr_m5, wr_m6, wr_m7,
		wr_l4, wr_l5, wr_l6, wr_l7, wr_inval, wr_inval, wr_inval, wr_inval
	},
	{
		wr_astat, wr_mstat, wr_inval, wr_imask, wr_icntl, wr_cntr, wr_sb, wr_px,
		wr_inval, wr_tx0, wr_inval, wr_tx1, wr_ifc, wr_owrctr, wr_inval, wr_topstack
	}
};



/*===========================================================================
    register reading
===========================================================================*/

static INT32 rd_inval(adsp2100_state *adsp) { logerror( "ADSP %04x: Writing to an invalid register!\n", adsp->ppc ); return 0; }
static INT32 rd_ax0(adsp2100_state *adsp)   { return adsp->core.ax0.s; }
static INT32 rd_ax1(adsp2100_state *adsp)   { return adsp->core.ax1.s; }
static INT32 rd_mx0(adsp2100_state *adsp)   { return adsp->core.mx0.s; }
static INT32 rd_mx1(adsp2100_state *adsp)   { return adsp->core.mx1.s; }
static INT32 rd_ay0(adsp2100_state *adsp)   { return adsp->core.ay0.s; }
static INT32 rd_ay1(adsp2100_state *adsp)   { return adsp->core.ay1.s; }
static INT32 rd_my0(adsp2100_state *adsp)   { return adsp->core.my0.s; }
static INT32 rd_my1(adsp2100_state *adsp)   { return adsp->core.my1.s; }
static INT32 rd_si(adsp2100_state *adsp)    { return adsp->core.si.s; }
static INT32 rd_se(adsp2100_state *adsp)    { return adsp->core.se.s; }
static INT32 rd_ar(adsp2100_state *adsp)    { return adsp->core.ar.s; }
static INT32 rd_mr0(adsp2100_state *adsp)   { return adsp->core.mr.mrx.mr0.s; }
static INT32 rd_mr1(adsp2100_state *adsp)   { return adsp->core.mr.mrx.mr1.s; }
static INT32 rd_mr2(adsp2100_state *adsp)   { return adsp->core.mr.mrx.mr2.s; }
static INT32 rd_sr0(adsp2100_state *adsp)   { return adsp->core.sr.srx.sr0.s; }
static INT32 rd_sr1(adsp2100_state *adsp)   { return adsp->core.sr.srx.sr1.s; }
static INT32 rd_i0(adsp2100_state *adsp)    { return adsp->i[0]; }
static INT32 rd_i1(adsp2100_state *adsp)    { return adsp->i[1]; }
static INT32 rd_i2(adsp2100_state *adsp)    { return adsp->i[2]; }
static INT32 rd_i3(adsp2100_state *adsp)    { return adsp->i[3]; }
static INT32 rd_i4(adsp2100_state *adsp)    { return adsp->i[4]; }
static INT32 rd_i5(adsp2100_state *adsp)    { return adsp->i[5]; }
static INT32 rd_i6(adsp2100_state *adsp)    { return adsp->i[6]; }
static INT32 rd_i7(adsp2100_state *adsp)    { return adsp->i[7]; }
static INT32 rd_m0(adsp2100_state *adsp)    { return adsp->m[0]; }
static INT32 rd_m1(adsp2100_state *adsp)    { return adsp->m[1]; }
static INT32 rd_m2(adsp2100_state *adsp)    { return adsp->m[2]; }
static INT32 rd_m3(adsp2100_state *adsp)    { return adsp->m[3]; }
static INT32 rd_m4(adsp2100_state *adsp)    { return adsp->m[4]; }
static INT32 rd_m5(adsp2100_state *adsp)    { return adsp->m[5]; }
static INT32 rd_m6(adsp2100_state *adsp)    { return adsp->m[6]; }
static INT32 rd_m7(adsp2100_state *adsp)    { return adsp->m[7]; }
static INT32 rd_l0(adsp2100_state *adsp)    { return adsp->l[0]; }
static INT32 rd_l1(adsp2100_state *adsp)    { return adsp->l[1]; }
static INT32 rd_l2(adsp2100_state *adsp)    { return adsp->l[2]; }
static INT32 rd_l3(adsp2100_state *adsp)    { return adsp->l[3]; }
static INT32 rd_l4(adsp2100_state *adsp)    { return adsp->l[4]; }
static INT32 rd_l5(adsp2100_state *adsp)    { return adsp->l[5]; }
static INT32 rd_l6(adsp2100_state *adsp)    { return adsp->l[6]; }
static INT32 rd_l7(adsp2100_state *adsp)    { return adsp->l[7]; }
static INT32 rd_astat(adsp2100_state *adsp) { return adsp->astat; }
static INT32 rd_mstat(adsp2100_state *adsp) { return adsp->mstat; }
static INT32 rd_sstat(adsp2100_state *adsp) { return adsp->sstat; }
static INT32 rd_imask(adsp2100_state *adsp) { return adsp->imask; }
static INT32 rd_icntl(adsp2100_state *adsp) { return adsp->icntl; }
static INT32 rd_cntr(adsp2100_state *adsp)  { return adsp->cntr; }
static INT32 rd_sb(adsp2100_state *adsp)    { return adsp->core.sb.s; }
static INT32 rd_px(adsp2100_state *adsp)    { return adsp->px; }
static INT32 rd_rx0(adsp2100_state *adsp)	{ if (adsp->sport_rx_callback) return (*adsp->sport_rx_callback)(adsp->device, 0); else return 0; }
static INT32 rd_rx1(adsp2100_state *adsp)	{ if (adsp->sport_rx_callback) return (*adsp->sport_rx_callback)(adsp->device, 1); else return 0; }
static INT32 rd_stacktop(adsp2100_state *adsp)	{ return pc_stack_pop_val(adsp); }

#define READ_REG(adsp,grp,reg) ((*rd_reg[grp][reg])(adsp))

static INT32 (*const rd_reg[4][16])(adsp2100_state *adsp) =
{
	{
		rd_ax0, rd_ax1, rd_mx0, rd_mx1, rd_ay0, rd_ay1, rd_my0, rd_my1,
		rd_si, rd_se, rd_ar, rd_mr0, rd_mr1, rd_mr2, rd_sr0, rd_sr1
	},
	{
		rd_i0, rd_i1, rd_i2, rd_i3, rd_m0, rd_m1, rd_m2, rd_m3,
		rd_l0, rd_l1, rd_l2, rd_l3, rd_inval, rd_inval, rd_inval, rd_inval
	},
	{
		rd_i4, rd_i5, rd_i6, rd_i7, rd_m4, rd_m5, rd_m6, rd_m7,
		rd_l4, rd_l5, rd_l6, rd_l7, rd_inval, rd_inval, rd_inval, rd_inval
	},
	{
		rd_astat, rd_mstat, rd_sstat, rd_imask, rd_icntl, rd_cntr, rd_sb, rd_px,
		rd_rx0, rd_inval, rd_rx1, rd_inval, rd_inval, rd_inval, rd_inval, rd_stacktop
	}
};



/*===========================================================================
    Modulus addressing logic
===========================================================================*/

INLINE void modify_address(adsp2100_state *adsp, UINT32 ireg, UINT32 mreg)
{
	UINT32 base = adsp->base[ireg];
	UINT32 i = adsp->i[ireg];
	UINT32 l = adsp->l[ireg];

	i += adsp->m[mreg];
	if (i < base) i += l;
	else if (i >= base + l) i -= l;
	adsp->i[ireg] = i;
}



/*===========================================================================
    Data memory accessors
===========================================================================*/

INLINE void data_write_dag1(adsp2100_state *adsp, UINT32 op, INT32 val)
{
	UINT32 ireg = (op >> 2) & 3;
	UINT32 mreg = op & 3;
	UINT32 base = adsp->base[ireg];
	UINT32 i = adsp->i[ireg];
	UINT32 l = adsp->l[ireg];

	if ( adsp->mstat & MSTAT_REVERSE )
	{
		UINT32 ir = reverse_table[ i & 0x3fff ];
		WWORD_DATA(adsp, ir, val);
	}
	else
		WWORD_DATA(adsp, i, val);

	i += adsp->m[mreg];
	if (i < base) i += l;
	else if (i >= base + l) i -= l;
	adsp->i[ireg] = i;
}


INLINE UINT32 data_read_dag1(adsp2100_state *adsp, UINT32 op)
{
	UINT32 ireg = (op >> 2) & 3;
	UINT32 mreg = op & 3;
	UINT32 base = adsp->base[ireg];
	UINT32 i = adsp->i[ireg];
	UINT32 l = adsp->l[ireg];
	UINT32 res;

	if (adsp->mstat & MSTAT_REVERSE)
	{
		UINT32 ir = reverse_table[i & 0x3fff];
		res = RWORD_DATA(adsp, ir);
	}
	else
		res = RWORD_DATA(adsp, i);

	i += adsp->m[mreg];
	if (i < base) i += l;
	else if (i >= base + l) i -= l;
	adsp->i[ireg] = i;

	return res;
}

INLINE void data_write_dag2(adsp2100_state *adsp, UINT32 op, INT32 val)
{
	UINT32 ireg = 4 + ((op >> 2) & 3);
	UINT32 mreg = 4 + (op & 3);
	UINT32 base = adsp->base[ireg];
	UINT32 i = adsp->i[ireg];
	UINT32 l = adsp->l[ireg];

	WWORD_DATA(adsp, i, val);

	i += adsp->m[mreg];
	if (i < base) i += l;
	else if (i >= base + l) i -= l;
	adsp->i[ireg] = i;
}


INLINE UINT32 data_read_dag2(adsp2100_state *adsp, UINT32 op)
{
	UINT32 ireg = 4 + ((op >> 2) & 3);
	UINT32 mreg = 4 + (op & 3);
	UINT32 base = adsp->base[ireg];
	UINT32 i = adsp->i[ireg];
	UINT32 l = adsp->l[ireg];

	UINT32 res = RWORD_DATA(adsp, i);

	i += adsp->m[mreg];
	if (i < base) i += l;
	else if (i >= base + l) i -= l;
	adsp->i[ireg] = i;

	return res;
}

/*===========================================================================
    Program memory accessors
===========================================================================*/

INLINE void pgm_write_dag2(adsp2100_state *adsp, UINT32 op, INT32 val)
{
	UINT32 ireg = 4 + ((op >> 2) & 3);
	UINT32 mreg = 4 + (op & 3);
	UINT32 base = adsp->base[ireg];
	UINT32 i = adsp->i[ireg];
	UINT32 l = adsp->l[ireg];

	WWORD_PGM(adsp, i, (val << 8) | adsp->px);

	i += adsp->m[mreg];
	if (i < base) i += l;
	else if (i >= base + l) i -= l;
	adsp->i[ireg] = i;
}


INLINE UINT32 pgm_read_dag2(adsp2100_state *adsp, UINT32 op)
{
	UINT32 ireg = 4 + ((op >> 2) & 3);
	UINT32 mreg = 4 + (op & 3);
	UINT32 base = adsp->base[ireg];
	UINT32 i = adsp->i[ireg];
	UINT32 l = adsp->l[ireg];
	UINT32 res;

	res = RWORD_PGM(adsp, i);
	adsp->px = res;
	res >>= 8;

	i += adsp->m[mreg];
	if (i < base) i += l;
	else if (i >= base + l) i -= l;
	adsp->i[ireg] = i;

	return res;
}



/*===========================================================================
    register reading
===========================================================================*/

#define ALU_GETXREG_UNSIGNED(a,x) (*(UINT16 *)(a)->alu_xregs[x])
#define ALU_GETYREG_UNSIGNED(a,y) (*(UINT16 *)(a)->alu_yregs[y])

#define MAC_GETXREG_UNSIGNED(a,x) (*(UINT16 *)(a)->mac_xregs[x])
#define MAC_GETXREG_SIGNED(a,x)   (*( INT16 *)(a)->mac_xregs[x])
#define MAC_GETYREG_UNSIGNED(a,y) (*(UINT16 *)(a)->mac_yregs[y])
#define MAC_GETYREG_SIGNED(a,y)   (*( INT16 *)(a)->mac_yregs[y])

#define SHIFT_GETXREG_UNSIGNED(a,x) (*(UINT16 *)(a)->shift_xregs[x])
#define SHIFT_GETXREG_SIGNED(a,x)   (*( INT16 *)(a)->shift_xregs[x])



/*===========================================================================
    ALU operations (result in AR)
===========================================================================*/

static void alu_op_ar(adsp2100_state *adsp, int op)
{
	INT32 xop = (op >> 8) & 7;
	INT32 yop = (op >> 11) & 3;
	INT32 res;

	switch (op & (15<<13))  /*JB*/
	{
		case 0x00<<13:
			/* Y                Clear when y = 0 */
			res = ALU_GETYREG_UNSIGNED(adsp, yop);
			CALC_NZ(res);
			break;
		case 0x01<<13:
			/* Y + 1            PASS 1 when y = 0 */
			yop = ALU_GETYREG_UNSIGNED(adsp, yop);
			res = yop + 1;
			CALC_NZ(res);
			if (yop == 0x7fff) SET_V;
			else if (yop == 0xffff) SET_C;
			break;
		case 0x02<<13:
			/* X + Y + C */
			xop = ALU_GETXREG_UNSIGNED(adsp, xop);
			yop = ALU_GETYREG_UNSIGNED(adsp, yop);
			yop += GET_C >> 3;
			res = xop + yop;
			CALC_NZVC(xop, yop, res);
			break;
		case 0x03<<13:
			/* X + Y            X when y = 0 */
			xop = ALU_GETXREG_UNSIGNED(adsp, xop);
			yop = ALU_GETYREG_UNSIGNED(adsp, yop);
			res = xop + yop;
			CALC_NZVC(xop, yop, res);
			break;
		case 0x04<<13:
			/* NOT Y */
			res = ALU_GETYREG_UNSIGNED(adsp, yop) ^ 0xffff;
			CALC_NZ(res);
			break;
		case 0x05<<13:
			/* -Y */
			yop = ALU_GETYREG_UNSIGNED(adsp, yop);
			res = -yop;
			CALC_NZ(res);
			if (yop == 0x8000) SET_V;
			if (yop == 0x0000) SET_C;
			break;
		case 0x06<<13:
			/* X - Y + C - 1    X + C - 1 when y = 0 */
			xop = ALU_GETXREG_UNSIGNED(adsp, xop);
			yop = ALU_GETYREG_UNSIGNED(adsp, yop);
			res = xop - yop + (GET_C >> 3) - 1;
			CALC_NZVC_SUB(xop, yop, res);
			break;
		case 0x07<<13:
			/* X - Y */
			xop = ALU_GETXREG_UNSIGNED(adsp, xop);
			yop = ALU_GETYREG_UNSIGNED(adsp, yop);
			res = xop - yop;
			CALC_NZVC_SUB(xop, yop, res);
			break;
		case 0x08<<13:
			/* Y - 1            PASS -1 when y = 0 */
			yop = ALU_GETYREG_UNSIGNED(adsp, yop);
			res = yop - 1;
			CALC_NZ(res);
			if (yop == 0x8000) SET_V;
			else if (yop == 0x0000) SET_C;
			break;
		case 0x09<<13:
			/* Y - X            -X when y = 0 */
			xop = ALU_GETXREG_UNSIGNED(adsp, xop);
			yop = ALU_GETYREG_UNSIGNED(adsp, yop);
			res = yop - xop;
			CALC_NZVC_SUB(yop, xop, res);
			break;
		case 0x0a<<13:
			/* Y - X + C - 1    -X + C - 1 when y = 0 */
			xop = ALU_GETXREG_UNSIGNED(adsp, xop);
			yop = ALU_GETYREG_UNSIGNED(adsp, yop);
			res = yop - xop + (GET_C >> 3) - 1;
			CALC_NZVC_SUB(yop, xop, res);
			break;
		case 0x0b<<13:
			/* NOT X */
			res = ALU_GETXREG_UNSIGNED(adsp, xop) ^ 0xffff;
			CALC_NZ(res);
			break;
		case 0x0c<<13:
			/* X AND Y */
			xop = ALU_GETXREG_UNSIGNED(adsp, xop);
			yop = ALU_GETYREG_UNSIGNED(adsp, yop);
			res = xop & yop;
			CALC_NZ(res);
			break;
		case 0x0d<<13:
			/* X OR Y */
			xop = ALU_GETXREG_UNSIGNED(adsp, xop);
			yop = ALU_GETYREG_UNSIGNED(adsp, yop);
			res = xop | yop;
			CALC_NZ(res);
			break;
		case 0x0e<<13:
			/* X XOR Y */
			xop = ALU_GETXREG_UNSIGNED(adsp, xop);
			yop = ALU_GETYREG_UNSIGNED(adsp, yop);
			res = xop ^ yop;
			CALC_NZ(res);
			break;
		case 0x0f<<13:
			/* ABS X */
			xop = ALU_GETXREG_UNSIGNED(adsp, xop);
			res = (xop & 0x8000) ? -xop : xop;
			if (xop == 0) SET_Z;
			if (xop == 0x8000) SET_N, SET_V;
			CLR_S;
			if (xop & 0x8000) SET_S;
			break;
		default:
			res = 0;	/* just to keep the compiler happy */
			break;
	}

	/* saturate */
	if ((adsp->mstat & MSTAT_SATURATE) && GET_V) res = GET_C ? -32768 : 32767;

	/* set the final value */
	adsp->core.ar.u = res;
}



/*===========================================================================
    ALU operations (result in AR, constant yop)
===========================================================================*/

static void alu_op_ar_const(adsp2100_state *adsp, int op)
{
	INT32 xop = (op >> 8) & 7;
	INT32 yop = constants[((op >> 5) & 0x07) | ((op >> 8) & 0x18)];
	INT32 res;

	switch (op & (15<<13))  /*JB*/
	{
		case 0x00<<13:
			/* Y                Clear when y = 0 */
			res = yop;
			CALC_NZ(res);
			break;
		case 0x01<<13:
			/* Y + 1            PASS 1 when y = 0 */
			res = yop + 1;
			CALC_NZ(res);
			if (yop == 0x7fff) SET_V;
			else if (yop == 0xffff) SET_C;
			break;
		case 0x02<<13:
			/* X + Y + C */
			xop = ALU_GETXREG_UNSIGNED(adsp, xop);
			yop += GET_C >> 3;
			res = xop + yop;
			CALC_NZVC(xop, yop, res);
			break;
		case 0x03<<13:
			/* X + Y            X when y = 0 */
			xop = ALU_GETXREG_UNSIGNED(adsp, xop);
			res = xop + yop;
			CALC_NZVC(xop, yop, res);
			break;
		case 0x04<<13:
			/* NOT Y */
			res = yop ^ 0xffff;
			CALC_NZ(res);
			break;
		case 0x05<<13:
			/* -Y */
			res = -yop;
			CALC_NZ(res);
			if (yop == 0x8000) SET_V;
			if (yop == 0x0000) SET_C;
			break;
		case 0x06<<13:
			/* X - Y + C - 1    X + C - 1 when y = 0 */
			xop = ALU_GETXREG_UNSIGNED(adsp, xop);
			res = xop - yop + (GET_C >> 3) - 1;
			CALC_NZVC_SUB(xop, yop, res);
			break;
		case 0x07<<13:
			/* X - Y */
			xop = ALU_GETXREG_UNSIGNED(adsp, xop);
			res = xop - yop;
			CALC_NZVC_SUB(xop, yop, res);
			break;
		case 0x08<<13:
			/* Y - 1            PASS -1 when y = 0 */
			res = yop - 1;
			CALC_NZ(res);
			if (yop == 0x8000) SET_V;
			else if (yop == 0x0000) SET_C;
			break;
		case 0x09<<13:
			/* Y - X            -X when y = 0 */
			xop = ALU_GETXREG_UNSIGNED(adsp, xop);
			res = yop - xop;
			CALC_NZVC_SUB(yop, xop, res);
			break;
		case 0x0a<<13:
			/* Y - X + C - 1    -X + C - 1 when y = 0 */
			xop = ALU_GETXREG_UNSIGNED(adsp, xop);
			res = yop - xop + (GET_C >> 3) - 1;
			CALC_NZVC_SUB(yop, xop, res);
			break;
		case 0x0b<<13:
			/* NOT X */
			res = ALU_GETXREG_UNSIGNED(adsp, xop) ^ 0xffff;
			CALC_NZ(res);
			break;
		case 0x0c<<13:
			/* X AND Y */
			xop = ALU_GETXREG_UNSIGNED(adsp, xop);
			res = xop & yop;
			CALC_NZ(res);
			break;
		case 0x0d<<13:
			/* X OR Y */
			xop = ALU_GETXREG_UNSIGNED(adsp, xop);
			res = xop | yop;
			CALC_NZ(res);
			break;
		case 0x0e<<13:
			/* X XOR Y */
			xop = ALU_GETXREG_UNSIGNED(adsp, xop);
			res = xop ^ yop;
			CALC_NZ(res);
			break;
		case 0x0f<<13:
			/* ABS X */
			xop = ALU_GETXREG_UNSIGNED(adsp, xop);
			res = (xop & 0x8000) ? -xop : xop;
			if (xop == 0) SET_Z;
			if (xop == 0x8000) SET_N, SET_V;
			CLR_S;
			if (xop & 0x8000) SET_S;
			break;
		default:
			res = 0;	/* just to keep the compiler happy */
			break;
	}

	/* saturate */
	if ((adsp->mstat & MSTAT_SATURATE) && GET_V) res = GET_C ? -32768 : 32767;

	/* set the final value */
	adsp->core.ar.u = res;
}



/*===========================================================================
    ALU operations (result in AF)
===========================================================================*/

static void alu_op_af(adsp2100_state *adsp, int op)
{
	INT32 xop = (op >> 8) & 7;
	INT32 yop = (op >> 11) & 3;
	INT32 res;

	switch (op & (15<<13))  /*JB*/
	{
		case 0x00<<13:
			/* Y                Clear when y = 0 */
			res = ALU_GETYREG_UNSIGNED(adsp, yop);
			CALC_NZ(res);
			break;
		case 0x01<<13:
			/* Y + 1            PASS 1 when y = 0 */
			yop = ALU_GETYREG_UNSIGNED(adsp, yop);
			res = yop + 1;
			CALC_NZ(res);
			if (yop == 0x7fff) SET_V;
			else if (yop == 0xffff) SET_C;
			break;
		case 0x02<<13:
			/* X + Y + C */
			xop = ALU_GETXREG_UNSIGNED(adsp, xop);
			yop = ALU_GETYREG_UNSIGNED(adsp, yop);
			yop += GET_C >> 3;
			res = xop + yop;
			CALC_NZVC(xop, yop, res);
			break;
		case 0x03<<13:
			/* X + Y            X when y = 0 */
			xop = ALU_GETXREG_UNSIGNED(adsp, xop);
			yop = ALU_GETYREG_UNSIGNED(adsp, yop);
			res = xop + yop;
			CALC_NZVC(xop, yop, res);
			break;
		case 0x04<<13:
			/* NOT Y */
			res = ALU_GETYREG_UNSIGNED(adsp, yop) ^ 0xffff;
			CALC_NZ(res);
			break;
		case 0x05<<13:
			/* -Y */
			yop = ALU_GETYREG_UNSIGNED(adsp, yop);
			res = -yop;
			CALC_NZ(res);
			if (yop == 0x8000) SET_V;
			if (yop == 0x0000) SET_C;
			break;
		case 0x06<<13:
			/* X - Y + C - 1    X + C - 1 when y = 0 */
			xop = ALU_GETXREG_UNSIGNED(adsp, xop);
			yop = ALU_GETYREG_UNSIGNED(adsp, yop);
			res = xop - yop + (GET_C >> 3) - 1;
			CALC_NZVC_SUB(xop, yop, res);
			break;
		case 0x07<<13:
			/* X - Y */
			xop = ALU_GETXREG_UNSIGNED(adsp, xop);
			yop = ALU_GETYREG_UNSIGNED(adsp, yop);
			res = xop - yop;
			CALC_NZVC_SUB(xop, yop, res);
			break;
		case 0x08<<13:
			/* Y - 1            PASS -1 when y = 0 */
			yop = ALU_GETYREG_UNSIGNED(adsp, yop);
			res = yop - 1;
			CALC_NZ(res);
			if (yop == 0x8000) SET_V;
			else if (yop == 0x0000) SET_C;
			break;
		case 0x09<<13:
			/* Y - X            -X when y = 0 */
			xop = ALU_GETXREG_UNSIGNED(adsp, xop);
			yop = ALU_GETYREG_UNSIGNED(adsp, yop);
			res = yop - xop;
			CALC_NZVC_SUB(yop, xop, res);
			break;
		case 0x0a<<13:
			/* Y - X + C - 1    -X + C - 1 when y = 0 */
			xop = ALU_GETXREG_UNSIGNED(adsp, xop);
			yop = ALU_GETYREG_UNSIGNED(adsp, yop);
			res = yop - xop + (GET_C >> 3) - 1;
			CALC_NZVC_SUB(yop, xop, res);
			break;
		case 0x0b<<13:
			/* NOT X */
			res = ALU_GETXREG_UNSIGNED(adsp, xop) ^ 0xffff;
			CALC_NZ(res);
			break;
		case 0x0c<<13:
			/* X AND Y */
			xop = ALU_GETXREG_UNSIGNED(adsp, xop);
			yop = ALU_GETYREG_UNSIGNED(adsp, yop);
			res = xop & yop;
			CALC_NZ(res);
			break;
		case 0x0d<<13:
			/* X OR Y */
			xop = ALU_GETXREG_UNSIGNED(adsp, xop);
			yop = ALU_GETYREG_UNSIGNED(adsp, yop);
			res = xop | yop;
			CALC_NZ(res);
			break;
		case 0x0e<<13:
			/* X XOR Y */
			xop = ALU_GETXREG_UNSIGNED(adsp, xop);
			yop = ALU_GETYREG_UNSIGNED(adsp, yop);
			res = xop ^ yop;
			CALC_NZ(res);
			break;
		case 0x0f<<13:
			/* ABS X */
			xop = ALU_GETXREG_UNSIGNED(adsp, xop);
			res = (xop & 0x8000) ? -xop : xop;
			if (xop == 0) SET_Z;
			if (xop == 0x8000) SET_N, SET_V;
			CLR_S;
			if (xop & 0x8000) SET_S;
			break;
		default:
			res = 0;	/* just to keep the compiler happy */
			break;
	}

	/* set the final value */
	adsp->core.af.u = res;
}



/*===========================================================================
    ALU operations (result in AF, constant yop)
===========================================================================*/

static void alu_op_af_const(adsp2100_state *adsp, int op)
{
	INT32 xop = (op >> 8) & 7;
	INT32 yop = constants[((op >> 5) & 0x07) | ((op >> 8) & 0x18)];
	INT32 res;

	switch (op & (15<<13))  /*JB*/
	{
		case 0x00<<13:
			/* Y                Clear when y = 0 */
			res = yop;
			CALC_NZ(res);
			break;
		case 0x01<<13:
			/* Y + 1            PASS 1 when y = 0 */
			res = yop + 1;
			CALC_NZ(res);
			if (yop == 0x7fff) SET_V;
			else if (yop == 0xffff) SET_C;
			break;
		case 0x02<<13:
			/* X + Y + C */
			xop = ALU_GETXREG_UNSIGNED(adsp, xop);
			yop += GET_C >> 3;
			res = xop + yop;
			CALC_NZVC(xop, yop, res);
			break;
		case 0x03<<13:
			/* X + Y            X when y = 0 */
			xop = ALU_GETXREG_UNSIGNED(adsp, xop);
			res = xop + yop;
			CALC_NZVC(xop, yop, res);
			break;
		case 0x04<<13:
			/* NOT Y */
			res = yop ^ 0xffff;
			CALC_NZ(res);
			break;
		case 0x05<<13:
			/* -Y */
			res = -yop;
			CALC_NZ(res);
			if (yop == 0x8000) SET_V;
			if (yop == 0x0000) SET_C;
			break;
		case 0x06<<13:
			/* X - Y + C - 1    X + C - 1 when y = 0 */
			xop = ALU_GETXREG_UNSIGNED(adsp, xop);
			res = xop - yop + (GET_C >> 3) - 1;
			CALC_NZVC_SUB(xop, yop, res);
			break;
		case 0x07<<13:
			/* X - Y */
			xop = ALU_GETXREG_UNSIGNED(adsp, xop);
			res = xop - yop;
			CALC_NZVC_SUB(xop, yop, res);
			break;
		case 0x08<<13:
			/* Y - 1            PASS -1 when y = 0 */
			res = yop - 1;
			CALC_NZ(res);
			if (yop == 0x8000) SET_V;
			else if (yop == 0x0000) SET_C;
			break;
		case 0x09<<13:
			/* Y - X            -X when y = 0 */
			xop = ALU_GETXREG_UNSIGNED(adsp, xop);
			res = yop - xop;
			CALC_NZVC_SUB(yop, xop, res);
			break;
		case 0x0a<<13:
			/* Y - X + C - 1    -X + C - 1 when y = 0 */
			xop = ALU_GETXREG_UNSIGNED(adsp, xop);
			res = yop - xop + (GET_C >> 3) - 1;
			CALC_NZVC_SUB(yop, xop, res);
			break;
		case 0x0b<<13:
			/* NOT X */
			res = ALU_GETXREG_UNSIGNED(adsp, xop) ^ 0xffff;
			CALC_NZ(res);
			break;
		case 0x0c<<13:
			/* X AND Y */
			xop = ALU_GETXREG_UNSIGNED(adsp, xop);
			res = xop & yop;
			CALC_NZ(res);
			break;
		case 0x0d<<13:
			/* X OR Y */
			xop = ALU_GETXREG_UNSIGNED(adsp, xop);
			res = xop | yop;
			CALC_NZ(res);
			break;
		case 0x0e<<13:
			/* X XOR Y */
			xop = ALU_GETXREG_UNSIGNED(adsp, xop);
			res = xop ^ yop;
			CALC_NZ(res);
			break;
		case 0x0f<<13:
			/* ABS X */
			xop = ALU_GETXREG_UNSIGNED(adsp, xop);
			res = (xop & 0x8000) ? -xop : xop;
			if (xop == 0) SET_Z;
			if (xop == 0x8000) SET_N, SET_V;
			CLR_S;
			if (xop & 0x8000) SET_S;
			break;
		default:
			res = 0;	/* just to keep the compiler happy */
			break;
	}

	/* set the final value */
	adsp->core.af.u = res;
}



/*===========================================================================
    ALU operations (no result)
===========================================================================*/

static void alu_op_none(adsp2100_state *adsp, int op)
{
	INT32 xop = (op >> 8) & 7;
	INT32 yop = (op >> 11) & 3;
	INT32 res;

	switch (op & (15<<13))  /*JB*/
	{
		case 0x00<<13:
			/* Y                Clear when y = 0 */
			res = ALU_GETYREG_UNSIGNED(adsp, yop);
			CALC_NZ(res);
			break;
		case 0x01<<13:
			/* Y + 1            PASS 1 when y = 0 */
			yop = ALU_GETYREG_UNSIGNED(adsp, yop);
			res = yop + 1;
			CALC_NZ(res);
			if (yop == 0x7fff) SET_V;
			else if (yop == 0xffff) SET_C;
			break;
		case 0x02<<13:
			/* X + Y + C */
			xop = ALU_GETXREG_UNSIGNED(adsp, xop);
			yop = ALU_GETYREG_UNSIGNED(adsp, yop);
			yop += GET_C >> 3;
			res = xop + yop;
			CALC_NZVC(xop, yop, res);
			break;
		case 0x03<<13:
			/* X + Y            X when y = 0 */
			xop = ALU_GETXREG_UNSIGNED(adsp, xop);
			yop = ALU_GETYREG_UNSIGNED(adsp, yop);
			res = xop + yop;
			CALC_NZVC(xop, yop, res);
			break;
		case 0x04<<13:
			/* NOT Y */
			res = ALU_GETYREG_UNSIGNED(adsp, yop) ^ 0xffff;
			CALC_NZ(res);
			break;
		case 0x05<<13:
			/* -Y */
			yop = ALU_GETYREG_UNSIGNED(adsp, yop);
			res = -yop;
			CALC_NZ(res);
			if (yop == 0x8000) SET_V;
			if (yop == 0x0000) SET_C;
			break;
		case 0x06<<13:
			/* X - Y + C - 1    X + C - 1 when y = 0 */
			xop = ALU_GETXREG_UNSIGNED(adsp, xop);
			yop = ALU_GETYREG_UNSIGNED(adsp, yop);
			res = xop - yop + (GET_C >> 3) - 1;
			CALC_NZVC_SUB(xop, yop, res);
			break;
		case 0x07<<13:
			/* X - Y */
			xop = ALU_GETXREG_UNSIGNED(adsp, xop);
			yop = ALU_GETYREG_UNSIGNED(adsp, yop);
			res = xop - yop;
			CALC_NZVC_SUB(xop, yop, res);
			break;
		case 0x08<<13:
			/* Y - 1            PASS -1 when y = 0 */
			yop = ALU_GETYREG_UNSIGNED(adsp, yop);
			res = yop - 1;
			CALC_NZ(res);
			if (yop == 0x8000) SET_V;
			else if (yop == 0x0000) SET_C;
			break;
		case 0x09<<13:
			/* Y - X            -X when y = 0 */
			xop = ALU_GETXREG_UNSIGNED(adsp, xop);
			yop = ALU_GETYREG_UNSIGNED(adsp, yop);
			res = yop - xop;
			CALC_NZVC_SUB(yop, xop, res);
			break;
		case 0x0a<<13:
			/* Y - X + C - 1    -X + C - 1 when y = 0 */
			xop = ALU_GETXREG_UNSIGNED(adsp, xop);
			yop = ALU_GETYREG_UNSIGNED(adsp, yop);
			res = yop - xop + (GET_C >> 3) - 1;
			CALC_NZVC_SUB(yop, xop, res);
			break;
		case 0x0b<<13:
			/* NOT X */
			res = ALU_GETXREG_UNSIGNED(adsp, xop) ^ 0xffff;
			CALC_NZ(res);
			break;
		case 0x0c<<13:
			/* X AND Y */
			xop = ALU_GETXREG_UNSIGNED(adsp, xop);
			yop = ALU_GETYREG_UNSIGNED(adsp, yop);
			res = xop & yop;
			CALC_NZ(res);
			break;
		case 0x0d<<13:
			/* X OR Y */
			xop = ALU_GETXREG_UNSIGNED(adsp, xop);
			yop = ALU_GETYREG_UNSIGNED(adsp, yop);
			res = xop | yop;
			CALC_NZ(res);
			break;
		case 0x0e<<13:
			/* X XOR Y */
			xop = ALU_GETXREG_UNSIGNED(adsp, xop);
			yop = ALU_GETYREG_UNSIGNED(adsp, yop);
			res = xop ^ yop;
			CALC_NZ(res);
			break;
		case 0x0f<<13:
			/* ABS X */
			xop = ALU_GETXREG_UNSIGNED(adsp, xop);
			res = (xop & 0x8000) ? -xop : xop;
			if (xop == 0) SET_Z;
			if (xop == 0x8000) SET_N, SET_V;
			CLR_S;
			if (xop & 0x8000) SET_S;
			break;
	}
}



/*===========================================================================
    MAC operations (result in MR)
===========================================================================*/

static void mac_op_mr(adsp2100_state *adsp, int op)
{
	INT8 shift = ((adsp->mstat & MSTAT_INTEGER) >> 4) ^ 1;
	INT32 xop = (op >> 8) & 7;
	INT32 yop = (op >> 11) & 3;
	INT32 temp;
	INT64 res;

	switch (op & (15<<13))	/*JB*/
	{
		case 0x00<<13:
			/* no-op */
			return;
		case 0x01<<13:
			/* X * Y (RND) */
			xop = MAC_GETXREG_SIGNED(adsp, xop);
			yop = MAC_GETYREG_SIGNED(adsp, yop);
			temp = (xop * yop) << shift;
			res = (INT64)temp;
#if 0
			if ((res & 0xffff) == 0x8000) res &= ~((UINT64)0x10000);
			else res += (res & 0x8000) << 1;
#else
			temp &= 0xffff;
			res += 0x8000;
			if ( temp == 0x8000 )
				res &= ~((UINT64)0x10000);
#endif
			break;
		case 0x02<<13:
			/* MR + X * Y (RND) */
			xop = MAC_GETXREG_SIGNED(adsp, xop);
			yop = MAC_GETYREG_SIGNED(adsp, yop);
			temp = (xop * yop) << shift;
			res = adsp->core.mr.mr + (INT64)temp;
#if 0
			if ((res & 0xffff) == 0x8000) res &= ~((UINT64)0x10000);
			else res += (res & 0x8000) << 1;
#else
			temp &= 0xffff;
			res += 0x8000;
			if ( temp == 0x8000 )
				res &= ~((UINT64)0x10000);
#endif
			break;
		case 0x03<<13:
			/* MR - X * Y (RND) */
			xop = MAC_GETXREG_SIGNED(adsp, xop);
			yop = MAC_GETYREG_SIGNED(adsp, yop);
			temp = (xop * yop) << shift;
			res = adsp->core.mr.mr - (INT64)temp;
#if 0
			if ((res & 0xffff) == 0x8000) res &= ~((UINT64)0x10000);
			else res += (res & 0x8000) << 1;
#else
			temp &= 0xffff;
			res += 0x8000;
			if ( temp == 0x8000 )
				res &= ~((UINT64)0x10000);
#endif
			break;
		case 0x04<<13:
			/* X * Y (SS)       Clear when y = 0 */
			xop = MAC_GETXREG_SIGNED(adsp, xop);
			yop = MAC_GETYREG_SIGNED(adsp, yop);
			temp = (xop * yop) << shift;
			res = (INT64)temp;
			break;
		case 0x05<<13:
			/* X * Y (SU) */
			xop = MAC_GETXREG_SIGNED(adsp, xop);
			yop = MAC_GETYREG_UNSIGNED(adsp, yop);
			temp = (xop * yop) << shift;
			res = (INT64)temp;
			break;
		case 0x06<<13:
			/* X * Y (US) */
			xop = MAC_GETXREG_UNSIGNED(adsp, xop);
			yop = MAC_GETYREG_SIGNED(adsp, yop);
			temp = (xop * yop) << shift;
			res = (INT64)temp;
			break;
		case 0x07<<13:
			/* X * Y (UU) */
			xop = MAC_GETXREG_UNSIGNED(adsp, xop);
			yop = MAC_GETYREG_UNSIGNED(adsp, yop);
			temp = (xop * yop) << shift;
			res = (INT64)temp;
			break;
		case 0x08<<13:
			/* MR + X * Y (SS) */
			xop = MAC_GETXREG_SIGNED(adsp, xop);
			yop = MAC_GETYREG_SIGNED(adsp, yop);
			temp = (xop * yop) << shift;
			res = adsp->core.mr.mr + (INT64)temp;
			break;
		case 0x09<<13:
			/* MR + X * Y (SU) */
			xop = MAC_GETXREG_SIGNED(adsp, xop);
			yop = MAC_GETYREG_UNSIGNED(adsp, yop);
			temp = (xop * yop) << shift;
			res = adsp->core.mr.mr + (INT64)temp;
			break;
		case 0x0a<<13:
			/* MR + X * Y (US) */
			xop = MAC_GETXREG_UNSIGNED(adsp, xop);
			yop = MAC_GETYREG_SIGNED(adsp, yop);
			temp = (xop * yop) << shift;
			res = adsp->core.mr.mr + (INT64)temp;
			break;
		case 0x0b<<13:
			/* MR + X * Y (UU) */
			xop = MAC_GETXREG_UNSIGNED(adsp, xop);
			yop = MAC_GETYREG_UNSIGNED(adsp, yop);
			temp = (xop * yop) << shift;
			res = adsp->core.mr.mr + (INT64)temp;
			break;
		case 0x0c<<13:
			/* MR - X * Y (SS) */
			xop = MAC_GETXREG_SIGNED(adsp, xop);
			yop = MAC_GETYREG_SIGNED(adsp, yop);
			temp = (xop * yop) << shift;
			res = adsp->core.mr.mr - (INT64)temp;
			break;
		case 0x0d<<13:
			/* MR - X * Y (SU) */
			xop = MAC_GETXREG_SIGNED(adsp, xop);
			yop = MAC_GETYREG_UNSIGNED(adsp, yop);
			temp = (xop * yop) << shift;
			res = adsp->core.mr.mr - (INT64)temp;
			break;
		case 0x0e<<13:
			/* MR - X * Y (US) */
			xop = MAC_GETXREG_UNSIGNED(adsp, xop);
			yop = MAC_GETYREG_SIGNED(adsp, yop);
			temp = (xop * yop) << shift;
			res = adsp->core.mr.mr - (INT64)temp;
			break;
		case 0x0f<<13:
			/* MR - X * Y (UU) */
			xop = MAC_GETXREG_UNSIGNED(adsp, xop);
			yop = MAC_GETYREG_UNSIGNED(adsp, yop);
			temp = (xop * yop) << shift;
			res = adsp->core.mr.mr - (INT64)temp;
			break;
		default:
			res = 0;	/* just to keep the compiler happy */
			break;
	}

	/* set the final value */
	temp = (res >> 31) & 0x1ff;
	CLR_MV;
	if (temp != 0x000 && temp != 0x1ff) SET_MV;
	adsp->core.mr.mr = res;
}



/*===========================================================================
    MAC operations (result in MR, yop == xop)
===========================================================================*/

static void mac_op_mr_xop(adsp2100_state *adsp, int op)
{
	INT8 shift = ((adsp->mstat & MSTAT_INTEGER) >> 4) ^ 1;
	INT32 xop = (op >> 8) & 7;
	INT32 temp;
	INT64 res;

	switch (op & (15<<13))	/*JB*/
	{
		case 0x00<<13:
			/* no-op */
			return;
		case 0x01<<13:
			/* X * Y (RND) */
			xop = MAC_GETXREG_SIGNED(adsp, xop);
			temp = (xop * xop) << shift;
			res = (INT64)temp;
#if 0
			if ((res & 0xffff) == 0x8000) res &= ~((UINT64)0x10000);
			else res += (res & 0x8000) << 1;
#else
			temp &= 0xffff;
			res += 0x8000;
			if ( temp == 0x8000 )
				res &= ~((UINT64)0x10000);
#endif
			break;
		case 0x02<<13:
			/* MR + X * Y (RND) */
			xop = MAC_GETXREG_SIGNED(adsp, xop);
			temp = (xop * xop) << shift;
			res = adsp->core.mr.mr + (INT64)temp;
#if 0
			if ((res & 0xffff) == 0x8000) res &= ~((UINT64)0x10000);
			else res += (res & 0x8000) << 1;
#else
			temp &= 0xffff;
			res += 0x8000;
			if ( temp == 0x8000 )
				res &= ~((UINT64)0x10000);
#endif
			break;
		case 0x03<<13:
			/* MR - X * Y (RND) */
			xop = MAC_GETXREG_SIGNED(adsp, xop);
			temp = (xop * xop) << shift;
			res = adsp->core.mr.mr - (INT64)temp;
#if 0
			if ((res & 0xffff) == 0x8000) res &= ~((UINT64)0x10000);
			else res += (res & 0x8000) << 1;
#else
			temp &= 0xffff;
			res += 0x8000;
			if ( temp == 0x8000 )
				res &= ~((UINT64)0x10000);
#endif
			break;
		case 0x04<<13:
			/* X * Y (SS)       Clear when y = 0 */
			xop = MAC_GETXREG_SIGNED(adsp, xop);
			temp = (xop * xop) << shift;
			res = (INT64)temp;
			break;
		case 0x05<<13:
			/* X * Y (SU) */
			xop = MAC_GETXREG_SIGNED(adsp, xop);
			temp = (xop * xop) << shift;
			res = (INT64)temp;
			break;
		case 0x06<<13:
			/* X * Y (US) */
			xop = MAC_GETXREG_UNSIGNED(adsp, xop);
			temp = (xop * xop) << shift;
			res = (INT64)temp;
			break;
		case 0x07<<13:
			/* X * Y (UU) */
			xop = MAC_GETXREG_UNSIGNED(adsp, xop);
			temp = (xop * xop) << shift;
			res = (INT64)temp;
			break;
		case 0x08<<13:
			/* MR + X * Y (SS) */
			xop = MAC_GETXREG_SIGNED(adsp, xop);
			temp = (xop * xop) << shift;
			res = adsp->core.mr.mr + (INT64)temp;
			break;
		case 0x09<<13:
			/* MR + X * Y (SU) */
			xop = MAC_GETXREG_SIGNED(adsp, xop);
			temp = (xop * xop) << shift;
			res = adsp->core.mr.mr + (INT64)temp;
			break;
		case 0x0a<<13:
			/* MR + X * Y (US) */
			xop = MAC_GETXREG_UNSIGNED(adsp, xop);
			temp = (xop * xop) << shift;
			res = adsp->core.mr.mr + (INT64)temp;
			break;
		case 0x0b<<13:
			/* MR + X * Y (UU) */
			xop = MAC_GETXREG_UNSIGNED(adsp, xop);
			temp = (xop * xop) << shift;
			res = adsp->core.mr.mr + (INT64)temp;
			break;
		case 0x0c<<13:
			/* MR - X * Y (SS) */
			xop = MAC_GETXREG_SIGNED(adsp, xop);
			temp = (xop * xop) << shift;
			res = adsp->core.mr.mr - (INT64)temp;
			break;
		case 0x0d<<13:
			/* MR - X * Y (SU) */
			xop = MAC_GETXREG_SIGNED(adsp, xop);
			temp = (xop * xop) << shift;
			res = adsp->core.mr.mr - (INT64)temp;
			break;
		case 0x0e<<13:
			/* MR - X * Y (US) */
			xop = MAC_GETXREG_UNSIGNED(adsp, xop);
			temp = (xop * xop) << shift;
			res = adsp->core.mr.mr - (INT64)temp;
			break;
		case 0x0f<<13:
			/* MR - X * Y (UU) */
			xop = MAC_GETXREG_UNSIGNED(adsp, xop);
			temp = (xop * xop) << shift;
			res = adsp->core.mr.mr - (INT64)temp;
			break;
		default:
			res = 0;	/* just to keep the compiler happy */
			break;
	}

	/* set the final value */
	temp = (res >> 31) & 0x1ff;
	CLR_MV;
	if (temp != 0x000 && temp != 0x1ff) SET_MV;
	adsp->core.mr.mr = res;
}



/*===========================================================================
    MAC operations (result in MF)
===========================================================================*/

static void mac_op_mf(adsp2100_state *adsp, int op)
{
	INT8 shift = ((adsp->mstat & MSTAT_INTEGER) >> 4) ^ 1;
	INT32 xop = (op >> 8) & 7;
	INT32 yop = (op >> 11) & 3;
	INT32 temp;
	INT64 res;

	switch (op & (15<<13))	/*JB*/
	{
		case 0x00<<13:
			/* no-op */
			return;
		case 0x01<<13:
			/* X * Y (RND) */
			xop = MAC_GETXREG_SIGNED(adsp, xop);
			yop = MAC_GETYREG_SIGNED(adsp, yop);
			temp = (xop * yop) << shift;
			res = (INT64)temp;
#if 0
			if ((res & 0xffff) == 0x8000) res &= ~((UINT64)0x10000);
			else res += (res & 0x8000) << 1;
#else
			temp &= 0xffff;
			res += 0x8000;
			if ( temp == 0x8000 )
				res &= ~((UINT64)0x10000);
#endif
			break;
		case 0x02<<13:
			/* MR + X * Y (RND) */
			xop = MAC_GETXREG_SIGNED(adsp, xop);
			yop = MAC_GETYREG_SIGNED(adsp, yop);
			temp = (xop * yop) << shift;
			res = adsp->core.mr.mr + (INT64)temp;
#if 0
			if ((res & 0xffff) == 0x8000) res &= ~((UINT64)0x10000);
			else res += (res & 0x8000) << 1;
#else
			temp &= 0xffff;
			res += 0x8000;
			if ( temp == 0x8000 )
				res &= ~((UINT64)0x10000);
#endif
			break;
		case 0x03<<13:
			/* MR - X * Y (RND) */
			xop = MAC_GETXREG_SIGNED(adsp, xop);
			yop = MAC_GETYREG_SIGNED(adsp, yop);
			temp = (xop * yop) << shift;
			res = adsp->core.mr.mr - (INT64)temp;
#if 0
			if ((res & 0xffff) == 0x8000) res &= ~((UINT64)0x10000);
			else res += (res & 0x8000) << 1;
#else
			temp &= 0xffff;
			res += 0x8000;
			if ( temp == 0x8000 )
				res &= ~((UINT64)0x10000);
#endif
			break;
		case 0x04<<13:
			/* X * Y (SS)       Clear when y = 0 */
			xop = MAC_GETXREG_SIGNED(adsp, xop);
			yop = MAC_GETYREG_SIGNED(adsp, yop);
			temp = (xop * yop) << shift;
			res = (INT64)temp;
			break;
		case 0x05<<13:
			/* X * Y (SU) */
			xop = MAC_GETXREG_SIGNED(adsp, xop);
			yop = MAC_GETYREG_UNSIGNED(adsp, yop);
			temp = (xop * yop) << shift;
			res = (INT64)temp;
			break;
		case 0x06<<13:
			/* X * Y (US) */
			xop = MAC_GETXREG_UNSIGNED(adsp, xop);
			yop = MAC_GETYREG_SIGNED(adsp, yop);
			temp = (xop * yop) << shift;
			res = (INT64)temp;
			break;
		case 0x07<<13:
			/* X * Y (UU) */
			xop = MAC_GETXREG_UNSIGNED(adsp, xop);
			yop = MAC_GETYREG_UNSIGNED(adsp, yop);
			temp = (xop * yop) << shift;
			res = (INT64)temp;
			break;
		case 0x08<<13:
			/* MR + X * Y (SS) */
			xop = MAC_GETXREG_SIGNED(adsp, xop);
			yop = MAC_GETYREG_SIGNED(adsp, yop);
			temp = (xop * yop) << shift;
			res = adsp->core.mr.mr + (INT64)temp;
			break;
		case 0x09<<13:
			/* MR + X * Y (SU) */
			xop = MAC_GETXREG_SIGNED(adsp, xop);
			yop = MAC_GETYREG_UNSIGNED(adsp, yop);
			temp = (xop * yop) << shift;
			res = adsp->core.mr.mr + (INT64)temp;
			break;
		case 0x0a<<13:
			/* MR + X * Y (US) */
			xop = MAC_GETXREG_UNSIGNED(adsp, xop);
			yop = MAC_GETYREG_SIGNED(adsp, yop);
			temp = (xop * yop) << shift;
			res = adsp->core.mr.mr + (INT64)temp;
			break;
		case 0x0b<<13:
			/* MR + X * Y (UU) */
			xop = MAC_GETXREG_UNSIGNED(adsp, xop);
			yop = MAC_GETYREG_UNSIGNED(adsp, yop);
			temp = (xop * yop) << shift;
			res = adsp->core.mr.mr + (INT64)temp;
			break;
		case 0x0c<<13:
			/* MR - X * Y (SS) */
			xop = MAC_GETXREG_SIGNED(adsp, xop);
			yop = MAC_GETYREG_SIGNED(adsp, yop);
			temp = (xop * yop) << shift;
			res = adsp->core.mr.mr - (INT64)temp;
			break;
		case 0x0d<<13:
			/* MR - X * Y (SU) */
			xop = MAC_GETXREG_SIGNED(adsp, xop);
			yop = MAC_GETYREG_UNSIGNED(adsp, yop);
			temp = (xop * yop) << shift;
			res = adsp->core.mr.mr - (INT64)temp;
			break;
		case 0x0e<<13:
			/* MR - X * Y (US) */
			xop = MAC_GETXREG_UNSIGNED(adsp, xop);
			yop = MAC_GETYREG_SIGNED(adsp, yop);
			temp = (xop * yop) << shift;
			res = adsp->core.mr.mr - (INT64)temp;
			break;
		case 0x0f<<13:
			/* MR - X * Y (UU) */
			xop = MAC_GETXREG_UNSIGNED(adsp, xop);
			yop = MAC_GETYREG_UNSIGNED(adsp, yop);
			temp = (xop * yop) << shift;
			res = adsp->core.mr.mr - (INT64)temp;
			break;
		default:
			res = 0;	/* just to keep the compiler happy */
			break;
	}

	/* set the final value */
	adsp->core.mf.u = (UINT32)res >> 16;
}



/*===========================================================================
    MAC operations (result in MF, yop == xop)
===========================================================================*/

static void mac_op_mf_xop(adsp2100_state *adsp, int op)
{
	INT8 shift = ((adsp->mstat & MSTAT_INTEGER) >> 4) ^ 1;
	INT32 xop = (op >> 8) & 7;
	INT32 temp;
	INT64 res;

	switch (op & (15<<13))	/*JB*/
	{
		case 0x00<<13:
			/* no-op */
			return;
		case 0x01<<13:
			/* X * Y (RND) */
			xop = MAC_GETXREG_SIGNED(adsp, xop);
			temp = (xop * xop) << shift;
			res = (INT64)temp;
#if 0
			if ((res & 0xffff) == 0x8000) res &= ~((UINT64)0x10000);
			else res += (res & 0x8000) << 1;
#else
			temp &= 0xffff;
			res += 0x8000;
			if ( temp == 0x8000 )
				res &= ~((UINT64)0x10000);
#endif
			break;
		case 0x02<<13:
			/* MR + X * Y (RND) */
			xop = MAC_GETXREG_SIGNED(adsp, xop);
			temp = (xop * xop) << shift;
			res = adsp->core.mr.mr + (INT64)temp;
#if 0
			if ((res & 0xffff) == 0x8000) res &= ~((UINT64)0x10000);
			else res += (res & 0x8000) << 1;
#else
			temp &= 0xffff;
			res += 0x8000;
			if ( temp == 0x8000 )
				res &= ~((UINT64)0x10000);
#endif
			break;
		case 0x03<<13:
			/* MR - X * Y (RND) */
			xop = MAC_GETXREG_SIGNED(adsp, xop);
			temp = (xop * xop) << shift;
			res = adsp->core.mr.mr - (INT64)temp;
#if 0
			if ((res & 0xffff) == 0x8000) res &= ~((UINT64)0x10000);
			else res += (res & 0x8000) << 1;
#else
			temp &= 0xffff;
			res += 0x8000;
			if ( temp == 0x8000 )
				res &= ~((UINT64)0x10000);
#endif
			break;
		case 0x04<<13:
			/* X * Y (SS)       Clear when y = 0 */
			xop = MAC_GETXREG_SIGNED(adsp, xop);
			temp = (xop * xop) << shift;
			res = (INT64)temp;
			break;
		case 0x05<<13:
			/* X * Y (SU) */
			xop = MAC_GETXREG_SIGNED(adsp, xop);
			temp = (xop * xop) << shift;
			res = (INT64)temp;
			break;
		case 0x06<<13:
			/* X * Y (US) */
			xop = MAC_GETXREG_UNSIGNED(adsp, xop);
			temp = (xop * xop) << shift;
			res = (INT64)temp;
			break;
		case 0x07<<13:
			/* X * Y (UU) */
			xop = MAC_GETXREG_UNSIGNED(adsp, xop);
			temp = (xop * xop) << shift;
			res = (INT64)temp;
			break;
		case 0x08<<13:
			/* MR + X * Y (SS) */
			xop = MAC_GETXREG_SIGNED(adsp, xop);
			temp = (xop * xop) << shift;
			res = adsp->core.mr.mr + (INT64)temp;
			break;
		case 0x09<<13:
			/* MR + X * Y (SU) */
			xop = MAC_GETXREG_SIGNED(adsp, xop);
			temp = (xop * xop) << shift;
			res = adsp->core.mr.mr + (INT64)temp;
			break;
		case 0x0a<<13:
			/* MR + X * Y (US) */
			xop = MAC_GETXREG_UNSIGNED(adsp, xop);
			temp = (xop * xop) << shift;
			res = adsp->core.mr.mr + (INT64)temp;
			break;
		case 0x0b<<13:
			/* MR + X * Y (UU) */
			xop = MAC_GETXREG_UNSIGNED(adsp, xop);
			temp = (xop * xop) << shift;
			res = adsp->core.mr.mr + (INT64)temp;
			break;
		case 0x0c<<13:
			/* MR - X * Y (SS) */
			xop = MAC_GETXREG_SIGNED(adsp, xop);
			temp = (xop * xop) << shift;
			res = adsp->core.mr.mr - (INT64)temp;
			break;
		case 0x0d<<13:
			/* MR - X * Y (SU) */
			xop = MAC_GETXREG_SIGNED(adsp, xop);
			temp = (xop * xop) << shift;
			res = adsp->core.mr.mr - (INT64)temp;
			break;
		case 0x0e<<13:
			/* MR - X * Y (US) */
			xop = MAC_GETXREG_UNSIGNED(adsp, xop);
			temp = (xop * xop) << shift;
			res = adsp->core.mr.mr - (INT64)temp;
			break;
		case 0x0f<<13:
			/* MR - X * Y (UU) */
			xop = MAC_GETXREG_UNSIGNED(adsp, xop);
			temp = (xop * xop) << shift;
			res = adsp->core.mr.mr - (INT64)temp;
			break;
		default:
			res = 0;	/* just to keep the compiler happy */
			break;
	}

	/* set the final value */
	adsp->core.mf.u = (UINT32)res >> 16;
}



/*===========================================================================
    SHIFT operations (result in SR/SE/SB)
===========================================================================*/

static void shift_op(adsp2100_state *adsp, int op)
{
	INT8 sc = adsp->core.se.s;
	INT32 xop = (op >> 8) & 7;
	UINT32 res;

	switch (op & (15<<11))	/*JB*/
	{
		case 0x00<<11:
			/* LSHIFT (HI) */
			xop = SHIFT_GETXREG_UNSIGNED(adsp, xop) << 16;
			if (sc > 0) res = (sc < 32) ? (xop << sc) : 0;
			else res = (sc > -32) ? ((UINT32)xop >> -sc) : 0;
			adsp->core.sr.sr = res;
			break;
		case 0x01<<11:
			/* LSHIFT (HI, OR) */
			xop = SHIFT_GETXREG_UNSIGNED(adsp, xop) << 16;
			if (sc > 0) res = (sc < 32) ? (xop << sc) : 0;
			else res = (sc > -32) ? ((UINT32)xop >> -sc) : 0;
			adsp->core.sr.sr |= res;
			break;
		case 0x02<<11:
			/* LSHIFT (LO) */
			xop = SHIFT_GETXREG_UNSIGNED(adsp, xop);
			if (sc > 0) res = (sc < 32) ? (xop << sc) : 0;
			else res = (sc > -32) ? (xop >> -sc) : 0;
			adsp->core.sr.sr = res;
			break;
		case 0x03<<11:
			/* LSHIFT (LO, OR) */
			xop = SHIFT_GETXREG_UNSIGNED(adsp, xop);
			if (sc > 0) res = (sc < 32) ? (xop << sc) : 0;
			else res = (sc > -32) ? (xop >> -sc) : 0;
			adsp->core.sr.sr |= res;
			break;
		case 0x04<<11:
			/* ASHIFT (HI) */
			xop = SHIFT_GETXREG_SIGNED(adsp, xop) << 16;
			if (sc > 0) res = (sc < 32) ? (xop << sc) : 0;
			else res = (sc > -32) ? (xop >> -sc) : (xop >> 31);
			adsp->core.sr.sr = res;
			break;
		case 0x05<<11:
			/* ASHIFT (HI, OR) */
			xop = SHIFT_GETXREG_SIGNED(adsp, xop) << 16;
			if (sc > 0) res = (sc < 32) ? (xop << sc) : 0;
			else res = (sc > -32) ? (xop >> -sc) : (xop >> 31);
			adsp->core.sr.sr |= res;
			break;
		case 0x06<<11:
			/* ASHIFT (LO) */
			xop = SHIFT_GETXREG_SIGNED(adsp, xop);
			if (sc > 0) res = (sc < 32) ? (xop << sc) : 0;
			else res = (sc > -32) ? (xop >> -sc) : (xop >> 31);
			adsp->core.sr.sr = res;
			break;
		case 0x07<<11:
			/* ASHIFT (LO, OR) */
			xop = SHIFT_GETXREG_SIGNED(adsp, xop);
			if (sc > 0) res = (sc < 32) ? (xop << sc) : 0;
			else res = (sc > -32) ? (xop >> -sc) : (xop >> 31);
			adsp->core.sr.sr |= res;
			break;
		case 0x08<<11:
			/* NORM (HI) */
			xop = SHIFT_GETXREG_SIGNED(adsp, xop) << 16;
			if (sc > 0)
			{
				xop = ((UINT32)xop >> 1) | ((adsp->astat & CFLAG) << 28);
				res = xop >> (sc - 1);
			}
			else res = (sc > -32) ? (xop << -sc) : 0;
			adsp->core.sr.sr = res;
			break;
		case 0x09<<11:
			/* NORM (HI, OR) */
			xop = SHIFT_GETXREG_SIGNED(adsp, xop) << 16;
			if (sc > 0)
			{
				xop = ((UINT32)xop >> 1) | ((adsp->astat & CFLAG) << 28);
				res = xop >> (sc - 1);
			}
			else res = (sc > -32) ? (xop << -sc) : 0;
			adsp->core.sr.sr |= res;
			break;
		case 0x0a<<11:
			/* NORM (LO) */
			xop = SHIFT_GETXREG_UNSIGNED(adsp, xop);
			if (sc > 0) res = (sc < 32) ? (xop >> sc) : 0;
			else res = (sc > -32) ? (xop << -sc) : 0;
			adsp->core.sr.sr = res;
			break;
		case 0x0b<<11:
			/* NORM (LO, OR) */
			xop = SHIFT_GETXREG_UNSIGNED(adsp, xop);
			if (sc > 0) res = (sc < 32) ? (xop >> sc) : 0;
			else res = (sc > -32) ? (xop << -sc) : 0;
			adsp->core.sr.sr |= res;
			break;
		case 0x0c<<11:
			/* EXP (HI) */
			xop = SHIFT_GETXREG_SIGNED(adsp, xop) << 16;
			res = 0;
			if (xop < 0)
			{
				SET_SS;
				while ((xop & 0x40000000) != 0) res++, xop <<= 1;
			}
			else
			{
				CLR_SS;
				xop |= 0x8000;
				while ((xop & 0x40000000) == 0) res++, xop <<= 1;
			}
			adsp->core.se.s = -res;
			break;
		case 0x0d<<11:
			/* EXP (HIX) */
			xop = SHIFT_GETXREG_SIGNED(adsp, xop) << 16;
			if (GET_V)
			{
				adsp->core.se.s = 1;
				if (xop < 0) CLR_SS;
				else SET_SS;
			}
			else
			{
				res = 0;
				if (xop < 0)
				{
					SET_SS;
					while ((xop & 0x40000000) != 0) res++, xop <<= 1;
				}
				else
				{
					CLR_SS;
					xop |= 0x8000;
					while ((xop & 0x40000000) == 0) res++, xop <<= 1;
				}
				adsp->core.se.s = -res;
			}
			break;
		case 0x0e<<11:
			/* EXP (LO) */
			if (adsp->core.se.s == -15)
			{
				xop = SHIFT_GETXREG_SIGNED(adsp, xop);
				res = 15;
				if (GET_SS)
					while ((xop & 0x8000) != 0) res++, xop <<= 1;
				else
				{
					xop = (xop << 1) | 1;
					while ((xop & 0x10000) == 0) res++, xop <<= 1;
				}
				adsp->core.se.s = -res;
			}
			break;
		case 0x0f<<11:
			/* EXPADJ */
			xop = SHIFT_GETXREG_SIGNED(adsp, xop) << 16;
			res = 0;
			if (xop < 0)
				while ((xop & 0x40000000) != 0) res++, xop <<= 1;
			else
			{
				xop |= 0x8000;
				while ((xop & 0x40000000) == 0) res++, xop <<= 1;
			}
			if (res < -adsp->core.sb.s)
				adsp->core.sb.s = -res;
			break;
	}
}



/*===========================================================================
    Immediate SHIFT operations (result in SR/SE/SB)
===========================================================================*/

static void shift_op_imm(adsp2100_state *adsp, int op)
{
	INT8 sc = (INT8)op;
	INT32 xop = (op >> 8) & 7;
	UINT32 res;

	switch (op & (15<<11))	/*JB*/
	{
		case 0x00<<11:
			/* LSHIFT (HI) */
			xop = SHIFT_GETXREG_UNSIGNED(adsp, xop) << 16;
			if (sc > 0) res = (sc < 32) ? (xop << sc) : 0;
			else res = (sc > -32) ? ((UINT32)xop >> -sc) : 0;
			adsp->core.sr.sr = res;
			break;
		case 0x01<<11:
			/* LSHIFT (HI, OR) */
			xop = SHIFT_GETXREG_UNSIGNED(adsp, xop) << 16;
			if (sc > 0) res = (sc < 32) ? (xop << sc) : 0;
			else res = (sc > -32) ? ((UINT32)xop >> -sc) : 0;
			adsp->core.sr.sr |= res;
			break;
		case 0x02<<11:
			/* LSHIFT (LO) */
			xop = SHIFT_GETXREG_UNSIGNED(adsp, xop);
			if (sc > 0) res = (sc < 32) ? (xop << sc) : 0;
			else res = (sc > -32) ? (xop >> -sc) : 0;
			adsp->core.sr.sr = res;
			break;
		case 0x03<<11:
			/* LSHIFT (LO, OR) */
			xop = SHIFT_GETXREG_UNSIGNED(adsp, xop);
			if (sc > 0) res = (sc < 32) ? (xop << sc) : 0;
			else res = (sc > -32) ? (xop >> -sc) : 0;
			adsp->core.sr.sr |= res;
			break;
		case 0x04<<11:
			/* ASHIFT (HI) */
			xop = SHIFT_GETXREG_SIGNED(adsp, xop) << 16;
			if (sc > 0) res = (sc < 32) ? (xop << sc) : 0;
			else res = (sc > -32) ? (xop >> -sc) : (xop >> 31);
			adsp->core.sr.sr = res;
			break;
		case 0x05<<11:
			/* ASHIFT (HI, OR) */
			xop = SHIFT_GETXREG_SIGNED(adsp, xop) << 16;
			if (sc > 0) res = (sc < 32) ? (xop << sc) : 0;
			else res = (sc > -32) ? (xop >> -sc) : (xop >> 31);
			adsp->core.sr.sr |= res;
			break;
		case 0x06<<11:
			/* ASHIFT (LO) */
			xop = SHIFT_GETXREG_SIGNED(adsp, xop);
			if (sc > 0) res = (sc < 32) ? (xop << sc) : 0;
			else res = (sc > -32) ? (xop >> -sc) : (xop >> 31);
			adsp->core.sr.sr = res;
			break;
		case 0x07<<11:
			/* ASHIFT (LO, OR) */
			xop = SHIFT_GETXREG_SIGNED(adsp, xop);
			if (sc > 0) res = (sc < 32) ? (xop << sc) : 0;
			else res = (sc > -32) ? (xop >> -sc) : (xop >> 31);
			adsp->core.sr.sr |= res;
			break;
		case 0x08<<11:
			/* NORM (HI) */
			xop = SHIFT_GETXREG_SIGNED(adsp, xop) << 16;
			if (sc > 0)
			{
				xop = ((UINT32)xop >> 1) | ((adsp->astat & CFLAG) << 28);
				res = xop >> (sc - 1);
			}
			else res = (sc > -32) ? (xop << -sc) : 0;
			adsp->core.sr.sr = res;
			break;
		case 0x09<<11:
			/* NORM (HI, OR) */
			xop = SHIFT_GETXREG_SIGNED(adsp, xop) << 16;
			if (sc > 0)
			{
				xop = ((UINT32)xop >> 1) | ((adsp->astat & CFLAG) << 28);
				res = xop >> (sc - 1);
			}
			else res = (sc > -32) ? (xop << -sc) : 0;
			adsp->core.sr.sr |= res;
			break;
		case 0x0a<<11:
			/* NORM (LO) */
			xop = SHIFT_GETXREG_UNSIGNED(adsp, xop);
			if (sc > 0) res = (sc < 32) ? (xop >> sc) : 0;
			else res = (sc > -32) ? (xop << -sc) : 0;
			adsp->core.sr.sr = res;
			break;
		case 0x0b<<11:
			/* NORM (LO, OR) */
			xop = SHIFT_GETXREG_UNSIGNED(adsp, xop);
			if (sc > 0) res = (sc < 32) ? (xop >> sc) : 0;
			else res = (sc > -32) ? (xop << -sc) : 0;
			adsp->core.sr.sr |= res;
			break;
	}
}
