Develop and Download Open Source Software

Browse CVS Repository

Contents of /mame32jp/mame32jp/src/timer.c

Parent Directory Parent Directory | Revision Log Revision Log | View Revision Graph Revision Graph


Revision 1.5 - (show annotations) (download) (as text)
Wed Apr 24 03:53:21 2002 UTC (21 years, 11 months ago) by zero
Branch: MAIN
CVS Tags: ver_0_60_1, ver0_59_13, ver0_59_14, ver0_60_2, ver0_60_3, ver0_60_4, ver0_60_5, HEAD
Changes since 1.4: +0 -0 lines
File MIME type: text/x-csrc
*** empty log message ***

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 #include <stdarg.h>
38
39
40 #define VERBOSE 0
41
42 #define MAX_TIMERS 256
43
44
45 /*-------------------------------------------------
46 internal timer structures
47 -------------------------------------------------*/
48
49 typedef struct timer_entry
50 {
51 struct timer_entry *next;
52 struct timer_entry *prev;
53 void (*callback)(int);
54 int callback_param;
55 int tag;
56 UINT8 enabled;
57 UINT8 temporary;
58 double period;
59 double start;
60 double expire;
61 } timer_entry;
62
63 typedef struct
64 {
65 int *icount;
66 void (*burn)(int cycles);
67 int index;
68 int suspended;
69 int trigger;
70 int nocount;
71 int lost;
72 double time;
73 double sec_to_cycles;
74 double cycles_to_sec;
75 double overclock;
76 } cpu_entry;
77
78
79
80 /*-------------------------------------------------
81 global variables
82 -------------------------------------------------*/
83
84 /* conversion constants */
85 double cycles_to_sec[MAX_CPU];
86 double sec_to_cycles[MAX_CPU];
87
88 /* list of per-CPU timer data */
89 static cpu_entry cpudata[MAX_CPU+1];
90 static cpu_entry *lastcpu;
91 static cpu_entry *active_cpu;
92 static cpu_entry *last_active_cpu;
93
94 /* list of active timers */
95 static timer_entry timers[MAX_TIMERS];
96 static timer_entry *timer_head;
97 static timer_entry *timer_free_head;
98 static timer_entry *timer_free_tail;
99
100 /* other internal states */
101 static double base_time;
102 static double global_offset;
103 static timer_entry *callback_timer;
104 static int callback_timer_modified;
105
106 /* prototypes */
107 static int pick_cpu(int *cpu, int *cycles, double expire);
108
109 #if VERBOSE
110 static void verbose_print(char *s, ...);
111 #endif
112
113
114
115 /*-------------------------------------------------
116 getabsolutetime - return the current absolute
117 time
118 -------------------------------------------------*/
119
120 INLINE double getabsolutetime(void)
121 {
122 if (active_cpu && (*active_cpu->icount + active_cpu->lost) > 0)
123 return base_time - ((double)(*active_cpu->icount + active_cpu->lost) * active_cpu->cycles_to_sec);
124 else
125 return base_time;
126 }
127
128
129 /*-------------------------------------------------
130 timer_adjust_icount - adjust the current CPU's
131 instruction counter so that a new event will
132 fire at the right time
133 -------------------------------------------------*/
134
135 INLINE void timer_adjust_icount(timer_entry *timer, double time, double period)
136 {
137 int newicount, diff;
138
139 /* compute a new icount for the current CPU */
140 if (period == TIME_NOW)
141 newicount = 0;
142 else
143 newicount = (int)((timer->expire - time) * active_cpu->sec_to_cycles) + 1;
144
145 /* determine if we're scheduled to run more cycles */
146 diff = *active_cpu->icount - newicount;
147
148 /* if so, set the new icount and compute the amount of "lost" time */
149 if (diff > 0)
150 {
151 active_cpu->lost += diff;
152 if (active_cpu->burn)
153 (*active_cpu->burn)(diff); /* let the CPU burn the cycles */
154 else
155 *active_cpu->icount = newicount; /* CPU doesn't care */
156 }
157 }
158
159
160 /*-------------------------------------------------
161 timer_new - allocate a new timer
162 -------------------------------------------------*/
163
164 INLINE timer_entry *timer_new(void)
165 {
166 timer_entry *timer;
167
168 /* remove an empty entry */
169 if (!timer_free_head)
170 return NULL;
171 timer = timer_free_head;
172 timer_free_head = timer->next;
173 if (!timer_free_head)
174 timer_free_tail = NULL;
175
176 return timer;
177 }
178
179
180 /*-------------------------------------------------
181 timer_list_insert - insert a new timer into
182 the list at the appropriate location
183 -------------------------------------------------*/
184
185 INLINE void timer_list_insert(timer_entry *timer)
186 {
187 double expire = timer->enabled ? timer->expire : TIME_NEVER;
188 timer_entry *t, *lt = NULL;
189
190 /* loop over the timer list */
191 for (t = timer_head; t; lt = t, t = t->next)
192 {
193 /* if the current list entry expires after us, we should be inserted before it */
194 /* note that due to floating point rounding, we need to allow a bit of slop here */
195 /* because two equal entries -- within rounding precision -- need to sort in */
196 /* the order they were inserted into the list */
197 if ((t->expire - expire) > TIME_IN_NSEC(1))
198 {
199 /* link the new guy in before the current list entry */
200 timer->prev = t->prev;
201 timer->next = t;
202
203 if (t->prev)
204 t->prev->next = timer;
205 else
206 timer_head = timer;
207 t->prev = timer;
208 return;
209 }
210 }
211
212 /* need to insert after the last one */
213 if (lt)
214 lt->next = timer;
215 else
216 timer_head = timer;
217 timer->prev = lt;
218 timer->next = NULL;
219 }
220
221
222 /*-------------------------------------------------
223 timer_list_remove - remove a timer from the
224 linked list
225 -------------------------------------------------*/
226
227 INLINE void timer_list_remove(timer_entry *timer)
228 {
229 /* remove it from the list */
230 if (timer->prev)
231 timer->prev->next = timer->next;
232 else
233 timer_head = timer->next;
234 if (timer->next)
235 timer->next->prev = timer->prev;
236 }
237
238
239 /*-------------------------------------------------
240 timer_init - initialize the timer system
241 -------------------------------------------------*/
242
243 void timer_init(void)
244 {
245 cpu_entry *cpu;
246 int i;
247
248 /* we need to wait until the first call to timer_cyclestorun before using real CPU times */
249 base_time = 0.0;
250 global_offset = 0.0;
251 callback_timer = NULL;
252 callback_timer_modified = 0;
253
254 /* reset the timers */
255 memset(timers, 0, sizeof(timers));
256
257 /* initialize the lists */
258 timer_head = NULL;
259 timer_free_head = &timers[0];
260 for (i = 0; i < MAX_TIMERS-1; i++)
261 {
262 timers[i].tag = -1;
263 timers[i].next = &timers[i+1];
264 }
265 timer_free_tail = &timers[MAX_TIMERS-1];
266
267 /* reset the CPU timers */
268 memset(cpudata, 0, sizeof(cpudata));
269
270 /* compute the cycle times */
271 lastcpu = cpudata;
272 for (cpu = cpudata, i = 0; i < MAX_CPU; cpu++, i++)
273 {
274 int cputype = Machine->drv->cpu[i].cpu_type & ~CPU_FLAGS_MASK;
275
276 /* stop when we hit a dummy */
277 if (cputype == CPU_DUMMY)
278 break;
279 lastcpu = cpu;
280
281 /* make a pointer to this CPU's interface functions */
282 cpu->icount = cputype_get_interface(cputype)->icount;
283 cpu->burn = cputype_get_interface(cputype)->burn;
284
285 /* get the CPU's overclocking factor */
286 cpu->overclock = cputype_get_interface(cputype)->overclock;
287
288 /* everyone is active but suspended by the reset line until further notice */
289 cpu->suspended = SUSPEND_REASON_RESET;
290
291 /* set the CPU index */
292 cpu->index = i;
293
294 /* compute the cycle times */
295 cpu->sec_to_cycles = sec_to_cycles[i] = cpu->overclock * Machine->drv->cpu[i].cpu_clock;
296 cpu->cycles_to_sec = cycles_to_sec[i] = 1.0 / sec_to_cycles[i];
297 }
298
299 /* reset our active CPU tracking */
300 active_cpu = NULL;
301 last_active_cpu = lastcpu;
302 }
303
304
305 /*-------------------------------------------------
306 timer_get_overclock - get overclocking factor
307 for a CPU
308 -------------------------------------------------*/
309
310 double timer_get_overclock(int cpunum)
311 {
312 cpu_entry *cpu = &cpudata[cpunum];
313 return cpu->overclock;
314 }
315
316
317 /*-------------------------------------------------
318 timer_set_overclock - set overclocking factor
319 for a CPU
320 -------------------------------------------------*/
321
322 void timer_set_overclock(int cpunum, double overclock)
323 {
324 cpu_entry *cpu = &cpudata[cpunum];
325 cpu->overclock = overclock;
326 cpu->sec_to_cycles = sec_to_cycles[cpunum] = cpu->overclock * Machine->drv->cpu[cpunum].cpu_clock;
327 cpu->cycles_to_sec = cycles_to_sec[cpunum] = 1.0 / sec_to_cycles[cpunum];
328 }
329
330
331 /*-------------------------------------------------
332 timer_alloc - allocate a permament timer that
333 isn't primed yet
334 -------------------------------------------------*/
335
336 void *timer_alloc(void (*callback)(int))
337 {
338 timer_entry *timer = timer_new();
339 double time = getabsolutetime();
340
341 /* fail if we can't allocate a new entry */
342 if (!timer)
343 return NULL;
344
345 /* fill in the record */
346 timer->callback = callback;
347 timer->callback_param = 0;
348 timer->enabled = 0;
349 timer->temporary = 0;
350 timer->tag = get_resource_tag();
351 timer->period = 0;
352
353 /* compute the time of the next firing and insert into the list */
354 timer->start = time;
355 timer->expire = TIME_NEVER;
356 timer_list_insert(timer);
357
358 /* return a handle */
359 return timer;
360 }
361
362
363 /*-------------------------------------------------
364 timer_adjust - adjust the time when this
365 timer will fire, and whether or not it will
366 fire periodically
367 -------------------------------------------------*/
368
369 void timer_adjust(void *which, double duration, int param, double period)
370 {
371 double time = getabsolutetime();
372 timer_entry *timer = which;
373
374 /* if this is the callback timer, mark it modified */
375 if (timer == callback_timer)
376 callback_timer_modified = 1;
377
378 /* compute the time of the next firing and insert into the list */
379 timer->callback_param = param;
380 timer->enabled = 1;
381
382 /* set the start and expire times */
383 timer->start = time;
384 timer->expire = time + duration;
385 timer->period = period;
386
387 /* remove and re-insert the timer in its new order */
388 timer_list_remove(timer);
389 timer_list_insert(timer);
390
391 /* if we're supposed to fire before the end of this cycle, adjust the counter */
392 if (active_cpu && timer->expire < base_time)
393 timer_adjust_icount(timer, time, period);
394 }
395
396
397 /*-------------------------------------------------
398 timer_pulse - allocate a pulse timer, which
399 repeatedly calls the callback using the given
400 period
401 -------------------------------------------------*/
402
403 void timer_pulse(double period, int param, void (*callback)(int))
404 {
405 void *timer = timer_alloc(callback);
406
407 /* fail if we can't allocate */
408 if (!timer)
409 return;
410
411 /* adjust to our liking */
412 timer_adjust(timer, period, param, period);
413 }
414
415
416 /*-------------------------------------------------
417 timer_set - allocate a one-shot timer, which
418 calls the callback after the given duration
419 -------------------------------------------------*/
420
421 void timer_set(double duration, int param, void (*callback)(int))
422 {
423 timer_entry *timer = timer_alloc(callback);
424
425 /* fail if we can't allocate */
426 if (!timer)
427 return;
428
429 /* mark the timer temporary */
430 timer->temporary = 1;
431
432 /* adjust to our liking */
433 timer_adjust(timer, duration, param, 0);
434 }
435
436
437 /*-------------------------------------------------
438 timer_reset - reset the timing on a timer
439 -------------------------------------------------*/
440
441 void timer_reset(void *which, double duration)
442 {
443 timer_entry *timer = which;
444
445 /* adjust the timer */
446 timer_adjust(timer, duration, timer->callback_param, timer->period);
447 }
448
449
450 /*-------------------------------------------------
451 timer_remove - remove a timer from the system
452 -------------------------------------------------*/
453
454 void timer_remove(void *which)
455 {
456 timer_entry *timer = which;
457
458 /* error if this is an inactive timer */
459 if (timer->tag == -1)
460 {
461 logerror("timer_remove: removed an inactive timer!\n");
462 return;
463 }
464
465 /* remove it from the list */
466 timer_list_remove(timer);
467
468 /* mark it as dead */
469 timer->tag = -1;
470
471 /* free it up by adding it back to the free list */
472 if (timer_free_tail)
473 timer_free_tail->next = timer;
474 else
475 timer_free_head = timer;
476 timer_free_tail = timer;
477
478 #if VERBOSE
479 verbose_print("T=%.6g: Removed %08X\n", getabsolutetime() + global_offset, timer);
480 #endif
481 }
482
483
484 /*-------------------------------------------------
485 timer_free - remove all timers on the current
486 resource tag
487 -------------------------------------------------*/
488
489 void timer_free(void)
490 {
491 int tag = get_resource_tag();
492 timer_entry *timer, *next;
493
494 /* scan the list */
495 for (timer = timer_head; timer != NULL; timer = next)
496 {
497 /* prefetch the next timer in case we remove this one */
498 next = timer->next;
499
500 /* if this tag matches, remove it */
501 if (timer->tag == tag)
502 timer_remove(timer);
503 }
504 }
505
506
507 /*-------------------------------------------------
508 timer_enable - enable/disable a timer
509 -------------------------------------------------*/
510
511 int timer_enable(void *which, int enable)
512 {
513 timer_entry *timer = which;
514 int old;
515
516 #if VERBOSE
517 if (enable) verbose_print("T=%.6g: Enabled %08X\n", getabsolutetime() + global_offset, timer);
518 else verbose_print("T=%.6g: Disabled %08X\n", getabsolutetime() + global_offset, timer);
519 #endif
520
521 /* set the enable flag */
522 old = timer->enabled;
523 timer->enabled = enable;
524
525 /* remove the timer and insert back into the list */
526 timer_list_remove(timer);
527 timer_list_insert(timer);
528
529 return old;
530 }
531
532
533 /*-------------------------------------------------
534 timer_timeelapsed - return the time since the
535 last trigger
536 -------------------------------------------------*/
537
538 double timer_timeelapsed(void *which)
539 {
540 double time = getabsolutetime();
541 timer_entry *timer = which;
542
543 return time - timer->start;
544 }
545
546
547 /*-------------------------------------------------
548 timer_timeleft - return the time until the
549 next trigger
550 -------------------------------------------------*/
551
552 double timer_timeleft(void *which)
553 {
554 double time = getabsolutetime();
555 timer_entry *timer = which;
556
557 return timer->expire - time;
558 }
559
560
561 /*-------------------------------------------------
562 timer_get_time - return the current time
563 -------------------------------------------------*/
564
565 double timer_get_time(void)
566 {
567 return global_offset + getabsolutetime();
568 }
569
570
571 /*-------------------------------------------------
572 timer_starttime - return the time when this
573 timer started counting
574 -------------------------------------------------*/
575
576 double timer_starttime(void *which)
577 {
578 timer_entry *timer = which;
579 return global_offset + timer->start;
580 }
581
582
583 /*-------------------------------------------------
584 timer_firetime - return the time when this
585 timer will fire next
586 -------------------------------------------------*/
587
588 double timer_firetime(void *which)
589 {
590 timer_entry *timer = which;
591 return global_offset + timer->expire;
592 }
593
594
595 /*-------------------------------------------------
596 timer_schedule_cpu - begin CPU execution by
597 determining how many cycles the CPU should run
598 -------------------------------------------------*/
599
600 int timer_schedule_cpu(int *cpu, int *cycles)
601 {
602 double end;
603
604 /* then see if there are any CPUs that aren't suspended and haven't yet been updated */
605 if (pick_cpu(cpu, cycles, timer_head->expire))
606 return 1;
607
608 /* everyone is up-to-date; expire any timers now */
609 end = timer_head->expire;
610 while (timer_head->expire <= end)
611 {
612 timer_entry *timer = timer_head;
613
614 /* the base time is now the time of the timer */
615 base_time = timer->expire;
616
617 #if VERBOSE
618 verbose_print("T=%.6g: %08X fired (exp time=%.6g)\n", getabsolutetime() + global_offset, timer, timer->expire + global_offset);
619 #endif
620
621 /* if this is a one-shot timer, disable it now */
622 if (timer->period == 0)
623 timer->enabled = 0;
624
625 /* set the global state of which callback we're in */
626 callback_timer_modified = 0;
627 callback_timer = timer;
628
629 /* call the callback */
630 if (timer->callback)
631 {
632 profiler_mark(PROFILER_TIMER_CALLBACK);
633 (*timer->callback)(timer->callback_param);
634 profiler_mark(PROFILER_END);
635 }
636
637 /* clear the callback timer global */
638 callback_timer = NULL;
639
640 /* reset or remove the timer, but only if it wasn't modified during the callback */
641 if (!callback_timer_modified)
642 {
643 /* if the timer is temporary, remove it now */
644 if (timer->temporary)
645 timer_remove(timer);
646
647 /* otherwise, reschedule it */
648 else
649 {
650 timer->start = timer->expire;
651 timer->expire += timer->period;
652
653 timer_list_remove(timer);
654 timer_list_insert(timer);
655 }
656 }
657 }
658
659 /* reset scheduling so it starts with CPU 0 */
660 last_active_cpu = lastcpu;
661
662 #ifdef MAME_DEBUG
663 {
664 extern int debug_key_delay;
665 debug_key_delay = 0x7ffe;
666 }
667 #endif
668
669 /* go back to scheduling */
670 return pick_cpu(cpu, cycles, timer_head->expire);
671 }
672
673
674 /*-------------------------------------------------
675 timer_update_cpu - end CPU execution by
676 updating the number of cycles the CPU
677 actually ran
678 -------------------------------------------------*/
679
680 void timer_update_cpu(int cpunum, int ran)
681 {
682 cpu_entry *cpu = cpudata + cpunum;
683
684 /* update the time if we haven't been suspended */
685 if (!cpu->suspended)
686 {
687 cpu->time += (double)(ran - cpu->lost) * cpu->cycles_to_sec;
688 cpu->lost = 0;
689 }
690
691 #if VERBOSE
692 verbose_print("T=%.6g: CPU %d finished (net=%d)\n", cpu->time + global_offset, cpunum, ran - cpu->lost);
693 #endif
694
695 /* time to renormalize? */
696 if (cpu->time >= 1.0)
697 {
698 static const double one = 1.0;
699 timer_entry *timer;
700 cpu_entry *c;
701
702 #if VERBOSE
703 verbose_print("T=%.6g: Renormalizing\n", cpu->time + global_offset);
704 #endif
705
706 /* renormalize all the CPU timers */
707 for (c = cpudata; c <= lastcpu; c++)
708 c->time -= one;
709
710 /* renormalize all the timers' times */
711 for (timer = timer_head; timer; timer = timer->next)
712 {
713 timer->start -= one;
714 timer->expire -= one;
715 }
716
717 /* renormalize the global timers */
718 global_offset += one;
719 }
720
721 /* now stop counting cycles */
722 base_time = cpu->time;
723 active_cpu = NULL;
724 }
725
726
727 /*-------------------------------------------------
728 timer_suspendcpu - suspend a CPU but continue
729 to count time for it
730 -------------------------------------------------*/
731
732 void timer_suspendcpu(int cpunum, int suspend, int reason)
733 {
734 cpu_entry *cpu = cpudata + cpunum;
735 int nocount = cpu->nocount;
736 int old = cpu->suspended;
737
738 #if VERBOSE
739 if (suspend) verbose_print("T=%.6g: Suspending CPU %d\n", getabsolutetime() + global_offset, cpunum);
740 else verbose_print("T=%.6g: Resuming CPU %d\n", getabsolutetime() + global_offset, cpunum);
741 #endif
742
743 /* mark the CPU */
744 if (suspend)
745 cpu->suspended |= reason;
746 else
747 cpu->suspended &= ~reason;
748 cpu->nocount = 0;
749
750 /* if this is the active CPU and we're halting, stop immediately */
751 if (active_cpu && cpu == active_cpu && !old && cpu->suspended)
752 {
753 #if VERBOSE
754 verbose_print("T=%.6g: Reset ICount\n", getabsolutetime() + global_offset);
755 #endif
756
757 /* set the CPU's time to the current time */
758 cpu->time = base_time = getabsolutetime(); /* ASG 990225 - also set base_time */
759 cpu->lost = 0;
760
761 /* no more instructions */
762 if (cpu->burn)
763 (*cpu->burn)(*cpu->icount); /* let the CPU burn the cycles */
764 else
765 *cpu->icount = 0; /* CPU doesn't care */
766 }
767
768 /* else if we're unsuspending a CPU, reset its time */
769 else if (old && !cpu->suspended && !nocount)
770 {
771 double time = getabsolutetime();
772
773 /* only update the time if it's later than the CPU's time */
774 if (time > cpu->time)
775 cpu->time = time;
776 cpu->lost = 0;
777
778 #if VERBOSE
779 verbose_print("T=%.6g: Resume time\n", cpu->time + global_offset);
780 #endif
781 }
782 }
783
784
785
786 /*-------------------------------------------------
787 timer_holdcpu - hold a CPU and don't count
788 time for it
789 -------------------------------------------------*/
790
791 void timer_holdcpu(int cpunum, int hold, int reason)
792 {
793 cpu_entry *cpu = cpudata + cpunum;
794
795 /* same as suspend */
796 timer_suspendcpu(cpunum, hold, reason);
797
798 /* except that we don't count time */
799 if (hold)
800 cpu->nocount = 1;
801 }
802
803
804
805 /*-------------------------------------------------
806 timer_iscpususpended - query if a CPU is
807 suspended or not
808 -------------------------------------------------*/
809
810 int timer_iscpususpended(int cpunum, int reason)
811 {
812 cpu_entry *cpu = cpudata + cpunum;
813 return (cpu->suspended & reason) && !cpu->nocount;
814 }
815
816
817
818 /*-------------------------------------------------
819 timer_iscpuheld - query if a CPU is held or not
820 -------------------------------------------------*/
821
822 int timer_iscpuheld(int cpunum, int reason)
823 {
824 cpu_entry *cpu = cpudata + cpunum;
825 return (cpu->suspended & reason) && cpu->nocount;
826 }
827
828
829
830 /*-------------------------------------------------
831 timer_suspendcpu_trigger - suspend a CPU until
832 a specified trigger condition is met
833 -------------------------------------------------*/
834
835 void timer_suspendcpu_trigger(int cpunum, int trigger)
836 {
837 cpu_entry *cpu = cpudata + cpunum;
838
839 #if VERBOSE
840 verbose_print("T=%.6g: CPU %d suspended until %d\n", getabsolutetime() + global_offset, cpunum, trigger);
841 #endif
842
843 /* suspend the CPU immediately if it's not already */
844 timer_suspendcpu(cpunum, 1, SUSPEND_REASON_TRIGGER);
845
846 /* set the trigger */
847 cpu->trigger = trigger;
848 }
849
850
851
852 /*-------------------------------------------------
853 timer_holdcpu_trigger - hold a CPU and don't
854 count time for it
855 -------------------------------------------------*/
856
857 void timer_holdcpu_trigger(int cpunum, int trigger)
858 {
859 cpu_entry *cpu = cpudata + cpunum;
860
861 #if VERBOSE
862 verbose_print("T=%.6g: CPU %d held until %d\n", getabsolutetime() + global_offset, cpunum, trigger);
863 #endif
864
865 /* suspend the CPU immediately if it's not already */
866 timer_holdcpu(cpunum, 1, SUSPEND_REASON_TRIGGER);
867
868 /* set the trigger */
869 cpu->trigger = trigger;
870 }
871
872
873
874 /*-------------------------------------------------
875 timer_trigger - generates a trigger to
876 unsuspend any CPUs waiting for it
877 -------------------------------------------------*/
878
879 void timer_trigger(int trigger)
880 {
881 cpu_entry *cpu;
882
883 /* cause an immediate resynchronization */
884 if (active_cpu)
885 {
886 int left = *active_cpu->icount;
887 if (left > 0)
888 {
889 active_cpu->lost += left;
890 if (active_cpu->burn)
891 (*active_cpu->burn)(left); /* let the CPU burn the cycles */
892 else
893 *active_cpu->icount = 0; /* CPU doesn't care */
894 }
895 }
896
897 /* look for suspended CPUs waiting for this trigger and unsuspend them */
898 for (cpu = cpudata; cpu <= lastcpu; cpu++)
899 {
900 if (cpu->suspended && cpu->trigger == trigger)
901 {
902 #if VERBOSE
903 verbose_print("T=%.6g: CPU %d triggered\n", getabsolutetime() + global_offset, cpu->index);
904 #endif
905
906 timer_suspendcpu(cpu->index, 0, SUSPEND_REASON_TRIGGER);
907 cpu->trigger = 0;
908 }
909 }
910 }
911
912
913 /*-------------------------------------------------
914 pick_cpu - pick the next CPU to run
915 -------------------------------------------------*/
916
917 static int pick_cpu(int *cpunum, int *cycles, double end)
918 {
919 cpu_entry *cpu = last_active_cpu;
920
921 /* look for a CPU that isn't suspended and hasn't run its full timeslice yet */
922 do
923 {
924 /* wrap around */
925 cpu += 1;
926 if (cpu > lastcpu)
927 cpu = cpudata;
928
929 /* if this CPU is suspended, just skip it */
930 if (cpu->suspended)
931 ;
932
933 /* if this CPU isn't suspended and has time left.... */
934 else if (cpu->time < end)
935 {
936 /* mark the CPU active, and remember the CPU number locally */
937 active_cpu = last_active_cpu = cpu;
938
939 /* return the number of cycles to execute and the CPU number */
940 *cpunum = cpu->index;
941 *cycles = (int)((double)(end - cpu->time) * cpu->sec_to_cycles);
942
943 if (*cycles > 0)
944 {
945 #if VERBOSE
946 verbose_print("T=%.6g: CPU %d runs %d cycles\n", cpu->time + global_offset, *cpunum, *cycles);
947 #endif
948
949 /* remember the base time for this CPU */
950 base_time = cpu->time + ((double)*cycles * cpu->cycles_to_sec);
951
952 /* success */
953 return 1;
954 }
955 }
956 } while (cpu != last_active_cpu);
957
958 /* ASG 990225 - bump all suspended CPU times after the slice has finished */
959 for (cpu = cpudata; cpu <= lastcpu; cpu++)
960 if (cpu->suspended && !cpu->nocount)
961 {
962 cpu->time = end;
963 cpu->lost = 0;
964 }
965
966 /* failure */
967 return 0;
968 }
969
970
971
972 /*-------------------------------------------------
973 debugging
974 -------------------------------------------------*/
975
976 #if VERBOSE
977
978 #ifdef macintosh
979 #undef printf
980 #endif
981
982 static void verbose_print(char *s, ...)
983 {
984 va_list ap;
985
986 va_start(ap, s);
987
988 #if (VERBOSE == 1)
989 if (errorlog) vfprintf(errorlog, s, ap);
990 #else
991 vprintf(s, ap);
992 fflush(NULL);
993 #endif
994
995 va_end(ap);
996 }
997
998 #endif

Back to OSDN">Back to OSDN
ViewVC Help
Powered by ViewVC 1.1.26