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

    esrip.c

    Implementation of the Entertainment Sciences
    AM29116-based Real Time Image Processor

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

#include "debugger.h"
#include "deprecat.h"
#include "esrip.h"


/***************************************************************************
    CONSTANTS
***************************************************************************/

#define IPT_RAM_SIZE	(8192 * sizeof(UINT16))


/***************************************************************************
    MACROS
***************************************************************************/

#define RIP_PC		(cpustate->pc | ((cpustate->status_out & 1) << 8))
#define _BIT(x, n)	((x) & (1 << (n)))
#define RISING_EDGE(old_val, new_val, bit)	(!(old_val & (1 << bit)) && (new_val & (1 << bit)))

#define UNHANDLED	do {printf("%s:UNHANDLED (%x)\n", __FUNCTION__, inst); assert(0);} while (0)
#define INVALID		do {printf("%s:INVALID (%x)\n", __FUNCTION__, inst); assert(0);} while (0)

#define RAM_ADDR	(inst & 0x1f)
#define MODE		(inst & 0x8000)
#define WORD_MODE	(inst & 0x8000)
#define BYTE_MODE	(!WORD_MODE)
#define N			((inst >> 9) & 0xf)
#define OPCODE		((inst >> 5) & 0xf)
#define SRC			((inst >> 9) & 0xf)
#define	DST			(inst & 0x1f)	// TEST

#define BW_WORD		(1 << 15)
#define	BW_BYTE		(0 << 15)

#define FLAG_3		(1 << 7)
#define FLAG_2		(1 << 6)
#define FLAG_1		(1 << 5)
#define L_FLAG		(1 << 4)
#define	V_FLAG		(1 << 3)
#define	N_FLAG		(1 << 2)
#define	C_FLAG		(1 << 1)
#define	Z_FLAG		(1 << 0)

#define CLEAR_FLAGS(a)	(cpustate->new_status &= ~(a))
#define SET_FLAGS(a)	(cpustate->new_status |=  (a))


/***************************************************************************
    STRUCTURES & TYPEDEFS
***************************************************************************/

typedef struct
{
	UINT16	ram[32];
	UINT16	acc;
	UINT16	d_latch;
	UINT16	i_latch;
	UINT16	result;
	UINT8	new_status;
	UINT8	status;
	UINT16	inst;
	UINT8	immflag;
	UINT8	ct;
	UINT8	t;

	/* Instruction latches - current and previous values */
	UINT8	l1, pl1;
	UINT8	l2, pl2;
	UINT8	l3, pl3;
	UINT8	l4, pl4;
	UINT8	l5, pl5;
	UINT8	l6, pl6;
	UINT8	l7, pl7;

	UINT8	pc;
	UINT8	status_out;

	UINT8	x_scale;
	UINT8	y_scale;
	UINT8	img_bank;
	UINT8	line_latch;
	UINT16	fig_latch;
	UINT16	attr_latch;
	UINT16	adl_latch;
	UINT16	adr_latch;
	UINT16	iaddr_latch;
	UINT8	c_latch;

	UINT16	fdt_cnt;
	UINT16	ipt_cnt;

	UINT8	fig;
	UINT16	fig_cycles;

	UINT8	*optable;

	UINT16	*ipt_ram;
	UINT8	*lbrm;

	const	device_config *device;
	const	address_space *program;
	int		icount;

	read16_device_func	fdt_r;
	write16_device_func	fdt_w;
	UINT8 (*status_in)(running_machine *machine);
	int (*draw)(running_machine *machine, int l, int r, int fig, int attr, int addr, int col, int x_scale, int bank);
} esrip_state;


/***************************************************************************
    PUBLIC FUNCTIONS
***************************************************************************/

UINT8 get_rip_status(const device_config *cpu)
{
	esrip_state *cpustate = cpu->token;
	return cpustate->status_out;
}


/***************************************************************************
    INITIALIZATION AND SHUTDOWN
***************************************************************************/

enum ops
{
	ROTR1, TOR1, ROTR2, ROTC, ROTM, BOR2, CRCF, CRCR,
	SVSTR, PRT, SOR, TOR2, SHFTR, TEST, NOP, SETST, RSTST,
	ROTNR, BONR, BOR1, SONR, SHFTNR, PRTNR, TONR
};

static void make_ops(esrip_state *cpustate)
{
	int inst;

	for (inst = 0; inst < 65536; ++inst)
	{
		int quad = (inst >> 13) & 3;

		if (quad == 0)
		{
			if (((inst >> 5) & 0xc) == 0xc)
				cpustate->optable[inst] = ROTR1;
			else
				cpustate->optable[inst] = TOR1;
		}
		else if (quad == 1)
		{
			if (OPCODE < 2)
				cpustate->optable[inst] = ROTR2;
			else if (OPCODE < 6)
				cpustate->optable[inst] = ROTC;
			else
				cpustate->optable[inst] = ROTM;
		}
		else if (quad == 2)
		{
			if (OPCODE > 11)
				cpustate->optable[inst] = BOR2;
			else
			{
				int tmp = (inst >> 5) & 0xff;

				if (tmp == 0x63)
					cpustate->optable[inst] = CRCF;
				else if (tmp == 0x69)
					cpustate->optable[inst] = CRCR;
				else if (tmp == 0x7a)
					cpustate->optable[inst] = SVSTR;
				else
				{
					if ((SRC > 7) && (SRC < 12))
						cpustate->optable[inst] = PRT;
					else if (SRC > 11)
						cpustate->optable[inst] = SOR;
					else if (SRC < 6)
						cpustate->optable[inst] = TOR2;
					else
						cpustate->optable[inst] = SHFTR;
				}
			}
		}
		else
		{
			if (inst == 0x7140)
				cpustate->optable[inst] = NOP;
			else
			{
				int x = (inst & 0xffe0);
				if (x == 0x7340)
					cpustate->optable[inst] = TEST;
				else if (x == 0x7740)
					cpustate->optable[inst] = SETST;
				else if (x == 0x7540)
					cpustate->optable[inst] = RSTST;
				else
				{
					int op = OPCODE;
					if (op == 0xc)
					{
						if ((inst & 0x18) == 0x18)
							cpustate->optable[inst] = ROTNR;
						else
							cpustate->optable[inst] = BONR;
					}
					else if ((op & 0xc) == 0xc)
						cpustate->optable[inst] = BOR1;
					else
					{
						int src = SRC;

						if ((src & 0xc) == 0xc)
							cpustate->optable[inst] = SONR;
						else if ((src & 0x6) == 0x6)
							cpustate->optable[inst] = SHFTNR;
						else if (src & 0x8)
							cpustate->optable[inst] = PRTNR;
						else
							cpustate->optable[inst] = TONR;
					}
				}
			}
		}
	}
}

static CPU_INIT( esrip )
{
	esrip_state *cpustate = device->token;
	esrip_config* _config = (esrip_config*)device->static_config;

	memset(cpustate, 0, sizeof(cpustate));

	/* Register configuration structure callbacks */
	cpustate->fdt_r = _config->fdt_r;
	cpustate->fdt_w = _config->fdt_w;
	cpustate->lbrm = (UINT8*)memory_region(device->machine, _config->lbrm_prom);
	cpustate->status_in = _config->status_in;
	cpustate->draw = _config->draw;

	/* Allocate image pointer table RAM */
	cpustate->ipt_ram = auto_malloc(IPT_RAM_SIZE);

	cpustate->device = device;
	cpustate->program = memory_find_address_space(device, ADDRESS_SPACE_PROGRAM);

	/* Create the instruction decode lookup table */
	cpustate->optable = auto_malloc(65536);
	make_ops(cpustate);

	/* Register stuff for state saving */
	state_save_register_device_item(device, 0, cpustate->acc);
	state_save_register_device_item_array(device, 0, cpustate->ram);
	state_save_register_device_item(device, 0, cpustate->d_latch);
	state_save_register_device_item(device, 0, cpustate->i_latch);
	state_save_register_device_item(device, 0, cpustate->result);
	state_save_register_device_item(device, 0, cpustate->new_status);
	state_save_register_device_item(device, 0, cpustate->status);
	state_save_register_device_item(device, 0, cpustate->inst);
	state_save_register_device_item(device, 0, cpustate->immflag);
	state_save_register_device_item(device, 0, cpustate->ct);
	state_save_register_device_item(device, 0, cpustate->t);
	state_save_register_device_item(device, 0, cpustate->l1);
	state_save_register_device_item(device, 0, cpustate->l2);
	state_save_register_device_item(device, 0, cpustate->l3);
	state_save_register_device_item(device, 0, cpustate->l4);
	state_save_register_device_item(device, 0, cpustate->l5);
	state_save_register_device_item(device, 0, cpustate->l6);
	state_save_register_device_item(device, 0, cpustate->l7);
	state_save_register_device_item(device, 0, cpustate->pl1);
	state_save_register_device_item(device, 0, cpustate->pl2);
	state_save_register_device_item(device, 0, cpustate->pl3);
	state_save_register_device_item(device, 0, cpustate->pl4);
	state_save_register_device_item(device, 0, cpustate->pl5);
	state_save_register_device_item(device, 0, cpustate->pl6);
	state_save_register_device_item(device, 0, cpustate->pl7);
	state_save_register_device_item(device, 0, cpustate->pc);
	state_save_register_device_item(device, 0, cpustate->status_out);
	state_save_register_device_item(device, 0, cpustate->x_scale);
	state_save_register_device_item(device, 0, cpustate->y_scale);
	state_save_register_device_item(device, 0, cpustate->img_bank);
	state_save_register_device_item(device, 0, cpustate->line_latch);
	state_save_register_device_item(device, 0, cpustate->fig_latch);
	state_save_register_device_item(device, 0, cpustate->attr_latch);
	state_save_register_device_item(device, 0, cpustate->adl_latch);
	state_save_register_device_item(device, 0, cpustate->adr_latch);
	state_save_register_device_item(device, 0, cpustate->iaddr_latch);
	state_save_register_device_item(device, 0, cpustate->c_latch);
	state_save_register_device_item(device, 0, cpustate->fdt_cnt);
	state_save_register_device_item(device, 0, cpustate->ipt_cnt);
	state_save_register_device_item(device, 0, cpustate->fig);
	state_save_register_device_item(device, 0, cpustate->fig_cycles);
	state_save_register_device_item_pointer(device, 0, cpustate->ipt_ram, IPT_RAM_SIZE / sizeof(UINT16));
}


static CPU_RESET( esrip )
{
	esrip_state *cpustate = device->token;

	cpustate->pc = 0;

	cpustate->pl1 = 0xff;
	cpustate->pl2 = 0xff;
	cpustate->pl3 = 0xff;
	cpustate->pl4 = 0xff;
	cpustate->pl5 = 0xff;
	cpustate->pl6 = 0xff;
	cpustate->pl7 = 0xff;

	cpustate->l1 = 0xff;
	cpustate->l2 = 0xff;
	cpustate->l3 = 0xff;
	cpustate->l4 = 0xff;
	cpustate->l5 = 0xff;
	cpustate->l6 = 0xff;
	cpustate->l7 = 0xff;

	cpustate->status_out = 0;
	cpustate->immflag = 0;
}


static CPU_EXIT( esrip )
{

}


/***************************************************************************
    PRIVATE FUNCTIONS
***************************************************************************/

static int get_hblank(running_machine *machine)
{
	return video_screen_get_hblank(machine->primary_screen);
}

/* Return the state of the LBRM line (Y-scaling related) */
static int get_lbrm(esrip_state *cpustate)
{
	int addr = ((cpustate->y_scale & 0x3f) << 3) | ((cpustate->line_latch >> 3) & 7);
	int sel = (cpustate->line_latch & 7);

	UINT8 val = cpustate->lbrm[addr];

	return (val >> sel) & 1;
}

INLINE int check_jmp(esrip_state *cpustate, running_machine *machine, UINT8 jmp_ctrl)
{
	int ret = 0;

	if (~jmp_ctrl & 0x10)
	{
		switch (jmp_ctrl & 7)
		{
			/* CT */      case 0: ret = cpustate->ct;         break;
			/* T1 */      case 4: ret = BIT(cpustate->t, 0);  break;
			/* T2 */      case 2: ret = BIT(cpustate->t, 1);  break;
			/* T3 */      case 6: ret = BIT(cpustate->t, 2);  break;
			/* T4 */      case 1: ret = BIT(cpustate->t, 3);  break;
			/* /LBRM */   case 5: ret = !get_lbrm(cpustate);  break;
			/* /HBLANK */ case 3: ret = !get_hblank(machine); break;
			/* JMP */     case 7: ret = 0;                    break;
		}

		ret ^= 1;
	}
	else if (~jmp_ctrl & 0x08)
	{
		switch (jmp_ctrl & 7)
		{
			/* CT */      case 0: ret = cpustate->ct;        break;
			/* T1 */      case 4: ret = BIT(cpustate->t, 0); break;
			/* T2 */      case 2: ret = BIT(cpustate->t, 1); break;
			/* T3 */      case 6: ret = BIT(cpustate->t, 2); break;
			/* T4 */      case 1: ret = BIT(cpustate->t, 3); break;
			/* /LBRM */   case 5: ret = !get_lbrm(cpustate); break;
			/* /FIG */    case 3: ret = !cpustate->fig;      break;
			/* JMP */     case 7: ret = 1;                   break;
		}
	}
	else
		assert(!"RIP: Invalid jump control");

	return ret;
}


INLINE void calc_z_flag(esrip_state *cpustate, UINT16 res)
{
	cpustate->new_status &= ~Z_FLAG;
	cpustate->new_status |= (res == 0);
}

INLINE void calc_c_flag_add(esrip_state *cpustate, UINT16 a, UINT16 b)
{
	cpustate->new_status &= ~C_FLAG;
	cpustate->new_status |= ((UINT16)(b) > (UINT16)(~(a))) ? 2 : 0;
}

INLINE void calc_c_flag_sub(esrip_state *cpustate, UINT16 a, UINT16 b)
{
	cpustate->new_status &= ~C_FLAG;
	cpustate->new_status |= ((UINT16)(b) <= (UINT16)(a)) ? 2 : 0;
}

INLINE void calc_n_flag(esrip_state *cpustate, UINT16 res)
{
	cpustate->new_status &= ~N_FLAG;
	cpustate->new_status |= (res & 0x8000) ? 4 : 0;
}

INLINE void calc_v_flag_add(esrip_state *cpustate, UINT16 a, UINT16 b, UINT32 r)
{
	cpustate->new_status &= ~V_FLAG;
	cpustate->new_status |= ((a ^ r) & (b ^ r) & 0x8000) ? 8 : 0;
}

INLINE void calc_v_flag_sub(esrip_state *cpustate, UINT16 a, UINT16 b, UINT32 r)
{
	cpustate->new_status &= ~V_FLAG;
	cpustate->new_status |= ((a ^ b) & (r ^ b) & 0x8000) ? 8 : 0;
}


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

enum
{
	ACC,
	Y_BUS,
	STATUS,
	RAM,
};

/*************************************
 *
 *  Single operand
 *
 *************************************/
enum
{
	MOVE = 0xc,
	COMP = 0xd,
	INC  = 0xe,
	NEG  = 0xf
};

enum
{
	SORA  = 0x0,
	SORY  = 0x2,
	SORS  = 0x3,
	SOAR  = 0x4,
	SODR  = 0x6,
	SOIR  = 0x7,
	SOZR  = 0x8,
	SOZER = 0x9,
	SOSER = 0xa,
	SORR  = 0xb
};

static UINT16 sor_op(esrip_state *cpustate, UINT16 r, UINT16 opcode)
{
	UINT32 res = 0;

	switch (opcode)
	{
		case MOVE:
		{
			res = r;
			CLEAR_FLAGS(V_FLAG | C_FLAG);
			calc_n_flag(cpustate, res);
			calc_z_flag(cpustate, res);
			break;
		}
		case COMP:
		{
			res = r ^ 0xffff;
			CLEAR_FLAGS(V_FLAG | C_FLAG);
			calc_n_flag(cpustate, res);
			calc_z_flag(cpustate, res);
			break;
		}
		case INC:
		{
			res = r + 1;
			calc_v_flag_add(cpustate, r, 1, res);
			calc_n_flag(cpustate, res);
			calc_c_flag_add(cpustate, r, 1);
			calc_z_flag(cpustate, res);
			break;
		}
		case NEG:
		{
			res = (r ^ 0xffff) + 1;
			calc_v_flag_sub(cpustate, 0, r, res);
			calc_n_flag(cpustate, res);
			calc_c_flag_sub(cpustate, 0, r);
			calc_z_flag(cpustate, res);
			break;
		}
		default: assert(0);
	}

	return res & 0xffff;
}

static void sor(esrip_state *cpustate, UINT16 inst)
{
	UINT16	r = 0;
	UINT16	dst = 0;
	UINT16	res = 0;

	if (BYTE_MODE)
	{
		printf("Byte Mode! %.4x\n", inst);
		UNHANDLED;
	}

	switch ((inst >> 5) & 0xf)
	{
		case SORA: r = cpustate->ram[RAM_ADDR];		dst = ACC;		break;
		case SORY: r = cpustate->ram[RAM_ADDR];		dst = Y_BUS;	break;
		case SORS: r = cpustate->ram[RAM_ADDR];		dst = STATUS;	break;
		case SOAR: r = cpustate->acc;				dst = RAM;		break;
		case SODR: r = cpustate->d_latch;			dst = RAM;		break;
		case SOIR:
		{
			if (cpustate->immflag == 0)		// Macrofiy this?
			{
				cpustate->i_latch = inst;
				cpustate->immflag = 1;
				return;
			}
			else
			{
				r = cpustate->inst;
				dst = RAM;
				cpustate->immflag = 0;
			}
			break;
		}
		case SOZR: r = 0;						dst = RAM;		break;
		case SORR: r = cpustate->ram[RAM_ADDR];	dst = RAM;		break;
		default: UNHANDLED;
	}

	/* Operation */
	res = sor_op(cpustate, r, (inst >> 9) & 0xf);

	switch (dst)
	{
		case Y_BUS: break;
		case ACC: cpustate->acc = res; break;
		case RAM: cpustate->ram[RAM_ADDR] = res; break;
		default: UNHANDLED;
	}

	cpustate->result = res;
}

enum
{
	SOA  = 0x4,
	SOD  = 0x6,
	SOI  = 0x7,
	SOZ  = 0x8,
	SOZE = 0x9,
	SOSE = 0xa,
};

enum
{
	NRY  = 0,
	NRA  = 1,
	NRS  = 4,
	NRAS = 5,
};

static void sonr(esrip_state *cpustate, UINT16 inst)
{
	UINT16	r = 0;
	UINT16	res = 0;

	switch ((inst >> 5) & 0xf)
	{
		case SOA:	r = cpustate->acc;		break;
		case SOD:	r = cpustate->d_latch;	break;
		case SOI:
		{
			if (cpustate->immflag == 0)
			{
				cpustate->i_latch = inst;
				cpustate->immflag = 1;
				return;
			}
			else
			{
				r = cpustate->inst;
				cpustate->immflag = 0;
			}
			break;
		}
		case SOZ:	r = 0; break;
		default: INVALID;
	}

	/* Operation */
	res = sor_op(cpustate, r, (inst >> 9) & 0xf);

	/* Destination */
	switch (inst & 0x1f)
	{
		case NRY: break;
		case NRA: cpustate->acc = res; break;
		default: UNHANDLED;
	}

	cpustate->result = res;
}

/*************************************
 *
 *  Two operand
 *
 *************************************/

enum
{
	SUBR  = 0x0,
	SUBRC = 0x1,
	SUBS  = 0x2,
	SUBSC = 0x3,
	ADD   = 0x4,
	ADDC  = 0x5,
	AND   = 0x6,
	NAND  = 0x7,
	EXOR  = 0x8,
	NOR   = 0x9,
	OR    = 0xa,
	EXNOR = 0xb
};

static UINT16 tor_op(esrip_state *cpustate, UINT16 r, UINT16 s, int opcode)
{
	UINT32 res = 0;

	switch (opcode)
	{
		case SUBR:
		{
			res = s - r;
			calc_v_flag_sub(cpustate, s, r, res);
			calc_n_flag(cpustate, res);
			calc_c_flag_sub(cpustate, s, r);
			calc_z_flag(cpustate, res);
			break;
		}
		case SUBRC: assert(0); break;
		case SUBS:
		{
			res = r - s;
			calc_v_flag_sub(cpustate, r, s, res);
			calc_n_flag(cpustate, res);
			calc_c_flag_sub(cpustate, r, s);
			calc_z_flag(cpustate, res);
			break;
		}
		case SUBSC: assert(0); break;
		case ADD:
		{
			res = r + s;
			calc_v_flag_add(cpustate, r, s, res);
			calc_n_flag(cpustate, res);
			calc_c_flag_add(cpustate, r, s);
			calc_z_flag(cpustate, res);
			break;
		}
		case ADDC:
		{
			// TODO TODO CHECK ME ETC
			res = r + s + ((cpustate->status >> 1) & 1);
			calc_v_flag_add(cpustate, r, s, res);
			calc_n_flag(cpustate, res);
			calc_c_flag_add(cpustate, r, s);
			calc_z_flag(cpustate, res);
			break;
		}
		case AND:
		{
			res = r & s;
			CLEAR_FLAGS(V_FLAG | C_FLAG);
			calc_n_flag(cpustate, res);
			calc_z_flag(cpustate, res);
			break;
		}
		case NAND:
		{
			res = (r & s) ^ 0xffff;
			CLEAR_FLAGS(V_FLAG | C_FLAG);
			calc_n_flag(cpustate, res);
			calc_z_flag(cpustate, res);
			break;
		}
		case EXOR:
		{
			res = r ^ s;
			CLEAR_FLAGS(V_FLAG | C_FLAG);
			calc_n_flag(cpustate, res);
			calc_z_flag(cpustate, res);
			break;
		}
		case NOR:
		{
			res = (r | s) ^ 0xffff;
			CLEAR_FLAGS(V_FLAG | C_FLAG);
			calc_n_flag(cpustate, res);
			calc_z_flag(cpustate, res);
			break;
		}
		case OR:
		{
			res = r | s;
			CLEAR_FLAGS(V_FLAG | C_FLAG);
			calc_n_flag(cpustate, res);
			calc_z_flag(cpustate, res);
			break;
		}
		case EXNOR:
		{
			res = (r ^ s) ^ 0xffff;
			CLEAR_FLAGS(V_FLAG | N_FLAG | C_FLAG);
			calc_z_flag(cpustate, res);
			break;
		}
		default: assert(0);
	}

	return res & 0xffff;
}

static void tor1(esrip_state *cpustate, UINT16 inst)
{
	UINT16 r = 0;
	UINT16 s = 0;
	UINT16 dst = 0;
	UINT16	res = 0;

	enum
	{
		TORAA = 0x0,
		TORIA = 0x2,
		TODRA = 0x3,
		TORAY = 0x8,
		TORIY = 0xa,
		TODRY = 0xb,
		TORAR = 0xc,
		TORIR = 0xe,
		TODRR = 0xf,
	};

	switch (SRC)
	{
		case TORAA: r = cpustate->ram[RAM_ADDR];	s = cpustate->acc;	dst = ACC;	break;
		case TORIA:
		{
			if (cpustate->immflag == 0)
			{
				cpustate->i_latch = inst;
				cpustate->immflag = 1;
				return;
			}
			else
			{
				r = cpustate->ram[RAM_ADDR];
				s = cpustate->inst;
				dst = ACC;
				cpustate->immflag = 0;
			}
			break;
		}
		case TODRA: r = cpustate->d_latch;		s = cpustate->ram[RAM_ADDR];	dst = ACC;	break;
		case TORAY: r = cpustate->ram[RAM_ADDR];	s = cpustate->acc;			dst = Y_BUS;break;
		case TORIY:
		{
			if (cpustate->immflag == 0)
			{
				cpustate->i_latch = inst;
				cpustate->immflag = 1;
				return;
			}
			else
			{
				r = cpustate->ram[RAM_ADDR];
				s = cpustate->inst;
				dst = Y_BUS;
				cpustate->immflag = 0;
			}
			break;
		}
		case TODRY: r = cpustate->d_latch;		s = cpustate->ram[RAM_ADDR];	dst = Y_BUS;break;
		case TORAR: r = cpustate->ram[RAM_ADDR];	s = cpustate->acc;			dst = RAM;	break;
		case TORIR:
		{
			if (cpustate->immflag == 0)
			{
				cpustate->i_latch = inst;
				cpustate->immflag = 1;
				return;
			}
			else
			{
				r = cpustate->ram[RAM_ADDR];
				s = cpustate->inst;
				dst = RAM;
				cpustate->immflag = 0;
			}
			break;
		}
		case TODRR: r = cpustate->d_latch;		s = cpustate->ram[RAM_ADDR];	dst = RAM;	break;
		default: INVALID;
	}

	/* Operation */
	res = tor_op(cpustate, r, s, (inst >> 5) & 0xf);

	/* Destination */
	switch (dst)
	{
		case ACC:	cpustate->acc = res; break;
		case Y_BUS:	break;
		case RAM:	cpustate->ram[RAM_ADDR] = res; break;
		default:	INVALID;
	}

	cpustate->result = res;
}

static void tor2(esrip_state *cpustate, UINT16 inst)
{
	UINT16 r = 0;
	UINT16 s = 0;
	UINT32 res = 0;

	enum
	{
		TODAR = 0x1,
		TOAIR = 0x2,
		TODIR = 0x5,
	};

	switch (SRC)
	{
		case TODAR: r = cpustate->d_latch;	s = cpustate->acc;	break;
		case TOAIR:
		{
			if (cpustate->immflag == 0)
			{
				cpustate->i_latch = inst;
				cpustate->immflag = 1;
				return;
			}
			else
			{
				r = cpustate->acc;
				s = cpustate->inst;
				cpustate->immflag = 0;
			}
			break;
		}
		case TODIR:
		{
			if (cpustate->immflag == 0)
			{
				cpustate->i_latch = inst;
				cpustate->immflag = 1;
				return;
			}
			else
			{
				r = cpustate->d_latch;
				s = cpustate->inst;
				cpustate->immflag = 0;
			}
			break;
		}
		default: INVALID;
	}

	/* Operation */
	res = tor_op(cpustate, r, s, (inst >> 5) & 0xf);

	/* Destination is always RAM */
	cpustate->ram[RAM_ADDR] = res;

	cpustate->result = res;
}

static void tonr(esrip_state *cpustate, UINT16 inst)
{
	enum
	{
		TODA  = 0x1,
		TOAI  = 0x2,
		TODI  = 0x5
	};

	enum
	{
		NRY = 0,
		NRA = 1,
		NRS = 4,
		NRAS = 5,
	};

	UINT16 r = 0;
	UINT16 s = 0;
	UINT16	res = 0;

	switch (SRC)
	{
		case TODA:
		{
			r = cpustate->d_latch;
			s = cpustate->acc;
			break;
		}
		case TOAI:
		{
			break;
		}
		case TODI:
		{
			if (cpustate->immflag == 0)
			{
				cpustate->i_latch = inst;
				cpustate->immflag = 1;
				return;
			}
			else
			{
				r = cpustate->d_latch;
				s = cpustate->inst;
				cpustate->immflag = 0;
			}
			break;
		}
		default: INVALID;
	}

	/* Operation */
	res = tor_op(cpustate, r, s, (inst >> 5) & 0xf);

	/* Destination */
	switch (DST)
	{
		case NRY:
			break;
		case NRA:
			cpustate->acc = res;
			break;
		case NRS:
			UNHANDLED;
			break;
		case NRAS:
			UNHANDLED;
			break;
		default:
			INVALID;
	}
	cpustate->result = res;
}

/*************************************
 *
 *  Bit operation
 *
 *************************************/

static void bonr(esrip_state *cpustate, UINT16 inst)
{
	enum
	{
		TSTNA  = 0x00,
		RSTNA  = 0x01,
		SETNA  = 0x02,
		A2NA   = 0x04,
		S2NA   = 0x05,
		LD2NA  = 0x06,
		LDC2NA = 0x07,
		TSTND  = 0x10,
		RSTND  = 0x11,
		SETND  = 0x12,
		A2NDY  = 0x14,
		S2NDY  = 0x15,
		LD2NY  = 0x16,
		LDC2NY = 0x17,
	};

	UINT16	res = 0;

	switch (inst & 0x1f)
	{
		case TSTNA:
		{
			res = cpustate->acc & (1 << N);
			CLEAR_FLAGS(V_FLAG | C_FLAG);
			calc_n_flag(cpustate, res);
			calc_z_flag(cpustate, res);
			break;
		}
		case RSTNA:
		{
			res = cpustate->acc & ~(1 << N);
			CLEAR_FLAGS(V_FLAG | C_FLAG);
			calc_n_flag(cpustate, res);
			calc_z_flag(cpustate, res);
			cpustate->acc = res;
			break;
		}
		case SETNA:
		{
			res = cpustate->acc | (1 << N);
			CLEAR_FLAGS(V_FLAG | C_FLAG | Z_FLAG);
			calc_n_flag(cpustate, res);
			cpustate->acc = res;
			break;
		}
		case A2NA:
		{
			UINT16 r = cpustate->acc;
			UINT16 s = 1 << N;
			res = r + s;
			calc_z_flag(cpustate, res);
			calc_n_flag(cpustate, res);
			calc_c_flag_add(cpustate, r, s);
			calc_v_flag_add(cpustate, r, s, res);
			cpustate->acc = res;
			break;
		}
		case S2NA:
		{
			UINT16 r = cpustate->acc;
			UINT16 s = 1 << N;
			res = r - s;
			calc_z_flag(cpustate, res);
			calc_n_flag(cpustate, res);
			calc_c_flag_sub(cpustate, r, s);
			calc_v_flag_sub(cpustate, r, s, res);
			cpustate->acc = res;
			break;
		}

		case TSTND:
		{
			res = cpustate->d_latch & (1 << N);
			CLEAR_FLAGS(V_FLAG | C_FLAG);
			calc_n_flag(cpustate, res);
			calc_z_flag(cpustate, res);
			break;
		}

		case SETND:
		{
			UINT16 r = cpustate->d_latch;
			res = r | (1 << N);
			cpustate->d_latch = res;

			CLEAR_FLAGS(V_FLAG | C_FLAG | Z_FLAG);
			calc_n_flag(cpustate, res);
			break;
		}
		case LD2NY:
		{
			res = (1 << N);
			CLEAR_FLAGS(V_FLAG | C_FLAG | Z_FLAG);
			calc_n_flag(cpustate, res);
			break;
		}
		case LDC2NY:
		{
			res = (1 << N) ^ 0xffff;
			CLEAR_FLAGS(Z_FLAG | C_FLAG | V_FLAG);
			calc_n_flag(cpustate, res);
			break;
		}

		case A2NDY:
		{
			UINT16 r = cpustate->d_latch;
			UINT16 s = 1 << N;
			res = r + s;

			calc_z_flag(cpustate, res);
			calc_n_flag(cpustate, res);
			calc_c_flag_add(cpustate, r, s);
			calc_v_flag_add(cpustate, r, s, res);
			break;
		}

		default:
			UNHANDLED;
	}

	cpustate->result = res;
}

static void bor1(esrip_state *cpustate, UINT16 inst)
{
	enum
	{
		SETNR  = 0xd,
		RSTNR  = 0xe,
		TSTNR  = 0xf,
	};

	UINT16	res = 0;

	switch ((inst >> 5) & 0xf)
	{
		case SETNR:
		{
			res = cpustate->ram[RAM_ADDR] | (1 << N);
			cpustate->ram[RAM_ADDR] = res;
			CLEAR_FLAGS(V_FLAG | C_FLAG | Z_FLAG);
			calc_n_flag(cpustate, res);
			break;
		}
		case RSTNR:
		{
			res = cpustate->ram[RAM_ADDR] & ~(1 << N);
			cpustate->ram[RAM_ADDR] = res;
			CLEAR_FLAGS(V_FLAG | C_FLAG);
			calc_n_flag(cpustate, res);
			calc_z_flag(cpustate, res);
			break;
		}
		case TSTNR:
		{
			res = cpustate->ram[RAM_ADDR] & (1 << N);
			CLEAR_FLAGS(V_FLAG | C_FLAG);
			calc_n_flag(cpustate, res);
			calc_z_flag(cpustate, res);
			break;
		}
		default: INVALID;
	}

	cpustate->result = res;
}



static void bor2(esrip_state *cpustate, UINT16 inst)
{
	enum
	{
		LD2NR  = 0xc,
		LDC2NR = 0xd,
		A2NR   = 0xe,
		S2NR   = 0xf,
	};

	UINT32 res = 0;

	switch ((inst >> 5) & 0xf)
	{
		case LD2NR:
		{
			res = 1 << N;
			CLEAR_FLAGS(V_FLAG | C_FLAG | Z_FLAG);
			calc_n_flag(cpustate, res);
			break;
		}
		case LDC2NR:
		{
			res = (1 << N) ^ 0xffff;
			CLEAR_FLAGS(V_FLAG | C_FLAG | Z_FLAG);
			calc_n_flag(cpustate, res);
			break;
		}
		case A2NR:
		{
			UINT16 r = cpustate->ram[RAM_ADDR];
			UINT16 s = 1 << N;

			res = r + s;
			calc_v_flag_add(cpustate, r, s, res);
			calc_n_flag(cpustate, res);
			calc_c_flag_add(cpustate, r, s);
			calc_z_flag(cpustate, res);
			break;
		}
		case S2NR:
		{
			UINT16 r = cpustate->ram[RAM_ADDR];
			UINT16 s = 1 << N;

			res = r - s;
			calc_v_flag_sub(cpustate, r, s, res);
			calc_n_flag(cpustate, res);
			calc_c_flag_sub(cpustate, r, s);
			calc_z_flag(cpustate, res);
			break;
		}
		default: INVALID;
	}

	/* Destination is RAM */
	cpustate->ram[RAM_ADDR] = res;
	cpustate->result = res;
}

/*************************************
 *
 *  Rotate
 *
 *************************************/

/* TODO Combine these */
static void rotr1(esrip_state *cpustate, UINT16 inst)
{
	enum
	{
		RTRA = 0xc,
		RTRY = 0xd,
		RTRR = 0xf,
	};

	UINT16	u = 0;
	UINT16	dst = 0;
	UINT16	res = 0;
	int		n = N;

	switch ((inst >> 5) & 0xf)
	{
		case RTRA: u = cpustate->ram[RAM_ADDR];	dst = ACC;		break;
		case RTRY: u = cpustate->ram[RAM_ADDR];	dst = Y_BUS;	break;
		case RTRR: u = cpustate->ram[RAM_ADDR];	dst = RAM;		break;
		default: INVALID;
	}

	res = (u << n) | (u >> (16 - n));
	CLEAR_FLAGS(V_FLAG | C_FLAG);
	calc_n_flag(cpustate, res);
	calc_z_flag(cpustate, res);

	switch (dst)
	{
		case ACC: cpustate->acc = res; break;
		case RAM: cpustate->ram[RAM_ADDR] = res; break;
	}

	cpustate->result = res;
}

static void rotr2(esrip_state *cpustate, UINT16 inst)
{
	enum
	{
		RTAR = 0,
		RTDR = 1,
	};

	UINT16	u = 0;
	UINT16	res = 0;

	switch ((inst >> 5) & 0xf)
	{
		case RTAR: u = cpustate->acc;		break;
		case RTDR: u = cpustate->d_latch;	break;
		default: INVALID;
	}

	res = (u << N) | (u >> (16 - N));
	CLEAR_FLAGS(V_FLAG | C_FLAG);
	calc_n_flag(cpustate, res);
	calc_z_flag(cpustate, res);
	cpustate->ram[RAM_ADDR] = res;

	cpustate->result = res;
}

static void rotnr(esrip_state *cpustate, UINT16 inst)
{
	enum
	{
		RTDY = 0x18,
		RTDA = 0x19,
		RTAY = 0x1c,
		RTAA = 0x1d,
	};

	UINT16	u = 0;
	UINT16	res = 0;
	UINT16	dst = 0;

	switch (inst & 0x1f)
	{
		case RTDY: u = cpustate->d_latch;	dst = Y_BUS;	break;
		case RTDA: u = cpustate->d_latch;	dst = ACC;		break;
		case RTAY: u = cpustate->acc;		dst = Y_BUS;	break;
		case RTAA: u = cpustate->acc;		dst = ACC;		break;
		default: INVALID;
	}

	res = (u << N) | (u >> (16 - N));
	CLEAR_FLAGS(V_FLAG | C_FLAG);
	calc_n_flag(cpustate, res);
	calc_z_flag(cpustate, res);

	switch (dst)
	{
		case Y_BUS: break;
		case ACC: cpustate->acc = res; break;
		case RAM: cpustate->ram[RAM_ADDR] = res; break;
		default: UNHANDLED;
	}

	cpustate->result = res;
}

/*************************************
 *
 *  Rotate and compare
 *
 *************************************/

static void rotc(esrip_state *cpustate, UINT16 inst)
{
	UNHANDLED;
}

/*************************************
 *
 *  Rotate and merge
 *
 *************************************/

static void rotm(esrip_state *cpustate, UINT16 inst)
{
	UNHANDLED;
}

/*************************************
 *
 *  Prioritize
 *
 *************************************/

static void prt(esrip_state *cpustate, UINT16 inst)
{
	UNHANDLED;
}

static void prtnr(esrip_state *cpustate, UINT16 inst)
{
	UNHANDLED;
}


/*************************************
 *
 *  CRC
 *
 *************************************/

static void crcf(esrip_state *cpustate, UINT16 inst)
{
	UNHANDLED;
}

static void crcr(esrip_state *cpustate, UINT16 inst)
{
	UNHANDLED;
}

/*************************************
 *
 *  Single bit shift
 *
 *************************************/

enum
{
	SHUPZ  = 0,
	SHUP1  = 1,
	SHUPL  = 2,
	SHDNZ  = 4,
	SHDN1  = 5,
	SHDNL  = 6,
	SHDNC  = 7,
	SHDNOV = 8,
};

#define	SET_LINK_flag(cpustate, x)	(cpustate->new_status &= ~L_FLAG); \
							(cpustate->new_status |= x ? L_FLAG : 0)

static UINT16 shift_op(esrip_state *cpustate, UINT16 u, int opcode)
{
	UINT32 res = 0;

	switch (opcode)
	{
		case SHUPZ:
		{
			res = (u << 1);
			SET_LINK_flag(cpustate, u & 0x8000);
			CLEAR_FLAGS(V_FLAG | C_FLAG);
			calc_n_flag(cpustate, res);
			calc_z_flag(cpustate, res);
			break;
		}
		case SHUP1:
		{
			res = (u << 1) | 1;
			SET_LINK_flag(cpustate, u & 0x8000);
			CLEAR_FLAGS(V_FLAG | C_FLAG);
			calc_n_flag(cpustate, res);
			calc_z_flag(cpustate, res);
			break;
		}
		case SHUPL:
		{
			res = (u << 1) | ((cpustate->status & L_FLAG) ? 1 : 0);
			SET_LINK_flag(cpustate, u & 0x8000);
			CLEAR_FLAGS(V_FLAG | C_FLAG);
			calc_n_flag(cpustate, res);
			calc_z_flag(cpustate, res);
			break;
		}

		case SHDNZ:
		case SHDN1:
		case SHDNL:
		case SHDNC:
		case SHDNOV:
		default: assert(0);
	}

	return res;
}

static void shftr(esrip_state *cpustate, UINT16 inst)
{
	enum
	{
		SHRR = 6,
		SHDR = 7,
	};

	UINT16	u = 0;
	UINT16	res = 0;

	switch ((inst >> 9) & 0xf)
	{
		case SHRR: u = cpustate->ram[RAM_ADDR];	break;
		case SHDR: u = cpustate->d_latch;			break;
		default: INVALID;
	}

	res = shift_op(cpustate, u, (inst >> 5) & 0xf);

	/* Destination is always RAM */
	cpustate->ram[RAM_ADDR] = res;
	cpustate->result = res;
}

static void shftnr(esrip_state *cpustate, UINT16 inst)
{
	enum
	{
		SHA = 6,
		SHD = 7,
	};

	UINT16	u = 0;
	UINT16	res = 0;

	switch ((inst >> 9) & 0xf)
	{
		case SHA: u = cpustate->acc;			break;
		case SHD: u = cpustate->d_latch;		break;
		default: INVALID;
	}

	res = shift_op(cpustate, u, (inst >> 5) & 0xf);

	switch (DST)
	{
		case NRY:	break;
		case NRA:	cpustate->acc = res; break;
		default:	INVALID;
	}
	cpustate->result = res;
}


/*************************************
 *
 *  Status
 *
 *************************************/

static void svstr(esrip_state *cpustate, UINT16 inst)
{
	UNHANDLED;
}

static void rstst(esrip_state *cpustate, UINT16 inst)
{
	enum
	{
		RONCZ = 0x3,
		RL    = 0x5,
		RF1   = 0x6,
		RF2   = 0x9,
		RF3   = 0xa,
	};

	switch (inst & 0x1f)
	{
		case RONCZ: CLEAR_FLAGS(V_FLAG | N_FLAG | C_FLAG | Z_FLAG); break;
		case RL:	CLEAR_FLAGS(L_FLAG); break;
		case RF1:	CLEAR_FLAGS(FLAG_1); break;
		case RF2:	CLEAR_FLAGS(FLAG_2); break;
		case RF3:	CLEAR_FLAGS(FLAG_3); break;
	}

	cpustate->result = 0;
}

static void setst(esrip_state *cpustate, UINT16 inst)
{
	enum
	{
		SONCZ = 0x3,
		SL    = 0x5,
		SF1   = 0x6,
		SF2   = 0x9,
		SF3   = 0xa,
	};

	switch (inst & 0x1f)
	{
		case SONCZ: SET_FLAGS(V_FLAG | N_FLAG | C_FLAG | Z_FLAG); break;
		case SL:	SET_FLAGS(L_FLAG); break;
		case SF1:	SET_FLAGS(FLAG_1); break;
		case SF2:	SET_FLAGS(FLAG_2); break;
		case SF3:	SET_FLAGS(FLAG_3); break;
	}

	cpustate->result = 0xffff;
}

static void test(esrip_state *cpustate, UINT16 inst)
{
	enum
	{
		TNOZ = 0x00,
		TNO  = 0x02,
		TZ   = 0x04,
		TOVR = 0x06,
		TLOW = 0x08,
		TC   = 0x0a,
		TZC  = 0x0c,
		TN   = 0x0e,
		TL   = 0x10,
		TF1  = 0x12,
		TF2  = 0x14,
		TF3  = 0x16
	};

	UINT32 res = 0;

	switch (inst & 0x1f)
	{
		case TNOZ: UNHANDLED; break;
		case TNO:  UNHANDLED; break;
		case TZ:   res = cpustate->status & (Z_FLAG); break;
		case TOVR: res = cpustate->status & (V_FLAG); break;
		case TLOW: UNHANDLED; break;
		case TC:   res = cpustate->status & (C_FLAG); break;
		case TZC:  UNHANDLED; break;
		case TN:   res = cpustate->status & (N_FLAG); break;
		case TL:   res = cpustate->status & (L_FLAG); break;
		case TF1:  res = cpustate->status & (FLAG_1); break;
		case TF2:  res = cpustate->status & (FLAG_2); break;
		case TF3:  res = cpustate->status & (FLAG_3); break;
		default:   INVALID;
	}

	cpustate->ct = res && 1;
}


/*************************************
 *
 *  No operation
 *
 *************************************/

static void nop(esrip_state *cpustate, UINT16 inst)
{
	cpustate->result = 0xff;	// Undefined
}

static void (*const operations[24])(esrip_state *cpustate, UINT16 inst) =
{
	rotr1, tor1, rotr2, rotc, rotm, bor2, crcf, crcr,
	svstr, prt, sor, tor2, shftr, test, nop, setst, rstst,
	rotnr, bonr, bor1, sonr, shftnr, prtnr, tonr
};

INLINE void am29116_execute(esrip_state *cpustate, UINT16 inst, int _sre)
{
	/* Status register shadow */
	cpustate->new_status = cpustate->status;

	/* Required for immediate source instructions */
	cpustate->inst = inst;

	if (cpustate->immflag == 1)
		inst = cpustate->i_latch;

	(*operations[cpustate->optable[inst]])(cpustate, inst);

	if (!_sre)
	{
		cpustate->status = cpustate->new_status;
		cpustate->t = cpustate->status;
	}
}


static CPU_EXECUTE( esrip )
{
	esrip_state *cpustate = device->token;
	int calldebugger = (device->machine->debug_flags & DEBUG_FLAG_ENABLED) != 0;
	UINT8 status;

	cpustate->icount = cycles;

	/* I think we can get away with placing this outside of the loop */
	status = cpustate->status_in(device->machine);

	/* Core execution loop */
	do
	{
		UINT64	inst;
		UINT8	next_pc;
		UINT16	x_bus = 0;
		UINT16	ipt_bus = 0;
		UINT16	y_bus = 0;

		int yoe = _BIT(cpustate->l5, 1);
		int bl46 = BIT(cpustate->l4, 6);
		int bl44 = BIT(cpustate->l4, 4);

		UINT32 in_h;
		UINT32 in_l;

		if (cpustate->fig_cycles)
		{
			if (--cpustate->fig_cycles == 0)
				cpustate->fig = 0;
		}

		/* /OEY = 1 : Y-bus is high imped */
		if (yoe)
		{
			/* Status In */
			if (!_BIT(cpustate->l2, 0))
				y_bus = status | (!cpustate->fig << 3);

			/* FDT RAM: /Enable, Direction and /RAM OE */
			else if (!bl44 && !_BIT(cpustate->l2, 3) && bl46)
				y_bus = cpustate->fdt_r(device, cpustate->fdt_cnt, 0);

			/* IPT RAM: /Enable and /READ */
			else if (!_BIT(cpustate->l2, 6) && !_BIT(cpustate->l4, 5))
				y_bus = cpustate->ipt_ram[cpustate->ipt_cnt];

			/* DLE  - latch the value on the Y-BUS into the data latch */
			if (_BIT(cpustate->l5, 0))
				cpustate->d_latch = y_bus;

			/* Now execute the AM29116 instruction */
			am29116_execute(cpustate, (cpustate->l7 << 8) | cpustate->l6, BIT(cpustate->l5, 2));
		}
		else
		{
			am29116_execute(cpustate, (cpustate->l7 << 8) | cpustate->l6, BIT(cpustate->l5, 2));

			y_bus = cpustate->result;

			if (BIT(cpustate->l5, 0))
				cpustate->d_latch = y_bus;
		}

		/* Determine what value is on the X-Bus */

		/* FDT RAM */
		if (!bl44)
			x_bus = cpustate->fdt_r(device, cpustate->fdt_cnt, 0);

		/* Buffer is enabled - write direction */
		else if (!BIT(cpustate->l2, 3) && !bl46)
		{
			if (!yoe)
				x_bus = y_bus;
			else if ( !BIT(cpustate->l2, 6) && !BIT(cpustate->l4, 5) )
				x_bus = cpustate->ipt_ram[cpustate->ipt_cnt];
		}

		/* IPT BUS */
		if (!BIT(cpustate->l2, 6))
			ipt_bus = cpustate->ipt_ram[cpustate->ipt_cnt];
		else if (!BIT(cpustate->l4, 5))
		{
			if (!BIT(cpustate->l5, 1))
				ipt_bus = y_bus;
			else
				ipt_bus = x_bus;
		}


		/* Write FDT RAM: /Enable, Direction and WRITE */
		if (!BIT(cpustate->l2, 3) && !bl46 && !BIT(cpustate->l4, 3))
			cpustate->fdt_w(device, cpustate->fdt_cnt, x_bus, 0);

		/* Write IPT RAM: /Enable and /WR */
		if (!BIT(cpustate->l2, 7) && !BIT(cpustate->l4, 5))
			cpustate->ipt_ram[cpustate->ipt_cnt] = ipt_bus;


		if ((((cpustate->l5 >> 3) & 0x1f) & 0x18) != 0x18)
		{
			if ( check_jmp(cpustate, device->machine, (cpustate->l5 >> 3) & 0x1f) )
				next_pc = cpustate->l1;
			else
				next_pc = cpustate->pc + 1;
		}
		else
			next_pc = cpustate->pc + 1;

		cpustate->pl1 = cpustate->l1;
		cpustate->pl2 = cpustate->l2;
		cpustate->pl3 = cpustate->l3;
		cpustate->pl4 = cpustate->l4;
		cpustate->pl5 = cpustate->l5;
		cpustate->pl6 = cpustate->l6;
		cpustate->pl7 = cpustate->l7;

		/* Latch instruction */
		inst = memory_decrypted_read_qword(cpustate->program, RIP_PC << 3);

		in_h = inst >> 32;
		in_l = inst & 0xffffffff;

		cpustate->l1 = (in_l >> 8);
		cpustate->l2 = (in_l >> 16);
		cpustate->l3 = (in_l >> 24);

		cpustate->l4 = (in_h >> 0);
		cpustate->l5 = (in_h >> 8);
		cpustate->l6 = (in_h >> 16);
		cpustate->l7 = (in_h >> 24);

		/* Colour latch */
		if (RISING_EDGE(cpustate->pl3, cpustate->l3, 0))
			cpustate->c_latch = (x_bus >> 12) & 0xf;

		/* Right pixel line buffer address */
		if (RISING_EDGE(cpustate->pl3, cpustate->l3, 1))
			cpustate->adr_latch = x_bus & 0xfff;

		/* Left pixel line buffer address */
		if (RISING_EDGE(cpustate->pl3, cpustate->l3, 2))
			cpustate->adl_latch = x_bus & 0xfff;

		/* FIGLD: Start the DMA */
		if (RISING_EDGE(cpustate->pl3, cpustate->l3, 3))
		{
			cpustate->attr_latch = x_bus;

			cpustate->fig = 1;
			cpustate->fig_cycles = cpustate->draw(device->machine, cpustate->adl_latch, cpustate->adr_latch, cpustate->fig_latch, cpustate->attr_latch, cpustate->iaddr_latch, cpustate->c_latch, cpustate->x_scale, cpustate->img_bank);
		}

		/* X-scale */
		if (RISING_EDGE(cpustate->pl3, cpustate->l3, 4))
			cpustate->x_scale = x_bus >> 8;

		/* Y-scale and image bank */
		if (RISING_EDGE(cpustate->pl4, cpustate->l4, 2))
		{
			cpustate->y_scale = x_bus & 0xff;
			cpustate->img_bank = (y_bus >> 14) & 3;
		}

		/* Image ROM address */
		if (RISING_EDGE(cpustate->pl3, cpustate->l3, 5))
			cpustate->iaddr_latch = y_bus;

		/* IXLLD */
		if (RISING_EDGE(cpustate->pl3, cpustate->l3, 6))
		{
			cpustate->line_latch = ipt_bus >> 10;
			cpustate->fig_latch  = ipt_bus & 0x3ff;
		}

		/* Status write */
		if (RISING_EDGE(cpustate->pl3, cpustate->l3, 7))
			cpustate->status_out = y_bus & 0xff;

		/* FDT address counter */
		if (!BIT(cpustate->pl2, 1))
			cpustate->fdt_cnt = y_bus & 0xfff;
		else if (BIT(cpustate->pl2, 2))
			cpustate->fdt_cnt = (cpustate->fdt_cnt + 1) & 0xfff;

		/* Now we can alter the IPT address counter */
		if (!BIT(cpustate->pl2, 4))
			cpustate->ipt_cnt = y_bus & 0x1fff;
		else if (BIT(cpustate->pl2, 5))
			cpustate->ipt_cnt = (cpustate->ipt_cnt + 1) & 0x1fff;

		if (calldebugger)
			debugger_instruction_hook(device, RIP_PC);

		cpustate->pc = next_pc;

		cpustate->icount--;
	} while (cpustate->icount > 0);

	return cycles - cpustate->icount;
}


/***************************************************************************
    DISASSEMBLY HOOK (TODO: FINISH)
***************************************************************************/

static CPU_DISASSEMBLE( esrip )
{
#if 0
	static const char* const jmp_types[] =
	{
		"JCT",
		"JT1",
		"JT2",
		"JT3",
		"JT4",
		"JLBRM",
		"J#HBLANK",
		"JMP",
	};

	static const char* const njmp_types[] =
	{
		"JNCT",
		"JNT1",
		"JNT2",
		"JNT3",
		"JNT4",
		"JNLBRM",
		"J#HBLANK",
		"  ",
	};
#endif

	UINT64 inst = BIG_ENDIANIZE_INT64(*(UINT64 *)oprom);

	UINT32 inst_hi = inst >> 32;
	UINT32 inst_lo = inst & 0xffffffff;

	UINT16 ins = (inst_hi >> 16) & 0xffff;
	UINT8  ctrl = (inst_hi >> 8) & 0xff;
	UINT8  jmp_dest = (inst_lo >> 8) & 0xff;

	UINT8 jmp_ctrl = (ctrl >> 3) & 0x1f;

	UINT8 ctrl1 = (inst_lo >> 16) & 0xff;
	UINT8 ctrl2 = (inst_lo >> 24) & 0xff;
	UINT8 ctrl3 = (inst_hi) & 0xff;

	sprintf(buffer, "%.4x %c%c%c%c %.2x %s%s%s%s%s%s%s%s %c%s%s%s %c%c%c%c%c%c%c%c\n",
			ins,
			ctrl & 1 ? 'D' : ' ',
			ctrl & 2 ? ' ' : 'Y',
			ctrl & 4 ? 'S' : ' ',
			(~jmp_ctrl & 0x18) ? 'J' : ' ',
			jmp_dest,
			ctrl1 & 0x01 ? "  " : "I ",
			ctrl1 & 0x02 ? "  " : "FL",
			ctrl1 & 0x04 ? "FE" : "  ",
			ctrl1 & 0x08 ? "  " : "FR",
			ctrl1 & 0x10 ? "  " : "IL",
			ctrl1 & 0x20 ? "IE" : "  ",
			ctrl1 & 0x40 ? "  " : "IR",
			ctrl1 & 0x80 ? "  " : "IW",

			ctrl2 & 0x80 ? ' ' : 'O',
			ctrl2 & 0x40 ? "     " : "IXLLD",
			ctrl2 & 0x20 ? "     " : "IADLD",
			ctrl2 & 0x10 ? "     " : "SCALD",

			ctrl3 & 0x01 ? ' ' : '0',
			ctrl3 & 0x02 ? ' ' : '1',
			ctrl3 & 0x04 ? ' ' : '2',
			ctrl3 & 0x08 ? ' ' : '3',
			ctrl3 & 0x10 ? ' ' : '4',
			ctrl3 & 0x20 ? ' ' : '5',
			ctrl3 & 0x40 ? ' ' : '6',
			ctrl3 & 0x80 ? ' ' : '7'
			);

	return 1 | DASMFLAG_SUPPORTED;
}

/**************************************************************************
 * set_info
 **************************************************************************/

static CPU_SET_INFO( esrip )
{
	esrip_state *cpustate = device->token;

	switch (state)
	{
		/* --- the following bits of info are set as 64-bit signed integers --- */
		case CPUINFO_INT_PC:
		case CPUINFO_INT_REGISTER + ESRIP_PC:	cpustate->pc = info->i & 0xff;
												cpustate->status_out &= ~1;
												cpustate->status_out |= ((info->i >> 8) & 1);
												break;
	}
}

/**************************************************************************
 * get_info
 **************************************************************************/

CPU_GET_INFO( esrip )
{
	esrip_state *cpustate = device->token;

	switch (state)
	{
		/* --- the following bits of info are returned as 64-bit signed integers --- */
		case CPUINFO_INT_CONTEXT_SIZE:					info->i = sizeof(esrip_state);	break;
		case CPUINFO_INT_ENDIANNESS:					info->i = ENDIANNESS_BIG;		break;
		case CPUINFO_INT_CLOCK_MULTIPLIER:				info->i = 1;					break;
		case CPUINFO_INT_CLOCK_DIVIDER:					info->i = 1;					break;
		case CPUINFO_INT_MIN_INSTRUCTION_BYTES:			info->i = 8;					break;
		case CPUINFO_INT_MAX_INSTRUCTION_BYTES:			info->i = 8;					break;
		case CPUINFO_INT_MIN_CYCLES:					info->i = 1;					break;
		case CPUINFO_INT_MAX_CYCLES:					info->i = 1;					break;

		case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_PROGRAM:	info->i = 64;			break;
		case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 9;			break;
		case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_PROGRAM: info->i = -3;			break;
		case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_DATA:	info->i = 0;			break;
		case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_DATA: 	info->i = 0;			break;
		case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_DATA: 	info->i = 0;			break;
		case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_IO:		info->i = 0;			break;
		case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_IO: 		info->i = 0;			break;
		case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_IO: 		info->i = 0;			break;

		case CPUINFO_INT_REGISTER:
		case CPUINFO_INT_PC:							info->i = RIP_PC;	break;
		case CPUINFO_INT_REGISTER + ESRIP_STATW:		info->i = cpustate->status_out; break;
		case CPUINFO_INT_REGISTER + ESRIP_FDTC:			info->i = cpustate->fdt_cnt; break;
		case CPUINFO_INT_REGISTER + ESRIP_IPTC:			info->i = cpustate->ipt_cnt; break;

		/* --- the following bits of info are returned as pointers to data or functions --- */
		case CPUINFO_FCT_SET_INFO:						info->setinfo = CPU_SET_INFO_NAME(esrip);		break;
		case CPUINFO_FCT_INIT:							info->init = CPU_INIT_NAME(esrip);			break;
		case CPUINFO_FCT_RESET:							info->reset = CPU_RESET_NAME(esrip);			break;
		case CPUINFO_FCT_EXIT:							info->exit = CPU_EXIT_NAME(esrip);			break;
		case CPUINFO_FCT_EXECUTE:						info->execute = CPU_EXECUTE_NAME(esrip);		break;
		case CPUINFO_FCT_BURN:							info->burn = NULL;						break;
		case CPUINFO_FCT_DISASSEMBLE:					info->disassemble = CPU_DISASSEMBLE_NAME(esrip);		break;
		case CPUINFO_PTR_INSTRUCTION_COUNTER:			info->icount = &cpustate->icount;		break;

		/* --- the following bits of info are returned as NULL-terminated strings --- */
		case CPUINFO_STR_NAME:							strcpy(info->s, "Real Time Image Processor");		break;
		case CPUINFO_STR_CORE_FAMILY:					strcpy(info->s, "Entertainment Sciences");			break;
		case CPUINFO_STR_CORE_VERSION:					strcpy(info->s, "1.0");					break;
		case CPUINFO_STR_CORE_FILE:						strcpy(info->s, __FILE__);				break;
		case CPUINFO_STR_CORE_CREDITS:					strcpy(info->s, "Copyright Philip J Bennett"); break;

		case CPUINFO_STR_FLAGS:							sprintf(info->s, "%c%c%c%c%c%c%c%c%c",
																		cpustate->status & 0x80 ? '3' : '.',
																		cpustate->status & 0x40 ? '2' : '.',
																		cpustate->status & 0x20 ? '1' : '.',
																		cpustate->status & 0x10 ? 'L' : '.',
																		cpustate->status & 0x08 ? 'V' : '.',
																		cpustate->status & 0x04 ? 'N' : '.',
																		cpustate->status & 0x02 ? 'C' : '.',
																		cpustate->status & 0x01 ? 'Z' : '.',
																		get_hblank(device->machine) ? 'H' : '.'); break;

		case CPUINFO_STR_REGISTER + ESRIP_PC:			sprintf(info->s, "PC: %04X", RIP_PC); break;
		case CPUINFO_STR_REGISTER + ESRIP_ACC:			sprintf(info->s, "ACC: %04X", cpustate->acc); break;
		case CPUINFO_STR_REGISTER + ESRIP_DLATCH:		sprintf(info->s, "DLATCH: %04X", cpustate->d_latch); break;
		case CPUINFO_STR_REGISTER + ESRIP_ILATCH:		sprintf(info->s, "ILATCH: %04X", cpustate->i_latch); break;
		case CPUINFO_STR_REGISTER + ESRIP_RAM00:		sprintf(info->s, "RAM[00]: %04X", cpustate->ram[0x00]); break;
		case CPUINFO_STR_REGISTER + ESRIP_RAM01:		sprintf(info->s, "RAM[01]: %04X", cpustate->ram[0x01]); break;
		case CPUINFO_STR_REGISTER + ESRIP_RAM02:		sprintf(info->s, "RAM[02]: %04X", cpustate->ram[0x02]); break;
		case CPUINFO_STR_REGISTER + ESRIP_RAM03:		sprintf(info->s, "RAM[03]: %04X", cpustate->ram[0x03]); break;
		case CPUINFO_STR_REGISTER + ESRIP_RAM04:		sprintf(info->s, "RAM[04]: %04X", cpustate->ram[0x04]); break;
		case CPUINFO_STR_REGISTER + ESRIP_RAM05:		sprintf(info->s, "RAM[05]: %04X", cpustate->ram[0x05]); break;
		case CPUINFO_STR_REGISTER + ESRIP_RAM06:		sprintf(info->s, "RAM[06]: %04X", cpustate->ram[0x06]); break;
		case CPUINFO_STR_REGISTER + ESRIP_RAM07:		sprintf(info->s, "RAM[07]: %04X", cpustate->ram[0x07]); break;
		case CPUINFO_STR_REGISTER + ESRIP_RAM08:		sprintf(info->s, "RAM[08]: %04X", cpustate->ram[0x08]); break;
		case CPUINFO_STR_REGISTER + ESRIP_RAM09:		sprintf(info->s, "RAM[09]: %04X", cpustate->ram[0x09]); break;
		case CPUINFO_STR_REGISTER + ESRIP_RAM0A:		sprintf(info->s, "RAM[0A]: %04X", cpustate->ram[0x0a]); break;
		case CPUINFO_STR_REGISTER + ESRIP_RAM0B:		sprintf(info->s, "RAM[0B]: %04X", cpustate->ram[0x0b]); break;
		case CPUINFO_STR_REGISTER + ESRIP_RAM0C:		sprintf(info->s, "RAM[0C]: %04X", cpustate->ram[0x0c]); break;
		case CPUINFO_STR_REGISTER + ESRIP_RAM0D:		sprintf(info->s, "RAM[0D]: %04X", cpustate->ram[0x0d]); break;
		case CPUINFO_STR_REGISTER + ESRIP_RAM0E:		sprintf(info->s, "RAM[0E]: %04X", cpustate->ram[0x0e]); break;
		case CPUINFO_STR_REGISTER + ESRIP_RAM0F:		sprintf(info->s, "RAM[0F]: %04X", cpustate->ram[0x0f]); break;
		case CPUINFO_STR_REGISTER + ESRIP_RAM10:		sprintf(info->s, "RAM[10]: %04X", cpustate->ram[0x10]); break;
		case CPUINFO_STR_REGISTER + ESRIP_RAM11:		sprintf(info->s, "RAM[11]: %04X", cpustate->ram[0x11]); break;
		case CPUINFO_STR_REGISTER + ESRIP_RAM12:		sprintf(info->s, "RAM[12]: %04X", cpustate->ram[0x12]); break;
		case CPUINFO_STR_REGISTER + ESRIP_RAM13:		sprintf(info->s, "RAM[13]: %04X", cpustate->ram[0x13]); break;
		case CPUINFO_STR_REGISTER + ESRIP_RAM14:		sprintf(info->s, "RAM[14]: %04X", cpustate->ram[0x14]); break;
		case CPUINFO_STR_REGISTER + ESRIP_RAM15:		sprintf(info->s, "RAM[15]: %04X", cpustate->ram[0x15]); break;
		case CPUINFO_STR_REGISTER + ESRIP_RAM16:		sprintf(info->s, "RAM[16]: %04X", cpustate->ram[0x16]); break;
		case CPUINFO_STR_REGISTER + ESRIP_RAM17:		sprintf(info->s, "RAM[17]: %04X", cpustate->ram[0x17]); break;
		case CPUINFO_STR_REGISTER + ESRIP_RAM18:		sprintf(info->s, "RAM[18]: %04X", cpustate->ram[0x18]); break;
		case CPUINFO_STR_REGISTER + ESRIP_RAM19:		sprintf(info->s, "RAM[19]: %04X", cpustate->ram[0x19]); break;
		case CPUINFO_STR_REGISTER + ESRIP_RAM1A:		sprintf(info->s, "RAM[1A]: %04X", cpustate->ram[0x1a]); break;
		case CPUINFO_STR_REGISTER + ESRIP_RAM1B:		sprintf(info->s, "RAM[1B]: %04X", cpustate->ram[0x1b]); break;
		case CPUINFO_STR_REGISTER + ESRIP_RAM1C:		sprintf(info->s, "RAM[1C]: %04X", cpustate->ram[0x1c]); break;
		case CPUINFO_STR_REGISTER + ESRIP_RAM1D:		sprintf(info->s, "RAM[1D]: %04X", cpustate->ram[0x1d]); break;
		case CPUINFO_STR_REGISTER + ESRIP_RAM1E:		sprintf(info->s, "RAM[1E]: %04X", cpustate->ram[0x1e]); break;
		case CPUINFO_STR_REGISTER + ESRIP_RAM1F:		sprintf(info->s, "RAM[1F]: %04X", cpustate->ram[0x1f]); break;
		case CPUINFO_STR_REGISTER + ESRIP_STATW:		sprintf(info->s, "STAT: %04X", cpustate->status_out); break;
		case CPUINFO_STR_REGISTER + ESRIP_FDTC:			sprintf(info->s, "FDTC: %04X", cpustate->fdt_cnt); break;
		case CPUINFO_STR_REGISTER + ESRIP_IPTC:			sprintf(info->s, "IPTC: %04X", cpustate->ipt_cnt); break;
		case CPUINFO_STR_REGISTER + ESRIP_XSCALE:		sprintf(info->s, "XSCL: %04X", cpustate->x_scale); break;
		case CPUINFO_STR_REGISTER + ESRIP_YSCALE:		sprintf(info->s, "YSCL: %04X", cpustate->y_scale); break;
		case CPUINFO_STR_REGISTER + ESRIP_BANK:			sprintf(info->s, "BANK: %04X", cpustate->img_bank); break;
		case CPUINFO_STR_REGISTER + ESRIP_LINE:			sprintf(info->s, "LINE: %04X", cpustate->line_latch); break;
		case CPUINFO_STR_REGISTER + ESRIP_FIG:			sprintf(info->s, "FIG: %04X", cpustate->fig_latch); break;
		case CPUINFO_STR_REGISTER + ESRIP_ATTR:			sprintf(info->s, "ATTR: %04X", cpustate->attr_latch); break;
		case CPUINFO_STR_REGISTER + ESRIP_ADRL:			sprintf(info->s, "ADRL: %04X", cpustate->adl_latch); break;
		case CPUINFO_STR_REGISTER + ESRIP_ADRR:			sprintf(info->s, "ADRR: %04X", cpustate->adr_latch); break;
		case CPUINFO_STR_REGISTER + ESRIP_COLR:			sprintf(info->s, "COLR: %04X", cpustate->c_latch); break;
		case CPUINFO_STR_REGISTER + ESRIP_IADDR:		sprintf(info->s, "IADR: %04X", cpustate->iaddr_latch); break;
	}
}
