First Commit of my working state
[simh.git] / sim_timer.c
CommitLineData
196ba1fc
PH
1/* sim_timer.c: simulator timer library\r
2\r
3 Copyright (c) 1993-2008, Robert M Supnik\r
4\r
5 Permission is hereby granted, free of charge, to any person obtaining a\r
6 copy of this software and associated documentation files (the "Software"),\r
7 to deal in the Software without restriction, including without limitation\r
8 the rights to use, copy, modify, merge, publish, distribute, sublicense,\r
9 and/or sell copies of the Software, and to permit persons to whom the\r
10 Software is furnished to do so, subject to the following conditions:\r
11\r
12 The above copyright notice and this permission notice shall be included in\r
13 all copies or substantial portions of the Software.\r
14\r
15 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r
16 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r
17 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL\r
18 ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\r
19 IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
20 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r
21\r
22 Except as contained in this notice, the name of Robert M Supnik shall not be\r
23 used in advertising or otherwise to promote the sale, use or other dealings\r
24 in this Software without prior written authorization from Robert M Supnik.\r
25\r
26 27-May-08 RMS Fixed bug in Linux idle routines (from Walter Mueller)\r
27 18-Jun-07 RMS Modified idle to exclude counted delays\r
28 22-Mar-07 RMS Added sim_rtcn_init_all\r
29 17-Oct-06 RMS Added idle support (based on work by Mark Pizzolato)\r
30 Added throttle support\r
31 16-Aug-05 RMS Fixed C++ declaration and cast problems\r
32 02-Jan-04 RMS Split out from SCP\r
33\r
34 This library includes the following routines:\r
35\r
36 sim_timer_init - initialize timing system\r
37 sim_rtc_init - initialize calibration\r
38 sim_rtc_calb - calibrate clock\r
39 sim_timer_init - initialize timing system\r
40 sim_idle - virtual machine idle\r
41 sim_os_msec - return elapsed time in msec\r
42 sim_os_sleep - sleep specified number of seconds\r
43 sim_os_ms_sleep - sleep specified number of milliseconds\r
44\r
45 The calibration, idle, and throttle routines are OS-independent; the _os_\r
46 routines are not.\r
47*/\r
48\r
49#include "sim_defs.h"\r
50#include <ctype.h>\r
51\r
52t_bool sim_idle_enab = FALSE; /* global flag */\r
53\r
54static uint32 sim_idle_rate_ms = 0;\r
55static uint32 sim_throt_ms_start = 0;\r
56static uint32 sim_throt_ms_stop = 0;\r
57static uint32 sim_throt_type = 0;\r
58static uint32 sim_throt_val = 0;\r
59static uint32 sim_throt_state = 0;\r
60static int32 sim_throt_wait = 0;\r
61extern int32 sim_interval, sim_switches;\r
62extern FILE *sim_log;\r
63extern UNIT *sim_clock_queue;\r
64\r
65t_stat sim_throt_svc (UNIT *uptr);\r
66\r
67UNIT sim_throt_unit = { UDATA (&sim_throt_svc, 0, 0) };\r
68\r
69/* OS-dependent timer and clock routines */\r
70\r
71/* VMS */\r
72\r
73#if defined (VMS)\r
74\r
75#if defined (__VAX)\r
76#define sys$gettim SYS$GETTIM\r
77#endif\r
78\r
79#include <starlet.h>\r
80#include <lib$routines.h>\r
81#include <unistd.h>\r
82\r
83const t_bool rtc_avail = TRUE;\r
84\r
85uint32 sim_os_msec ()\r
86{\r
87uint32 quo, htod, tod[2];\r
88int32 i;\r
89\r
90sys$gettim (tod); /* time 0.1usec */\r
91\r
92/* To convert to msec, must divide a 64b quantity by 10000. This is actually done\r
93 by dividing the 96b quantity 0'time by 10000, producing 64b of quotient, the\r
94 high 32b of which are discarded. This can probably be done by a clever multiply...\r
95*/\r
96\r
97quo = htod = 0;\r
98for (i = 0; i < 64; i++) { /* 64b quo */\r
99 htod = (htod << 1) | ((tod[1] >> 31) & 1); /* shift divd */\r
100 tod[1] = (tod[1] << 1) | ((tod[0] >> 31) & 1);\r
101 tod[0] = tod[0] << 1;\r
102 quo = quo << 1; /* shift quo */\r
103 if (htod >= 10000) { /* divd work? */\r
104 htod = htod - 10000; /* subtract */\r
105 quo = quo | 1; /* set quo bit */\r
106 }\r
107 }\r
108return quo;\r
109}\r
110\r
111void sim_os_sleep (unsigned int sec)\r
112{\r
113sleep (sec);\r
114return;\r
115}\r
116\r
117uint32 sim_os_ms_sleep_init (void)\r
118{\r
119#if defined (__VAX)\r
120return 10; /* VAX/VMS is 10ms */\r
121#else\r
122return 1; /* Alpha/VMS is 1ms */\r
123#endif\r
124}\r
125\r
126uint32 sim_os_ms_sleep (unsigned int msec)\r
127{\r
128uint32 stime = sim_os_msec ();\r
129uint32 qtime[2];\r
130int32 nsfactor = -10000;\r
131static int32 zero = 0;\r
132\r
133lib$emul (&msec, &nsfactor, &zero, qtime);\r
134sys$setimr (2, qtime, 0, 0);\r
135sys$waitfr (2);\r
136return sim_os_msec () - stime;\r
137}\r
138\r
139/* Win32 routines */\r
140\r
141#elif defined (_WIN32)\r
142\r
143#include <windows.h>\r
144\r
145const t_bool rtc_avail = TRUE;\r
146\r
147uint32 sim_os_msec ()\r
148{\r
149if (sim_idle_rate_ms) return timeGetTime ();\r
150else return GetTickCount ();\r
151}\r
152\r
153void sim_os_sleep (unsigned int sec)\r
154{\r
155Sleep (sec * 1000);\r
156return;\r
157}\r
158\r
159void sim_timer_exit (void)\r
160{\r
161timeEndPeriod (sim_idle_rate_ms);\r
162return;\r
163}\r
164\r
165uint32 sim_os_ms_sleep_init (void)\r
166{\r
167TIMECAPS timers;\r
168\r
169if (timeGetDevCaps (&timers, sizeof (timers)) != TIMERR_NOERROR)\r
170 return 0;\r
171if ((timers.wPeriodMin == 0) || (timers.wPeriodMin > SIM_IDLE_MAX))\r
172 return 0;\r
173if (timeBeginPeriod (timers.wPeriodMin) != TIMERR_NOERROR)\r
174 return 0;\r
175atexit (sim_timer_exit);\r
176Sleep (1);\r
177Sleep (1);\r
178Sleep (1);\r
179Sleep (1);\r
180Sleep (1);\r
181return timers.wPeriodMin; /* sim_idle_rate_ms */\r
182}\r
183\r
184uint32 sim_os_ms_sleep (unsigned int msec)\r
185{\r
186uint32 stime = sim_os_msec();\r
187\r
188Sleep (msec);\r
189return sim_os_msec () - stime;\r
190}\r
191\r
192/* OS/2 routines, from Bruce Ray */\r
193\r
194#elif defined (__OS2__)\r
195\r
196const t_bool rtc_avail = FALSE;\r
197\r
198uint32 sim_os_msec ()\r
199{\r
200return 0;\r
201}\r
202\r
203void sim_os_sleep (unsigned int sec)\r
204{\r
205return;\r
206}\r
207\r
208uint32 sim_os_ms_sleep_init (void)\r
209{\r
210return FALSE;\r
211}\r
212\r
213uint32 sim_os_ms_sleep (unsigned int msec)\r
214{\r
215return 0;\r
216}\r
217\r
218/* Metrowerks CodeWarrior Macintosh routines, from Ben Supnik */\r
219\r
220#elif defined (__MWERKS__) && defined (macintosh)\r
221\r
222#include <Timer.h>\r
223#include <Mactypes.h>\r
224#include <sioux.h>\r
225#include <unistd.h>\r
226#include <siouxglobals.h>\r
227#define NANOS_PER_MILLI 1000000\r
228#define MILLIS_PER_SEC 1000\r
229\r
230const t_bool rtc_avail = TRUE;\r
231\r
232uint32 sim_os_msec (void)\r
233{\r
234unsigned long long micros;\r
235UnsignedWide macMicros;\r
236unsigned long millis;\r
237\r
238Microseconds (&macMicros);\r
239micros = *((unsigned long long *) &macMicros);\r
240millis = micros / 1000LL;\r
241return (uint32) millis;\r
242}\r
243\r
244void sim_os_sleep (unsigned int sec)\r
245{\r
246sleep (sec);\r
247return;\r
248}\r
249\r
250uint32 sim_os_ms_sleep_init (void)\r
251{\r
252return 1;\r
253}\r
254\r
255uint32 sim_os_ms_sleep (unsigned int milliseconds)\r
256{\r
257uint32 stime = sim_os_msec ();\r
258struct timespec treq;\r
259\r
260treq.tv_sec = milliseconds / MILLIS_PER_SEC;\r
261treq.tv_nsec = (milliseconds % MILLIS_PER_SEC) * NANOS_PER_MILLI;\r
262(void) nanosleep (&treq, NULL);\r
263return sim_os_msec () - stime;\r
264}\r
265\r
266#else\r
267\r
268/* UNIX routines */\r
269\r
270#include <time.h>\r
271#include <sys/time.h>\r
272#include <unistd.h>\r
273#define NANOS_PER_MILLI 1000000\r
274#define MILLIS_PER_SEC 1000\r
275#define sleep1Samples 100\r
276\r
277const t_bool rtc_avail = TRUE;\r
278\r
279uint32 sim_os_msec ()\r
280{\r
281struct timeval cur;\r
282struct timezone foo;\r
283uint32 msec;\r
284\r
285gettimeofday (&cur, &foo);\r
286msec = (((uint32) cur.tv_sec) * 1000) + (((uint32) cur.tv_usec) / 1000);\r
287return msec;\r
288}\r
289\r
290void sim_os_sleep (unsigned int sec)\r
291{\r
292sleep (sec);\r
293return;\r
294}\r
295\r
296uint32 sim_os_ms_sleep_init (void)\r
297{\r
298#if defined (_POSIX_SOURCE) /* POSIX-compliant */\r
299\r
300struct timespec treq;\r
301uint32 msec;\r
302\r
303if (clock_getres (CLOCK_REALTIME, &treq) != 0)\r
304 return 0;\r
305msec = (treq.tv_nsec + (NANOS_PER_MILLI - 1)) / NANOS_PER_MILLI;\r
306if (msec > SIM_IDLE_MAX) return 0;\r
307return msec;\r
308\r
309#else /* others */\r
310\r
311uint32 i, t1, t2, tot, tim;\r
312\r
313for (i = 0, tot = 0; i < sleep1Samples; i++) {\r
314 t1 = sim_os_msec ();\r
315 sim_os_ms_sleep (1);\r
316 t2 = sim_os_msec ();\r
317 tot += (t2 - t1);\r
318 }\r
319tim = (tot + (sleep1Samples - 1)) / sleep1Samples;\r
320if (tim == 0) tim = 1;\r
321else if (tim > SIM_IDLE_MAX) tim = 0;\r
322return tim;\r
323\r
324#endif\r
325}\r
326\r
327uint32 sim_os_ms_sleep (unsigned int milliseconds)\r
328{\r
329uint32 stime = sim_os_msec ();\r
330struct timespec treq;\r
331\r
332treq.tv_sec = milliseconds / MILLIS_PER_SEC;\r
333treq.tv_nsec = (milliseconds % MILLIS_PER_SEC) * NANOS_PER_MILLI;\r
334(void) nanosleep (&treq, NULL);\r
335return sim_os_msec () - stime;\r
336}\r
337\r
338#endif\r
339\r
340/* OS independent clock calibration package */\r
341\r
342static int32 rtc_ticks[SIM_NTIMERS] = { 0 }; /* ticks */\r
343static int32 rtc_hz[SIM_NTIMERS] = { 0 }; /* tick rate */\r
344static uint32 rtc_rtime[SIM_NTIMERS] = { 0 }; /* real time */\r
345static uint32 rtc_vtime[SIM_NTIMERS] = { 0 }; /* virtual time */\r
346static uint32 rtc_nxintv[SIM_NTIMERS] = { 0 }; /* next interval */\r
347static int32 rtc_based[SIM_NTIMERS] = { 0 }; /* base delay */\r
348static int32 rtc_currd[SIM_NTIMERS] = { 0 }; /* current delay */\r
349static int32 rtc_initd[SIM_NTIMERS] = { 0 }; /* initial delay */\r
350\r
351void sim_rtcn_init_all (void)\r
352{\r
353uint32 i;\r
354\r
355for (i = 0; i < SIM_NTIMERS; i++) {\r
356 if (rtc_initd[i] != 0) sim_rtcn_init (rtc_initd[i], i);\r
357 }\r
358return;\r
359}\r
360\r
361int32 sim_rtcn_init (int32 time, int32 tmr)\r
362{\r
363if (time == 0) time = 1;\r
364if ((tmr < 0) || (tmr >= SIM_NTIMERS)) return time;\r
365rtc_rtime[tmr] = sim_os_msec ();\r
366rtc_vtime[tmr] = rtc_rtime[tmr];\r
367rtc_nxintv[tmr] = 1000;\r
368rtc_ticks[tmr] = 0;\r
369rtc_hz[tmr] = 0;\r
370rtc_based[tmr] = time;\r
371rtc_currd[tmr] = time;\r
372rtc_initd[tmr] = time;\r
373return time;\r
374}\r
375\r
376int32 sim_rtcn_calb (int32 ticksper, int32 tmr)\r
377{\r
378uint32 new_rtime, delta_rtime;\r
379int32 delta_vtime;\r
380\r
381if ((tmr < 0) || (tmr >= SIM_NTIMERS)) return 10000;\r
382rtc_hz[tmr] = ticksper;\r
383rtc_ticks[tmr] = rtc_ticks[tmr] + 1; /* count ticks */\r
384if (rtc_ticks[tmr] < ticksper) return rtc_currd[tmr]; /* 1 sec yet? */\r
385rtc_ticks[tmr] = 0; /* reset ticks */\r
386if (!rtc_avail) return rtc_currd[tmr]; /* no timer? */\r
387new_rtime = sim_os_msec (); /* wall time */\r
388if (new_rtime < rtc_rtime[tmr]) { /* time running backwards? */\r
389 rtc_rtime[tmr] = new_rtime; /* reset wall time */\r
390 return rtc_currd[tmr]; /* can't calibrate */\r
391 }\r
392delta_rtime = new_rtime - rtc_rtime[tmr]; /* elapsed wtime */\r
393rtc_rtime[tmr] = new_rtime; /* adv wall time */\r
394rtc_vtime[tmr] = rtc_vtime[tmr] + 1000; /* adv sim time */\r
395if (delta_rtime > 30000) /* gap too big? */\r
396 return rtc_initd[tmr]; /* can't calibr */\r
397if (delta_rtime == 0) /* gap too small? */\r
398 rtc_based[tmr] = rtc_based[tmr] * ticksper; /* slew wide */\r
399else rtc_based[tmr] = (int32) (((double) rtc_based[tmr] * (double) rtc_nxintv[tmr]) /\r
400 ((double) delta_rtime)); /* new base rate */\r
401delta_vtime = rtc_vtime[tmr] - rtc_rtime[tmr]; /* gap */\r
402if (delta_vtime > SIM_TMAX) delta_vtime = SIM_TMAX; /* limit gap */\r
403else if (delta_vtime < -SIM_TMAX) delta_vtime = -SIM_TMAX;\r
404rtc_nxintv[tmr] = 1000 + delta_vtime; /* next wtime */\r
405rtc_currd[tmr] = (int32) (((double) rtc_based[tmr] * (double) rtc_nxintv[tmr]) /\r
406 1000.0); /* next delay */\r
407if (rtc_based[tmr] <= 0) rtc_based[tmr] = 1; /* never negative or zero! */\r
408if (rtc_currd[tmr] <= 0) rtc_currd[tmr] = 1; /* never negative or zero! */\r
409return rtc_currd[tmr];\r
410}\r
411\r
412/* Prior interfaces - default to timer 0 */\r
413\r
414int32 sim_rtc_init (int32 time)\r
415{\r
416return sim_rtcn_init (time, 0);\r
417}\r
418\r
419int32 sim_rtc_calb (int32 ticksper)\r
420{\r
421return sim_rtcn_calb (ticksper, 0);\r
422}\r
423\r
424/* sim_timer_init - get minimum sleep time available on this host */\r
425\r
426t_bool sim_timer_init (void)\r
427{\r
428sim_idle_enab = FALSE; /* init idle off */\r
429sim_idle_rate_ms = sim_os_ms_sleep_init (); /* get OS timer rate */\r
430return (sim_idle_rate_ms != 0);\r
431}\r
432\r
433/* sim_idle - idle simulator until next event or for specified interval\r
434\r
435 Inputs:\r
436 tmr = calibrated timer to use\r
437\r
438 Must solve the linear equation\r
439\r
440 ms_to_wait = w * ms_per_wait\r
441\r
442 Or\r
443 w = ms_to_wait / ms_per_wait\r
444*/\r
445\r
446t_bool sim_idle (uint32 tmr, t_bool sin_cyc)\r
447{\r
448uint32 cyc_ms, w_ms, w_idle, act_ms;\r
449int32 act_cyc;\r
450\r
451if ((sim_clock_queue == NULL) || /* clock queue empty? */\r
452 ((sim_clock_queue->flags & UNIT_IDLE) == 0)) { /* event not idle-able? */\r
453 if (sin_cyc) sim_interval = sim_interval - 1;\r
454 return FALSE;\r
455 }\r
456cyc_ms = (rtc_currd[tmr] * rtc_hz[tmr]) / 1000; /* cycles per msec */\r
457if ((sim_idle_rate_ms == 0) || (cyc_ms == 0)) { /* not possible? */\r
458 if (sin_cyc) sim_interval = sim_interval - 1;\r
459 return FALSE;\r
460 }\r
461w_ms = (uint32) sim_interval / cyc_ms; /* ms to wait */\r
462w_idle = w_ms / sim_idle_rate_ms; /* intervals to wait */\r
463if (w_idle == 0) { /* none? */\r
464 if (sin_cyc) sim_interval = sim_interval - 1;\r
465 return FALSE;\r
466 }\r
467act_ms = sim_os_ms_sleep (w_idle); /* wait */\r
468act_cyc = act_ms * cyc_ms;\r
469if (sim_interval > act_cyc)\r
470 sim_interval = sim_interval - act_cyc;\r
471else sim_interval = 1;\r
472return TRUE;\r
473}\r
474\r
475/* Set idling - implicitly disables throttling */\r
476\r
477t_stat sim_set_idle (UNIT *uptr, int32 val, char *cptr, void *desc)\r
478{\r
479if (sim_idle_rate_ms == 0) return SCPE_NOFNC;\r
480if ((val != 0) && (sim_idle_rate_ms > (uint32) val))\r
481 return SCPE_NOFNC;\r
482sim_idle_enab = TRUE;\r
483if (sim_throt_type != SIM_THROT_NONE) {\r
484 sim_set_throt (0, NULL);\r
485 printf ("Throttling disabled\n");\r
486 if (sim_log) fprintf (sim_log, "Throttling disabled\n");\r
487 }\r
488return SCPE_OK;\r
489}\r
490\r
491/* Clear idling */\r
492\r
493t_stat sim_clr_idle (UNIT *uptr, int32 val, char *cptr, void *desc)\r
494{\r
495sim_idle_enab = FALSE;\r
496return SCPE_OK;\r
497}\r
498\r
499/* Show idling */\r
500\r
501t_stat sim_show_idle (FILE *st, UNIT *uptr, int32 val, void *desc)\r
502{\r
503fprintf (st, sim_idle_enab? "idle enabled": "idle disabled");\r
504return SCPE_OK;\r
505}\r
506\r
507/* Throttling package */\r
508\r
509t_stat sim_set_throt (int32 arg, char *cptr)\r
510{\r
511char *tptr, c;\r
512t_value val;\r
513\r
514if (arg == 0) {\r
515 if ((cptr != 0) && (*cptr != 0)) return SCPE_ARG;\r
516 sim_throt_type = SIM_THROT_NONE;\r
517 sim_throt_cancel ();\r
518 }\r
519else if (sim_idle_rate_ms == 0) return SCPE_NOFNC;\r
520else {\r
521 val = strtotv (cptr, &tptr, 10);\r
522 if (cptr == tptr) return SCPE_ARG;\r
523 c = toupper (*tptr++);\r
524 if (*tptr != 0) return SCPE_ARG;\r
525 if (c == 'M') sim_throt_type = SIM_THROT_MCYC;\r
526 else if (c == 'K') sim_throt_type = SIM_THROT_KCYC;\r
527 else if ((c == '%') && (val > 0) && (val < 100))\r
528 sim_throt_type = SIM_THROT_PCT;\r
529 else return SCPE_ARG;\r
530 if (sim_idle_enab) {\r
531 printf ("Idling disabled\n");\r
532 if (sim_log) fprintf (sim_log, "Idling disabled\n");\r
533 sim_clr_idle (NULL, 0, NULL, NULL);\r
534 }\r
535 sim_throt_val = (uint32) val;\r
536 }\r
537return SCPE_OK;\r
538}\r
539\r
540t_stat sim_show_throt (FILE *st, DEVICE *dnotused, UNIT *unotused, int32 flag, char *cptr)\r
541{\r
542if (sim_idle_rate_ms == 0)\r
543 fprintf (st, "Throttling not available\n");\r
544else {\r
545 switch (sim_throt_type) {\r
546\r
547 case SIM_THROT_MCYC:\r
548 fprintf (st, "Throttle = %d megacycles\n", sim_throt_val);\r
549 break;\r
550\r
551 case SIM_THROT_KCYC:\r
552 fprintf (st, "Throttle = %d kilocycles\n", sim_throt_val);\r
553 break;\r
554\r
555 case SIM_THROT_PCT:\r
556 fprintf (st, "Throttle = %d%%\n", sim_throt_val);\r
557 break;\r
558\r
559 default:\r
560 fprintf (st, "Throttling disabled\n");\r
561 break;\r
562 }\r
563\r
564 if (sim_switches & SWMASK ('D')) {\r
565 fprintf (st, "Wait rate = %d ms\n", sim_idle_rate_ms);\r
566 if (sim_throt_type != 0)\r
567 fprintf (st, "Throttle interval = %d cycles\n", sim_throt_wait);\r
568 }\r
569 }\r
570return SCPE_OK;\r
571}\r
572\r
573void sim_throt_sched (void)\r
574{\r
575sim_throt_state = 0;\r
576if (sim_throt_type)\r
577 sim_activate (&sim_throt_unit, SIM_THROT_WINIT);\r
578return;\r
579}\r
580\r
581void sim_throt_cancel (void)\r
582{\r
583sim_cancel (&sim_throt_unit);\r
584}\r
585\r
586/* Throttle service\r
587\r
588 Throttle service has three distinct states\r
589\r
590 0 take initial measurement\r
591 1 take final measurement, calculate wait values\r
592 2 periodic waits to slow down the CPU\r
593*/\r
594\r
595t_stat sim_throt_svc (UNIT *uptr)\r
596{\r
597uint32 delta_ms;\r
598double a_cps, d_cps;\r
599\r
600switch (sim_throt_state) {\r
601\r
602 case 0: /* take initial reading */\r
603 sim_throt_ms_start = sim_os_msec ();\r
604 sim_throt_wait = SIM_THROT_WST;\r
605 sim_throt_state++; /* next state */\r
606 break; /* reschedule */\r
607\r
608 case 1: /* take final reading */\r
609 sim_throt_ms_stop = sim_os_msec ();\r
610 delta_ms = sim_throt_ms_stop - sim_throt_ms_start;\r
611 if (delta_ms < SIM_THROT_MSMIN) { /* not enough time? */\r
612 if (sim_throt_wait >= 100000000) { /* too many inst? */\r
613 sim_throt_state = 0; /* fails in 32b! */\r
614 return SCPE_OK;\r
615 }\r
616 sim_throt_wait = sim_throt_wait * SIM_THROT_WMUL;\r
617 sim_throt_ms_start = sim_throt_ms_stop;\r
618 }\r
619 else { /* long enough */\r
620 a_cps = ((double) sim_throt_wait) * 1000.0 / (double) delta_ms;\r
621 if (sim_throt_type == SIM_THROT_MCYC) /* calc desired cps */\r
622 d_cps = (double) sim_throt_val * 1000000.0;\r
623 else if (sim_throt_type == SIM_THROT_KCYC)\r
624 d_cps = (double) sim_throt_val * 1000.0;\r
625 else d_cps = (a_cps * ((double) sim_throt_val)) / 100.0;\r
626 if (d_cps >= a_cps) {\r
627 sim_throt_state = 0;\r
628 return SCPE_OK;\r
629 }\r
630 sim_throt_wait = (int32) /* time between waits */\r
631 ((a_cps * d_cps * ((double) sim_idle_rate_ms)) /\r
632 (1000.0 * (a_cps - d_cps)));\r
633 if (sim_throt_wait < SIM_THROT_WMIN) { /* not long enough? */\r
634 sim_throt_state = 0;\r
635 return SCPE_OK;\r
636 }\r
637 sim_throt_state++;\r
638// fprintf (stderr, "Throttle values a_cps = %f, d_cps = %f, wait = %d\n",\r
639// a_cps, d_cps, sim_throt_wait);\r
640 }\r
641 break;\r
642\r
643 case 2: /* throttling */\r
644 sim_os_ms_sleep (1);\r
645 break;\r
646 }\r
647\r
648sim_activate (uptr, sim_throt_wait); /* reschedule */\r
649return SCPE_OK;\r
650}\r