mirror of
https://github.com/holub/mame
synced 2025-10-07 09:25:34 +03:00

Use standard uint64_t, uint32_t, uint16_t or uint8_t instead of UINT64, UINT32, UINT16 or UINT8 also use standard int64_t, int32_t, int16_t or int8_t instead of INT64, INT32, INT16 or INT8
290 lines
8.2 KiB
C++
290 lines
8.2 KiB
C++
// license:BSD-3-Clause
|
|
// copyright-holders:Aaron Giles
|
|
/***************************************************************************
|
|
|
|
timer.cpp
|
|
|
|
Timer devices.
|
|
|
|
***************************************************************************/
|
|
|
|
#include "emu.h"
|
|
|
|
|
|
/***************************************************************************
|
|
// DEBUGGING
|
|
***************************************************************************/
|
|
|
|
#define VERBOSE 0
|
|
|
|
#define LOG(x) do { if (VERBOSE) logerror x; } while (0)
|
|
|
|
|
|
|
|
|
|
//**************************************************************************
|
|
// LIVE TIMER DEVICE
|
|
//**************************************************************************
|
|
|
|
const device_type TIMER = &device_creator<timer_device>;
|
|
|
|
//-------------------------------------------------
|
|
// timer_device - constructor
|
|
//-------------------------------------------------
|
|
|
|
timer_device::timer_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
|
|
: device_t(mconfig, TIMER, "Timer", tag, owner, clock, "timer", __FILE__),
|
|
m_type(TIMER_TYPE_GENERIC),
|
|
m_callback(timer_device_expired_delegate()),
|
|
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, timer_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, timer_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, timer_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, timer_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;
|
|
}
|
|
}
|
|
}
|