// license:BSD-3-Clause
// copyright-holders:hap

// MM77/MM78 opcode handlers

#include "emu.h"
#include "mm78.h"


// changed opcodes

void mm78_device::op_lba()
{
	// LBA: no RAM delay
	mm76_device::op_lba();
	m_ram_delay = false;
}

void mm78_device::op_acsk()
{
	// ACSK: skip logic is inverted
	mm76_device::op_acsk();
	m_skip = !m_skip;
}

void mm78_device::op_aisk()
{
	// AISK x: don't skip if x=6 (aka DC opcode)
	mm76_device::op_aisk();
	if ((m_op & 0xf) == 6)
		m_skip = false;
}

void mm78_device::op_sb()
{
	// SB x: SB/SOS opcodes are separated
	ram_w(ram_r() | (1 << (m_op & 3)));
}

void mm78_device::op_rb()
{
	// RB x: RB/ROS opcodes are separated
	ram_w(ram_r() & ~(1 << (m_op & 3)));
}

void mm78_device::op_skbf()
{
	// SKBF x: SKBF/SKISL opcodes are separated
	m_skip = !BIT(ram_r(), m_op & 3);
}

void mm78_device::op_sos()
{
	// SOS: SB/SOS opcodes are separated

	// B7 must be low
	if (m_ram_addr & 0x40)
	{
		logerror("SOS invalid access at $%03X\n", m_prev_pc);
		return;
	}

	u8 bl = m_ram_addr & 0xf;
	if (bl < m_d_pins)
	{
		m_d_output = (m_d_output | (1 << bl)) & m_d_mask;
		m_write_d(m_d_output);
	}
	else if (bl < 12)
		m_int_ff[~bl & 1] = 1;
	else
		logerror("SOS invalid pin %d at $%03X\n", bl, m_prev_pc);
}

void mm78_device::op_ros()
{
	// ROS: RB/ROS opcodes are separated

	// B7 must be low
	if (m_ram_addr & 0x40)
	{
		logerror("ROS invalid access at $%03X\n", m_prev_pc);
		return;
	}

	u8 bl = m_ram_addr & 0xf;
	if (bl < m_d_pins)
	{
		m_d_output = m_d_output & ~(1 << bl);
		m_write_d(m_d_output);
	}
	else if (bl < 12)
		m_int_ff[~bl & 1] = 0;
	else
		logerror("ROS invalid pin %d at $%03X\n", bl, m_prev_pc);
}

void mm78_device::op_skisl()
{
	// SKISL: SKBF/SKISL opcodes are separated

	// B7 must be low
	if (m_ram_addr & 0x40)
	{
		logerror("SKISL invalid access at $%03X\n", m_prev_pc);
		return;
	}

	u8 bl = m_ram_addr & 0xf;
	if (bl < m_d_pins)
		m_skip = !BIT((m_d_output | m_read_d()) & m_d_mask, bl);
	else if (bl < 12)
		m_skip = !m_int_ff[~bl & 1];
	else
		logerror("SKISL invalid pin %d at $%03X\n", bl, m_prev_pc);
}


// new opcodes

void mm78_device::op_sag()
{
	// SAG: set Bu to 3 for the next cycle
	m_sag = true;
}

void mm78_device::op_lxa()
{
	// LXA: load X from A
	m_x = m_a;
}

void mm78_device::op_xax()
{
	// XAX: exchange A with X
	u8 a = m_a;
	m_a = m_x;
	m_x = a;
}

void mm78_device::op_tlb()
{
	// TLB x: transfer long banked
	op_tl();
	m_pc |= 0x400;
}

void mm78_device::op_tmlb()
{
	// TMLB x: transfer and mark long banked
	op_tml();
	m_pc |= 0x400;
}

void mm78_device::op_tab()
{
	// TAB: table look up transfer
	m_skip_count = m_a + 1;
	m_a = 0xf;
}

void mm78_device::op_ix()
{
	// IX: input to X from channel X(aka B)
	m_x = (m_read_r() & m_r_output) >> 4 & 0xf;
}

void mm78_device::op_ox()
{
	// OX: output from X to channel X(aka B)
	m_r_output = (m_r_output & 0xf) | m_x << 4;
	m_write_r(m_r_output);
}

void mm78_device::op_ioa()
{
	// IOA: exchange A with channel A
	u8 a = m_read_r() & m_r_output & 0xf;
	m_r_output = (m_r_output & ~0xf) | m_a;
	m_write_r(m_r_output);
	m_a = a;
}

void mm78_device::op_i1sk()
{
	// I1SK: add channel 1 to A, skip on no overflow
	m_a += m_read_p() & 0xf;
	m_skip = !(m_a & 0x10);
	m_a &= 0xf;
}

void mm78_device::op_int0h()
{
	// INT0H: skip on INT0 high
	m_skip = bool(m_int_line[0]);
}

void mm78_device::op_int1l()
{
	// INT1L: skip on INT1 low
	m_skip = !m_int_line[1];
}
