Timers and timing
Timers in MAME are objects which can call you back after a very precise amount of emulated time has passed. You can use them in your drivers and devices to emulate hardware timers or do other kinds of periodic tasks.
The basics
Creating a timer
Each timer is an object which you refer to by an opaque pointer, like many other things in MAME. For timers, they are of type "emu_timer", like this:
emu_timer *my_timer;
To instantiate a timer, you call timer_alloc().
my_timer = timer_alloc(machine, callback, reference_pointer);
machine is the current machine pointer. You generally should be calling timer_alloc in either your MACHINE_INIT(), DRIVER_INIT(), or DEVICE_INIT()/CPU_INIT() functions, all of which have the current machine pointer available.
callback is your function that is called when the timer expires. It's of this form:
TIMER_CALLBACK( my_timer_callback ) { }
reference_pointer is any value you want that you can fit into a pointer (beware of 32/64 bit issues here!). It is passed to your callback as a void * named ptr.
Your callback also gets a pointer to the current machine named machine and one more parameter we will discuss a little later.
Arming a timer
Timers can either be one-shot or periodic. One-shot timers fire once and then never again. Periodic timers automatically start over again after they fire and will keep going off until you stop them. You can change a timer's "mode" on the fly if you wish - each new arm call makes the timer mode behave as specified.
This is how you arm a timer for one-shot operation:
timer_adjust_oneshot(my_timer, time_to_fire, reference_integer);
my_timer is the emu_timer object pointer you allocated, time_to_fire is the amount of time from the current point in the emulation when the timer should fire, and reference_integer is a number for your own use which is passed to your callback as an int named param.
Here's the equivalent for periodic:
timer_adjust_periodic(my_timer, time_to_delay, reference_integer, time_to_fire);
This is quite similar, but it has two time parameters. The first (time_to_delay) is an optional amount of time to wait before beginning our periodic operation. The time_to_fire parameter gives the period of the timer.
About those time parameters
Time in MAME is in terms of "attotime", a high-precision 96 bit fixed point representation accurate to 1 attosecond. Fortunately a variety of helpers are provided in case you don't speak attoseconds:
attotime_never is a constant for infinity, or as close to it as MAME can get. If you use it as a timer's time value the timer will never go off. This is useful for when you're emulating a hardware timer and it's disabled.
attotime_zero is a constant for zero time. If you use this as a timer value the callback will occur immediately.
The following conversion macros are also available:
ATTOTIME_IN_HZ(x)
This creates an attotime for a timer which fires x number of times per second.
ATTOTIME_IN_SEC(x)
This creates an attotime for a timer which fires every x seconds.
ATTOTIME_IN_MSEC(x) ATTOTIME_IN_USEC(x) ATTOTIME_IN_NSEC(x)
These work similarly to ATTOTIME_IN_SEC but work in terms of milliseconds, microseconds, and nanoseconds. They are rarely used, obviously.
Math operations on attotime values are available; refer to the attotime.h file for more information.