summaryrefslogtreecommitdiffstatshomepage
path: root/src/emu/timer.c
diff options
context:
space:
mode:
author Aaron Giles <aaron@aarongiles.com>2011-02-06 07:15:01 +0000
committer Aaron Giles <aaron@aarongiles.com>2011-02-06 07:15:01 +0000
commit0e627f1a5443528526eb35ec3a9cb7fb9e5af907 (patch)
tree3b44469d96597a98080accaec1bccbbad3815acc /src/emu/timer.c
parentf38d3384b648811571b50acd16709ae47becaabd (diff)
Convert emu_timers to objects. Move implementation and management of
timers into the scheduler. Retain TIMER devices as a separate wrapper in timer.c/.h. Inline wrappers are currently provided for all timer operations; a future update will bulk clean these up. Rather than using macros which hide generation of a string-ified name for callback functions, the new methods require passing both a function pointer plus a name string. A new macro FUNC() can be used to output both, and another macro MFUNC() can be used to output a stub-wrapped class member as a callback. Also added a time() method on the machine, so that machine->time() gives the current emulated time. A wrapper for timer_get_time is currently provided but will be bulk replaced in the future. For this update, convert all classic timer_alloc, timer_set, timer_pulse, and timer_call_after_resynch calls into method calls on the scheduler. For new device timers, added methods to the device_t class that make creating and managing these much simpler. Modern devices were updated to use these. Here are the regexes used; some manual cleanup (compiler-caught) will be needed since regex doesn't handle nested parentheses cleanly 1. Convert timer_call_after_resynch calls timer_call_after_resynch( *)\(( *)([^,;]+), *([^,;]+), *([^,;]+), *([^);]+)\) \3->scheduler().synchronize\1\(\2FUNC(\6), \5, \4\) 2. Clean up trailing 0, NULL parameters (synchronize[^;]+), 0, NULL\) \1) 3. Clean up trailing NULL parameters (synchronize[^;]+), NULL\) \1) 4. Clean up completely empty parameter lists synchronize\(FUNC\(NULL\)\) synchronize() 5. Convert timer_set calls timer_set( *)\(( *)([^,;]+), *([^,;]+), *([^,;]+), *([^,;]+), *([^);]+)\) \3->scheduler().timer_set\1\(\2\4, FUNC(\7), \6, \5\) 6. Clean up trailing 0, NULL parameters (timer_set[^;]+), 0, NULL\) \1) 7. Clean up trailing NULL parameters (timer_set[^;]+), NULL\) \1) 8. Convert timer_set calls timer_pulse( *)\(( *)([^,;]+), *([^,;]+), *([^,;]+), *([^,;]+), *([^);]+)\) \3->scheduler().timer_pulse\1\(\2\4, FUNC(\7), \6, \5\) 9. Clean up trailing 0, NULL parameters (timer_pulse[^;]+), 0, NULL\) \1) 10. Clean up trailing NULL parameters (timer_pulse[^;]+), NULL\) \1) 11. Convert timer_alloc calls timer_alloc( *)\(( *)([^,;]+), *([^,;]+), *([^);]+)\) \3->scheduler().timer_alloc\1\(\2FUNC(\4), \5\) 12. Clean up trailing NULL parameters (timer_alloc[^;]+), NULL\) \1) 13. Clean up trailing 0 parameters (timer_alloc[^;]+), 0\) \1) 14. Fix oddities introduced \&m_machine->scheduler() m_machine.scheduler()
Diffstat (limited to 'src/emu/timer.c')
-rw-r--r--src/emu/timer.c1038
1 files changed, 70 insertions, 968 deletions
diff --git a/src/emu/timer.c b/src/emu/timer.c
index e93a85fbd87..05f959ee95a 100644
--- a/src/emu/timer.c
+++ b/src/emu/timer.c
@@ -2,11 +2,38 @@
timer.c
- Functions needed to generate timing and synchronization between several
- CPUs.
-
- Copyright Nicola Salmoria and the MAME Team.
- Visit http://mamedev.org for licensing and usage restrictions.
+ Timer devices.
+
+****************************************************************************
+
+ Copyright Aaron Giles
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are
+ met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+ * Neither the name 'MAME' nor the names of its contributors may be
+ used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY AARON GILES ''AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL AARON GILES BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
***************************************************************************/
@@ -15,7 +42,7 @@
/***************************************************************************
- DEBUGGING
+// DEBUGGING
***************************************************************************/
#define VERBOSE 0
@@ -25,944 +52,13 @@
/***************************************************************************
- CONSTANTS
-***************************************************************************/
-
-#define MAX_TIMERS 256
-#define MAX_QUANTA 16
-
-#define DEFAULT_MINIMUM_QUANTUM ATTOSECONDS_IN_MSEC(100)
-
-
-
-/***************************************************************************
- DEVICE DEFINITIONS
+// DEVICE DEFINITIONS
***************************************************************************/
const device_type TIMER = timer_device_config::static_alloc_device_config;
-/***************************************************************************
- TYPE DEFINITIONS
-***************************************************************************/
-
-class emu_timer
-{
-public:
- running_machine * machine; /* pointer to the owning machine */
- emu_timer * next; /* next timer in order in the list */
- emu_timer * prev; /* previous timer in order in the list */
- timer_fired_func callback; /* callback function */
- INT32 param; /* integer parameter */
- void * ptr; /* pointer parameter */
- const char * file; /* file that created the timer */
- int line; /* line number that created the timer */
- const char * func; /* string name of the callback function */
- UINT8 enabled; /* is the timer enabled? */
- UINT8 temporary; /* is the timer temporary? */
- attotime period; /* the repeat frequency of the timer */
- attotime start; /* time when the timer was started */
- attotime expire; /* time when the timer will expire */
- device_t * device; /* for device timers, a pointer to the device */
- device_timer_id id; /* for device timers, the ID of the timer */
-};
-
-
-/* a single minimum quantum */
-typedef struct _quantum_slot quantum_slot;
-struct _quantum_slot
-{
- attoseconds_t actual; /* actual duration of the quantum */
- attoseconds_t requested; /* duration of the requested quantum */
- attotime expire; /* absolute expiration time of this quantum */
-};
-
-
-/* global private data */
-/* In mame.h: typedef struct _timer_private timer_private; */
-struct _timer_private
-{
- /* list of active timers */
- emu_timer timers[MAX_TIMERS]; /* actual timers */
- emu_timer * activelist; /* head of the active list */
- emu_timer * freelist; /* head of the free list */
- emu_timer * freelist_tail; /* tail of the free list */
-
- /* execution state */
- timer_execution_state exec; /* current global execution state */
-
- /* other internal states */
- emu_timer * callback_timer; /* pointer to the current callback timer */
- UINT8 callback_timer_modified; /* TRUE if the current callback timer was modified */
- attotime callback_timer_expire_time; /* the original expiration time */
-
- /* scheduling quanta */
- quantum_slot quantum_list[MAX_QUANTA]; /* list of scheduling quanta */
- quantum_slot * quantum_current; /* current minimum quantum */
- attoseconds_t quantum_minimum; /* duration of minimum quantum */
-};
-
-
-
-/***************************************************************************
- FUNCTION PROTOTYPES
-***************************************************************************/
-
-static STATE_POSTLOAD( timer_postload );
-static void timer_logtimers(running_machine *machine);
-static void timer_remove(emu_timer *which);
-
-
-
-/***************************************************************************
- INLINE FUNCTIONS
-***************************************************************************/
-
-/*-------------------------------------------------
- get_current_time - return the current time
--------------------------------------------------*/
-
-INLINE attotime get_current_time(running_machine *machine)
-{
- timer_private *global = machine->timer_data;
-
- /* if we're currently in a callback, use the timer's expiration time as a base */
- if (global->callback_timer != NULL)
- return global->callback_timer_expire_time;
-
- /* if we're executing as a particular CPU, use its local time as a base */
- /* otherwise, return the global base time */
- device_execute_interface *execdevice = machine->scheduler().currently_executing();
- return (execdevice != NULL) ? execdevice->local_time() : global->exec.basetime;
-}
-
-
-/*-------------------------------------------------
- timer_new - allocate a new timer
--------------------------------------------------*/
-
-INLINE emu_timer *timer_new(running_machine *machine)
-{
- timer_private *global = machine->timer_data;
- emu_timer *timer;
-
- /* if nothing remains available, fatal error -- we should never hit this */
- if (global->freelist == NULL)
- {
- timer_logtimers(machine);
- fatalerror("Out of timers!");
- }
-
- /* pull an entry from the free list */
- timer = global->freelist;
- global->freelist = timer->next;
- if (global->freelist == NULL)
- global->freelist_tail = NULL;
-
- /* set up the machine */
- timer->machine = machine;
- return timer;
-}
-
-
-/*-------------------------------------------------
- timer_list_insert - insert a new timer into
- the list at the appropriate location
--------------------------------------------------*/
-
-INLINE void timer_list_insert(emu_timer *timer)
-{
- attotime expire = timer->enabled ? timer->expire : attotime::never;
- timer_private *global = timer->machine->timer_data;
- emu_timer *t, *lt = NULL;
-
- /* sanity checks for the debug build */
- #ifdef MAME_DEBUG
- {
- int tnum = 0;
-
- /* loop over the timer list */
- for (t = global->activelist; t; t = t->next, tnum++)
- {
- if (t == timer)
- fatalerror("This timer is already inserted in the list!");
- if (tnum == MAX_TIMERS-1)
- fatalerror("Timer list is full!");
- }
- }
- #endif
-
- /* loop over the timer list */
- for (t = global->activelist; t != NULL; lt = t, t = t->next)
- {
- /* if the current list entry expires after us, we should be inserted before it */
- if (t->expire > expire)
- {
- /* link the new guy in before the current list entry */
- timer->prev = t->prev;
- timer->next = t;
-
- if (t->prev != NULL)
- t->prev->next = timer;
- else
- {
- global->activelist = timer;
- global->exec.nextfire = timer->expire;
- }
- t->prev = timer;
- return;
- }
- }
-
- /* need to insert after the last one */
- if (lt != NULL)
- lt->next = timer;
- else
- {
- global->activelist = timer;
- global->exec.nextfire = timer->expire;
- }
- timer->prev = lt;
- timer->next = NULL;
-}
-
-
-/*-------------------------------------------------
- timer_list_remove - remove a timer from the
- linked list
--------------------------------------------------*/
-
-INLINE void timer_list_remove(emu_timer *timer)
-{
- timer_private *global = timer->machine->timer_data;
-
- /* sanity checks for the debug build */
- #ifdef MAME_DEBUG
- {
- emu_timer *t;
-
- /* loop over the timer list */
- for (t = global->activelist; t && t != timer; t = t->next) ;
- if (t == NULL)
- fatalerror("timer (%s from %s:%d) not found in list", timer->func, timer->file, timer->line);
- }
- #endif
-
- /* remove it from the list */
- if (timer->prev != NULL)
- timer->prev->next = timer->next;
- else
- {
- global->activelist = timer->next;
- if (global->activelist != NULL)
- global->exec.nextfire = global->activelist->expire;
- }
- if (timer->next != NULL)
- timer->next->prev = timer->prev;
-}
-
-
-
-/***************************************************************************
- INITIALIZATION
-***************************************************************************/
-
-/*-------------------------------------------------
- timer_init - initialize the timer system
--------------------------------------------------*/
-
-void timer_init(running_machine *machine)
-{
- timer_private *global;
- int i;
-
- /* allocate global data */
- global = machine->timer_data = auto_alloc_clear(machine, timer_private);
-
- /* we need to wait until the first call to timer_cyclestorun before using real CPU times */
- global->exec.basetime = attotime::zero;
- global->exec.nextfire = attotime::never;
- global->exec.curquantum = DEFAULT_MINIMUM_QUANTUM;
- global->callback_timer = NULL;
- global->callback_timer_modified = FALSE;
-
- /* register with the save state system */
- state_save_register_item(machine, "timer", NULL, 0, global->exec.basetime.seconds);
- state_save_register_item(machine, "timer", NULL, 0, global->exec.basetime.attoseconds);
- state_save_register_postload(machine, timer_postload, NULL);
-
- /* initialize the lists */
- global->activelist = NULL;
- global->freelist = &global->timers[0];
- for (i = 0; i < MAX_TIMERS-1; i++)
- global->timers[i].next = &global->timers[i+1];
- global->timers[MAX_TIMERS-1].next = NULL;
- global->freelist_tail = &global->timers[MAX_TIMERS-1];
-
- /* reset the quanta */
- global->quantum_list[0].requested = DEFAULT_MINIMUM_QUANTUM;
- global->quantum_list[0].actual = DEFAULT_MINIMUM_QUANTUM;
- global->quantum_list[0].expire = attotime::never;
- global->quantum_current = &global->quantum_list[0];
- global->quantum_minimum = ATTOSECONDS_IN_NSEC(1) / 1000;
-}
-
-
-/*-------------------------------------------------
- timer_destructor - destruct a timer from a
- pool callback
--------------------------------------------------*/
-
-void timer_destructor(void *ptr, size_t size)
-{
- timer_remove((emu_timer *)ptr);
-}
-
-
-
-/***************************************************************************
- SCHEDULING HELPERS
-***************************************************************************/
-
-/*-------------------------------------------------
- timer_get_execution_state - return a pointer
- to the execution state
--------------------------------------------------*/
-
-timer_execution_state *timer_get_execution_state(running_machine *machine)
-{
- timer_private *global = machine->timer_data;
- return &global->exec;
-}
-
-
-/*-------------------------------------------------
- timer_execute_timers - execute timers and
- update scheduling quanta
--------------------------------------------------*/
-
-void timer_execute_timers(running_machine *machine)
-{
- timer_private *global = machine->timer_data;
- emu_timer *timer;
-
- /* if the current quantum has expired, find a new one */
- if (global->exec.basetime >= global->quantum_current->expire)
- {
- int curr;
-
- global->quantum_current->requested = 0;
- global->quantum_current = &global->quantum_list[0];
- for (curr = 1; curr < ARRAY_LENGTH(global->quantum_list); curr++)
- if (global->quantum_list[curr].requested != 0 && global->quantum_list[curr].requested < global->quantum_current->requested)
- global->quantum_current = &global->quantum_list[curr];
- global->exec.curquantum = global->quantum_current->actual;
- }
-
- LOG(("timer_set_global_time: new=%s head->expire=%s\n", global->exec.basetime.as_string(), global->activelist->expire.as_string()));
-
- /* now process any timers that are overdue */
- while (global->activelist->expire <= global->exec.basetime)
- {
- int was_enabled = global->activelist->enabled;
-
- /* if this is a one-shot timer, disable it now */
- timer = global->activelist;
- if (timer->period == attotime::zero || timer->period == attotime::never)
- timer->enabled = FALSE;
-
- /* set the global state of which callback we're in */
- global->callback_timer_modified = FALSE;
- global->callback_timer = timer;
- global->callback_timer_expire_time = timer->expire;
-
- /* call the callback */
- if (was_enabled)
- {
- if (timer->device != NULL)
- timer->device->timer_fired(*timer, timer->id, timer->param, timer->ptr);
- else if (timer->callback != NULL)
- {
- LOG(("Timer %s:%d[%s] fired (expire=%s)\n", timer->file, timer->line, timer->func, timer->expire.as_string()));
- g_profiler.start(PROFILER_TIMER_CALLBACK);
- (*timer->callback)(machine, timer->ptr, timer->param);
- g_profiler.stop();
- }
- }
-
- /* clear the callback timer global */
- global->callback_timer = NULL;
-
- /* reset or remove the timer, but only if it wasn't modified during the callback */
- if (!global->callback_timer_modified)
- {
- /* if the timer is temporary, remove it now */
- if (timer->temporary)
- timer_remove(timer);
-
- /* otherwise, reschedule it */
- else
- {
- timer->start = timer->expire;
- timer->expire += timer->period;
-
- timer_list_remove(timer);
- timer_list_insert(timer);
- }
- }
- }
-}
-
-
-/*-------------------------------------------------
- timer_add_scheduling_quantum - add a
- scheduling quantum; the smallest active one
- is the one that is in use
--------------------------------------------------*/
-
-void timer_add_scheduling_quantum(running_machine *machine, attoseconds_t quantum, attotime duration)
-{
- timer_private *global = machine->timer_data;
- attotime curtime = timer_get_time(machine);
- attotime expire = curtime + duration;
- int curr, blank = -1;
-
- /* a 0 request (minimum) needs to be non-zero to occupy a slot */
- if (quantum == 0)
- quantum = 1;
-
- /* find an equal-duration slot or an empty slot */
- for (curr = 1; curr < ARRAY_LENGTH(global->quantum_list); curr++)
- {
- quantum_slot *slot = &global->quantum_list[curr];
-
- /* look for a matching quantum and extend it */
- if (slot->requested == quantum)
- {
- slot->expire = max(slot->expire, expire);
- return;
- }
-
- /* remember any empty slots in case of no match */
- if (slot->requested == 0)
- {
- if (blank == -1)
- blank = curr;
- }
-
- /* otherwise, expire any expired slots */
- else if (curtime >= slot->expire)
- slot->requested = 0;
- }
-
- /* fatal error if no slots left */
- assert_always(blank != -1, "Out of scheduling quantum slots!");
-
- /* fill in the item */
- global->quantum_list[blank].requested = quantum;
- global->quantum_list[blank].actual = MAX(global->quantum_list[blank].requested, global->quantum_minimum);
- global->quantum_list[blank].expire = expire;
-
- /* update the minimum */
- if (quantum < global->quantum_current->requested)
- {
- global->quantum_current = &global->quantum_list[blank];
- global->exec.curquantum = global->quantum_current->actual;
- }
-}
-
-
-/*-------------------------------------------------
- timer_set_minimum_quantum - control the
- minimum useful quantum (used by cpuexec only)
--------------------------------------------------*/
-
-void timer_set_minimum_quantum(running_machine *machine, attoseconds_t quantum)
-{
- timer_private *global = machine->timer_data;
- int curr;
-
- /* do nothing if nothing changed */
- if (global->quantum_minimum == quantum)
- return;
- global->quantum_minimum = quantum;
-
- /* adjust all the actuals; this doesn't affect the current */
- for (curr = 0; curr < ARRAY_LENGTH(global->quantum_list); curr++)
- if (global->quantum_list[curr].requested != 0)
- global->quantum_list[curr].actual = MAX(global->quantum_list[curr].requested, global->quantum_minimum);
-
- /* ensure that the live current quantum is up to date */
- global->exec.curquantum = global->quantum_current->actual;
-}
-
-
-
-/***************************************************************************
- SAVE/RESTORE HELPERS
-***************************************************************************/
-
-/*-------------------------------------------------
- timer_register_save - register ourself with
- the save state system
--------------------------------------------------*/
-
-static void timer_register_save(emu_timer *timer)
-{
- timer_private *global = timer->machine->timer_data;
- int count = 0;
- emu_timer *t;
-
- /* find other timers that match our func name */
- for (t = global->activelist; t; t = t->next)
- if (!strcmp(t->func, timer->func))
- count++;
-
- /* use different instances to differentiate the bits */
- state_save_register_item(timer->machine, "timer", timer->func, count, timer->param);
- state_save_register_item(timer->machine, "timer", timer->func, count, timer->enabled);
- state_save_register_item(timer->machine, "timer", timer->func, count, timer->period.seconds);
- state_save_register_item(timer->machine, "timer", timer->func, count, timer->period.attoseconds);
- state_save_register_item(timer->machine, "timer", timer->func, count, timer->start.seconds);
- state_save_register_item(timer->machine, "timer", timer->func, count, timer->start.attoseconds);
- state_save_register_item(timer->machine, "timer", timer->func, count, timer->expire.seconds);
- state_save_register_item(timer->machine, "timer", timer->func, count, timer->expire.attoseconds);
- if (timer->device != NULL)
- state_save_register_item(timer->machine, "timer", timer->func, count, timer->id);
-}
-
-
-/*-------------------------------------------------
- timer_postload - after loading a save state
--------------------------------------------------*/
-
-static STATE_POSTLOAD( timer_postload )
-{
- timer_private *global = machine->timer_data;
- emu_timer *privlist = NULL;
- emu_timer *t;
-
- /* remove all timers and make a private list */
- while (global->activelist != NULL)
- {
- t = global->activelist;
-
- /* temporary timers go away entirely */
- if (t->temporary)
- timer_remove(t);
-
- /* permanent ones get added to our private list */
- else
- {
- timer_list_remove(t);
- t->next = privlist;
- privlist = t;
- }
- }
-
- /* now add them all back in; this effectively re-sorts them by time */
- while (privlist != NULL)
- {
- t = privlist;
- privlist = t->next;
- timer_list_insert(t);
- }
-}
-
-
-/*-------------------------------------------------
- timer_count_anonymous - count the number of
- anonymous (non-saveable) timers
--------------------------------------------------*/
-
-int timer_count_anonymous(running_machine *machine)
-{
- timer_private *global = machine->timer_data;
- emu_timer *t;
- int count = 0;
-
- logerror("timer_count_anonymous:\n");
- for (t = global->activelist; t; t = t->next)
- if (t->temporary && t != global->callback_timer)
- {
- count++;
- logerror(" Temp. timer %p, file %s:%d[%s]\n", (void *) t, t->file, t->line, t->func);
- }
- logerror("%d temporary timers found\n", count);
-
- return count;
-}
-
-
-
-/***************************************************************************
- CORE TIMER ALLOCATION
-***************************************************************************/
-
-/*-------------------------------------------------
- timer_alloc - allocate a permament timer that
- isn't primed yet
--------------------------------------------------*/
-
-INLINE emu_timer *_timer_alloc_common(running_machine *machine, device_t *device, device_timer_id id, timer_fired_func callback, void *ptr, const char *file, int line, const char *func, int temp)
-{
- attotime time = get_current_time(machine);
- emu_timer *timer = timer_new(machine);
-
- /* fill in the record */
- timer->callback = callback;
- timer->ptr = ptr;
- timer->param = 0;
- timer->enabled = FALSE;
- timer->temporary = temp;
- timer->period = attotime::zero;
- timer->file = file;
- timer->line = line;
- timer->func = func;
- timer->device = device;
- timer->id = id;
-
- /* compute the time of the next firing and insert into the list */
- timer->start = time;
- timer->expire = attotime::never;
- timer_list_insert(timer);
-
- /* if we're not temporary, register ourselves with the save state system */
- if (!temp)
- {
- if (!state_save_registration_allowed(machine))
- fatalerror("timer_alloc() called after save state registration closed! (file %s, line %d)\n", file, line);
- timer_register_save(timer);
- }
-
- /* return a handle */
- return timer;
-}
-
-emu_timer *_timer_alloc_internal(running_machine *machine, timer_fired_func callback, void *ptr, const char *file, int line, const char *func)
-{
- return _timer_alloc_common(machine, NULL, 0, callback, ptr, file, line, func, FALSE);
-}
-
-emu_timer *device_timer_alloc(device_t &device, UINT32 id, void *ptr)
-{
- return _timer_alloc_common(device.machine, &device, id, NULL, ptr, __FILE__, __LINE__, device.tag(), FALSE);
-}
-
-
-/*-------------------------------------------------
- timer_remove - remove a timer from the
- system
--------------------------------------------------*/
-
-static void timer_remove(emu_timer *which)
-{
- timer_private *global = which->machine->timer_data;
-
- /* if this is a callback timer, note that */
- if (which == global->callback_timer)
- global->callback_timer_modified = TRUE;
-
- /* remove it from the list */
- timer_list_remove(which);
-
- /* free it up by adding it back to the free list */
- if (global->freelist_tail)
- global->freelist_tail->next = which;
- else
- global->freelist = which;
- which->next = NULL;
- global->freelist_tail = which;
-}
-
-
-
-/***************************************************************************
- CORE TIMER ADJUSTMENT
-***************************************************************************/
-
-/*-------------------------------------------------
- timer_adjust_oneshot - adjust the time when this timer
- will fire and disable any periodic firings
--------------------------------------------------*/
-
-void timer_adjust_oneshot(emu_timer *which, attotime duration, INT32 param)
-{
- timer_adjust_periodic(which, duration, param, attotime::never);
-}
-
-
-/*-------------------------------------------------
- timer_adjust_periodic - adjust the time when
- this timer will fire and specify a period for
- subsequent firings
--------------------------------------------------*/
-
-void timer_adjust_periodic(emu_timer *which, attotime start_delay, INT32 param, attotime period)
-{
- timer_private *global = which->machine->timer_data;
- attotime time = get_current_time(which->machine);
-
- /* if this is the callback timer, mark it modified */
- if (which == global->callback_timer)
- global->callback_timer_modified = TRUE;
-
- /* compute the time of the next firing and insert into the list */
- which->param = param;
- which->enabled = TRUE;
-
- /* clamp negative times to 0 */
- if (start_delay.seconds < 0)
- start_delay = attotime::zero;
-
- /* set the start and expire times */
- which->start = time;
- which->expire = time + start_delay;
- which->period = period;
-
- /* remove and re-insert the timer in its new order */
- timer_list_remove(which);
- timer_list_insert(which);
-
- /* if this was inserted as the head, abort the current timeslice and resync */
- LOG(("timer_adjust_oneshot %s.%s:%d to expire @ %s\n", which->file, which->func, which->line, which->expire.as_string()));
- if (which == global->activelist)
- which->machine->scheduler().abort_timeslice();
-}
-
-
-
-/***************************************************************************
- SIMPLIFIED ANONYMOUS TIMER MANAGEMENT
-***************************************************************************/
-
-void device_timer_call_after_resynch(device_t &device, device_timer_id id, INT32 param, void *ptr)
-{
- emu_timer *timer = _timer_alloc_common(device.machine, &device, id, NULL, ptr, __FILE__, __LINE__, device.tag(), TRUE);
- timer_adjust_oneshot(timer, attotime::zero, param);
-}
-
-
-/*-------------------------------------------------
- timer_pulse - allocate a pulse timer, which
- repeatedly calls the callback using the given
- period
--------------------------------------------------*/
-
-void _timer_pulse_internal(running_machine *machine, attotime period, void *ptr, INT32 param, timer_fired_func callback, const char *file, int line, const char *func)
-{
- emu_timer *timer = _timer_alloc_common(machine, NULL, 0, callback, ptr, file, line, func, FALSE);
- timer_adjust_periodic(timer, period, param, period);
-}
-
-
-/*-------------------------------------------------
- timer_set - allocate a one-shot timer, which
- calls the callback after the given duration
--------------------------------------------------*/
-
-void _timer_set_internal(running_machine *machine, attotime duration, void *ptr, INT32 param, timer_fired_func callback, const char *file, int line, const char *func)
-{
- emu_timer *timer = _timer_alloc_common(machine, NULL, 0, callback, ptr, file, line, func, TRUE);
- timer_adjust_oneshot(timer, duration, param);
-}
-
-
-
-/***************************************************************************
- MISCELLANEOUS CONTROLS
-***************************************************************************/
-
-/*-------------------------------------------------
- timer_reset - reset the timing on a timer
--------------------------------------------------*/
-
-void timer_reset(emu_timer *which, attotime duration)
-{
- timer_adjust_periodic(which, duration, which->param, which->period);
-}
-
-
-/*-------------------------------------------------
- timer_enable - enable/disable a timer
--------------------------------------------------*/
-
-int timer_enable(emu_timer *which, int enable)
-{
- int old = which->enabled;
-
- /* reschedule only if the state has changed */
- if (old != enable)
- {
- /* set the enable flag */
- which->enabled = enable;
-
- /* remove the timer and insert back into the list */
- timer_list_remove(which);
- timer_list_insert(which);
- }
-
- return old;
-}
-
-
-/*-------------------------------------------------
- timer_enabled - determine if a timer is
- enabled
--------------------------------------------------*/
-
-int timer_enabled(emu_timer *which)
-{
- return which->enabled;
-}
-
-
-/*-------------------------------------------------
- timer_get_param - returns the callback
- parameter of a timer
--------------------------------------------------*/
-
-int timer_get_param(emu_timer *which)
-{
- return which->param;
-}
-
-
-/*-------------------------------------------------
- timer_set_param - changes the callback
- parameter of a timer
--------------------------------------------------*/
-
-void timer_set_param(emu_timer *which, int param)
-{
- which->param = param;
-}
-
-
-/*-------------------------------------------------
- timer_get_ptr - returns the callback pointer
- of a timer
--------------------------------------------------*/
-
-void *timer_get_ptr(emu_timer *which)
-{
- return which->ptr;
-}
-
-
-/*-------------------------------------------------
- timer_set_ptr - changes the callback pointer
- of a timer
--------------------------------------------------*/
-
-void timer_set_ptr(emu_timer *which, void *ptr)
-{
- which->ptr = ptr;
-}
-
-
-
-/***************************************************************************
- TIMING FUNCTIONS
-***************************************************************************/
-
-/*-------------------------------------------------
- timer_timeelapsed - return the time since the
- last trigger
--------------------------------------------------*/
-
-attotime timer_timeelapsed(emu_timer *which)
-{
- return get_current_time(which->machine) - which->start;
-}
-
-
-/*-------------------------------------------------
- timer_timeleft - return the time until the
- next trigger
--------------------------------------------------*/
-
-attotime timer_timeleft(emu_timer *which)
-{
- return which->expire - get_current_time(which->machine);
-}
-
-
-/*-------------------------------------------------
- timer_get_time - return the current time
--------------------------------------------------*/
-
-attotime timer_get_time(running_machine *machine)
-{
- return get_current_time(machine);
-}
-
-
-/*-------------------------------------------------
- timer_starttime - return the time when this
- timer started counting
--------------------------------------------------*/
-
-attotime timer_starttime(emu_timer *which)
-{
- return which->start;
-}
-
-
-/*-------------------------------------------------
- timer_firetime - return the time when this
- timer will fire next
--------------------------------------------------*/
-
-attotime timer_firetime(emu_timer *which)
-{
- return which->expire;
-}
-
-
-
-/***************************************************************************
- DEBUGGING
-***************************************************************************/
-
-/*-------------------------------------------------
- timer_logtimers - log all the timers
--------------------------------------------------*/
-
-static void timer_logtimers(running_machine *machine)
-{
- timer_private *global = machine->timer_data;
- emu_timer *t;
-
- logerror("===============\n");
- logerror("TIMER LOG START\n");
- logerror("===============\n");
-
- logerror("Enqueued timers:\n");
- for (t = global->activelist; t; t = t->next)
- logerror(" Start=%15.6f Exp=%15.6f Per=%15.6f Ena=%d Tmp=%d (%s:%d[%s])\n",
- t->start.as_double(), t->expire.as_double(), t->period.as_double(), t->enabled, t->temporary, t->file, t->line, t->func);
-
- logerror("Free timers:\n");
- for (t = global->freelist; t; t = t->next)
- logerror(" Start=%15.6f Exp=%15.6f Per=%15.6f Ena=%d Tmp=%d (%s:%d[%s])\n",
- t->start.as_double(), t->expire.as_double(), t->period.as_double(), t->enabled, t->temporary, t->file, t->line, t->func);
-
- logerror("==============\n");
- logerror("TIMER LOG STOP\n");
- logerror("==============\n");
-}
-
-
-void timer_print_first_timer(running_machine *machine)
-{
- timer_private *global = machine->timer_data;
- emu_timer *t = global->activelist;
- printf(" Start=%15.6f Exp=%15.6f Per=%15.6f Ena=%d Tmp=%d (%s)\n",
- t->start.as_double(), t->expire.as_double(), t->period.as_double(), t->enabled, t->temporary, t->func);
-}
-
//**************************************************************************
// TIMER DEVICE CONFIGURATION
@@ -1187,7 +283,7 @@ void timer_device::device_start()
m_screen = downcast<screen_device *>(machine->device(m_config.m_screen));
// allocate the timer
- m_timer = timer_alloc(machine, (m_config.m_type == timer_device_config::TIMER_TYPE_SCANLINE) ? static_scanline_timer_callback : static_periodic_timer_callback, (void *)this);
+ m_timer = timer_alloc();
// register for save states
state_save_register_device_item(this, 0, m_first_time);
@@ -1235,41 +331,47 @@ void timer_device::device_reset()
}
-/*-------------------------------------------------
- periodic_timer_callback - calls the timer
- device specific callback
--------------------------------------------------*/
+//-------------------------------------------------
+// device_timer - handle timer expiration events
+//-------------------------------------------------
-void timer_device::periodic_timer_callback(int param)
+void timer_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
{
- if (m_config.m_callback != NULL)
- (*m_config.m_callback)(*this, m_ptr, param);
-}
+ switch (m_config.m_type)
+ {
+ // general periodic timers just call through
+ case timer_device_config::TIMER_TYPE_GENERIC:
+ case timer_device_config::TIMER_TYPE_PERIODIC:
+ if (m_config.m_type != timer_device_config::TIMER_TYPE_SCANLINE)
+ {
+ if (m_config.m_callback != NULL)
+ (*m_config.m_callback)(*this, m_ptr, param);
+ }
+ break;
-/*-------------------------------------------------
- scanline_timer_device_timer_callback -
- manages the scanline based timer's state
--------------------------------------------------*/
+ // scanline timers have to do some additiona bookkeeping
+ case timer_device_config::TIMER_TYPE_SCANLINE:
+ {
+ // by default, we fire at the first position
+ int next_vpos = m_config.m_first_vpos;
-void timer_device::scanline_timer_callback(int scanline)
-{
- // by default, we fire at the first position
- int next_vpos = m_config.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();
+ (*m_config.m_callback)(*this, m_ptr, 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();
- (*m_config.m_callback)(*this, m_ptr, vpos);
+ // advance by the increment only if we will still be within the screen bounds
+ if (m_config.m_increment != 0 && (vpos + m_config.m_increment) < m_screen->height())
+ next_vpos = vpos + m_config.m_increment;
+ }
+ m_first_time = false;
- // advance by the increment only if we will still be within the screen bounds
- if (m_config.m_increment != 0 && (vpos + m_config.m_increment) < m_screen->height())
- next_vpos = vpos + m_config.m_increment;
+ // adjust the timer
+ timer_adjust_oneshot(m_timer, m_screen->time_until_pos(next_vpos), 0);
+ break;
+ }
}
- m_first_time = false;
-
- // adjust the timer
- timer_adjust_oneshot(m_timer, m_screen->time_until_pos(next_vpos), 0);
}