summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/machine/timer.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices/machine/timer.cpp')
-rw-r--r--src/devices/machine/timer.cpp291
1 files changed, 291 insertions, 0 deletions
diff --git a/src/devices/machine/timer.cpp b/src/devices/machine/timer.cpp
new file mode 100644
index 00000000000..1bc10dab25a
--- /dev/null
+++ b/src/devices/machine/timer.cpp
@@ -0,0 +1,291 @@
+// license:BSD-3-Clause
+// copyright-holders:Aaron Giles
+/***************************************************************************
+
+ timer.cpp
+
+ Timer devices.
+
+***************************************************************************/
+
+#include "emu.h"
+#include "machine/timer.h"
+#include "screen.h"
+
+
+/***************************************************************************
+// DEBUGGING
+***************************************************************************/
+
+#define VERBOSE 0
+
+#define LOG(x) do { if (VERBOSE) logerror x; } while (0)
+
+
+
+
+//**************************************************************************
+// LIVE TIMER DEVICE
+//**************************************************************************
+
+DEFINE_DEVICE_TYPE(TIMER, timer_device, "timer", "Timer")
+
+//-------------------------------------------------
+// timer_device - constructor
+//-------------------------------------------------
+
+timer_device::timer_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
+ : device_t(mconfig, TIMER, tag, owner, clock),
+ m_type(TIMER_TYPE_GENERIC),
+ m_callback(),
+ m_ptr(nullptr),
+ m_start_delay(attotime::zero),
+ m_period(attotime::zero),
+ m_param(0),
+ m_screen_tag(nullptr),
+ m_screen(nullptr),
+ m_first_vpos(0),
+ m_increment(0),
+ m_timer(nullptr),
+ m_first_time(true)
+{
+}
+
+
+//-------------------------------------------------
+// static_configure_generic - configuration
+// helper to set up a generic timer
+//-------------------------------------------------
+
+void timer_device::static_configure_generic(device_t &device, expired_delegate callback)
+{
+ timer_device &timer = downcast<timer_device &>(device);
+ timer.m_type = TIMER_TYPE_GENERIC;
+ timer.m_callback = callback;
+}
+
+
+//-------------------------------------------------
+// static_configure_periodic - configuration
+// helper to set up a periodic timer
+//-------------------------------------------------
+
+void timer_device::static_configure_periodic(device_t &device, expired_delegate callback, const attotime &period)
+{
+ timer_device &timer = downcast<timer_device &>(device);
+ timer.m_type = TIMER_TYPE_PERIODIC;
+ timer.m_callback = callback;
+ timer.m_period = period;
+}
+
+
+//-------------------------------------------------
+// static_configure_scanline - configuration
+// helper to set up a scanline timer
+//-------------------------------------------------
+
+void timer_device::static_configure_scanline(device_t &device, expired_delegate callback, const char *screen, int first_vpos, int increment)
+{
+ timer_device &timer = downcast<timer_device &>(device);
+ timer.m_type = TIMER_TYPE_SCANLINE;
+ timer.m_callback = callback;
+ timer.m_screen_tag = screen;
+ timer.m_first_vpos = first_vpos;
+ timer.m_increment = increment;
+}
+
+
+//-------------------------------------------------
+// static_set_callback - configuration helper
+// to set the callback
+//-------------------------------------------------
+
+void timer_device::static_set_callback(device_t &device, expired_delegate callback)
+{
+ timer_device &timer = downcast<timer_device &>(device);
+ timer.m_callback = callback;
+}
+
+
+//-------------------------------------------------
+// static_set_start_delay - configuration helper
+// to set the starting delay
+//-------------------------------------------------
+
+void timer_device::static_set_start_delay(device_t &device, const attotime &delay)
+{
+ timer_device &timer = downcast<timer_device &>(device);
+ timer.m_start_delay = delay;
+}
+
+
+//-------------------------------------------------
+// static_set_param - configuration helper to set
+// the integer parameter
+//-------------------------------------------------
+
+void timer_device::static_set_param(device_t &device, int param)
+{
+ timer_device &timer = downcast<timer_device &>(device);
+ timer.m_param = param;
+}
+
+
+//-------------------------------------------------
+// static_set_ptr - configuration helper to set
+// the pointer parameter
+//-------------------------------------------------
+
+void timer_device::static_set_ptr(device_t &device, void *ptr)
+{
+ timer_device &timer = downcast<timer_device &>(device);
+ timer.m_ptr = ptr;
+}
+
+
+//-------------------------------------------------
+// device_validity_check - validate the device
+// configuration
+//-------------------------------------------------
+
+void timer_device::device_validity_check(validity_checker &valid) const
+{
+ // type based configuration
+ switch (m_type)
+ {
+ case TIMER_TYPE_GENERIC:
+ if (m_screen_tag != nullptr || m_first_vpos != 0 || m_start_delay != attotime::zero)
+ osd_printf_warning("Generic timer specified parameters for a scanline timer\n");
+ if (m_period != attotime::zero || m_start_delay != attotime::zero)
+ osd_printf_warning("Generic timer specified parameters for a periodic timer\n");
+ break;
+
+ case TIMER_TYPE_PERIODIC:
+ if (m_screen_tag != nullptr || m_first_vpos != 0)
+ osd_printf_warning("Periodic timer specified parameters for a scanline timer\n");
+ if (m_period <= attotime::zero)
+ osd_printf_error("Periodic timer specified invalid period\n");
+ break;
+
+ case TIMER_TYPE_SCANLINE:
+ if (m_period != attotime::zero || m_start_delay != attotime::zero)
+ osd_printf_warning("Scanline timer specified parameters for a periodic timer\n");
+ if (m_param != 0)
+ osd_printf_warning("Scanline timer specified parameter which is ignored\n");
+// if (m_first_vpos < 0)
+// osd_printf_error("Scanline timer specified invalid initial position\n");
+// if (m_increment < 0)
+// osd_printf_error("Scanline timer specified invalid increment\n");
+ break;
+
+ default:
+ osd_printf_error("Invalid type specified\n");
+ break;
+ }
+}
+
+
+//-------------------------------------------------
+// device_start - perform device-specific
+// startup
+//-------------------------------------------------
+
+void timer_device::device_start()
+{
+ // fetch the screen
+ if (m_screen_tag != nullptr)
+ m_screen = machine().device<screen_device>(m_screen_tag);
+
+ // allocate the timer
+ m_timer = timer_alloc();
+
+ m_callback.bind_relative_to(*owner());
+
+ // register for save states
+ save_item(NAME(m_first_time));
+}
+
+
+//-------------------------------------------------
+// device_reset - reset the device
+//-------------------------------------------------
+
+void timer_device::device_reset()
+{
+ // type based configuration
+ switch (m_type)
+ {
+ case TIMER_TYPE_GENERIC:
+ case TIMER_TYPE_PERIODIC:
+ {
+ // convert the period into attotime
+ attotime period;
+ if (m_period > attotime::zero)
+ {
+ period = m_period;
+
+ // convert the start_delay into attotime
+ attotime start_delay = attotime::zero;
+ if (m_start_delay > attotime::zero)
+ start_delay = m_start_delay;
+
+ // allocate and start the backing timer
+ m_timer->adjust(start_delay, m_param, period);
+ }
+ break;
+ }
+
+ case TIMER_TYPE_SCANLINE:
+ if (m_screen == nullptr)
+ fatalerror("timer '%s': unable to find screen '%s'\n", tag(), m_screen_tag);
+
+ // set the timer to fire immediately
+ m_first_time = true;
+ m_timer->adjust(attotime::zero, m_param);
+ break;
+ }
+}
+
+
+//-------------------------------------------------
+// device_timer - handle timer expiration events
+//-------------------------------------------------
+
+void timer_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+{
+ switch (m_type)
+ {
+ // general periodic timers just call through
+ case TIMER_TYPE_GENERIC:
+ case TIMER_TYPE_PERIODIC:
+ if (!m_callback.isnull())
+ (m_callback)(*this, m_ptr, param);
+ break;
+
+
+ // scanline timers have to do some additiona bookkeeping
+ case TIMER_TYPE_SCANLINE:
+ {
+ // by default, we fire at the first position
+ int next_vpos = m_first_vpos;
+
+ // the first time through we just go with the default position
+ if (!m_first_time)
+ {
+ // call the real callback
+ int vpos = m_screen->vpos();
+ if (!m_callback.isnull())
+ (m_callback)(*this, m_ptr, vpos);
+
+ // advance by the increment only if we will still be within the screen bounds
+ if (m_increment != 0 && (vpos + m_increment) < m_screen->height())
+ next_vpos = vpos + m_increment;
+ }
+ m_first_time = false;
+
+ // adjust the timer
+ m_timer->adjust(m_screen->time_until_pos(next_vpos));
+ break;
+ }
+ }
+}