// license:GPL-2.0+
// copyright-holders:Dirk Best
/***************************************************************************

    GAYLE

    Gate array used in the Amiga 600 and Amiga 1200 computers.

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

#include "emu.h"
#include "gayle.h"


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

#define VERBOSE 0


//**************************************************************************
//  DEVICE DEFINITIONS
//**************************************************************************

DEFINE_DEVICE_TYPE(GAYLE, gayle_device, "gayle", "Amiga GAYLE")


//**************************************************************************
//  LIVE DEVICE
//**************************************************************************

//-------------------------------------------------
//  gayle_device - constructor
//-------------------------------------------------

gayle_device::gayle_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
	device_t(mconfig, GAYLE, tag, owner, clock),
	m_int2_w(*this),
	m_cs0_read(*this),
	m_cs0_write(*this),
	m_cs1_read(*this),
	m_cs1_write(*this),
	m_gayle_id(0xff),
	m_gayle_id_count(0)
{
}

//-------------------------------------------------
//  device_start - device-specific startup
//-------------------------------------------------

void gayle_device::device_start()
{
	// resolve callbacks
	m_int2_w.resolve_safe();
	m_cs0_read.resolve_safe(0xffff);
	m_cs0_write.resolve_safe();
	m_cs1_read.resolve_safe(0xffff);
	m_cs1_write.resolve_safe();

	save_item(NAME(m_gayle_id_count));
	save_item(NAME(m_gayle_reg));
}

//-------------------------------------------------
//  device_reset - device-specific reset
//-------------------------------------------------

void gayle_device::device_reset()
{
	m_gayle_reg[0] = 0;
	m_gayle_reg[1] = 0;
	m_gayle_reg[2] = 0;
	m_gayle_reg[3] = 0;
}


//**************************************************************************
//  IMPLEMENTATION
//**************************************************************************

uint16_t gayle_device::gayle_r(offs_t offset, uint16_t mem_mask)
{
	uint16_t data = 0xffff;
	offset <<= 1;

	// swap
	mem_mask = swapendian_int16(mem_mask);

	if (BIT(offset, 15))
	{
		switch (offset & 0x7fff)
		{
		case 0x0000: data = m_gayle_reg[0]; break;
		case 0x1000: data = m_gayle_reg[1]; break;
		case 0x2000: data = m_gayle_reg[2]; break;
		case 0x3000: data = m_gayle_reg[3]; break;
		}
	}
	else
	{
		if (!BIT(offset, 14))
		{
			if (BIT(offset, 13))
				data = m_cs0_read((offset >> 2) & 0x07, mem_mask);
			else
				data = m_cs1_read((offset >> 2) & 0x07, mem_mask);
		}
	}

	if (VERBOSE)
		logerror("gayle_r(%06x): %04x & %04x\n", offset, data, mem_mask);

	// swap data
	data = swapendian_int16(data);

	return data;
}

void gayle_device::gayle_w(offs_t offset, uint16_t data, uint16_t mem_mask)
{
	offset <<= 1;

	// swap
	mem_mask = swapendian_int16(mem_mask);
	data = swapendian_int16(data) & mem_mask;

	if (VERBOSE)
		logerror("gayle_w(%06x): %04x & %04x\n", offset, data, mem_mask);

	if (BIT(offset, 15))
	{
		switch (offset & 0x7fff)
		{
		case 0x0000:
			m_gayle_reg[0] = data;
			break;
		case 0x1000:
			m_gayle_reg[1] &= data;
			m_gayle_reg[1] |= data & 0x03;
			break;
		case 0x2000:
			m_gayle_reg[2] = data;
			break;
		case 0x3000:
			m_gayle_reg[3] = data;
			break;
		}
	}
	else
	{
		if (!BIT(offset, 14))
		{
			if (BIT(offset, 13))
				m_cs0_write((offset >> 2) & 0x07, data, mem_mask);
			else
				m_cs1_write((offset >> 2) & 0x07, data, mem_mask);
		}
	}
}

WRITE_LINE_MEMBER( gayle_device::ide_interrupt_w )
{
	if (VERBOSE)
		logerror("ide_interrupt_w: %d\n", state);

	// did we change state?
	if (BIT(m_gayle_reg[GAYLE_CS], 7) != state)
		m_gayle_reg[GAYLE_IRQ] |= 1 << 7;

	// set line state
	if (state)
		m_gayle_reg[GAYLE_CS] |= 1 << 7;
	else
		m_gayle_reg[GAYLE_CS] &= ~(1 << 7);

	// update interrupts
	if (BIT(m_gayle_reg[GAYLE_INTEN], 7))
		m_int2_w(BIT(m_gayle_reg[GAYLE_CS], 7));
}

uint16_t gayle_device::gayle_id_r(offs_t offset, uint16_t mem_mask)
{
	uint16_t data;

	if (ACCESSING_BITS_8_15)
		data = ((m_gayle_id << m_gayle_id_count++) & 0x80) << 8;
	else
		data = 0xffff;

	if (VERBOSE)
		logerror("gayle_id_r(%06x): %04x & %04x (id=%02x)\n", offset, data, mem_mask, m_gayle_id);

	return data;
}

void gayle_device::gayle_id_w(offs_t offset, uint16_t data, uint16_t mem_mask)
{
	if (VERBOSE)
		logerror("gayle_id_w(%06x): %04x & %04x (id=%02x)\n", offset, data, mem_mask, m_gayle_id);

	m_gayle_id_count = 0;
}
