// license:BSD-3-Clause
// copyright-holders:Philip Bennett
/***************************************************************************

    esrip.c

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

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

#include "emu.h"
#include "esrip.h"
#include "esripdsm.h"

#include "debugger.h"
#include "screen.h"


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

#define IPT_RAM_SIZE    (8192 * sizeof(uint16_t))


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

#define RIP_PC      (m_pc | ((m_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)  (m_new_status &= ~(a))
#define SET_FLAGS(a)    (m_new_status |=  (a))


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

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

uint8_t esrip_device::get_rip_status()
{
	return m_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
};

void esrip_device::make_ops()
{
	int inst;

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

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

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

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

void esrip_device::device_start()
{
	/* Register configuration structure callbacks */
	m_fdt_r.resolve_safe(0);
	m_fdt_w.resolve_safe();
	m_lbrm = (uint8_t*)machine().root_device().memregion(m_lbrm_prom)->base();
	m_status_in.resolve_safe(0);
	m_draw.bind_relative_to(*owner());

	/* Allocate image pointer table RAM */
	m_ipt_ram.resize(IPT_RAM_SIZE/2);

	m_program = &space(AS_PROGRAM);
	m_direct = m_program->direct<-3>();

	// register our state for the debugger
	state_add(STATE_GENPC,     "GENPC",     m_rip_pc).noshow();
	state_add(STATE_GENPCBASE, "CURPC",     m_rip_pc).noshow();
	state_add(STATE_GENFLAGS,  "GENFLAGS",  m_status).callimport().callexport().formatstr("%8s").noshow();
	state_add(ESRIP_PC,        "PC:",       m_rip_pc).mask(0xffff);
	state_add(ESRIP_ACC,       "ACC:",      m_acc).mask(0xffff);
	state_add(ESRIP_DLATCH,    "DLATCH:",   m_d_latch).mask(0xff);
	state_add(ESRIP_ILATCH,    "ILATCH:",   m_i_latch).mask(0xffff);
	state_add(ESRIP_RAM00,     "RAM[00]:",  m_ram[0x00]).mask(0xffff);
	state_add(ESRIP_RAM01,     "RAM[01]:",  m_ram[0x01]).mask(0xffff);
	state_add(ESRIP_RAM02,     "RAM[02]:",  m_ram[0x02]).mask(0xffff);
	state_add(ESRIP_RAM03,     "RAM[03]:",  m_ram[0x03]).mask(0xffff);
	state_add(ESRIP_RAM04,     "RAM[04]:",  m_ram[0x04]).mask(0xffff);
	state_add(ESRIP_RAM05,     "RAM[05]:",  m_ram[0x05]).mask(0xffff);
	state_add(ESRIP_RAM06,     "RAM[06]:",  m_ram[0x06]).mask(0xffff);
	state_add(ESRIP_RAM07,     "RAM[07]:",  m_ram[0x07]).mask(0xffff);
	state_add(ESRIP_RAM08,     "RAM[08]:",  m_ram[0x08]).mask(0xffff);
	state_add(ESRIP_RAM09,     "RAM[09]:",  m_ram[0x09]).mask(0xffff);
	state_add(ESRIP_RAM0A,     "RAM[0A]:",  m_ram[0x0a]).mask(0xffff);
	state_add(ESRIP_RAM0B,     "RAM[0B]:",  m_ram[0x0b]).mask(0xffff);
	state_add(ESRIP_RAM0C,     "RAM[0C]:",  m_ram[0x0c]).mask(0xffff);
	state_add(ESRIP_RAM0D,     "RAM[0D]:",  m_ram[0x0d]).mask(0xffff);
	state_add(ESRIP_RAM0E,     "RAM[0E]:",  m_ram[0x0e]).mask(0xffff);
	state_add(ESRIP_RAM0F,     "RAM[0F]:",  m_ram[0x0f]).mask(0xffff);
	state_add(ESRIP_RAM10,     "RAM[10]:",  m_ram[0x10]).mask(0xffff);
	state_add(ESRIP_RAM11,     "RAM[11]:",  m_ram[0x11]).mask(0xffff);
	state_add(ESRIP_RAM12,     "RAM[12]:",  m_ram[0x12]).mask(0xffff);
	state_add(ESRIP_RAM13,     "RAM[13]:",  m_ram[0x13]).mask(0xffff);
	state_add(ESRIP_RAM14,     "RAM[14]:",  m_ram[0x14]).mask(0xffff);
	state_add(ESRIP_RAM15,     "RAM[15]:",  m_ram[0x15]).mask(0xffff);
	state_add(ESRIP_RAM16,     "RAM[16]:",  m_ram[0x16]).mask(0xffff);
	state_add(ESRIP_RAM17,     "RAM[17]:",  m_ram[0x17]).mask(0xffff);
	state_add(ESRIP_RAM18,     "RAM[18]:",  m_ram[0x18]).mask(0xffff);
	state_add(ESRIP_RAM19,     "RAM[19]:",  m_ram[0x19]).mask(0xffff);
	state_add(ESRIP_RAM1A,     "RAM[1A]:",  m_ram[0x1a]).mask(0xffff);
	state_add(ESRIP_RAM1B,     "RAM[1B]:",  m_ram[0x1b]).mask(0xffff);
	state_add(ESRIP_RAM1C,     "RAM[1C]:",  m_ram[0x1c]).mask(0xffff);
	state_add(ESRIP_RAM1D,     "RAM[1D]:",  m_ram[0x1d]).mask(0xffff);
	state_add(ESRIP_RAM1E,     "RAM[1E]:",  m_ram[0x1e]).mask(0xffff);
	state_add(ESRIP_RAM1F,     "RAM[1F]:",  m_ram[0x1f]).mask(0xffff);
	state_add(ESRIP_STATW,     "STAT:",     m_status_out).mask(0xffff);
	state_add(ESRIP_FDTC,      "FDTC:",     m_fdt_cnt).mask(0xffff);
	state_add(ESRIP_IPTC,      "IPTC:",     m_ipt_cnt).mask(0xffff);
	state_add(ESRIP_XSCALE,    "XSCL:",     m_x_scale).mask(0xffff);
	state_add(ESRIP_YSCALE,    "YSCL:",     m_y_scale).mask(0xffff);
	state_add(ESRIP_BANK,      "BANK:",     m_img_bank).mask(0xffff);
	state_add(ESRIP_LINE,      "LINE:",     m_line_latch).mask(0xffff);
	state_add(ESRIP_FIG,       "FIG:",      m_fig_latch).mask(0xffff);
	state_add(ESRIP_ATTR,      "ATTR:",     m_attr_latch).mask(0xffff);
	state_add(ESRIP_ADRL,      "ADRL:",     m_adl_latch).mask(0xffff);
	state_add(ESRIP_ADRR,      "ADRR:",     m_adr_latch).mask(0xffff);
	state_add(ESRIP_COLR,      "COLR:",     m_c_latch).mask(0xffff);
	state_add(ESRIP_IADDR,     "IADR:",     m_iaddr_latch).mask(0xffff);

	/* Create the instruction decode lookup table */
	make_ops();

	/* Register stuff for state saving */
	save_item(NAME(m_acc));
	save_item(NAME(m_ram));
	save_item(NAME(m_d_latch));
	save_item(NAME(m_i_latch));
	save_item(NAME(m_result));
	save_item(NAME(m_new_status));
	save_item(NAME(m_status));
	save_item(NAME(m_inst));
	save_item(NAME(m_immflag));
	save_item(NAME(m_ct));
	save_item(NAME(m_t));
	save_item(NAME(m_l1));
	save_item(NAME(m_l2));
	save_item(NAME(m_l3));
	save_item(NAME(m_l4));
	save_item(NAME(m_l5));
	save_item(NAME(m_l6));
	save_item(NAME(m_l7));
	save_item(NAME(m_pl1));
	save_item(NAME(m_pl2));
	save_item(NAME(m_pl3));
	save_item(NAME(m_pl4));
	save_item(NAME(m_pl5));
	save_item(NAME(m_pl6));
	save_item(NAME(m_pl7));
	save_item(NAME(m_pc));
	save_item(NAME(m_status_out));
	save_item(NAME(m_x_scale));
	save_item(NAME(m_y_scale));
	save_item(NAME(m_img_bank));
	save_item(NAME(m_line_latch));
	save_item(NAME(m_fig_latch));
	save_item(NAME(m_attr_latch));
	save_item(NAME(m_adl_latch));
	save_item(NAME(m_adr_latch));
	save_item(NAME(m_iaddr_latch));
	save_item(NAME(m_c_latch));
	save_item(NAME(m_fdt_cnt));
	save_item(NAME(m_ipt_cnt));
	save_item(NAME(m_fig));
	save_item(NAME(m_fig_cycles));
	save_item(NAME(m_ipt_ram));

	// set our instruction counter
	m_icountptr = &m_icount;
	m_icount = 0;
}


void esrip_device::device_reset()
{
	m_pc = 0;

	m_pl1 = 0xff;
	m_pl2 = 0xff;
	m_pl3 = 0xff;
	m_pl4 = 0xff;
	m_pl5 = 0xff;
	m_pl6 = 0xff;
	m_pl7 = 0xff;

	m_l1 = 0xff;
	m_l2 = 0xff;
	m_l3 = 0xff;
	m_l4 = 0xff;
	m_l5 = 0xff;
	m_l6 = 0xff;
	m_l7 = 0xff;

	m_status_out = 0;
	m_immflag = 0;

	m_rip_pc = (m_pc | ((m_status_out & 1) << 8));
}

void esrip_device::device_stop()
{
}


//-------------------------------------------------
//  memory_space_config - return the configuration
//  of the specified address space, or nullptr if
//  the space doesn't exist
//-------------------------------------------------

device_memory_interface::space_config_vector esrip_device::memory_space_config() const
{
	return space_config_vector {
		std::make_pair(AS_PROGRAM, &m_program_config),
	};
}


//-------------------------------------------------
//  state_string_export - export state as a string
//  for the debugger
//-------------------------------------------------

void esrip_device::state_string_export(const device_state_entry &entry, std::string &str) const
{
	switch (entry.index())
	{
		case STATE_GENFLAGS:
			str = string_format("%c%c%c%c%c%c%c%c%c",
				(m_status & 0x80) ? '3' : '.',
				(m_status & 0x40) ? '2' : '.',
				(m_status & 0x20) ? '1' : '.',
				(m_status & 0x10) ? 'L' : '.',
				(m_status & 0x08) ? 'V' : '.',
				(m_status & 0x04) ? 'N' : '.',
				(m_status & 0x02) ? 'C' : '.',
				(m_status & 0x01) ? 'Z' : '.',
				get_hblank() ? 'H' : '.');
			break;
	}
}


//-------------------------------------------------
//  disassemble - call the disassembly
//  helper function
//-------------------------------------------------

util::disasm_interface *esrip_device::create_disassembler()
{
	return new esrip_disassembler;
}

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

int esrip_device::get_hblank() const
{
	return machine().first_screen()->hblank();
}

/* Return the state of the LBRM line (Y-scaling related) */
int esrip_device::get_lbrm() const
{
	int addr = ((m_y_scale & 0x3f) << 3) | ((m_line_latch >> 3) & 7);
	int sel = (m_line_latch & 7);

	uint8_t val = m_lbrm[addr];

	return (val >> sel) & 1;
}

int esrip_device::check_jmp(uint8_t jmp_ctrl) const
{
	int ret = 0;

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

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

	return ret;
}


void esrip_device::calc_z_flag(uint16_t res)
{
	m_new_status &= ~Z_FLAG;
	m_new_status |= (res == 0);
}

void esrip_device::calc_c_flag_add(uint16_t a, uint16_t b)
{
	m_new_status &= ~C_FLAG;
	m_new_status |= ((uint16_t)(b) > (uint16_t)(~(a))) ? 2 : 0;
}

void esrip_device::calc_c_flag_sub(uint16_t a, uint16_t b)
{
	m_new_status &= ~C_FLAG;
	m_new_status |= ((uint16_t)(b) <= (uint16_t)(a)) ? 2 : 0;
}

void esrip_device::calc_n_flag(uint16_t res)
{
	m_new_status &= ~N_FLAG;
	m_new_status |= (res & 0x8000) ? 4 : 0;
}

void esrip_device::calc_v_flag_add(uint16_t a, uint16_t b, uint32_t r)
{
	m_new_status &= ~V_FLAG;
	m_new_status |= ((a ^ r) & (b ^ r) & 0x8000) ? 8 : 0;
}

void esrip_device::calc_v_flag_sub(uint16_t a, uint16_t b, uint32_t r)
{
	m_new_status &= ~V_FLAG;
	m_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
};

uint16_t esrip_device::sor_op(uint16_t r, uint16_t opcode)
{
	uint32_t res = 0;

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

	return res & 0xffff;
}

void esrip_device::sor(uint16_t inst)
{
	uint16_t  r = 0;
	uint16_t  dst = 0;
	uint16_t  res = 0;

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

	switch ((inst >> 5) & 0xf)
	{
		case SORA: r = m_ram[RAM_ADDR];     dst = ACC;      break;
		case SORY: r = m_ram[RAM_ADDR];     dst = Y_BUS;    break;
		case SORS: r = m_ram[RAM_ADDR];     dst = STATUS;   break;
		case SOAR: r = m_acc;               dst = RAM;      break;
		case SODR: r = m_d_latch;           dst = RAM;      break;
		case SOIR:
		{
			if (m_immflag == 0)     // Macrofiy this?
			{
				m_i_latch = inst;
				m_immflag = 1;
				return;
			}
			else
			{
				r = m_inst;
				dst = RAM;
				m_immflag = 0;
			}
			break;
		}
		case SOZR: r = 0;                       dst = RAM;      break;
		case SORR: r = m_ram[RAM_ADDR]; dst = RAM;      break;
		default: UNHANDLED;
	}

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

	switch (dst)
	{
		case Y_BUS: break;
		case ACC: m_acc = res; break;
		case RAM: m_ram[RAM_ADDR] = res; break;
		default: UNHANDLED;
	}

	m_result = res;
}

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

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

void esrip_device::sonr(uint16_t inst)
{
	uint16_t  r = 0;
	uint16_t  res = 0;

	switch ((inst >> 5) & 0xf)
	{
		case SOA:   r = m_acc;      break;
		case SOD:   r = m_d_latch;  break;
		case SOI:
		{
			if (m_immflag == 0)
			{
				m_i_latch = inst;
				m_immflag = 1;
				return;
			}
			else
			{
				r = m_inst;
				m_immflag = 0;
			}
			break;
		}
		case SOZ:   r = 0; break;
		default: INVALID;
	}

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

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

	m_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
};

uint16_t esrip_device::tor_op(uint16_t r, uint16_t s, int opcode)
{
	uint32_t res = 0;

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

	return res & 0xffff;
}

void esrip_device::tor1(uint16_t inst)
{
	uint16_t r = 0;
	uint16_t s = 0;
	uint16_t dst = 0;
	uint16_t  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 = m_ram[RAM_ADDR];    s = m_acc;  dst = ACC;  break;
		case TORIA:
		{
			if (m_immflag == 0)
			{
				m_i_latch = inst;
				m_immflag = 1;
				return;
			}
			else
			{
				r = m_ram[RAM_ADDR];
				s = m_inst;
				dst = ACC;
				m_immflag = 0;
			}
			break;
		}
		case TODRA: r = m_d_latch;      s = m_ram[RAM_ADDR];    dst = ACC;  break;
		case TORAY: r = m_ram[RAM_ADDR];    s = m_acc;          dst = Y_BUS;break;
		case TORIY:
		{
			if (m_immflag == 0)
			{
				m_i_latch = inst;
				m_immflag = 1;
				return;
			}
			else
			{
				r = m_ram[RAM_ADDR];
				s = m_inst;
				dst = Y_BUS;
				m_immflag = 0;
			}
			break;
		}
		case TODRY: r = m_d_latch;      s = m_ram[RAM_ADDR];    dst = Y_BUS;break;
		case TORAR: r = m_ram[RAM_ADDR];    s = m_acc;          dst = RAM;  break;
		case TORIR:
		{
			if (m_immflag == 0)
			{
				m_i_latch = inst;
				m_immflag = 1;
				return;
			}
			else
			{
				r = m_ram[RAM_ADDR];
				s = m_inst;
				dst = RAM;
				m_immflag = 0;
			}
			break;
		}
		case TODRR: r = m_d_latch;      s = m_ram[RAM_ADDR];    dst = RAM;  break;
		default: INVALID;
	}

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

	/* Destination */
	switch (dst)
	{
		case ACC:   m_acc = res; break;
		case Y_BUS: break;
		case RAM:   m_ram[RAM_ADDR] = res; break;
		default:    INVALID;
	}

	m_result = res;
}

void esrip_device::tor2(uint16_t inst)
{
	uint16_t r = 0;
	uint16_t s = 0;
	uint32_t res = 0;

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

	switch (SRC)
	{
		case TODAR: r = m_d_latch;  s = m_acc;  break;
		case TOAIR:
		{
			if (m_immflag == 0)
			{
				m_i_latch = inst;
				m_immflag = 1;
				return;
			}
			else
			{
				r = m_acc;
				s = m_inst;
				m_immflag = 0;
			}
			break;
		}
		case TODIR:
		{
			if (m_immflag == 0)
			{
				m_i_latch = inst;
				m_immflag = 1;
				return;
			}
			else
			{
				r = m_d_latch;
				s = m_inst;
				m_immflag = 0;
			}
			break;
		}
		default: INVALID;
	}

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

	/* Destination is always RAM */
	m_ram[RAM_ADDR] = res;

	m_result = res;
}

void esrip_device::tonr(uint16_t inst)
{
	enum
	{
		TODA  = 0x1,
		TOAI  = 0x2,
		TODI  = 0x5
	};

	uint16_t r = 0;
	uint16_t s = 0;
	uint16_t  res = 0;

	switch (SRC)
	{
		case TODA:
		{
			r = m_d_latch;
			s = m_acc;
			break;
		}
		case TOAI:
		{
			break;
		}
		case TODI:
		{
			if (m_immflag == 0)
			{
				m_i_latch = inst;
				m_immflag = 1;
				return;
			}
			else
			{
				r = m_d_latch;
				s = m_inst;
				m_immflag = 0;
			}
			break;
		}
		default: INVALID;
	}

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

	/* Destination */
	switch (DST)
	{
		case NRY:
			break;
		case NRA:
			m_acc = res;
			break;
		case NRS:
			UNHANDLED;
			break;
		case NRAS:
			UNHANDLED;
			break;
		default:
			INVALID;
	}
	m_result = res;
}

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

void esrip_device::bonr(uint16_t 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_t  res = 0;

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

		case TSTND:
		{
			res = m_d_latch & (1 << N);
			CLEAR_FLAGS(V_FLAG | C_FLAG);
			calc_n_flag(res);
			calc_z_flag(res);
			break;
		}

		case SETND:
		{
			uint16_t r = m_d_latch;
			res = r | (1 << N);
			m_d_latch = res;

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

		case A2NDY:
		{
			uint16_t r = m_d_latch;
			uint16_t s = 1 << N;
			res = r + s;

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

		default:
			UNHANDLED;
	}

	m_result = res;
}

void esrip_device::bor1(uint16_t inst)
{
	enum
	{
		SETNR  = 0xd,
		RSTNR  = 0xe,
		TSTNR  = 0xf
	};

	uint16_t  res = 0;

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

	m_result = res;
}

void esrip_device::bor2(uint16_t inst)
{
	enum
	{
		LD2NR  = 0xc,
		LDC2NR = 0xd,
		A2NR   = 0xe,
		S2NR   = 0xf
	};

	uint32_t res = 0;

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

			res = r + s;
			calc_v_flag_add(r, s, res);
			calc_n_flag(res);
			calc_c_flag_add(r, s);
			calc_z_flag(res);
			break;
		}
		case S2NR:
		{
			uint16_t r = m_ram[RAM_ADDR];
			uint16_t s = 1 << N;

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

	/* Destination is RAM */
	m_ram[RAM_ADDR] = res;
	m_result = res;
}

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

/* TODO Combine these */
void esrip_device::rotr1(uint16_t inst)
{
	enum
	{
		RTRA = 0xc,
		RTRY = 0xd,
		RTRR = 0xf
	};

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

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

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

	switch (dst)
	{
		case ACC: m_acc = res; break;
		case RAM: m_ram[RAM_ADDR] = res; break;
	}

	m_result = res;
}

void esrip_device::rotr2(uint16_t inst)
{
	enum
	{
		RTAR = 0,
		RTDR = 1
	};

	uint16_t  u = 0;
	uint16_t  res = 0;

	switch ((inst >> 5) & 0xf)
	{
		case RTAR: u = m_acc;       break;
		case RTDR: u = m_d_latch;   break;
		default: INVALID;
	}

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

	m_result = res;
}

void esrip_device::rotnr(uint16_t inst)
{
	enum
	{
		RTDY = 0x18,
		RTDA = 0x19,
		RTAY = 0x1c,
		RTAA = 0x1d
	};

	uint16_t  u = 0;
	uint16_t  res = 0;
	uint16_t  dst = 0;

	switch (inst & 0x1f)
	{
		case RTDY: u = m_d_latch;   dst = Y_BUS;    break;
		case RTDA: u = m_d_latch;   dst = ACC;      break;
		case RTAY: u = m_acc;       dst = Y_BUS;    break;
		case RTAA: u = m_acc;       dst = ACC;      break;
		default: INVALID;
	}

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

	switch (dst)
	{
		case Y_BUS: break;
		case ACC: m_acc = res; break;
		case RAM: m_ram[RAM_ADDR] = res; break;
		default: UNHANDLED;
	}

	m_result = res;
}

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

void esrip_device::rotc(uint16_t inst)
{
	UNHANDLED;
}

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

void esrip_device::rotm(uint16_t inst)
{
	UNHANDLED;
}

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

void esrip_device::prt(uint16_t inst)
{
	UNHANDLED;
}

void esrip_device::prtnr(uint16_t inst)
{
	UNHANDLED;
}


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

void esrip_device::crcf(uint16_t inst)
{
	UNHANDLED;
}

void esrip_device::crcr(uint16_t 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(x)    (m_new_status &= ~L_FLAG); \
							(m_new_status |= x ? L_FLAG : 0)

uint16_t esrip_device::shift_op(uint16_t u, int opcode)
{
	uint32_t res = 0;

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

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

	return res;
}

void esrip_device::shftr(uint16_t inst)
{
	enum
	{
		SHRR = 6,
		SHDR = 7
	};

	uint16_t  u = 0;
	uint16_t  res = 0;

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

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

	/* Destination is always RAM */
	m_ram[RAM_ADDR] = res;
	m_result = res;
}

void esrip_device::shftnr(uint16_t inst)
{
	enum
	{
		SHA = 6,
		SHD = 7
	};

	uint16_t  u = 0;
	uint16_t  res = 0;

	switch ((inst >> 9) & 0xf)
	{
		case SHA: u = m_acc;            break;
		case SHD: u = m_d_latch;        break;
		default: INVALID;
	}

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

	switch (DST)
	{
		case NRY:   break;
		case NRA:   m_acc = res; break;
		default:    INVALID;
	}
	m_result = res;
}


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

void esrip_device::svstr(uint16_t inst)
{
	UNHANDLED;
}

void esrip_device::rstst(uint16_t 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;
	}

	m_result = 0;
}

void esrip_device::setst(uint16_t 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;
	}

	m_result = 0xffff;
}

void esrip_device::test(uint16_t 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_t res = 0;

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

	m_ct = res ? 1 : 0;
}


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

void esrip_device::nop(uint16_t inst)
{
	m_result = 0xff;    // Undefined
}

//**************************************************************************
//  DEVICE INTERFACE
//**************************************************************************

DEFINE_DEVICE_TYPE(ESRIP, esrip_device, "esrip", "Entertainment Sciences RIP")

//-------------------------------------------------
//  esrip_device - constructor
//-------------------------------------------------

esrip_device::esrip_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
	: cpu_device(mconfig, ESRIP, tag, owner, clock),
		m_program_config("program", ENDIANNESS_BIG, 64, 9, -3),
		m_fdt_r(*this),
		m_fdt_w(*this),
		m_status_in(*this),
		m_lbrm_prom(nullptr)
{
	// build the opcode table
	for (int op = 0; op < 24; op++)
		m_opcode[op] = s_opcodetable[op];
}


//**************************************************************************
//  STATIC OPCODE TABLES
//**************************************************************************

const esrip_device::ophandler esrip_device::s_opcodetable[24] =
{
	&esrip_device::rotr1,   &esrip_device::tor1,    &esrip_device::rotr2,   &esrip_device::rotc,
	&esrip_device::rotm,    &esrip_device::bor2,    &esrip_device::crcf,    &esrip_device::crcr,
	&esrip_device::svstr,   &esrip_device::prt,     &esrip_device::sor,     &esrip_device::tor2,
	&esrip_device::shftr,   &esrip_device::test,    &esrip_device::nop,     &esrip_device::setst,
	&esrip_device::rstst,   &esrip_device::rotnr,   &esrip_device::bonr,    &esrip_device::bor1,
	&esrip_device::sonr,    &esrip_device::shftnr,  &esrip_device::prtnr,   &esrip_device::tonr
};


void esrip_device::am29116_execute(uint16_t inst, int _sre)
{
	/* Status register shadow */
	m_new_status = m_status;

	/* Required for immediate source instructions */
	m_inst = inst;

	if (m_immflag == 1)
		inst = m_i_latch;

	(this->*m_opcode[m_optable[inst]])(inst);

	if (!_sre)
	{
		m_status = m_new_status;
		m_t = m_status;
	}
}


//-------------------------------------------------
//  execute_min_cycles - return minimum number of
//  cycles it takes for one instruction to execute
//-------------------------------------------------

uint32_t esrip_device::execute_min_cycles() const
{
	return 1;
}


//-------------------------------------------------
//  execute_max_cycles - return maximum number of
//  cycles it takes for one instruction to execute
//-------------------------------------------------

uint32_t esrip_device::execute_max_cycles() const
{
	return 1;
}


//-------------------------------------------------
//  execute_input_lines - return the number of
//  input/interrupt lines
//-------------------------------------------------

uint32_t esrip_device::execute_input_lines() const
{
	return 0;
}


//-------------------------------------------------
//  execute_set_input - act on a changed input/
//  interrupt line
//-------------------------------------------------

void esrip_device::execute_set_input(int inputnum, int state)
{
}


void esrip_device::execute_run()
{
	int calldebugger = (machine().debug_flags & DEBUG_FLAG_ENABLED) != 0;
	uint8_t status;

	/* I think we can get away with placing this outside of the loop */
	status = m_status_in(*m_program, 0);

	/* Core execution loop */
	do
	{
		uint64_t  inst;
		uint8_t   next_pc;
		uint16_t  x_bus = 0;
		uint16_t  ipt_bus = 0;
		uint16_t  y_bus = 0;

		int yoe = _BIT(m_l5, 1);
		int bl46 = BIT(m_l4, 6);
		int bl44 = BIT(m_l4, 4);

		uint32_t in_h;
		uint32_t in_l;

		if (m_fig_cycles)
		{
			if (--m_fig_cycles == 0)
				m_fig = 0;
		}

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

			/* FDT RAM: /Enable, Direction and /RAM OE */
			else if (!bl44 && !_BIT(m_l2, 3) && bl46)
				y_bus = m_fdt_r(*m_program, m_fdt_cnt, 0xffff);

			/* IPT RAM: /Enable and /READ */
			else if (!_BIT(m_l2, 6) && !_BIT(m_l4, 5))
				y_bus = m_ipt_ram[m_ipt_cnt];

			/* DLE  - latch the value on the Y-BUS into the data latch */
			if (_BIT(m_l5, 0))
				m_d_latch = y_bus;

			/* Now execute the AM29116 instruction */
			am29116_execute((m_l7 << 8) | m_l6, BIT(m_l5, 2));
		}
		else
		{
			am29116_execute((m_l7 << 8) | m_l6, BIT(m_l5, 2));

			y_bus = m_result;

			if (BIT(m_l5, 0))
				m_d_latch = y_bus;
		}

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

		/* FDT RAM */
		if (!bl44)
			x_bus = m_fdt_r(*m_program, m_fdt_cnt, 0xffff);

		/* Buffer is enabled - write direction */
		else if (!BIT(m_l2, 3) && !bl46)
		{
			if (!yoe)
				x_bus = y_bus;
			else if ( !BIT(m_l2, 6) && !BIT(m_l4, 5) )
				x_bus = m_ipt_ram[m_ipt_cnt];
		}

		/* IPT BUS */
		if (!BIT(m_l2, 6))
			ipt_bus = m_ipt_ram[m_ipt_cnt];
		else if (!BIT(m_l4, 5))
		{
			if (!BIT(m_l5, 1))
				ipt_bus = y_bus;
			else
				ipt_bus = x_bus;
		}


		/* Write FDT RAM: /Enable, Direction and WRITE */
		if (!BIT(m_l2, 3) && !bl46 && !BIT(m_l4, 3))
			m_fdt_w(*m_program, m_fdt_cnt, x_bus, 0xffff);

		/* Write IPT RAM: /Enable and /WR */
		if (!BIT(m_l2, 7) && !BIT(m_l4, 5))
			m_ipt_ram[m_ipt_cnt] = ipt_bus;


		if ((((m_l5 >> 3) & 0x1f) & 0x18) != 0x18)
		{
			if ( check_jmp((m_l5 >> 3) & 0x1f) )
				next_pc = m_l1;
			else
				next_pc = m_pc + 1;
		}
		else
			next_pc = m_pc + 1;

		m_pl1 = m_l1;
		m_pl2 = m_l2;
		m_pl3 = m_l3;
		m_pl4 = m_l4;
		m_pl5 = m_l5;
		m_pl6 = m_l6;
		m_pl7 = m_l7;

		/* Latch instruction */
		inst = m_direct->read_qword(RIP_PC);

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

		m_l1 = (in_l >> 8);
		m_l2 = (in_l >> 16);
		m_l3 = (in_l >> 24);

		m_l4 = (in_h >> 0);
		m_l5 = (in_h >> 8);
		m_l6 = (in_h >> 16);
		m_l7 = (in_h >> 24);

		/* Colour latch */
		if (RISING_EDGE(m_pl3, m_l3, 0))
			m_c_latch = (x_bus >> 12) & 0xf;

		/* Right pixel line buffer address */
		if (RISING_EDGE(m_pl3, m_l3, 1))
			m_adr_latch = x_bus & 0xfff;

		/* Left pixel line buffer address */
		if (RISING_EDGE(m_pl3, m_l3, 2))
			m_adl_latch = x_bus & 0xfff;

		/* FIGLD: Start the DMA */
		if (RISING_EDGE(m_pl3, m_l3, 3))
		{
			m_attr_latch = x_bus;

			m_fig = 1;
			m_fig_cycles = m_draw(m_adl_latch, m_adr_latch, m_fig_latch, m_attr_latch, m_iaddr_latch, m_c_latch, m_x_scale, m_img_bank);
		}

		/* X-scale */
		if (RISING_EDGE(m_pl3, m_l3, 4))
			m_x_scale = x_bus >> 8;

		/* Y-scale and image bank */
		if (RISING_EDGE(m_pl4, m_l4, 2))
		{
			m_y_scale = x_bus & 0xff;
			m_img_bank = (y_bus >> 14) & 3;
		}

		/* Image ROM address */
		if (RISING_EDGE(m_pl3, m_l3, 5))
			m_iaddr_latch = y_bus;

		/* IXLLD */
		if (RISING_EDGE(m_pl3, m_l3, 6))
		{
			m_line_latch = ipt_bus >> 10;
			m_fig_latch  = ipt_bus & 0x3ff;
		}

		/* Status write */
		if (RISING_EDGE(m_pl3, m_l3, 7))
			m_status_out = y_bus & 0xff;

		/* FDT address counter */
		if (!BIT(m_pl2, 1))
			m_fdt_cnt = y_bus & 0xfff;
		else if (BIT(m_pl2, 2))
			m_fdt_cnt = (m_fdt_cnt + 1) & 0xfff;

		/* Now we can alter the IPT address counter */
		if (!BIT(m_pl2, 4))
			m_ipt_cnt = y_bus & 0x1fff;
		else if (BIT(m_pl2, 5))
			m_ipt_cnt = (m_ipt_cnt + 1) & 0x1fff;

		if (calldebugger)
			debugger_instruction_hook(this, RIP_PC);

		m_pc = next_pc;
		m_rip_pc = (m_pc | ((m_status_out & 1) << 8));

		m_icount--;
	} while (m_icount > 0);
}
