diff options
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 |
commit | 0e627f1a5443528526eb35ec3a9cb7fb9e5af907 (patch) | |
tree | 3b44469d96597a98080accaec1bccbbad3815acc /src/emu/timer.c | |
parent | f38d3384b648811571b50acd16709ae47becaabd (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.c | 1038 |
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); } |