1
/***************************************************************************
5
Core device execution and scheduling engine.
7
****************************************************************************
12
Redistribution and use in source and binary forms, with or without
13
modification, are permitted provided that the following conditions are
16
* Redistributions of source code must retain the above copyright
17
notice, this list of conditions and the following disclaimer.
18
* Redistributions in binary form must reproduce the above copyright
19
notice, this list of conditions and the following disclaimer in
20
the documentation and/or other materials provided with the
22
* Neither the name 'MAME' nor the names of its contributors may be
23
used to endorse or promote products derived from this software
24
without specific prior written permission.
26
THIS SOFTWARE IS PROVIDED BY AARON GILES ''AS IS'' AND ANY EXPRESS OR
27
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
28
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
29
DISCLAIMED. IN NO EVENT SHALL AARON GILES BE LIABLE FOR ANY DIRECT,
30
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
31
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
32
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
34
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
35
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36
POSSIBILITY OF SUCH DAMAGE.
38
***************************************************************************/
45
//**************************************************************************
47
//**************************************************************************
51
#define LOG(x) do { if (VERBOSE) logerror x; } while (0)
57
//**************************************************************************
59
//**************************************************************************
61
// internal trigger IDs
65
TRIGGER_YIELDTIME = -3000,
66
TRIGGER_SUSPENDTIME = -4000
71
//**************************************************************************
73
//**************************************************************************
75
// these are macros to ensure inlining in device_scheduler::timeslice
76
#define ATTOTIME_LT(a,b) ((a).seconds < (b).seconds || ((a).seconds == (b).seconds && (a).attoseconds < (b).attoseconds))
77
#define ATTOTIME_NORMALIZE(a) do { if ((a).attoseconds >= ATTOSECONDS_PER_SECOND) { (a).seconds++; (a).attoseconds -= ATTOSECONDS_PER_SECOND; } } while (0)
81
//**************************************************************************
83
//**************************************************************************
85
//-------------------------------------------------
86
// device_scheduler - constructor
87
//-------------------------------------------------
89
device_scheduler::device_scheduler(running_machine &machine) :
92
m_executing_device(NULL),
98
//-------------------------------------------------
99
// device_scheduler - destructor
100
//-------------------------------------------------
102
device_scheduler::~device_scheduler()
107
//-------------------------------------------------
108
// timeslice - execute all devices for a single
110
//-------------------------------------------------
112
void device_scheduler::timeslice()
114
bool call_debugger = ((m_machine.debug_flags & DEBUG_FLAG_ENABLED) != 0);
115
timer_execution_state *timerexec = timer_get_execution_state(&m_machine);
116
if (TEMPLOG) printf("Timeslice start\n");
118
// build the execution list if we don't have one yet
119
if (m_execute_list == NULL)
120
rebuild_execute_list();
122
// loop until we hit the next timer
123
while (ATTOTIME_LT(timerexec->basetime, timerexec->nextfire))
127
void timer_print_first_timer(running_machine *machine);
128
printf("Timeslice loop: basetime=%15.6f\n", attotime_to_double(timerexec->basetime));
129
timer_print_first_timer(&m_machine);
133
// by default, assume our target is the end of the next quantum
135
target.seconds = timerexec->basetime.seconds;
136
target.attoseconds = timerexec->basetime.attoseconds + timerexec->curquantum;
137
ATTOTIME_NORMALIZE(target);
139
// however, if the next timer is going to fire before then, override
140
assert(attotime_sub(timerexec->nextfire, target).seconds <= 0);
141
if (ATTOTIME_LT(timerexec->nextfire, target))
142
target = timerexec->nextfire;
144
LOG(("------------------\n"));
145
LOG(("cpu_timeslice: target = %s\n", attotime_string(target, 9)));
147
// apply pending suspension changes
148
UINT32 suspendchanged = 0;
149
for (device_execute_interface *exec = m_execute_list; exec != NULL; exec = exec->m_nextexec)
151
suspendchanged |= (exec->m_suspend ^ exec->m_nextsuspend);
152
exec->m_suspend = exec->m_nextsuspend;
153
exec->m_nextsuspend &= ~SUSPEND_REASON_TIMESLICE;
154
exec->m_eatcycles = exec->m_nexteatcycles;
157
// recompute the execute list if any CPUs changed their suspension state
158
if (suspendchanged != 0)
159
rebuild_execute_list();
161
// loop over non-suspended CPUs
162
for (device_execute_interface *exec = m_execute_list; exec != NULL; exec = exec->m_nextexec)
164
// only process if our target is later than the CPU's current time (coarse check)
165
if (target.seconds >= exec->m_localtime.seconds)
167
// compute how many attoseconds to execute this CPU
168
attoseconds_t delta = target.attoseconds - exec->m_localtime.attoseconds;
169
if (delta < 0 && target.seconds > exec->m_localtime.seconds)
170
delta += ATTOSECONDS_PER_SECOND;
171
assert(delta == attotime_to_attoseconds(attotime_sub(target, exec->m_localtime)));
173
// if we have enough for at least 1 cycle, do the math
174
if (delta >= exec->m_attoseconds_per_cycle)
176
// compute how many cycles we want to execute
177
int ran = exec->m_cycles_running = divu_64x32((UINT64)delta >> exec->m_divshift, exec->m_divisor);
178
LOG((" cpu '%s': %d cycles\n", exec->device().tag(), exec->m_cycles_running));
180
// if we're not suspended, actually execute
181
if (exec->m_suspend == 0)
183
profiler_mark_start(exec->m_profiler);
185
// note that this global variable cycles_stolen can be modified
186
// via the call to cpu_execute
187
exec->m_cycles_stolen = 0;
188
if (TEMPLOG) printf("Executing %s for %d cycles\n", exec->device().tag(), ran);
189
m_executing_device = exec;
190
*exec->m_icount = exec->m_cycles_running;
195
debugger_start_cpu_hook(&exec->device(), target);
197
debugger_stop_cpu_hook(&exec->device());
200
// adjust for any cycles we took back
201
assert(ran >= *exec->m_icount);
202
ran -= *exec->m_icount;
203
assert(ran >= exec->m_cycles_stolen);
204
ran -= exec->m_cycles_stolen;
208
if (TEMPLOG) printf("Skipping %s for %d cycles\n", exec->device().tag(), ran);
210
// account for these cycles
211
exec->m_totalcycles += ran;
213
// update the local time for this CPU
214
attoseconds_t actualdelta = exec->m_attoseconds_per_cycle * ran;
215
exec->m_localtime.attoseconds += actualdelta;
216
ATTOTIME_NORMALIZE(exec->m_localtime);
217
LOG((" %d ran, %d total, time = %s\n", ran, (INT32)exec->m_totalcycles, attotime_string(exec->m_localtime, 9)));
219
// if the new local CPU time is less than our target, move the target up
220
if (ATTOTIME_LT(exec->m_localtime, target))
222
assert(attotime_compare(exec->m_localtime, target) < 0);
223
target = exec->m_localtime;
225
// however, if this puts us before the base, clamp to the base as a minimum
226
if (ATTOTIME_LT(target, timerexec->basetime))
228
assert(attotime_compare(target, timerexec->basetime) < 0);
229
target = timerexec->basetime;
231
LOG((" (new target)\n"));
236
m_executing_device = NULL;
238
// update the base time
239
timerexec->basetime = target;
241
if (TEMPLOG) printf("Timeslice end\n");
244
timer_execute_timers(&m_machine);
248
//-------------------------------------------------
249
// boost_interleave - temporarily boosts the
251
//-------------------------------------------------
253
void device_scheduler::boost_interleave(attotime timeslice_time, attotime boost_duration)
255
// ignore timeslices > 1 second
256
if (timeslice_time.seconds > 0)
258
timer_add_scheduling_quantum(&m_machine, timeslice_time.attoseconds, boost_duration);
262
//-------------------------------------------------
263
// eat_all_cycles - eat a ton of cycles on all
264
// CPUs to force a quick exit
265
//-------------------------------------------------
267
void device_scheduler::eat_all_cycles()
269
for (device_execute_interface *exec = m_execute_list; exec != NULL; exec = exec->m_nextexec)
270
exec->eat_cycles(1000000000);
275
//**************************************************************************
277
//**************************************************************************
279
//-------------------------------------------------
280
// cpuexec_abort_timeslice - abort execution
281
// for the current timeslice
282
//-------------------------------------------------
284
void device_scheduler::abort_timeslice()
286
if (m_executing_device != NULL)
287
m_executing_device->abort_timeslice();
291
//-------------------------------------------------
292
// trigger - generate a global trigger
293
//-------------------------------------------------
295
void device_scheduler::trigger(int trigid, attotime after)
297
// ensure we have a list of executing devices
298
if (m_execute_list == NULL)
299
rebuild_execute_list();
301
// if we have a non-zero time, schedule a timer
302
if (after.attoseconds != 0 || after.seconds != 0)
303
timer_set(&m_machine, after, (void *)this, trigid, static_timed_trigger);
305
// send the trigger to everyone who cares
307
for (device_execute_interface *exec = m_execute_list; exec != NULL; exec = exec->m_nextexec)
308
exec->trigger(trigid);
312
//-------------------------------------------------
313
// static_timed_trigger - generate a trigger
314
// after a given amount of time
315
//-------------------------------------------------
317
TIMER_CALLBACK( device_scheduler::static_timed_trigger )
319
reinterpret_cast<device_scheduler *>(ptr)->trigger(param);
323
//-------------------------------------------------
324
// compute_perfect_interleave - compute the
325
// "perfect" interleave interval
326
//-------------------------------------------------
328
void device_scheduler::compute_perfect_interleave()
330
// ensure we have a list of executing devices
331
if (m_execute_list == NULL)
332
rebuild_execute_list();
334
// start with the first one
335
device_execute_interface *first = m_execute_list;
338
attoseconds_t smallest = first->minimum_quantum();
339
attoseconds_t perfect = ATTOSECONDS_PER_SECOND - 1;
341
// start with a huge time factor and find the 2nd smallest cycle time
342
for (device_execute_interface *exec = first->m_nextexec; exec != NULL; exec = exec->m_nextexec)
344
attoseconds_t curquantum = exec->minimum_quantum();
346
// find the 2nd smallest cycle interval
347
if (curquantum < smallest)
350
smallest = curquantum;
352
else if (curquantum < perfect)
353
perfect = curquantum;
356
// adjust the final value
357
timer_set_minimum_quantum(&m_machine, perfect);
359
LOG(("Perfect interleave = %.9f, smallest = %.9f\n", ATTOSECONDS_TO_DOUBLE(perfect), ATTOSECONDS_TO_DOUBLE(smallest)));
364
//-------------------------------------------------
365
// rebuild_execute_list - rebuild the list of
366
// executing CPUs, moving suspended CPUs to the
368
//-------------------------------------------------
370
void device_scheduler::rebuild_execute_list()
372
// if we haven't yet set a scheduling quantum, do it now
375
// set the core scheduling quantum
376
attotime min_quantum = m_machine.config->m_minimum_quantum;
378
// if none specified default to 60Hz
379
if (attotime_compare(min_quantum, attotime_zero) == 0)
380
min_quantum = ATTOTIME_IN_HZ(60);
382
// if the configuration specifies a device to make perfect, pick that as the minimum
383
if (m_machine.config->m_perfect_cpu_quantum != NULL)
385
device_t *device = m_machine.device(m_machine.config->m_perfect_cpu_quantum);
387
fatalerror("Device '%s' specified for perfect interleave is not present!", m_machine.config->m_perfect_cpu_quantum);
389
device_execute_interface *exec;
390
if (!device->interface(exec))
391
fatalerror("Device '%s' specified for perfect interleave is not an executing device!", m_machine.config->m_perfect_cpu_quantum);
393
attotime cpu_quantum = attotime_make(0, exec->minimum_quantum());
394
min_quantum = attotime_min(cpu_quantum, min_quantum);
397
// inform the timer system of our decision
398
assert(min_quantum.seconds == 0);
399
timer_add_scheduling_quantum(&m_machine, min_quantum.attoseconds, attotime_never);
400
if (TEMPLOG) printf("Setting quantum: %08X%08X\n", (UINT32)(min_quantum.attoseconds >> 32), (UINT32)min_quantum.attoseconds);
401
m_quantum_set = true;
404
// start with an empty list
405
device_execute_interface **active_tailptr = &m_execute_list;
406
*active_tailptr = NULL;
408
// also make an empty list of suspended devices
409
device_execute_interface *suspend_list = NULL;
410
device_execute_interface **suspend_tailptr = &suspend_list;
412
// iterate over all devices
413
device_execute_interface *exec = NULL;
414
for (bool gotone = m_machine.m_devicelist.first(exec); gotone; gotone = exec->next(exec))
416
// append to the appropriate list
417
exec->m_nextexec = NULL;
418
if (exec->m_suspend == 0)
420
*active_tailptr = exec;
421
active_tailptr = &exec->m_nextexec;
425
*suspend_tailptr = exec;
426
suspend_tailptr = &exec->m_nextexec;
430
// append the suspend list to the end of the active list
431
*active_tailptr = suspend_list;
434
printf("Execute list:");
435
for (exec = m_execute_list; exec != NULL; exec = exec->m_nextexec)
436
printf(" %s", exec->device().tag());