diff options
author | 2008-11-05 16:04:56 +0000 | |
---|---|---|
committer | 2008-11-05 16:04:56 +0000 | |
commit | a33640f46d16c62ace042db3d788279006e5319e (patch) | |
tree | 550b75365697963288c5abb3bb161aaa4f0d9732 /src/emu | |
parent | 82c3ffc15337feabd3407f3dc5fce04f98279f71 (diff) |
Added concept of scheduling quanta to the timer system. Also added
means of setting the minimum useful scheduling quantum, and clamping
all quanta to that value.
Changed interleave/boost handling to use scheduling quanta instead
of timers.
Added machine parameter to cpu_boost_interleave.
Updated cpuexec to compute the "perfect" interleave value taking into
account the minimum number of cycles per instruction specified by the
CPU core. Updated Z80 core to indicate that the minimum cpi is 2. Fixed
incorrect minimum cpi in the 68020+ cores.
Simplified a bit of logic in cpuexec_timeslice.
Diffstat (limited to 'src/emu')
-rw-r--r-- | src/emu/cpu/m68000/m68kmame.c | 4 | ||||
-rw-r--r-- | src/emu/cpu/z80/z80.c | 2 | ||||
-rw-r--r-- | src/emu/cpuexec.c | 179 | ||||
-rw-r--r-- | src/emu/cpuexec.h | 3 | ||||
-rw-r--r-- | src/emu/machine/ldv1000.c | 2 | ||||
-rw-r--r-- | src/emu/machine/ldvp931.c | 4 | ||||
-rw-r--r-- | src/emu/mame.c | 2 | ||||
-rw-r--r-- | src/emu/mconfig.c | 5 | ||||
-rw-r--r-- | src/emu/timer.c | 120 | ||||
-rw-r--r-- | src/emu/timer.h | 7 |
10 files changed, 197 insertions, 131 deletions
diff --git a/src/emu/cpu/m68000/m68kmame.c b/src/emu/cpu/m68000/m68kmame.c index 46df696283a..b4bc9ef0dca 100644 --- a/src/emu/cpu/m68000/m68kmame.c +++ b/src/emu/cpu/m68000/m68kmame.c @@ -862,7 +862,7 @@ void m68020_get_info(UINT32 state, cpuinfo *info) case CPUINFO_INT_CLOCK_DIVIDER: info->i = 1; break; case CPUINFO_INT_MIN_INSTRUCTION_BYTES: info->i = 2; break; case CPUINFO_INT_MAX_INSTRUCTION_BYTES: info->i = 20; break; - case CPUINFO_INT_MIN_CYCLES: info->i = 4; break; + case CPUINFO_INT_MIN_CYCLES: info->i = 2; break; case CPUINFO_INT_MAX_CYCLES: info->i = 158; break; case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 32; break; @@ -1100,7 +1100,7 @@ void m68040_get_info(UINT32 state, cpuinfo *info) case CPUINFO_INT_CLOCK_DIVIDER: info->i = 1; break; case CPUINFO_INT_MIN_INSTRUCTION_BYTES: info->i = 2; break; case CPUINFO_INT_MAX_INSTRUCTION_BYTES: info->i = 20; break; - case CPUINFO_INT_MIN_CYCLES: info->i = 4; break; + case CPUINFO_INT_MIN_CYCLES: info->i = 2; break; case CPUINFO_INT_MAX_CYCLES: info->i = 158; break; case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 32; break; diff --git a/src/emu/cpu/z80/z80.c b/src/emu/cpu/z80/z80.c index 20bf8b779f6..139c7043b8c 100644 --- a/src/emu/cpu/z80/z80.c +++ b/src/emu/cpu/z80/z80.c @@ -3768,7 +3768,7 @@ void z80_get_info(UINT32 state, cpuinfo *info) case CPUINFO_INT_CLOCK_DIVIDER: info->i = 1; break; case CPUINFO_INT_MIN_INSTRUCTION_BYTES: info->i = 1; break; case CPUINFO_INT_MAX_INSTRUCTION_BYTES: info->i = 4; break; - case CPUINFO_INT_MIN_CYCLES: info->i = 1; break; + case CPUINFO_INT_MIN_CYCLES: info->i = 2; break; case CPUINFO_INT_MAX_CYCLES: info->i = 16; break; case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 8; break; diff --git a/src/emu/cpuexec.c b/src/emu/cpuexec.c index e502d940df9..4ad6fff0187 100644 --- a/src/emu/cpuexec.c +++ b/src/emu/cpuexec.c @@ -51,7 +51,6 @@ /* internal trigger IDs */ enum { - TRIGGER_TIMESLICE = -1000, TRIGGER_INT = -2000, TRIGGER_YIELDTIME = -3000, TRIGGER_SUSPENDTIME = -4000 @@ -99,15 +98,6 @@ static int cycles_running; static int cycles_stolen; -/* timer variables */ -static emu_timer *timeslice_timer; -static attotime timeslice_period; - -static emu_timer *interleave_boost_timer; -static emu_timer *interleave_boost_timer_end; -static attotime perfect_interleave; - - /*************************************************************************** FUNCTION PROTOTYPES @@ -117,7 +107,6 @@ static void cpuexec_exit(running_machine *machine); static void cpuexec_reset(running_machine *machine); static void cpu_inittimers(running_machine *machine); static void update_clock_information(running_machine *machine, int cpunum); -static TIMER_CALLBACK( end_interleave_boost ); static TIMER_CALLBACK( trigger_partial_frame_interrupt ); static void compute_perfect_interleave(running_machine *machine); @@ -189,10 +178,6 @@ void cpuexec_init(running_machine *machine) } add_reset_callback(machine, cpuexec_reset); add_exit_callback(machine, cpuexec_exit); - - /* allocate timers to handle interleave boosts */ - interleave_boost_timer = timer_alloc(NULL, NULL); - interleave_boost_timer_end = timer_alloc(end_interleave_boost, NULL); } @@ -254,32 +239,28 @@ void cpuexec_timeslice(running_machine *machine) LOG(("------------------\n")); LOG(("cpu_timeslice: target = %s\n", attotime_string(target, 9))); - /* process any pending suspends */ + /* apply pending suspension changes */ for (cpunum = 0; machine->config->cpu[cpunum].type != CPU_DUMMY; cpunum++) { - if (cpu[cpunum].suspend != cpu[cpunum].nextsuspend) - LOG(("--> updated CPU%d suspend from %X to %X\n", cpunum, cpu[cpunum].suspend, cpu[cpunum].nextsuspend)); - cpu[cpunum].suspend = cpu[cpunum].nextsuspend; - cpu[cpunum].eatcycles = cpu[cpunum].nexteatcycles; + cpuexec_data *cpudata = &cpu[cpunum]; + cpudata->suspend = cpudata->nextsuspend; + cpudata->nextsuspend &= ~SUSPEND_REASON_TIMESLICE; + cpudata->eatcycles = cpudata->nexteatcycles; } - /* loop over CPUs */ + /* loop over non-suspended CPUs */ for (cpunum = 0; machine->config->cpu[cpunum].type != CPU_DUMMY; cpunum++) { - /* only process if we're not suspended */ - if (!cpu[cpunum].suspend) + cpuexec_data *cpudata = &cpu[cpunum]; + if (cpudata->suspend == 0) { - attotime delta = attotime_sub(target, cpu[cpunum].localtime); - if (delta.seconds >= 0) + attotime delta = attotime_sub(target, cpudata->localtime); + if (delta.seconds >= 0 && delta.attoseconds >= attoseconds_per_cycle[cpunum]) { - - /* compute how long to run */ - cycles_running = ATTOTIME_TO_CYCLES(cpunum, attotime_sub(target, cpu[cpunum].localtime)); - LOG((" cpu %d: %d cycles\n", cpunum, cycles_running)); + /* compute how long to run */ + cycles_running = ATTOTIME_TO_CYCLES(cpunum, delta); + LOG((" cpu %d: %d cycles\n", cpunum, cycles_running)); - /* run for the requested number of cycles */ - if (cycles_running > 0) - { profiler_mark(PROFILER_CPU1 + cpunum); /* note that this global variable cycles_stolen can be modified */ @@ -298,44 +279,36 @@ void cpuexec_timeslice(running_machine *machine) profiler_mark(PROFILER_END); /* account for these cycles */ - cpu[cpunum].totalcycles += ran; - cpu[cpunum].localtime = attotime_add(cpu[cpunum].localtime, ATTOTIME_IN_CYCLES(ran, cpunum)); - LOG((" %d ran, %d total, time = %s\n", ran, (INT32)cpu[cpunum].totalcycles, attotime_string(cpu[cpunum].localtime, 9))); + cpudata->totalcycles += ran; + cpudata->localtime = attotime_add_attoseconds(cpudata->localtime, ran * attoseconds_per_cycle[cpunum]); + LOG((" %d ran, %d total, time = %s\n", ran, (INT32)cpudata->totalcycles, attotime_string(cpudata->localtime, 9))); /* if the new local CPU time is less than our target, move the target up */ - if (attotime_compare(cpu[cpunum].localtime, target) < 0) + if (attotime_compare(cpudata->localtime, target) < 0) { - if (attotime_compare(cpu[cpunum].localtime, base) > 0) - target = cpu[cpunum].localtime; - else - target = base; + target = attotime_max(cpudata->localtime, base); LOG((" (new target)\n")); } } - } } } /* update the local times of all CPUs */ for (cpunum = 0; machine->config->cpu[cpunum].type != CPU_DUMMY; cpunum++) { + cpuexec_data *cpudata = &cpu[cpunum]; + /* if we're suspended and counting, process */ - if (cpu[cpunum].suspend && cpu[cpunum].eatcycles && attotime_compare(cpu[cpunum].localtime, target) < 0) + if (cpudata->suspend != 0 && cpudata->eatcycles && attotime_compare(cpudata->localtime, target) < 0) { /* compute how long to run */ - cycles_running = ATTOTIME_TO_CYCLES(cpunum, attotime_sub(target, cpu[cpunum].localtime)); + cycles_running = ATTOTIME_TO_CYCLES(cpunum, attotime_sub(target, cpudata->localtime)); LOG((" cpu %d: %d cycles (suspended)\n", cpunum, cycles_running)); - cpu[cpunum].totalcycles += cycles_running; - cpu[cpunum].localtime = attotime_add(cpu[cpunum].localtime, ATTOTIME_IN_CYCLES(cycles_running, cpunum)); - LOG((" %d skipped, %d total, time = %s\n", cycles_running, (INT32)cpu[cpunum].totalcycles, attotime_string(cpu[cpunum].localtime, 9))); + cpudata->totalcycles += cycles_running; + cpudata->localtime = attotime_add(cpudata->localtime, ATTOTIME_IN_CYCLES(cycles_running, cpunum)); + LOG((" %d skipped, %d total, time = %s\n", cycles_running, (INT32)cpudata->totalcycles, attotime_string(cpudata->localtime, 9))); } - - /* update the suspend state */ - if (cpu[cpunum].suspend != cpu[cpunum].nextsuspend) - LOG(("--> updated CPU%d suspend from %X to %X\n", cpunum, cpu[cpunum].suspend, cpu[cpunum].nextsuspend)); - cpu[cpunum].suspend = cpu[cpunum].nextsuspend; - cpu[cpunum].eatcycles = cpu[cpunum].nexteatcycles; } /* update the global time */ @@ -353,20 +326,12 @@ void cpuexec_timeslice(running_machine *machine) interleave factor -------------------------------------------------*/ -void cpu_boost_interleave(attotime timeslice_time, attotime boost_duration) +void cpu_boost_interleave(running_machine *machine, attotime timeslice_time, attotime boost_duration) { - /* if you pass 0 for the timeslice_time, it means pick something reasonable */ - if (attotime_compare(timeslice_time, perfect_interleave) < 0) - timeslice_time = perfect_interleave; - - LOG(("cpu_boost_interleave(%s, %s)\n", attotime_string(timeslice_time, 9), attotime_string(boost_duration, 9))); - - /* adjust the interleave timer */ - timer_adjust_periodic(interleave_boost_timer, timeslice_time, 0, timeslice_time); - - /* adjust the end timer, but only if we are going to extend it */ - if (!timer_enabled(interleave_boost_timer_end) || attotime_compare(timer_timeleft(interleave_boost_timer_end), boost_duration) < 0) - timer_adjust_oneshot(interleave_boost_timer_end, boost_duration, 0); + /* ignore timeslices > 1 second */ + if (timeslice_time.seconds > 0) + return; + timer_add_scheduling_quantum(machine, timeslice_time.attoseconds, boost_duration); } @@ -400,12 +365,8 @@ void cpunum_suspend(int cpunum, int reason, int eatcycles) { VERIFY_CPUNUM(cpunum_suspend); LOG(("cpunum_suspend (CPU=%d, r=%X, eat=%d)\n", cpunum, reason, eatcycles)); - - /* set the pending suspend bits, and force a resync */ cpu[cpunum].nextsuspend |= reason; cpu[cpunum].nexteatcycles = eatcycles; - if (cpu_getexecutingcpu() >= 0) - activecpu_abort_timeslice(); } @@ -418,11 +379,7 @@ void cpunum_resume(int cpunum, int reason) { VERIFY_CPUNUM(cpunum_resume); LOG(("cpunum_resume (CPU=%d, r=%X)\n", cpunum, reason)); - - /* clear the pending suspend bits, and force a resync */ cpu[cpunum].nextsuspend &= ~reason; - if (cpu_getexecutingcpu() >= 0) - activecpu_abort_timeslice(); } @@ -612,8 +569,8 @@ static void cpunum_suspend_until_trigger(int cpunum, int trigger, int eatcycles) void cpu_yield(void) { int cpunum = cpu_getexecutingcpu(); - VERIFY_EXECUTINGCPU(cpu_yielduntil_trigger); - cpunum_suspend_until_trigger(cpunum, TRIGGER_TIMESLICE, FALSE); + VERIFY_EXECUTINGCPU(cpu_yield); + cpunum_suspend(cpunum, SUSPEND_REASON_TIMESLICE, FALSE); } @@ -625,8 +582,8 @@ void cpu_yield(void) void cpu_spin(void) { int cpunum = cpu_getexecutingcpu(); - VERIFY_EXECUTINGCPU(cpu_yielduntil_trigger); - cpunum_suspend_until_trigger(cpunum, TRIGGER_TIMESLICE, TRUE); + VERIFY_EXECUTINGCPU(cpu_spin); + cpunum_suspend(cpunum, SUSPEND_REASON_TIMESLICE, TRUE); } @@ -873,59 +830,39 @@ static TIMER_CALLBACK( cpu_timedintcallback ) /*------------------------------------------------- - cpu_timeslicecallback - timer callback for - timeslicing --------------------------------------------------*/ - -static TIMER_CALLBACK( cpu_timeslicecallback ) -{ - cpu_trigger(machine, TRIGGER_TIMESLICE); -} - - -/*------------------------------------------------- - end_interleave_boost - timer callback to end - temporary interleave boost --------------------------------------------------*/ - -static TIMER_CALLBACK( end_interleave_boost ) -{ - timer_adjust_oneshot(interleave_boost_timer, attotime_never, 0); - LOG(("end_interleave_boost\n")); -} - - -/*------------------------------------------------- compute_perfect_interleave - compute the "perfect" interleave interval -------------------------------------------------*/ static void compute_perfect_interleave(running_machine *machine) { - attoseconds_t smallest = attoseconds_per_cycle[0]; - int cpunum; + if (attoseconds_per_cycle[0] != 0) + { + attoseconds_t smallest = attoseconds_per_cycle[0] * cputype_min_cycles(machine->config->cpu[0].type); + attoseconds_t perfect = ATTOSECONDS_PER_SECOND - 1; + int cpunum; - /* start with a huge time factor and find the 2nd smallest cycle time */ - perfect_interleave = attotime_zero; - perfect_interleave.attoseconds = ATTOSECONDS_PER_SECOND - 1; - for (cpunum = 1; machine->config->cpu[cpunum].type != CPU_DUMMY; cpunum++) - if (attoseconds_per_cycle[cpunum] != 0) - { - /* find the 2nd smallest cycle interval */ - if (attoseconds_per_cycle[cpunum] < smallest) + /* start with a huge time factor and find the 2nd smallest cycle time */ + for (cpunum = 1; machine->config->cpu[cpunum].type != CPU_DUMMY; cpunum++) + if (attoseconds_per_cycle[cpunum] != 0) { - perfect_interleave.attoseconds = smallest; - smallest = attoseconds_per_cycle[cpunum]; + attoseconds_t curtime = attoseconds_per_cycle[cpunum] * cputype_min_cycles(machine->config->cpu[cpunum].type); + + /* find the 2nd smallest cycle interval */ + if (curtime < smallest) + { + perfect = smallest; + smallest = curtime; + } + else if (curtime < perfect) + perfect = attoseconds_per_cycle[cpunum]; } - else if (attoseconds_per_cycle[cpunum] < perfect_interleave.attoseconds) - perfect_interleave.attoseconds = attoseconds_per_cycle[cpunum]; - } - /* adjust the final value */ - if (perfect_interleave.attoseconds == ATTOSECONDS_PER_SECOND - 1) - perfect_interleave.attoseconds = attoseconds_per_cycle[0]; + /* adjust the final value */ + timer_set_minimum_quantum(machine, perfect); - LOG(("Perfect interleave = %s, smallest = %.9f\n", attotime_string(perfect_interleave, 9), ATTOSECONDS_TO_DOUBLE(smallest))); + LOG(("Perfect interleave = %.9f, smallest = %.9f\n", ATTOSECONDS_TO_DOUBLE(perfect), ATTOSECONDS_TO_DOUBLE(smallest))); + } } @@ -944,9 +881,7 @@ static void cpu_inittimers(running_machine *machine) if (ipf <= 0) ipf = 1; refresh_attosecs = (numscreens == 0) ? HZ_TO_ATTOSECONDS(60) : video_screen_get_frame_period(machine->primary_screen).attoseconds; - timeslice_period = attotime_make(0, refresh_attosecs / ipf); - timeslice_timer = timer_alloc(cpu_timeslicecallback, NULL); - timer_adjust_periodic(timeslice_timer, timeslice_period, 0, timeslice_period); + timer_add_scheduling_quantum(machine, refresh_attosecs / ipf, attotime_never); /* register the interrupt handler callbacks */ for (cpunum = 0; cpunum < cpu_gettotalcpu(); cpunum++) diff --git a/src/emu/cpuexec.h b/src/emu/cpuexec.h index 5dbad532151..5e0a28ea54e 100644 --- a/src/emu/cpuexec.h +++ b/src/emu/cpuexec.h @@ -39,6 +39,7 @@ enum SUSPEND_REASON_SPIN = 0x0004, SUSPEND_REASON_TRIGGER = 0x0008, SUSPEND_REASON_DISABLE = 0x0010, + SUSPEND_REASON_TIMESLICE= 0x0020, SUSPEND_ANY_REASON = ~0 }; @@ -311,7 +312,7 @@ void cpuexec_timeslice(running_machine *machine); /* ----- CPU scheduling----- */ /* temporarily boosts the interleave factor */ -void cpu_boost_interleave(attotime timeslice_time, attotime boost_duration); +void cpu_boost_interleave(running_machine *machine, attotime timeslice_time, attotime boost_duration); /* aborts the timeslice for the active CPU */ void activecpu_abort_timeslice(void); diff --git a/src/emu/machine/ldv1000.c b/src/emu/machine/ldv1000.c index e57f8de5733..4bbbafbf9d1 100644 --- a/src/emu/machine/ldv1000.c +++ b/src/emu/machine/ldv1000.c @@ -277,7 +277,7 @@ static void ldv1000_vsync(laserdisc_state *ld, const vbi_metadata *vbi, int fiel timer_set(video_screen_get_time_until_pos(ld->screen, 19*2, 0), ld, 0, vbi_data_fetch); /* boost interleave for the first 1ms to improve communications */ - cpu_boost_interleave(attotime_zero, ATTOTIME_IN_MSEC(1)); + cpu_boost_interleave(ld->device->machine, attotime_zero, ATTOTIME_IN_MSEC(1)); } diff --git a/src/emu/machine/ldvp931.c b/src/emu/machine/ldvp931.c index 88ac93f2259..5ecdcddb114 100644 --- a/src/emu/machine/ldvp931.c +++ b/src/emu/machine/ldvp931.c @@ -298,7 +298,7 @@ static UINT8 vp931_data_r(laserdisc_state *ld) } /* also boost interleave for 4 scanlines to ensure proper communications */ - cpu_boost_interleave(attotime_zero, attotime_mul(video_screen_get_scan_period(ld->screen), 4)); + cpu_boost_interleave(ld->device->machine, attotime_zero, attotime_mul(video_screen_get_scan_period(ld->screen), 4)); return player->tocontroller; } @@ -632,7 +632,7 @@ static WRITE8_HANDLER( to_controller_w ) (*player->data_ready_cb)(ld->device, TRUE); /* also boost interleave for 4 scanlines to ensure proper communications */ - cpu_boost_interleave(attotime_zero, attotime_mul(video_screen_get_scan_period(ld->screen), 4)); + cpu_boost_interleave(ld->device->machine, attotime_zero, attotime_mul(video_screen_get_scan_period(ld->screen), 4)); } diff --git a/src/emu/mame.c b/src/emu/mame.c index 066190731f4..a2a05482096 100644 --- a/src/emu/mame.c +++ b/src/emu/mame.c @@ -349,7 +349,7 @@ int mame_execute(core_options *options) video_frame_update(machine, FALSE); /* handle save/load */ - if (mame->saveload_schedule_callback) + if (mame->saveload_schedule_callback != NULL) (*mame->saveload_schedule_callback)(machine); profiler_mark(PROFILER_END); diff --git a/src/emu/mconfig.c b/src/emu/mconfig.c index 3e0dbe3db87..af235ac14fa 100644 --- a/src/emu/mconfig.c +++ b/src/emu/mconfig.c @@ -13,6 +13,11 @@ #include "devintrf.h" #include <ctype.h> +#if defined(_MSC_VER) +#pragma optimize ("", off) +#endif + + /*************************************************************************** FUNCTION PROTOTYPES diff --git a/src/emu/timer.c b/src/emu/timer.c index 0a11d42c3e7..2144e8adee1 100644 --- a/src/emu/timer.c +++ b/src/emu/timer.c @@ -30,6 +30,7 @@ ***************************************************************************/ #define MAX_TIMERS 256 +#define MAX_QUANTA 16 @@ -77,6 +78,21 @@ struct _timer_state }; +/*------------------------------------------------- + quantum_slot - a single minimum quantum + request +-------------------------------------------------*/ + +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 VARIABLES ***************************************************************************/ @@ -97,6 +113,11 @@ static emu_timer *callback_timer; static int callback_timer_modified; static attotime callback_timer_expire_time; +/* scheduling quanta */ +static quantum_slot quantum_list[MAX_QUANTA]; +static quantum_slot *quantum_current; +static attoseconds_t quantum_minimum; + /*************************************************************************** @@ -292,6 +313,14 @@ void timer_init(running_machine *machine) timers[i].next = &timers[i+1]; timers[MAX_TIMERS-1].next = NULL; timer_free_tail = &timers[MAX_TIMERS-1]; + + /* reset the quanta */ + memset(quantum_list, 0, sizeof(quantum_list)); + quantum_list[0].requested = ATTOSECONDS_IN_MSEC(100); + quantum_list[0].actual = ATTOSECONDS_IN_MSEC(100); + quantum_list[0].expire = attotime_never; + quantum_current = &quantum_list[0]; + quantum_minimum = ATTOSECONDS_IN_NSEC(1) / 1000; } @@ -318,7 +347,21 @@ void timer_destructor(void *ptr, size_t size) attotime timer_next_fire_time(void) { - return timer_head->expire; + attotime quantum_time; + + /* if the current quantum has expired, find a new one */ + if (attotime_compare(global_basetime, quantum_current->expire) >= 0) + { + int curr; + + quantum_current->requested = 0; + quantum_current = &quantum_list[0]; + for (curr = 1; curr < ARRAY_LENGTH(quantum_list); curr++) + if (quantum_list[curr].requested < quantum_current->requested) + quantum_current = &quantum_list[curr]; + } + quantum_time = attotime_add_attoseconds(global_basetime, quantum_current->actual); + return attotime_min(quantum_time, timer_head->expire); } @@ -384,6 +427,81 @@ void timer_set_global_time(running_machine *machine, attotime newbase) } +/*------------------------------------------------- + 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) +{ + attotime curtime = timer_get_time(); + attotime expire = attotime_add(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(quantum_list); curr++) + { + quantum_slot *slot = &quantum_list[curr]; + + /* look for a matching quantum and extend it */ + if (slot->requested == quantum) + { + slot->expire = attotime_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 (attotime_compare(curtime, slot->expire) >= 0) + slot->requested = 0; + } + + /* fatal error if no slots left */ + assert_always(blank != -1, "Out of scheduling quantum slots!"); + + /* fill in the item */ + quantum_list[blank].requested = quantum; + quantum_list[blank].actual = MAX(quantum_list[curr].requested, quantum_minimum); + quantum_list[blank].expire = expire; + + /* update the minimum */ + if (quantum < quantum_current->requested) + quantum_current = &quantum_list[blank]; +} + + +/*------------------------------------------------- + timer_set_minimum_quantum - control the + minimum useful quantum (used by cpuexec only) +-------------------------------------------------*/ + +void timer_set_minimum_quantum(running_machine *machine, attoseconds_t quantum) +{ + int curr; + + /* do nothing if nothing changed */ + if (quantum_minimum == quantum) + return; + quantum_minimum = quantum; + + /* adjust all the actuals; this doesn't affect the current */ + for (curr = 0; curr < ARRAY_LENGTH(quantum_list); curr++) + if (quantum_list[curr].requested != 0) + quantum_list[curr].actual = MAX(quantum_list[curr].requested, quantum_minimum); +} + + /*************************************************************************** SAVE/RESTORE HELPERS diff --git a/src/emu/timer.h b/src/emu/timer.h index f729e3b14f2..234c1f9f398 100644 --- a/src/emu/timer.h +++ b/src/emu/timer.h @@ -33,6 +33,7 @@ enum }; + /*************************************************************************** MACROS ***************************************************************************/ @@ -178,6 +179,12 @@ attotime timer_next_fire_time(void); /* adjust the global time; this is also where we fire the timers */ void timer_set_global_time(running_machine *machine, attotime newbase); +/* 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); + +/* control the minimum useful quantum (used by cpuexec only) */ +void timer_set_minimum_quantum(running_machine *machine, attoseconds_t quantum); + /* ----- save/restore helpers ----- */ |