diff options
Diffstat (limited to 'src/devices/machine/spg290_timer.cpp')
-rw-r--r-- | src/devices/machine/spg290_timer.cpp | 156 |
1 files changed, 156 insertions, 0 deletions
diff --git a/src/devices/machine/spg290_timer.cpp b/src/devices/machine/spg290_timer.cpp new file mode 100644 index 00000000000..f0c0867a612 --- /dev/null +++ b/src/devices/machine/spg290_timer.cpp @@ -0,0 +1,156 @@ +// license:BSD-3-Clause +// copyright-holders:Sandro Ronco +/***************************************************************************** + + SPG290 Timer + +*****************************************************************************/ + +#include "emu.h" +#include "spg290_timer.h" + + +DEFINE_DEVICE_TYPE(SPG290_TIMER, spg290_timer_device, "spg290_timer", "SPG290 Timer") + + +spg290_timer_device::spg290_timer_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : device_t(mconfig, SPG290_TIMER, tag, owner, clock) + , m_irq_cb(*this) + , m_enabled(false) +{ +} + +void spg290_timer_device::device_start() +{ + m_tick_timer = timer_alloc(FUNC(spg290_timer_device::timer_update), this); + + save_item(NAME(m_enabled)); + save_item(NAME(m_control)); + save_item(NAME(m_control2)); + save_item(NAME(m_preload)); + save_item(NAME(m_counter)); + save_item(NAME(m_ccp)); + save_item(NAME(m_upcount)); +} + +void spg290_timer_device::device_reset() +{ + m_enabled = false; + m_control = 0; + m_control2 = 0; + m_preload = 0; + m_counter = 0; + m_ccp = 0; + m_upcount = 0; + + m_tick_timer->adjust(attotime::never); + + m_irq_cb(CLEAR_LINE); +} + +void spg290_timer_device::device_clock_changed() +{ + if (m_enabled) + m_tick_timer->adjust(attotime::from_hz(clock()), 0, attotime::from_hz(clock())); + else + m_tick_timer->adjust(attotime::never); +} + +TIMER_CALLBACK_MEMBER(spg290_timer_device::timer_update) +{ + if (!BIT(m_control, 31)) + return; + + switch ((m_control2 >> 30) & 0x03) + { + case 0: // Timer Mode + if (m_counter == 0xffff) + { + m_counter = m_preload & 0xffff; + if (BIT(m_control, 27)) + { + m_control |= 0x04000000; + m_irq_cb(ASSERT_LINE); + } + } + else + m_counter++; + break; + case 1: // Capture Mode + fatalerror("[%s] %s: unemulated timer Capture Mode\n", tag(), machine().describe_context()); + break; + case 2: // Comparison Mode + fatalerror("[%s] %s: unemulated timer Comparison Mode\n", tag(), machine().describe_context()); + break; + case 3: // PWM Mode + fatalerror("[%s] %s: unemulated timer PWM Mode\n", tag(), machine().describe_context()); + break; + } +} + +void spg290_timer_device::control_w(uint32_t data) +{ + bool enabled = data & 1; + if (m_enabled != enabled) + { + m_enabled = enabled; + spg290_timer_device::device_clock_changed(); + } + + if (data & 2) + m_counter = m_preload & 0xffff; +} + +uint32_t spg290_timer_device::read(offs_t offset, uint32_t mem_mask) +{ + switch (offset << 2) + { + case 0x00: // Control 1 + return m_control; + case 0x04: // Control 2 + return m_control2; + case 0x08: // Preload + return m_preload; + case 0x0c: // CCP + return m_ccp; + case 0x10: // Upcount + return m_upcount; + default: + logerror("[%s] %s: unknown read %x\n", tag(), machine().describe_context(), offset << 2); + } + + return 0; +} + + +void spg290_timer_device::write(offs_t offset, uint32_t data, uint32_t mem_mask) +{ + switch (offset << 2) + { + case 0x00: // Control 1 + COMBINE_DATA(&m_control); + + if (ACCESSING_BITS_24_31) + { + m_control &= ~(data & 0x04000000); // IRQ ack + + if (!(m_control & 0x04000000)) + m_irq_cb(CLEAR_LINE); + } + break; + case 0x04: // Control 2 + COMBINE_DATA(&m_control2); + break; + case 0x08: // Preload + COMBINE_DATA(&m_preload); + break; + case 0x0c: // CCP + COMBINE_DATA(&m_ccp); + break; + case 0x10: // Upcount + COMBINE_DATA(&m_upcount); + break; + default: + logerror("[%s] %s: unknown write %x = %x\n", tag(), machine().describe_context(), offset << 2, data); + } +} |