This source file includes following definitions.
- _compute_minimum_sleep
- sim_idle_ms_sleep
- sim_os_set_thread_priority
- sim_os_set_thread_priority
- sim_os_msec
- sim_os_sleep
- sim_timer_exit
- sim_os_ms_sleep_init
- sim_os_ms_sleep
- sim_os_msec
- sim_os_sleep
- sim_os_ms_sleep_init
- sim_os_ms_sleep
- sim_timespec_diff
- sim_rtcn_init_all
- sim_rtcn_init
- sim_rtcn_init_unit
- sim_rtcn_calb
- sim_timer_init
- sim_show_timers
- sim_show_clock_queues
- sim_timer_clr_catchup
- sim_timer_set_catchup
- sim_timer_show_catchup
- sim_timer_tick_svc
- win32_usleep
- sim_usleep
- _timespec_to_double
- _double_to_timespec
- sim_timer_clock_tick_svc
- _rtcn_configure_calibrated_clock
- sim_timer_clock_reset
- sim_start_timer_services
- sim_stop_timer_services
- sim_timer_inst_per_sec
- sim_timer_activate
- sim_timer_activate_after
- sim_register_clock_unit_tmr
- _sim_coschedule_cancel
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53 #include "sim_defs.h"
54 #include <ctype.h>
55 #include <math.h>
56
57 #define SIM_INTERNAL_CLK (SIM_NTIMERS+(1<<30))
58 #define SIM_INTERNAL_UNIT sim_internal_timer_unit
59
60 #if defined(MIN)
61 # undef MIN
62 #endif
63 #define MIN(a,b) (((a) < (b)) ? (a) : (b))
64
65 #if defined(MAX)
66 # undef MAX
67 #endif
68 #define MAX(a,b) (((a) > (b)) ? (a) : (b))
69
70 uint32 sim_idle_ms_sleep (unsigned int msec);
71
72 static int32 sim_calb_tmr = -1;
73 static int32 sim_calb_tmr_last = -1;
74 static double sim_inst_per_sec_last = 0;
75
76 static uint32 sim_idle_rate_ms = 0;
77 static uint32 sim_os_sleep_min_ms = 0;
78 static uint32 sim_os_sleep_inc_ms = 0;
79 static uint32 sim_os_clock_resoluton_ms = 0;
80 static uint32 sim_os_tick_hz = 0;
81 static uint32 sim_idle_calib_pct = 0;
82 static UNIT *sim_clock_unit[SIM_NTIMERS+1] = {NULL};
83 UNIT * volatile sim_clock_cosched_queue[SIM_NTIMERS+1] = {NULL};
84 static int32 sim_cosched_interval[SIM_NTIMERS+1];
85 static t_bool sim_catchup_ticks = FALSE;
86
87 #define sleep1Samples 10
88
89 static uint32 _compute_minimum_sleep (void)
90 {
91 uint32 i, tot, tim;
92
93 sim_os_set_thread_priority (PRIORITY_ABOVE_NORMAL);
94 sim_idle_ms_sleep (1);
95 for (i = 0, tot = 0; i < sleep1Samples; i++)
96 tot += sim_idle_ms_sleep (1);
97 tim = tot / sleep1Samples;
98 sim_os_sleep_min_ms = tim;
99 sim_idle_ms_sleep (1);
100 for (i = 0, tot = 0; i < sleep1Samples; i++)
101 tot += sim_idle_ms_sleep (sim_os_sleep_min_ms + 1);
102 tim = tot / sleep1Samples;
103 sim_os_sleep_inc_ms = tim - sim_os_sleep_min_ms;
104 sim_os_set_thread_priority (PRIORITY_NORMAL);
105 return sim_os_sleep_min_ms;
106 }
107
108 uint32 sim_idle_ms_sleep (unsigned int msec)
109 {
110 return sim_os_ms_sleep (msec);
111 }
112
113 #if defined(_WIN32)
114
115
116
117
118 t_stat sim_os_set_thread_priority (int below_normal_above)
119 {
120 const static int val[3] = {THREAD_PRIORITY_BELOW_NORMAL, THREAD_PRIORITY_NORMAL, THREAD_PRIORITY_ABOVE_NORMAL};
121
122 if ((below_normal_above < -1) || (below_normal_above > 1))
123 return SCPE_ARG;
124 SetThreadPriority (GetCurrentThread(), val[1 + below_normal_above]);
125 return SCPE_OK;
126 }
127 #else
128
129 t_stat sim_os_set_thread_priority (int below_normal_above)
130 {
131 int sched_policy, min_prio, max_prio;
132 struct sched_param sched_priority;
133
134 # if !defined(__gnu_hurd__)
135 if ((below_normal_above < -1) || (below_normal_above > 1))
136 return SCPE_ARG;
137
138 pthread_getschedparam (pthread_self(), &sched_policy, &sched_priority);
139 # if !defined(__PASE__)
140 min_prio = sched_get_priority_min(sched_policy);
141 max_prio = sched_get_priority_max(sched_policy);
142 # else
143 min_prio = 1;
144 max_prio = 127;
145 # endif
146 switch (below_normal_above) {
147 case PRIORITY_BELOW_NORMAL:
148 sched_priority.sched_priority = min_prio;
149 break;
150 case PRIORITY_NORMAL:
151 sched_priority.sched_priority = (max_prio + min_prio) / 2;
152 break;
153 case PRIORITY_ABOVE_NORMAL:
154 sched_priority.sched_priority = max_prio;
155 break;
156 }
157 pthread_setschedparam (pthread_self(), sched_policy, &sched_priority);
158 # endif
159 return SCPE_OK;
160 }
161 #endif
162
163
164
165 #if defined (_WIN32)
166
167
168
169 const t_bool rtc_avail = TRUE;
170
171 uint32 sim_os_msec (void)
172 {
173 return timeGetTime ();
174 }
175
176 void sim_os_sleep (unsigned int sec)
177 {
178 Sleep (sec * 1000);
179 return;
180 }
181
182 void sim_timer_exit (void)
183 {
184 timeEndPeriod (sim_idle_rate_ms);
185 return;
186 }
187
188 uint32 sim_os_ms_sleep_init (void)
189 {
190 TIMECAPS timers;
191
192 if (timeGetDevCaps (&timers, sizeof (timers)) != TIMERR_NOERROR)
193 return 0;
194 if (timers.wPeriodMin == 0)
195 return 0;
196 if (timeBeginPeriod (timers.wPeriodMin) != TIMERR_NOERROR)
197 return 0;
198 atexit (sim_timer_exit);
199
200 return _compute_minimum_sleep ();
201 }
202
203 uint32 sim_os_ms_sleep (unsigned int msec)
204 {
205 uint32 stime = sim_os_msec();
206
207 Sleep (msec);
208 return sim_os_msec () - stime;
209 }
210
211 #else
212
213
214
215 # include <time.h>
216 # include <sys/time.h>
217 # include <signal.h>
218 # include <unistd.h>
219 # define NANOS_PER_MILLI 1000000
220 # define MILLIS_PER_SEC 1000
221
222 const t_bool rtc_avail = TRUE;
223
224 uint32 sim_os_msec (void)
225 {
226 struct timeval cur;
227 struct timezone foo;
228 int st1ret;
229 uint32 msec;
230
231 st1ret = gettimeofday (&cur, &foo);
232 if (st1ret != 0)
233 {
234 fprintf (stderr, "\rFATAL: gettimeofday failure! Aborting at %s[%s:%d]\r\n",
235 __func__, __FILE__, __LINE__);
236 # if defined(USE_BACKTRACE)
237 # if defined(SIGUSR2)
238 (void)raise(SIGUSR2);
239
240 # endif
241 # endif
242 abort();
243 }
244 msec = (((uint32) cur.tv_sec) * 1000UL) + (((uint32) cur.tv_usec) / 1000UL);
245 return msec;
246 }
247
248 void sim_os_sleep (unsigned int sec)
249 {
250 sleep (sec);
251 return;
252 }
253
254 uint32 sim_os_ms_sleep_init (void)
255 {
256 return _compute_minimum_sleep ();
257 }
258
259 uint32 sim_os_ms_sleep (unsigned int milliseconds)
260 {
261 uint32 stime = sim_os_msec ();
262 struct timespec treq;
263
264 treq.tv_sec = milliseconds / MILLIS_PER_SEC;
265 treq.tv_nsec = (milliseconds % MILLIS_PER_SEC) * NANOS_PER_MILLI;
266 (void) nanosleep (&treq, NULL);
267 return sim_os_msec () - stime;
268 }
269
270 #endif
271
272
273 void
274 sim_timespec_diff (struct timespec *diff, const struct timespec *min, struct timespec *sub)
275 {
276
277 *diff = *min;
278
279 while (sub->tv_nsec > diff->tv_nsec) {
280 --diff->tv_sec;
281 diff->tv_nsec += 1000000000L;
282 }
283 diff->tv_nsec -= sub->tv_nsec;
284 diff->tv_sec -= sub->tv_sec;
285
286 while (diff->tv_nsec > 1000000000L) {
287 ++diff->tv_sec;
288 diff->tv_nsec -= 1000000000L;
289 }
290 }
291
292
293
294 static double _timespec_to_double (struct timespec *time);
295 static void _double_to_timespec (struct timespec *time, double dtime);
296 static void _rtcn_configure_calibrated_clock (int32 newtmr);
297 static void _sim_coschedule_cancel(UNIT *uptr);
298
299
300
301 static int32 rtc_ticks[SIM_NTIMERS+1] = { 0 };
302 static uint32 rtc_hz[SIM_NTIMERS+1] = { 0 };
303 static uint32 rtc_rtime[SIM_NTIMERS+1] = { 0 };
304 static uint32 rtc_vtime[SIM_NTIMERS+1] = { 0 };
305 static double rtc_gtime[SIM_NTIMERS+1] = { 0 };
306 static uint32 rtc_nxintv[SIM_NTIMERS+1] = { 0 };
307 static int32 rtc_based[SIM_NTIMERS+1] = { 0 };
308 static int32 rtc_currd[SIM_NTIMERS+1] = { 0 };
309 static int32 rtc_initd[SIM_NTIMERS+1] = { 0 };
310 static uint32 rtc_elapsed[SIM_NTIMERS+1] = { 0 };
311 static uint32 rtc_calibrations[SIM_NTIMERS+1] = { 0 };
312 static double rtc_clock_skew_max[SIM_NTIMERS+1] = { 0 };
313 static double rtc_clock_start_gtime[SIM_NTIMERS+1] = { 0 };
314 static double rtc_clock_tick_size[SIM_NTIMERS+1] = { 0 };
315 static uint32 rtc_calib_initializations[SIM_NTIMERS+1] = { 0 };
316 static double rtc_calib_tick_time[SIM_NTIMERS+1] = { 0 };
317 static double rtc_calib_tick_time_tot[SIM_NTIMERS+1] = { 0 };
318 static uint32 rtc_calib_ticks_acked[SIM_NTIMERS+1] = { 0 };
319 static uint32 rtc_calib_ticks_acked_tot[SIM_NTIMERS+1] = { 0 };
320 static uint32 rtc_clock_ticks[SIM_NTIMERS+1] = { 0 };
321 static uint32 rtc_clock_ticks_tot[SIM_NTIMERS+1] = { 0 };
322 static double rtc_clock_catchup_base_time[SIM_NTIMERS+1] = { 0 };
323 static uint32 rtc_clock_catchup_ticks[SIM_NTIMERS+1] = { 0 };
324 static uint32 rtc_clock_catchup_ticks_tot[SIM_NTIMERS+1] = { 0 };
325 static t_bool rtc_clock_catchup_pending[SIM_NTIMERS+1] = { 0 };
326 static t_bool rtc_clock_catchup_eligible[SIM_NTIMERS+1] = { 0 };
327 static uint32 rtc_clock_time_idled[SIM_NTIMERS+1] = { 0 };
328 static uint32 rtc_clock_calib_skip_idle[SIM_NTIMERS+1] = { 0 };
329 static uint32 rtc_clock_calib_gap2big[SIM_NTIMERS+1] = { 0 };
330 static uint32 rtc_clock_calib_backwards[SIM_NTIMERS+1] = { 0 };
331
332 UNIT sim_timer_units[SIM_NTIMERS+1];
333
334 UNIT sim_internal_timer_unit;
335 UNIT sim_throttle_unit;
336
337 t_stat sim_timer_tick_svc (UNIT *uptr);
338
339 #define DBG_TRC 0x008
340 #define DBG_CAL 0x010
341 #define DBG_TIM 0x020
342 #define DBG_ACK 0x080
343 DEBTAB sim_timer_debug[] = {
344 {"TRACE", DBG_TRC, "Trace routine calls"},
345 {"IACK", DBG_ACK, "interrupt acknowledgement activities"},
346 {"CALIB", DBG_CAL, "Calibration activities"},
347 {"TIME", DBG_TIM, "Activation and scheduling activities"},
348 {0}
349 };
350
351
352 extern DEVICE sim_timer_dev;
353 extern DEVICE sim_throttle_dev;
354
355 void sim_rtcn_init_all (void)
356 {
357 int32 tmr;
358
359 for (tmr = 0; tmr <= SIM_NTIMERS; tmr++)
360 if (rtc_initd[tmr] != 0)
361 sim_rtcn_init (rtc_initd[tmr], tmr);
362 return;
363 }
364
365 int32 sim_rtcn_init (int32 time, int32 tmr)
366 {
367 return sim_rtcn_init_unit (NULL, time, tmr);
368 }
369
370 int32 sim_rtcn_init_unit (UNIT *uptr, int32 time, int32 tmr)
371 {
372 if (time == 0)
373 time = 1;
374 if (tmr == SIM_INTERNAL_CLK)
375 tmr = SIM_NTIMERS;
376 else {
377 if ((tmr < 0) || (tmr >= SIM_NTIMERS))
378 return time;
379 }
380
381
382
383
384
385 if (rtc_currd[tmr])
386 time = rtc_currd[tmr];
387 if (!uptr)
388 uptr = sim_clock_unit[tmr];
389 sim_debug (DBG_CAL, &sim_timer_dev, "_sim_rtcn_init_unit(unit=%s, time=%d, tmr=%d)\n", sim_uname(uptr), time, tmr);
390 if (uptr) {
391 if (!sim_clock_unit[tmr])
392 sim_register_clock_unit_tmr (uptr, tmr);
393 }
394 rtc_clock_start_gtime[tmr] = sim_gtime();
395 rtc_rtime[tmr] = sim_os_msec ();
396 rtc_vtime[tmr] = rtc_rtime[tmr];
397 rtc_nxintv[tmr] = 1000;
398 rtc_ticks[tmr] = 0;
399 rtc_hz[tmr] = 0;
400 rtc_based[tmr] = time;
401 rtc_currd[tmr] = time;
402 rtc_initd[tmr] = time;
403 rtc_elapsed[tmr] = 0;
404 rtc_calibrations[tmr] = 0;
405 rtc_clock_ticks_tot[tmr] += rtc_clock_ticks[tmr];
406 rtc_clock_ticks[tmr] = 0;
407 rtc_calib_tick_time_tot[tmr] += rtc_calib_tick_time[tmr];
408 rtc_calib_tick_time[tmr] = 0;
409 rtc_clock_catchup_pending[tmr] = FALSE;
410 rtc_clock_catchup_eligible[tmr] = FALSE;
411 rtc_clock_catchup_ticks_tot[tmr] += rtc_clock_catchup_ticks[tmr];
412 rtc_clock_catchup_ticks[tmr] = 0;
413 rtc_calib_ticks_acked_tot[tmr] += rtc_calib_ticks_acked[tmr];
414 rtc_calib_ticks_acked[tmr] = 0;
415 ++rtc_calib_initializations[tmr];
416 _rtcn_configure_calibrated_clock (tmr);
417 return time;
418 }
419
420 int32 sim_rtcn_calb (uint32 ticksper, int32 tmr)
421 {
422 if (tmr == SIM_INTERNAL_CLK)
423 tmr = SIM_NTIMERS;
424 else {
425 if ((tmr < 0) || (tmr >= SIM_NTIMERS))
426 return 10000;
427 }
428 if (rtc_hz[tmr] != ticksper) {
429 rtc_hz[tmr] = ticksper;
430 rtc_clock_tick_size[tmr] = 1.0/ticksper;
431 _rtcn_configure_calibrated_clock (tmr);
432 rtc_currd[tmr] = (int32)(sim_timer_inst_per_sec()/ticksper);
433 }
434 if (sim_clock_unit[tmr] == NULL) {
435 rtc_clock_ticks[tmr] += 1;
436 rtc_calib_tick_time[tmr] += rtc_clock_tick_size[tmr];
437 }
438 if (rtc_clock_catchup_pending[tmr]) {
439 ++rtc_clock_catchup_ticks[tmr];
440 rtc_clock_catchup_pending[tmr] = FALSE;
441 }
442 return rtc_currd[tmr];
443 }
444
445
446
447 t_bool sim_timer_init (void)
448 {
449 int tmr;
450 uint32 clock_start, clock_last, clock_now;
451
452 sim_debug (DBG_TRC, &sim_timer_dev, "sim_timer_init()\n");
453 for (tmr=0; tmr<=SIM_NTIMERS; tmr++) {
454 sim_timer_units[tmr].action = &sim_timer_tick_svc;
455 sim_timer_units[tmr].flags = UNIT_DIS | UNIT_IDLE;
456 }
457 SIM_INTERNAL_UNIT.flags = UNIT_DIS | UNIT_IDLE;
458 sim_register_internal_device (&sim_timer_dev);
459 sim_register_clock_unit_tmr (&SIM_INTERNAL_UNIT, SIM_INTERNAL_CLK);
460 sim_idle_rate_ms = sim_os_ms_sleep_init ();
461
462 clock_last = clock_start = sim_os_msec ();
463 sim_os_clock_resoluton_ms = 1000;
464 do {
465 uint32 clock_diff;
466
467 clock_now = sim_os_msec ();
468 clock_diff = clock_now - clock_last;
469 if ((clock_diff > 0) && (clock_diff < sim_os_clock_resoluton_ms))
470 sim_os_clock_resoluton_ms = clock_diff;
471 clock_last = clock_now;
472 } while (clock_now < clock_start + 100);
473 sim_os_tick_hz = 1000/(sim_os_clock_resoluton_ms * (sim_idle_rate_ms/sim_os_clock_resoluton_ms));
474 return (sim_idle_rate_ms != 0);
475 }
476
477
478 t_stat sim_show_timers (FILE* st, DEVICE *dptr, UNIT* uptr, int32 val, CONST char* desc)
479 {
480 int tmr, clocks;
481 struct timespec now;
482 time_t time_t_now;
483 int32 calb_tmr = (sim_calb_tmr == -1) ? sim_calb_tmr_last : sim_calb_tmr;
484
485 for (tmr=clocks=0; tmr<=SIM_NTIMERS; ++tmr) {
486 if (0 == rtc_initd[tmr])
487 continue;
488
489 if (sim_clock_unit[tmr]) {
490 ++clocks;
491 fprintf (st, "%s clock device is %s%s%s\n",
492 sim_name,
493 (tmr == SIM_NTIMERS) ? "Internal Calibrated Timer(" : "",
494 sim_uname(sim_clock_unit[tmr]),
495 (tmr == SIM_NTIMERS) ? ")" : "");
496 }
497
498 fprintf (st, "%s%sTimer %d:\n", "",
499 rtc_hz[tmr] ? "Calibrated " : "Uncalibrated ",
500 tmr);
501 if (rtc_hz[tmr]) {
502 fprintf (st, " Running at: %lu Hz\n",
503 (unsigned long)rtc_hz[tmr]);
504 fprintf (st, " Tick Size: %s\n",
505 sim_fmt_secs (rtc_clock_tick_size[tmr]));
506 fprintf (st, " Ticks in current second: %lu\n",
507 (unsigned long)rtc_ticks[tmr]);
508 }
509 fprintf (st, " Seconds Running: %lu (%s)\n",
510 (unsigned long)rtc_elapsed[tmr],
511 sim_fmt_secs ((double)rtc_elapsed[tmr]));
512 if (tmr == calb_tmr) {
513 fprintf (st, " Calibration Opportunities: %lu\n",
514 (unsigned long)rtc_calibrations[tmr]);
515 if (sim_idle_calib_pct)
516 fprintf (st, " Calib Skip Idle Thresh %%: %lu\n",
517 (unsigned long)sim_idle_calib_pct);
518 if (rtc_clock_calib_skip_idle[tmr])
519 fprintf (st, " Calibs Skip While Idle: %lu\n",
520 (unsigned long)rtc_clock_calib_skip_idle[tmr]);
521 if (rtc_clock_calib_backwards[tmr])
522 fprintf (st, " Calibs Skip Backwards: %lu\n",
523 (unsigned long)rtc_clock_calib_backwards[tmr]);
524 if (rtc_clock_calib_gap2big[tmr])
525 fprintf (st, " Calibs Skip Gap Too Big: %lu\n",
526 (unsigned long)rtc_clock_calib_gap2big[tmr]);
527 }
528 if (rtc_gtime[tmr])
529 fprintf (st, " Instruction Time: %.0f\n",
530 rtc_gtime[tmr]);
531 fprintf (st, " Current Insts Per Tick: %lu\n",
532 (unsigned long)rtc_currd[tmr]);
533 fprintf (st, " Initializations: %lu\n",
534 (unsigned long)rtc_calib_initializations[tmr]);
535 fprintf (st, " Total Ticks: %lu\n",
536 (unsigned long)rtc_clock_ticks_tot[tmr]+(unsigned long)rtc_clock_ticks[tmr]);
537 if (rtc_clock_skew_max[tmr] != 0.0)
538 fprintf (st, " Peak Clock Skew: %s%s\n",
539 sim_fmt_secs (fabs(rtc_clock_skew_max[tmr])),
540 (rtc_clock_skew_max[tmr] < 0) ? " fast" : " slow");
541 if (rtc_calib_ticks_acked[tmr])
542 fprintf (st, " Ticks Acked: %lu\n",
543 (unsigned long)rtc_calib_ticks_acked[tmr]);
544 if (rtc_calib_ticks_acked_tot[tmr]+rtc_calib_ticks_acked[tmr] != rtc_calib_ticks_acked[tmr])
545 fprintf (st, " Total Ticks Acked: %lu\n",
546 (unsigned long)rtc_calib_ticks_acked_tot[tmr]+(unsigned long)rtc_calib_ticks_acked[tmr]);
547 if (rtc_calib_tick_time[tmr])
548 fprintf (st, " Tick Time: %s\n",
549 sim_fmt_secs (rtc_calib_tick_time[tmr]));
550 if (rtc_calib_tick_time_tot[tmr]+rtc_calib_tick_time[tmr] != rtc_calib_tick_time[tmr])
551 fprintf (st, " Total Tick Time: %s\n",
552 sim_fmt_secs (rtc_calib_tick_time_tot[tmr]+rtc_calib_tick_time[tmr]));
553 if (rtc_clock_catchup_ticks[tmr])
554 fprintf (st, " Catchup Ticks Sched: %lu\n",
555 (unsigned long)rtc_clock_catchup_ticks[tmr]);
556 if (rtc_clock_catchup_ticks_tot[tmr]+rtc_clock_catchup_ticks[tmr] != rtc_clock_catchup_ticks[tmr])
557 fprintf (st, " Total Catchup Ticks Sched: %lu\n",
558 (unsigned long)rtc_clock_catchup_ticks_tot[tmr]+(unsigned long)rtc_clock_catchup_ticks[tmr]);
559 clock_gettime (CLOCK_REALTIME, &now);
560 time_t_now = (time_t)now.tv_sec;
561 fprintf (st, " Wall Clock Time Now: %8.8s.%03d\n", 11+ctime(&time_t_now), (int)(now.tv_nsec/1000000));
562 if (rtc_clock_catchup_eligible[tmr]) {
563 _double_to_timespec (&now, rtc_clock_catchup_base_time[tmr]+rtc_calib_tick_time[tmr]);
564 time_t_now = (time_t)now.tv_sec;
565 fprintf (st, " Catchup Tick Time: %8.8s.%03d\n", 11+ctime(&time_t_now), (int)(now.tv_nsec/1000000));
566 _double_to_timespec (&now, rtc_clock_catchup_base_time[tmr]);
567 time_t_now = (time_t)now.tv_sec;
568 fprintf (st, " Catchup Base Time: %8.8s.%03d\n", 11+ctime(&time_t_now), (int)(now.tv_nsec/1000000));
569 }
570 if (rtc_clock_time_idled[tmr])
571 fprintf (st, " Total Time Idled: %s\n", sim_fmt_secs (rtc_clock_time_idled[tmr]/1000.0));
572 }
573 if (clocks == 0)
574 fprintf (st, "%s clock device is not specified, co-scheduling is unavailable\n", sim_name);
575 return SCPE_OK;
576 }
577
578 t_stat sim_show_clock_queues (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
579 {
580 int tmr;
581
582 for (tmr=0; tmr<=SIM_NTIMERS; ++tmr) {
583 if (sim_clock_unit[tmr] == NULL)
584 continue;
585 if (sim_clock_cosched_queue[tmr] != QUEUE_LIST_END) {
586 int32 accum;
587
588 fprintf (st, "%s clock (%s) co-schedule event queue status\n",
589 sim_name, sim_uname(sim_clock_unit[tmr]));
590 accum = 0;
591 for (uptr = sim_clock_cosched_queue[tmr]; uptr != QUEUE_LIST_END; uptr = uptr->next) {
592 if ((dptr = find_dev_from_unit (uptr)) != NULL) {
593 fprintf (st, " %s", sim_dname (dptr));
594 if (dptr->numunits > 1)
595 fprintf (st, " unit %d", (int32) (uptr - dptr->units));
596 }
597 else
598 fprintf (st, " Unknown");
599 if (accum > 0)
600 fprintf (st, " after %d ticks", accum);
601 fprintf (st, "\n");
602 accum = accum + uptr->time;
603 }
604 }
605 }
606 return SCPE_OK;
607 }
608
609 REG sim_timer_reg[] = {
610 { NULL }
611 };
612
613
614
615 t_stat sim_timer_clr_catchup (UNIT *uptr, int32 val, CONST char *cptr, void *desc)
616 {
617 if (sim_catchup_ticks)
618 sim_catchup_ticks = FALSE;
619 return SCPE_OK;
620 }
621
622 t_stat sim_timer_set_catchup (UNIT *uptr, int32 val, CONST char *cptr, void *desc)
623 {
624 if (!sim_catchup_ticks)
625 sim_catchup_ticks = TRUE;
626 return SCPE_OK;
627 }
628
629 t_stat sim_timer_show_catchup (FILE *st, UNIT *uptr, int32 val, CONST void *desc)
630 {
631 fprintf (st, "Calibrated Ticks%s", sim_catchup_ticks ? " with Catchup Ticks" : "");
632 return SCPE_OK;
633 }
634
635 MTAB sim_timer_mod[] = {
636 { MTAB_VDV, MTAB_VDV, "CATCHUP", "CATCHUP", \
637 &sim_timer_set_catchup, &sim_timer_show_catchup, NULL, "Enables/Displays Clock Tick catchup mode" },
638 { MTAB_VDV, 0, NULL, "NOCATCHUP", \
639 &sim_timer_clr_catchup, NULL, NULL, "Disables Clock Tick catchup mode" },
640 { 0 },
641 };
642
643 static t_stat sim_timer_clock_reset (DEVICE *dptr);
644
645 DEVICE sim_timer_dev = {
646 "TIMER", sim_timer_units, sim_timer_reg, sim_timer_mod,
647 SIM_NTIMERS+1, 0, 0, 0, 0, 0,
648 NULL, NULL, &sim_timer_clock_reset, NULL, NULL, NULL,
649 NULL, DEV_DEBUG | DEV_NOSAVE, 0, sim_timer_debug};
650
651
652 t_stat sim_timer_tick_svc (UNIT *uptr)
653 {
654 int tmr = (int)(uptr-sim_timer_units);
655 t_stat stat;
656
657 rtc_clock_ticks[tmr] += 1;
658 rtc_calib_tick_time[tmr] += rtc_clock_tick_size[tmr];
659
660
661
662
663
664
665
666
667 if (sim_clock_unit[tmr]->action == NULL)
668 return SCPE_IERR;
669 stat = sim_clock_unit[tmr]->action (sim_clock_unit[tmr]);
670 --sim_cosched_interval[tmr];
671 if (stat == SCPE_OK) {
672 if (rtc_clock_catchup_eligible[tmr]) {
673 struct timespec now;
674 double skew;
675
676 clock_gettime(CLOCK_REALTIME, &now);
677 skew = (_timespec_to_double(&now) - (rtc_calib_tick_time[tmr]+rtc_clock_catchup_base_time[tmr]));
678
679 if (fabs(skew) > fabs(rtc_clock_skew_max[tmr]))
680 rtc_clock_skew_max[tmr] = skew;
681 }
682 while ((sim_clock_cosched_queue[tmr] != QUEUE_LIST_END) &&
683 (sim_cosched_interval[tmr] < sim_clock_cosched_queue[tmr]->time)) {
684 UNIT *cptr = sim_clock_cosched_queue[tmr];
685 sim_clock_cosched_queue[tmr] = cptr->next;
686 cptr->next = NULL;
687 cptr->cancel = NULL;
688 _sim_activate (cptr, 0);
689 }
690 if (sim_clock_cosched_queue[tmr] != QUEUE_LIST_END)
691 sim_cosched_interval[tmr] = sim_clock_cosched_queue[tmr]->time;
692 else
693 sim_cosched_interval[tmr] = 0;
694 }
695 sim_timer_activate_after (uptr, 1000000/rtc_hz[tmr]);
696 return stat;
697 }
698
699 #if !defined(__CYGWIN__) && \
700 ( defined(_WIN32) || defined(__MINGW32__) || defined(__MINGW64__) || \
701 defined(CROSS_MINGW32) || defined(CROSS_MINGW64) )
702 void win32_usleep(__int64 usec)
703 {
704 HANDLE timer;
705 LARGE_INTEGER ft;
706
707 ft.QuadPart = -(10*usec);
708
709 timer = CreateWaitableTimer(NULL, TRUE, NULL);
710 SetWaitableTimer(timer, &ft, 0, NULL, NULL, 0);
711 WaitForSingleObject(timer, INFINITE);
712 CloseHandle(timer);
713 }
714 #endif
715
716
717
718 int
719 sim_usleep(useconds_t tusleep)
720 {
721 #if ( !defined(__APPLE__) && !defined(__OpenBSD__) )
722 # if !defined(__CYGWIN__) && \
723 ( defined(_WIN32) || defined(__MINGW32__) || defined(__MINGW64__) || \
724 defined(CROSS_MINGW32) || defined(CROSS_MINGW64) )
725 win32_usleep(tusleep);
726
727 return 0;
728 # else
729 # if !defined(__PASE__)
730 struct timespec rqt;
731 rqt.tv_sec = tusleep / 1000000L;
732 rqt.tv_nsec = (tusleep % 1000000L) * 1000L;
733
734 return clock_nanosleep(CLOCK_MONOTONIC, 0, &rqt, NULL);
735 # else
736 return usleep(tusleep);
737 # endif
738 # endif
739
740
741 #else
742 # if defined(__APPLE__)
743 struct timespec rqt;
744 rqt.tv_sec = tusleep / 1000000L;
745 rqt.tv_nsec = (tusleep % 1000000L) * 1000L;
746 return nanosleep(&rqt, NULL);
747 # else
748 return usleep(tusleep);
749 # endif
750 #endif
751 }
752
753 static double _timespec_to_double (struct timespec *time)
754 {
755 return ((double)time->tv_sec)+(double)(time->tv_nsec)/1000000000.0;
756 }
757
758 static void _double_to_timespec (struct timespec *time, double dtime)
759 {
760 time->tv_sec = (time_t)floor(dtime);
761 time->tv_nsec = (long)((dtime-floor(dtime))*1000000000.0);
762 }
763
764 #define CLK_TPS 10
765 #define CLK_INIT (SIM_INITIAL_IPS/CLK_TPS)
766 static int32 sim_int_clk_tps;
767
768 static t_stat sim_timer_clock_tick_svc (UNIT *uptr)
769 {
770 sim_rtcn_calb (sim_int_clk_tps, SIM_INTERNAL_CLK);
771 sim_activate_after (uptr, 1000000/sim_int_clk_tps);
772 return SCPE_OK;
773 }
774
775 static void _rtcn_configure_calibrated_clock (int32 newtmr)
776 {
777 int32 tmr;
778
779
780 sim_int_clk_tps = MIN(CLK_TPS, sim_os_tick_hz);
781 for (tmr=0; tmr<SIM_NTIMERS; tmr++) {
782 if ((rtc_hz[tmr]) &&
783 (rtc_hz[tmr] <= (uint32)sim_os_tick_hz))
784 break;
785 }
786 if (tmr == SIM_NTIMERS) {
787 if ((tmr != newtmr) && (!sim_is_active (&SIM_INTERNAL_UNIT))) {
788
789 sim_calb_tmr = SIM_NTIMERS;
790 sim_debug (DBG_CAL, &sim_timer_dev,
791 "_rtcn_configure_calibrated_clock() - Starting Internal Calibrated Timer at %dHz\n",
792 sim_int_clk_tps);
793 SIM_INTERNAL_UNIT.action = &sim_timer_clock_tick_svc;
794 SIM_INTERNAL_UNIT.flags = UNIT_DIS | UNIT_IDLE;
795 sim_activate_abs (&SIM_INTERNAL_UNIT, 0);
796 sim_rtcn_init_unit (&SIM_INTERNAL_UNIT, (CLK_INIT*CLK_TPS)/sim_int_clk_tps, SIM_INTERNAL_CLK);
797 }
798 return;
799 }
800 if ((tmr == newtmr) &&
801 (sim_calb_tmr == newtmr))
802 return;
803 if (sim_calb_tmr == SIM_NTIMERS) {
804 sim_debug (DBG_CAL, &sim_timer_dev,
805 "_rtcn_configure_calibrated_clock() - Stopping Internal Calibrated Timer, New Timer = %d (%dHz)\n",
806 tmr, rtc_hz[tmr]);
807 rtc_initd[SIM_NTIMERS] = 0;
808 rtc_hz[SIM_NTIMERS] = 0;
809 sim_cancel (&SIM_INTERNAL_UNIT);
810
811 while (sim_clock_cosched_queue[SIM_NTIMERS] != QUEUE_LIST_END) {
812 UNIT *uptr = sim_clock_cosched_queue[SIM_NTIMERS];
813 _sim_coschedule_cancel (uptr);
814 _sim_activate (uptr, 1);
815 }
816 }
817 else {
818 sim_debug (DBG_CAL, &sim_timer_dev,
819 "_rtcn_configure_calibrated_clock() - Changing Calibrated Timer from %d (%dHz) to %d (%dHz)\n",
820 sim_calb_tmr, rtc_hz[sim_calb_tmr], tmr, rtc_hz[tmr]);
821 sim_calb_tmr = tmr;
822 }
823 sim_calb_tmr = tmr;
824 }
825
826 static t_stat sim_timer_clock_reset (DEVICE *dptr)
827 {
828 sim_debug (DBG_TRC, &sim_timer_dev, "sim_timer_clock_reset()\n");
829 _rtcn_configure_calibrated_clock (sim_calb_tmr);
830 if (sim_switches & SWMASK ('P')) {
831 sim_cancel (&SIM_INTERNAL_UNIT);
832 sim_calb_tmr = -1;
833 }
834 return SCPE_OK;
835 }
836
837 void sim_start_timer_services (void)
838 {
839 sim_debug (DBG_TRC, &sim_timer_dev, "sim_start_timer_services()\n");
840 _rtcn_configure_calibrated_clock (sim_calb_tmr);
841 }
842
843 void sim_stop_timer_services (void)
844 {
845 int tmr;
846
847 sim_debug (DBG_TRC, &sim_timer_dev, "sim_stop_timer_services()\n");
848
849 for (tmr=0; tmr<=SIM_NTIMERS; tmr++) {
850 int32 accum;
851
852 if (sim_clock_unit[tmr]) {
853
854 sim_cancel (&sim_timer_units[tmr]);
855 if (rtc_hz[tmr])
856 sim_activate (sim_clock_unit[tmr], rtc_currd[tmr]);
857
858 accum = 1;
859 while (sim_clock_cosched_queue[tmr] != QUEUE_LIST_END) {
860 UNIT *cptr = sim_clock_cosched_queue[tmr];
861
862 sim_clock_cosched_queue[tmr] = cptr->next;
863 cptr->next = NULL;
864 cptr->cancel = NULL;
865
866 accum += cptr->time;
867 _sim_activate (cptr, accum*rtc_currd[tmr]);
868 }
869 }
870 }
871 sim_cancel (&SIM_INTERNAL_UNIT);
872 sim_calb_tmr_last = sim_calb_tmr;
873 sim_inst_per_sec_last = sim_timer_inst_per_sec ();
874 sim_calb_tmr = -1;
875 }
876
877
878
879 double sim_timer_inst_per_sec (void)
880 {
881 double inst_per_sec = SIM_INITIAL_IPS;
882
883 if (sim_calb_tmr == -1)
884 return inst_per_sec;
885 inst_per_sec = ((double)rtc_currd[sim_calb_tmr])*rtc_hz[sim_calb_tmr];
886 if (0 == inst_per_sec)
887 inst_per_sec = ((double)rtc_currd[sim_calb_tmr])*sim_int_clk_tps;
888 return inst_per_sec;
889 }
890
891 t_stat sim_timer_activate (UNIT *uptr, int32 interval)
892 {
893 return sim_timer_activate_after (uptr, (uint32)((interval * 1000000.0) / sim_timer_inst_per_sec ()));
894 }
895
896 t_stat sim_timer_activate_after (UNIT *uptr, uint32 usec_delay)
897 {
898 int inst_delay, tmr;
899 double inst_delay_d, inst_per_sec;
900
901
902 for (tmr=0; tmr<=SIM_NTIMERS; tmr++)
903 if (sim_clock_unit[tmr] == uptr) {
904 uptr = &sim_timer_units[tmr];
905 break;
906 }
907 if (sim_is_active (uptr))
908 return SCPE_OK;
909 inst_per_sec = sim_timer_inst_per_sec ();
910 inst_delay_d = ((inst_per_sec*usec_delay)/1000000.0);
911
912
913 if (inst_delay_d > (double)0x7fffffff)
914 inst_delay_d = (double)0x7fffffff;
915 inst_delay = (int32)inst_delay_d;
916 if ((inst_delay == 0) && (usec_delay != 0))
917 inst_delay = 1;
918 sim_debug (DBG_TIM, &sim_timer_dev, "sim_timer_activate_after() - queue addition %s at %d (%d usecs)\n",
919 sim_uname(uptr), inst_delay, usec_delay);
920 return _sim_activate (uptr, inst_delay);
921 }
922
923 t_stat sim_register_clock_unit_tmr (UNIT *uptr, int32 tmr)
924 {
925 if (tmr == SIM_INTERNAL_CLK)
926 tmr = SIM_NTIMERS;
927 else {
928 if ((tmr < 0) || (tmr >= SIM_NTIMERS))
929 return SCPE_IERR;
930 }
931 if (NULL == uptr) {
932 while (sim_clock_cosched_queue[tmr] != QUEUE_LIST_END) {
933 UNIT *uptr = sim_clock_cosched_queue[tmr];
934
935 _sim_coschedule_cancel (uptr);
936 _sim_activate (uptr, 1);
937 }
938 sim_clock_unit[tmr] = NULL;
939 return SCPE_OK;
940 }
941 if (NULL == sim_clock_unit[tmr])
942 sim_clock_cosched_queue[tmr] = QUEUE_LIST_END;
943 sim_clock_unit[tmr] = uptr;
944 uptr->dynflags |= UNIT_TMR_UNIT;
945 sim_timer_units[tmr].flags = UNIT_DIS | (sim_clock_unit[tmr] ? UNIT_IDLE : 0);
946 return SCPE_OK;
947 }
948
949
950 static void _sim_coschedule_cancel (UNIT *uptr)
951 {
952 if (uptr->next) {
953 int tmr;
954
955 for (tmr=0; tmr<SIM_NTIMERS; tmr++) {
956 if (uptr == sim_clock_cosched_queue[tmr]) {
957 sim_clock_cosched_queue[tmr] = uptr->next;
958 uptr->next = NULL;
959 }
960 else {
961 UNIT *cptr;
962 for (cptr = sim_clock_cosched_queue[tmr];
963 (cptr != QUEUE_LIST_END);
964 cptr = cptr->next)
965 if (cptr->next == (uptr)) {
966 cptr->next = (uptr)->next;
967 uptr->next = NULL;
968 break;
969 }
970 }
971 if (uptr->next == NULL) {
972 uptr->cancel = NULL;
973 sim_debug (SIM_DBG_EVENT, &sim_timer_dev, "Canceled Clock Coscheduled Event for %s\n", sim_uname(uptr));
974 return;
975 }
976 }
977 }
978 }
979