1 /***************************************************************************
2 
3   timer.c
4 
5   Functions needed to generate timing and synchronization between several
6   CPUs.
7 
8   Changes 2/27/99:
9   	- added some rounding to the sorting of timers so that two timers
10   		allocated to go off at the same time will go off in the order
11   		they were allocated, without concern for floating point rounding
12   		errors (thanks Juergen!)
13   	- fixed a bug where the base_time was not updated when a CPU was
14   		suspended, making subsequent calls to getabsolutetime() return an
15   		incorrect time (thanks Nicola!)
16   	- changed suspended CPUs so that they don't eat their timeslice until
17   		all other CPUs have used up theirs; this allows a slave CPU to
18   		trigger a higher priority CPU in the middle of the timeslice
19   	- added the ability to call timer_reset() on a oneshot or pulse timer
20   		from within that timer's callback; in this case, the timer won't
21   		get removed (oneshot) or won't get reprimed (pulse)
22 
23   Changes 12/17/99 (HJB):
24 	- added overclocking factor and functions to set/get it at runtime.
25 
26   Changes 12/23/99 (HJB):
27 	- added burn() function pointer to tell CPU cores when we want to
28 	  burn cycles, because the cores might need to adjust internal
29 	  counters or timers.
30 
31 ***************************************************************************/
32 
33 #include "cpuintrf.h"
34 #include "driver.h"
35 #include "timer.h"
36 
37 #define MAX_TIMERS 256
38 
39 /*
40  *		internal timer structures
41  */
42 
43 typedef struct
44 {
45 	int *icount;
46 	void (*burn)(int cycles);
47     int index;
48 	int suspended;
49 	int trigger;
50 	int nocount;
51 	int lost;
52 	timer_tm time;
53 	timer_tm sec_to_cycles;
54 	timer_tm cycles_to_sec;
55 	float overclock;
56 } cpu_entry;
57 
58 
59 /* conversion constants */
60 timer_tm cycles_to_sec[MAX_CPU];
61 timer_tm sec_to_cycles[MAX_CPU];
62 
63 /* list of per-CPU timer data */
64 static cpu_entry cpudata[MAX_CPU+1];
65 static cpu_entry *lastcpu;
66 static cpu_entry *activecpu;
67 static cpu_entry *last_activecpu;
68 
69 /* list of active timers */
70 static timer_entry timers[MAX_TIMERS];
71 static timer_entry *timer_head;
72 static timer_entry *timer_free_head;
73 
74 /* other internal states */
75 static timer_tm base_time;
76 static timer_tm global_offset;
77 static timer_entry *callback_timer;
78 static int callback_timer_modified;
79 
80 /* prototypes */
81 static int pick_cpu(int *cpu, int *cycles, timer_tm expire);
82 
83 /*
84  *		return the current absolute time
85  */
getabsolutetime(void)86 timer_tm getabsolutetime(void)
87 {
88 	if (activecpu && (*activecpu->icount + activecpu->lost) > 0)
89 		return base_time - ((timer_tm)(*activecpu->icount + activecpu->lost) * activecpu->cycles_to_sec);
90 	else
91 		return base_time;
92 }
93 
94 
95 /*
96  *		adjust the current CPU's timer so that a new event will fire at the right time
97  */
timer_adjust(timer_entry * timer,timer_tm time,timer_tm period)98 static INLINE void timer_adjust(timer_entry *timer, timer_tm time, timer_tm period)
99 {
100 	int newicount, diff;
101 
102 	/* compute a new icount for the current CPU */
103 	if (period == TIME_NOW)
104 		newicount = 0;
105 	else
106 	    newicount = CYCLES_CALC(timer->expire - time,activecpu->sec_to_cycles)+1;
107 
108 	/* determine if we're scheduled to run more cycles */
109 	diff = *activecpu->icount - newicount;
110 
111 	/* if so, set the new icount and compute the amount of "lost" time */
112 	if (diff > 0)
113 	{
114 		activecpu->lost += diff;
115 		if (activecpu->burn)
116 			(*activecpu->burn)(diff);  /* let the CPU burn the cycles */
117 		else
118 			*activecpu->icount = newicount;  /* CPU doesn't care */
119 	}
120 }
121 
122 
123 /*
124  *		allocate a new timer
125  */
timer_new(void)126 static INLINE timer_entry *timer_new(void)
127 {
128 	timer_entry *timer;
129 
130 	/* remove an empty entry */
131 	if (!timer_free_head)
132 		return NULL;
133 	timer = timer_free_head;
134 	timer_free_head = timer->next;
135 
136 	return timer;
137 }
138 
139 
140 /*
141  *		insert a new timer into the list at the appropriate location
142  */
timer_list_insert(timer_entry * timer)143 static INLINE void timer_list_insert(timer_entry *timer)
144 {
145 	timer_entry *t=timer_head;
146 	timer_entry *lt = NULL;
147     timer_tm expire = (t && timer->enabled) ? timer->expire : TIME_NEVER;
148 
149     if (expire==TIME_NOW)
150     {
151        	/* loop over the timer list */
152        	for (t = timer_head; t; lt = t, t = t->next)
153        	{
154        		if (t->expire!=TIME_NOW)
155        		{
156        			/* link the new guy in before the current list entry */
157        			timer->prev = t->prev;
158        			timer->next = t;
159 
160        			if (t->prev)
161        				t->prev->next = timer;
162        			else
163        				timer_head = timer;
164        			t->prev = timer;
165        			return;
166        		}
167        	}
168     }
169     else if (expire!=TIME_NEVER)
170     {
171        	/* loop over the timer list */
172        	for (t = timer_head; t; lt = t, t = t->next)
173        	{
174        		/* if the current list entry expires after us, we should be inserted before it */
175        		/* note that due to floating point rounding, we need to allow a bit of slop here */
176        		/* because two equal entries -- within rounding precision -- need to sort in */
177        		/* the order they were inserted into the list */
178        		//if ((t->expire - expire) > TIME_IN_NSEC(1))
179        		if (t->expire > expire)
180        		{
181        			/* link the new guy in before the current list entry */
182        			timer->prev = t->prev;
183        			timer->next = t;
184 
185        			if (t->prev)
186        				t->prev->next = timer;
187        			else
188        				timer_head = timer;
189        			t->prev = timer;
190        			return;
191        		}
192        	}
193     }
194     else
195     {
196        	/* loop over the timer list */
197        	for (t = timer_head; t; lt = t, t = t->next)
198        	{
199        	}
200     }
201 
202 	/* need to insert after the last one */
203 	if (lt)
204 		lt->next = timer;
205 	else
206 		timer_head = timer;
207 	timer->prev = lt;
208 	timer->next = NULL;
209 }
210 
211 
212 /*
213  *		remove a timer from the linked list
214  */
timer_list_remove(timer_entry * timer)215 static INLINE void timer_list_remove(timer_entry *timer)
216 {
217 	/* remove it from the list */
218 	if (timer->prev)
219 		timer->prev->next = timer->next;
220 	else
221 		timer_head = timer->next;
222 	if (timer->next)
223 		timer->next->prev = timer->prev;
224 }
225 
226 
227 /*
228  *		initialize the timer system
229  */
timer_init(void)230 void timer_init(void)
231 {
232 	cpu_entry *cpu;
233 	int i;
234 
235 	/* keep a local copy of how many total CPU's */
236 	lastcpu = cpudata + cpu_gettotalcpu() - 1;
237 
238 	/* we need to wait until the first call to timer_cyclestorun before using real CPU times */
239 	base_time = 0;
240 	global_offset = 0;
241 	callback_timer = NULL;
242 	callback_timer_modified = 0;
243 
244 	/* reset the timers */
245 	memset(timers, 0, sizeof(timers));
246 
247 	/* initialize the lists */
248 	timer_head = NULL;
249 	timer_free_head = &timers[0];
250 	for (i = 0; i < MAX_TIMERS-1; i++)
251 		timers[i].next = &timers[i+1];
252 
253 	/* reset the CPU timers */
254 	memset(cpudata, 0, sizeof(cpudata));
255 	activecpu = NULL;
256 	last_activecpu = lastcpu;
257 
258 	/* compute the cycle times */
259 	for (cpu = cpudata, i = 0; cpu <= lastcpu; cpu++, i++)
260 	{
261 		/* make a pointer to this CPU's interface functions */
262 		cpu->icount = cpuintf[Machine->drv->cpu[i].cpu_type & ~CPU_FLAGS_MASK].icount;
263 		cpu->burn = cpuintf[Machine->drv->cpu[i].cpu_type & ~CPU_FLAGS_MASK].burn;
264 
265 		/* get the CPU's overclocking factor */
266 		cpu->overclock = cpuintf[Machine->drv->cpu[i].cpu_type & ~CPU_FLAGS_MASK].overclock;
267 
268         	/* everyone is active but suspended by the reset line until further notice */
269 		cpu->suspended = SUSPEND_REASON_RESET;
270 
271 		/* set the CPU index */
272 		cpu->index = i;
273 
274 		/* compute the cycle times */
275 #ifndef MAME_UNDERCLOCK
276 		cpu->sec_to_cycles = sec_to_cycles[i] = cpu->overclock * Machine->drv->cpu[i].cpu_clock;
277 #else
278 		/* Franxis 21/01/2007 */
279 		{
280 			extern int underclock_sound;
281 			extern int underclock_cpu;
282 			if (Machine->drv->cpu[i].cpu_type&CPU_AUDIO_CPU)
283 				cpu->sec_to_cycles = sec_to_cycles[i] = ((float)(cpu->overclock * Machine->drv->cpu[i].cpu_clock))
284 					* ((((float)100)-((float)underclock_sound))/((float)100));
285 			else
286 				cpu->sec_to_cycles = sec_to_cycles[i] = ((float)(cpu->overclock * Machine->drv->cpu[i].cpu_clock))
287 					* ((((float)100)-((float)underclock_cpu))/((float)100));
288 		}
289 #endif
290 		cpu->cycles_to_sec = cycles_to_sec[i] = TIME_ONE_SEC / sec_to_cycles[i];
291 	}
292 }
293 
294 /*
295  *		get overclocking factor for a CPU
296  */
timer_get_overclock(int cpunum)297 float timer_get_overclock(int cpunum)
298 {
299 	cpu_entry *cpu = &cpudata[cpunum];
300 	return cpu->overclock;
301 }
302 
303 /*
304  *		set overclocking factor for a CPU
305  */
timer_set_overclock(int cpunum,float overclock)306 void timer_set_overclock(int cpunum, float overclock)
307 {
308 	cpu_entry *cpu = &cpudata[cpunum];
309 	cpu->overclock = overclock;
310 	cpu->sec_to_cycles = sec_to_cycles[cpunum] = cpu->overclock * Machine->drv->cpu[cpunum].cpu_clock;
311 	cpu->cycles_to_sec = cycles_to_sec[cpunum] = TIME_ONE_SEC / sec_to_cycles[cpunum];
312 }
313 
314 /*
315  *		allocate a pulse timer, which repeatedly calls the callback using the given period
316  */
timer_pulse(timer_tm period,int param,void (* callback)(int))317 void *timer_pulse(timer_tm period, int param, void (*callback)(int))
318 {
319 	timer_tm time = getabsolutetime();
320 	timer_entry *timer;
321 
322 	/* allocate a new entry */
323 	timer = timer_new();
324 	if (!timer)
325 		return NULL;
326 
327 	/* fill in the record */
328 	timer->callback = callback;
329 	timer->callback_param = param;
330 	timer->enabled = 1;
331 	timer->period = period;
332 
333 	/* compute the time of the next firing and insert into the list */
334 	timer->start = time;
335 	if (period==TIME_NEVER)
336 	    timer->expire = TIME_NEVER;
337 	else
338 	    timer->expire = time + period;
339 
340 	timer_list_insert(timer);
341 
342 	/* if we're supposed to fire before the end of this cycle, adjust the counter */
343 	if (activecpu && timer->expire < base_time)
344 		timer_adjust(timer, time, period);
345 
346 	/* return a handle */
347 	return timer;
348 }
349 
350 
351 /*
352  *		allocate a one-shot timer, which calls the callback after the given duration
353  */
timer_set(timer_tm duration,int param,void (* callback)(int))354 void *timer_set(timer_tm duration, int param, void (*callback)(int))
355 {
356 	timer_tm time = getabsolutetime();
357 	timer_entry *timer;
358 
359 	/* allocate a new entry */
360 	timer = timer_new();
361 	if (!timer)
362 		return NULL;
363 
364 	/* fill in the record */
365 	timer->callback = callback;
366 	timer->callback_param = param;
367 	timer->enabled = 1;
368 	timer->period = 0;
369 
370 	/* compute the time of the next firing and insert into the list */
371 	timer->start = time;
372 	if (duration==TIME_NOW) timer->expire = time;
373 	else if (duration==TIME_NEVER) timer->expire = TIME_NEVER;
374 	else timer->expire = time + duration;
375 	timer_list_insert(timer);
376 
377 	/* if we're supposed to fire before the end of this cycle, adjust the counter */
378 	if (activecpu && timer->expire < base_time)
379 		timer_adjust(timer, time, duration);
380 
381 	/* return a handle */
382 	return timer;
383 }
384 
385 
386 /*
387  *		reset the timing on a timer
388  */
timer_reset(void * which,timer_tm duration)389 void timer_reset(void *which, timer_tm duration)
390 {
391 	timer_tm time = getabsolutetime();
392 	timer_entry *timer = (timer_entry *)which;
393 
394 	/* compute the time of the next firing */
395 	timer->start = time;
396 	if (duration==TIME_NOW) timer->expire = time;
397 	else if (duration==TIME_NEVER) timer->expire = TIME_NEVER;
398 	else timer->expire = time + duration;
399 
400 	/* remove the timer and insert back into the list */
401 	timer_list_remove(timer);
402 	timer_list_insert(timer);
403 
404 	/* if we're supposed to fire before the end of this cycle, adjust the counter */
405 	if (activecpu && timer->expire < base_time)
406 		timer_adjust(timer, time, duration);
407 
408 	/* if this is the callback timer, mark it modified */
409 	if (timer == callback_timer)
410 		callback_timer_modified = 1;
411 }
412 
413 
414 /*
415  *		remove a timer from the system
416  */
timer_remove(void * which)417 void timer_remove(void *which)
418 {
419 	timer_entry *timer = (timer_entry *)which;
420 
421 	/* remove it from the list */
422 	timer_list_remove(timer);
423 
424 	/* free it up by adding it back to the free list */
425 	timer->next = timer_free_head;
426 	timer_free_head = timer;
427 }
428 
429 
430 /*
431  *		enable/disable a timer
432  */
timer_enable(void * which,int enable)433 int timer_enable(void *which, int enable)
434 {
435 	timer_entry *timer = (timer_entry *)which;
436 	int old;
437 
438 	/* set the enable flag */
439 	old = timer->enabled;
440 	timer->enabled = enable;
441 
442 	/* remove the timer and insert back into the list */
443 	timer_list_remove(timer);
444 	timer_list_insert(timer);
445 
446 	return old;
447 }
448 
449 
450 /*
451  *		return the time since the last trigger
452  */
timer_timeelapsed(void * which)453 timer_tm timer_timeelapsed(void *which)
454 {
455 	timer_tm time = getabsolutetime();
456 	timer_entry *timer = (timer_entry *)which;
457 
458 	return time - timer->start;
459 }
460 
461 
462 /*
463  *		return the time until the next trigger
464  */
timer_timeleft(void * which)465 timer_tm timer_timeleft(void *which)
466 {
467 	timer_tm time = getabsolutetime();
468 	timer_entry *timer = (timer_entry *)which;
469 
470     if (timer->expire==TIME_NEVER)
471         return TIME_NEVER;
472 	else
473 	    return timer->expire - time;
474 }
475 
476 
477 /*
478  *		return the current time
479  */
timer_get_time(void)480 float timer_get_time(void)
481 {
482 	return (float)global_offset + ((float)getabsolutetime()/(float)TIME_ONE_SEC);
483 }
484 
485 
486 /*
487  *		begin CPU execution by determining how many cycles the CPU should run
488  */
timer_schedule_cpu(int * cpu,int * cycles)489 int timer_schedule_cpu(int *cpu, int *cycles)
490 {
491 	timer_tm end;
492 
493 	/* then see if there are any CPUs that aren't suspended and haven't yet been updated */
494 	if (pick_cpu(cpu, cycles, timer_head->expire))
495 		return 1;
496 
497 	/* everyone is up-to-date; expire any timers now */
498 	end = timer_head->expire;
499 	while (timer_head->expire <= end)
500 	{
501 		timer_entry *timer = timer_head;
502 
503 		/* the base time is now the time of the timer */
504 		base_time = timer->expire;
505 
506 		/* set the global state of which callback we're in */
507 		callback_timer_modified = 0;
508 		callback_timer = timer;
509 
510 		/* call the callback */
511 		if (timer->callback)
512 		{
513 			profiler_mark(PROFILER_TIMER_CALLBACK);
514 			(*timer->callback)(timer->callback_param);
515 			profiler_mark(PROFILER_END);
516 		}
517 
518 		/* clear the callback timer global */
519 		callback_timer = NULL;
520 
521 		/* reset or remove the timer, but only if it wasn't modified during the callback */
522 		if (!callback_timer_modified)
523 		{
524 			if (timer->period)
525 			{
526 				timer->start = timer->expire;
527 				timer->expire += timer->period;
528 
529 				timer_list_remove(timer);
530 				timer_list_insert(timer);
531 			}
532 			else
533 				timer_remove(timer);
534 		}
535 	}
536 
537 	/* reset scheduling so it starts with CPU 0 */
538 	last_activecpu = lastcpu;
539 
540 	/* go back to scheduling */
541 	return pick_cpu(cpu, cycles, timer_head->expire);
542 }
543 
544 
545 /*
546  *		end CPU execution by updating the number of cycles the CPU actually ran
547  */
timer_update_cpu(int cpunum,int ran)548 void timer_update_cpu(int cpunum, int ran)
549 {
550 	cpu_entry *cpu = cpudata + cpunum;
551 
552 	/* update the time if we haven't been suspended */
553 	if (!cpu->suspended)
554 	{
555 		cpu->time += (timer_tm)(ran - cpu->lost) * cpu->cycles_to_sec;
556 		cpu->lost = 0;
557 	}
558 
559 	/* time to renormalize? */
560 	if (cpu->time >= TIME_ONE_SEC)
561 	{
562 		timer_entry *timer;
563 		cpu_entry *c;
564 
565 		/* renormalize all the CPU timers */
566 		for (c = cpudata; c <= lastcpu; c++)
567 			c->time -= TIME_ONE_SEC;
568 
569 		/* renormalize all the timers' times */
570 		for (timer = timer_head; timer; timer = timer->next)
571 		{
572 			timer->start -= TIME_ONE_SEC;
573 			if (timer->expire!=TIME_NEVER)
574 			    timer->expire -= TIME_ONE_SEC;
575 		}
576 
577 		/* renormalize the global timers */
578 		global_offset += 1;
579 	}
580 
581 	/* now stop counting cycles */
582 	base_time = cpu->time;
583 	activecpu = NULL;
584 }
585 
586 
587 /*
588  *		suspend a CPU but continue to count time for it
589  */
timer_suspendcpu(int cpunum,int suspend,int reason)590 void timer_suspendcpu(int cpunum, int suspend, int reason)
591 {
592 	cpu_entry *cpu = cpudata + cpunum;
593 	int nocount = cpu->nocount;
594 	int old = cpu->suspended;
595 
596 	/* mark the CPU */
597 	if (suspend)
598 		cpu->suspended |= reason;
599 	else
600 		cpu->suspended &= ~reason;
601 	cpu->nocount = 0;
602 
603 	/* if this is the active CPU and we're halting, stop immediately */
604 	if (activecpu && cpu == activecpu && !old && cpu->suspended)
605 	{
606 		/* set the CPU's time to the current time */
607 		cpu->time = base_time = getabsolutetime();	/* ASG 990225 - also set base_time */
608 		cpu->lost = 0;
609 
610 		/* no more instructions */
611 		if (cpu->burn)
612 			(*cpu->burn)(*cpu->icount); /* let the CPU burn the cycles */
613 		else
614 			*cpu->icount = 0;	/* CPU doesn't care */
615     }
616 
617 	/* else if we're unsuspending a CPU, reset its time */
618 	else if (old && !cpu->suspended && !nocount)
619 	{
620 		timer_tm time = getabsolutetime();
621 
622 		/* only update the time if it's later than the CPU's time */
623 		if (time > cpu->time)
624 			cpu->time = time;
625 		cpu->lost = 0;
626 	}
627 }
628 
629 
630 
631 /*
632  *		hold a CPU and don't count time for it
633  */
timer_holdcpu(int cpunum,int hold,int reason)634 void timer_holdcpu(int cpunum, int hold, int reason)
635 {
636 	cpu_entry *cpu = cpudata + cpunum;
637 
638 	/* same as suspend */
639 	timer_suspendcpu(cpunum, hold, reason);
640 
641 	/* except that we don't count time */
642 	if (hold)
643 		cpu->nocount = 1;
644 }
645 
646 
647 
648 /*
649  *		query if a CPU is suspended or not
650  */
timer_iscpususpended(int cpunum,int reason)651 int timer_iscpususpended(int cpunum, int reason)
652 {
653 	cpu_entry *cpu = cpudata + cpunum;
654 	return (cpu->suspended & reason) && !cpu->nocount;
655 }
656 
657 
658 
659 /*
660  *		query if a CPU is held or not
661  */
timer_iscpuheld(int cpunum,int reason)662 int timer_iscpuheld(int cpunum, int reason)
663 {
664 	cpu_entry *cpu = cpudata + cpunum;
665 	return (cpu->suspended & reason) && cpu->nocount;
666 }
667 
668 
669 
670 /*
671  *		suspend a CPU until a specified trigger condition is met
672  */
timer_suspendcpu_trigger(int cpunum,int trigger)673 void timer_suspendcpu_trigger(int cpunum, int trigger)
674 {
675 	cpu_entry *cpu = cpudata + cpunum;
676 
677 	/* suspend the CPU immediately if it's not already */
678 	timer_suspendcpu(cpunum, 1, SUSPEND_REASON_TRIGGER);
679 
680 	/* set the trigger */
681 	cpu->trigger = trigger;
682 }
683 
684 
685 
686 /*
687  *		hold a CPU and don't count time for it
688  */
timer_holdcpu_trigger(int cpunum,int trigger)689 void timer_holdcpu_trigger(int cpunum, int trigger)
690 {
691 	cpu_entry *cpu = cpudata + cpunum;
692 
693 	/* suspend the CPU immediately if it's not already */
694 	timer_holdcpu(cpunum, 1, SUSPEND_REASON_TRIGGER);
695 
696 	/* set the trigger */
697 	cpu->trigger = trigger;
698 }
699 
700 
701 
702 /*
703  *		generates a trigger to unsuspend any CPUs waiting for it
704  */
timer_trigger(int trigger)705 void timer_trigger(int trigger)
706 {
707 	cpu_entry *cpu;
708 
709 	/* cause an immediate resynchronization */
710 	if (activecpu)
711 	{
712 		int left = *activecpu->icount;
713 		if (left > 0)
714 		{
715 			activecpu->lost += left;
716 			if (activecpu->burn)
717 				(*activecpu->burn)(left); /* let the CPU burn the cycles */
718 			else
719 				*activecpu->icount = 0; /* CPU doesn't care */
720 		}
721 	}
722 
723 	/* look for suspended CPUs waiting for this trigger and unsuspend them */
724 	for (cpu = cpudata; cpu <= lastcpu; cpu++)
725 	{
726 		if (cpu->suspended && cpu->trigger == trigger)
727 		{
728 			timer_suspendcpu(cpu->index, 0, SUSPEND_REASON_TRIGGER);
729 			cpu->trigger = 0;
730 		}
731 	}
732 }
733 
734 
735 /*
736  *		pick the next CPU to run
737  */
pick_cpu(int * cpunum,int * cycles,timer_tm end)738 static int pick_cpu(int *cpunum, int *cycles, timer_tm end)
739 {
740 	cpu_entry *cpu = last_activecpu;
741 
742 	/* look for a CPU that isn't suspended and hasn't run its full timeslice yet */
743 	do
744 	{
745 		/* wrap around */
746 		cpu += 1;
747 		if (cpu > lastcpu)
748 			cpu = cpudata;
749 
750 		/* if this CPU isn't suspended and has time left.... */
751 		if ((!cpu->suspended) && (cpu->time < end))
752 		{
753 			/* mark the CPU active, and remember the CPU number locally */
754 			activecpu = last_activecpu = cpu;
755 
756 			/* return the number of cycles to execute and the CPU number */
757 			*cpunum = cpu->index;
758 			*cycles=CYCLES_CALC(end - cpu->time,cpu->sec_to_cycles);
759 
760 			if (*cycles > 0)
761 			{
762 				/* remember the base time for this CPU */
763 				base_time = cpu->time + ((timer_tm)*cycles * cpu->cycles_to_sec);
764 
765 				/* success */
766 				return 1;
767 			}
768 		}
769 	}
770 	while (cpu != last_activecpu);
771 
772 	/* ASG 990225 - bump all suspended CPU times after the slice has finished */
773 	for (cpu = cpudata; cpu <= lastcpu; cpu++)
774 		if (cpu->suspended && !cpu->nocount)
775 		{
776 			cpu->time = end;
777 			cpu->lost = 0;
778 		}
779 
780 	/* failure */
781 	return 0;
782 }
783