// 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();
}