// license:BSD-3-Clause
// copyright-holders:David Haywood

// Do timers auto reload?
// Does writing to Enable actually turn on the timer, or writing to preload MSB? (which appears to be done AFTER turning on in many cases)

#include "emu.h"
#include "machine/vt1682_timer.h"

#define LOG_TIMER     (1U << 1)

#define LOG_ALL           ( LOG_TIMER )

#define VERBOSE             (LOG_TIMER)
#include "logmacro.h"

// NOTE, system timer base clock can also be changed with "0x210B TSYNEN"
// this can be handled externally by changing device clock?

DEFINE_DEVICE_TYPE(VT_VT1682_TIMER, vrt_vt1682_timer_device, "vt1682timer", "VRT VT1682 Timer")

vrt_vt1682_timer_device::vrt_vt1682_timer_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
	device_t(mconfig, VT_VT1682_TIMER, tag, owner, clock),
	m_timer(*this, "snd_timera"),
	m_irq_cb(*this)
{
}

void vrt_vt1682_timer_device::device_start()
{
	save_item(NAME(m_timer_preload_7_0));
	save_item(NAME(m_timer_preload_15_8));
	save_item(NAME(m_timer_enable));

	m_irq_cb.resolve();
}

void vrt_vt1682_timer_device::device_reset()
{
	m_timer_preload_7_0 = 0;
	m_timer_preload_15_8 = 0;
	m_timer_enable = 0;
}



/*
    Address 0x2100 r/w (SOUND CPU, Timer A)
    Address 0x2110 r/w (SOUND CPU, Timer B)

    Address 0x2101 r/w (MAIN CPU, Timer)

    0x80 - Timer xx Preload:7
    0x40 - Timer xx Preload:6
    0x20 - Timer xx Preload:5
    0x10 - Timer xx Preload:4
    0x08 - Timer xx Preload:3
    0x04 - Timer xx Preload:2
    0x02 - Timer xx Preload:1
    0x01 - Timer xx Preload:0
*/

uint8_t vrt_vt1682_timer_device::vt1682_timer_preload_7_0_r()
{
	uint8_t ret = m_timer_preload_7_0;
	if (!m_is_sound_timer) LOGMASKED(LOG_TIMER,"%s: vt1682_timer_preload_7_0_r returning: %02x\n", machine().describe_context(), ret);
	return ret;
}

void vrt_vt1682_timer_device::vt1682_timer_preload_7_0_w(uint8_t data)
{
	if (!m_is_sound_timer) LOGMASKED(LOG_TIMER,"%s: vt1682_timer_preload_7_0_w writing: %02x\n", machine().describe_context(), data);
	m_timer_preload_7_0 = data;
}


/*
    Address 0x2101 r/w (SOUND CPU, Timer A)
    Address 0x2111 r/w (SOUND CPU, Timer B)

    Address 0x2104 r/w (MAIN CPU, Timer)

    0x80 - Timer xx Preload:15
    0x40 - Timer xx Preload:14
    0x20 - Timer xx Preload:13
    0x10 - Timer xx Preload:12
    0x08 - Timer xx Preload:11
    0x04 - Timer xx Preload:10
    0x02 - Timer xx Preload:9
    0x01 - Timer xx Preload:8
*/

uint8_t vrt_vt1682_timer_device::vt1682_timer_preload_15_8_r()
{
	uint8_t ret = m_timer_preload_15_8;
	if (!m_is_sound_timer) LOGMASKED(LOG_TIMER,"%s: vt1682_timer_preload_15_8_r returning: %02x\n", machine().describe_context(), ret);
	return ret;
}

void vrt_vt1682_timer_device::update_timer()
{
	if (m_timer_enable & 0x01)
	{
		uint16_t preload = (m_timer_preload_15_8 << 8) | m_timer_preload_7_0;
		int realpreload = 65536 - preload;
		m_timer->adjust(attotime::from_hz(clock()) * realpreload, 0, attotime::from_hz(clock()) * realpreload);
	}
}

void vrt_vt1682_timer_device::vt1682_timer_preload_15_8_w(uint8_t data)
{
	if (!m_is_sound_timer) LOGMASKED(LOG_TIMER,"%s: vt1682_timer_preload_15_8_w writing: %02x\n", machine().describe_context(), data);
	m_timer_preload_15_8 = data;

	update_timer();
}





/*
    Address 0x2102 r/w (SOUND CPU, Timer A)
    Address 0x2112 r/w (SOUND CPU, Timer B)

    Address 0x2102 r/w (MAIN CPU, Timer)

    0x80 - (unused)
    0x40 - (unused)
    0x20 - (unused)
    0x10 - (unused)
    0x08 - (unused)
    0x04 - (unused)
    0x02 - TMRxx IRQ
    0x01 - TMRxx EN
*/

uint8_t vrt_vt1682_timer_device::vt1682_timer_enable_r()
{
	uint8_t ret = m_timer_enable;
	if (!m_is_sound_timer) LOGMASKED(LOG_TIMER,"%s: vt1682_timer_enable_r returning: %02x\n", machine().describe_context(), ret);
	return ret;
}

void vrt_vt1682_timer_device::vt1682_timer_enable_w(uint8_t data)
{
	// Timer A notes
	// For NTSC
	//Period = (65536 - Timer _PreLoad) / 21.4772 MHz
	//Timer PreLoad = 65536 - (Period in seconds) * 21.4772 * 1000000 )

	// For PAL
	// Period = (65536 - Timer PreLoad) / 26.601712 MHz
	//Timer PreLoad = 65536 - (Period in seconds) * 26.601712 * 1000000 )

	if (!m_is_sound_timer) LOGMASKED(LOG_TIMER, "%s: vt1682_timer_enable_w writing: %02x\n", machine().describe_context(), data);
	m_timer_enable = data;

	if (m_timer_enable & 0x01)
	{
		update_timer();
	}
	else
	{
		m_timer->adjust(attotime::never);
	}
}

TIMER_DEVICE_CALLBACK_MEMBER(vrt_vt1682_timer_device::timer_expired)
{
	if (m_timer_enable & 0x02)
	{
		m_irq_cb(true);
	}
}

/*
    Address 0x2103 r/w (SOUND CPU, Timer A)
    Address 0x2113 r/w (SOUND CPU, Timer B)

    Address 0x2103 r/w (MAIN CPU, Timer) (read or write?)

    0x80 - Timer xx IRQ Clear
    0x40 - Timer xx IRQ Clear
    0x20 - Timer xx IRQ Clear
    0x10 - Timer xx IRQ Clear
    0x08 - Timer xx IRQ Clear
    0x04 - Timer xx IRQ Clear
    0x02 - Timer xx IRQ Clear
    0x01 - Timer xx IRQ Clear

*/

void vrt_vt1682_timer_device::vt1682_timer_irqclear_w(uint8_t data)
{
	//if (!m_is_sound_timer) LOGMASKED(LOG_TIMER,"%s: vt1682_timer_irqclear_w writing: %02x\n", machine().describe_context(), data);
	m_irq_cb(false);
}

void vrt_vt1682_timer_device::device_add_mconfig(machine_config& config)
{
	TIMER(config, m_timer).configure_generic(FUNC(vrt_vt1682_timer_device::timer_expired));
}

void vrt_vt1682_timer_device::change_clock()
{
	notify_clock_changed();
}
