From 0b6718d42952d1c80545b51ad88355600b9bdfe0 Mon Sep 17 00:00:00 2001 From: Richard Cornwell Date: Thu, 20 Jun 2019 07:38:21 -0400 Subject: [PATCH] SCP: Updated to current. --- scp.c | 9 ++- sim_timer.c | 229 +++++++++++++++++++++++++++++++--------------------- sim_timer.h | 4 +- 3 files changed, 146 insertions(+), 96 deletions(-) diff --git a/scp.c b/scp.c index 84b97ff..6552a5d 100644 --- a/scp.c +++ b/scp.c @@ -2619,6 +2619,10 @@ if (*argv[0]) { /* sim name arg? */ setenv ("SIM_BIN_PATH", argv[0], 1); } sim_argv = argv; + +if (sim_switches & SWMASK ('T')) /* Command Line -T switch */ + stat = sim_library_unit_tests (); /* run library unit tests */ + cptr = getenv("HOME"); if (cptr == NULL) { cptr = getenv("HOMEPATH"); @@ -2657,9 +2661,6 @@ else if (*argv[0]) { /* sim name arg? */ if (SCPE_BARE_STATUS(stat) == SCPE_OPENERR) /* didn't exist/can't open? */ stat = SCPE_OK; -if (sim_switches & SWMASK ('T')) /* Command Line -T switch */ - stat = sim_library_unit_tests (); /* run library unit tests */ - if (SCPE_BARE_STATUS(stat) != SCPE_EXIT) process_stdin_commands (SCPE_BARE_STATUS(stat), argv); @@ -6942,7 +6943,7 @@ else { uptr->fileref = sim_fopen (cptr, "wb+"); /* open new file */ if (uptr->fileref == NULL) /* open fail? */ return attach_err (uptr, SCPE_OPENERR); /* yes, error */ - sim_messagef (SCPE_OK, "%s: creating new file\n", sim_dname (dptr)); + sim_messagef (SCPE_OK, "%s: creating new file: %s\n", sim_dname (dptr), cptr); } else { /* normal */ uptr->fileref = sim_fopen (cptr, "rb+"); /* open r/w */ diff --git a/sim_timer.c b/sim_timer.c index 9648695..49e61d6 100644 --- a/sim_timer.c +++ b/sim_timer.c @@ -155,8 +155,9 @@ static int32 sim_calb_tmr = -1; /* the system calibrated tim static int32 sim_calb_tmr_last = -1; /* shadow value when at sim> prompt */ static double sim_inst_per_sec_last = 0; /* shadow value when at sim> prompt */ static uint32 sim_stop_time = 0; /* time when sim_stop_timer_services was called */ +double sim_time_at_sim_prompt = 0; /* time spent processing commands from sim> prompt */ -static uint32 sim_idle_rate_ms = 0; +static uint32 sim_idle_rate_ms = 0; /* Minimum Sleep time */ static uint32 sim_os_sleep_min_ms = 0; static uint32 sim_os_sleep_inc_ms = 0; static uint32 sim_os_clock_resoluton_ms = 0; @@ -182,10 +183,11 @@ static uint32 sim_throt_delay = 3; static int32 sim_int_clk_tps; typedef struct RTC { - UNIT *clock_unit; + UNIT *clock_unit; /* registered ticking clock unit */ + UNIT *timer_unit; /* points to related clock assist unit (sim_timer_units) */ UNIT *clock_cosched_queue; int32 cosched_interval; - int32 ticks; /* ticks */ + uint32 ticks; /* ticks */ uint32 hz; /* tick rate */ uint32 last_hz; /* prior tick rate */ uint32 rtime; /* real time (usecs) */ @@ -198,7 +200,6 @@ typedef struct RTC { uint32 elapsed; /* seconds since init */ uint32 calibrations; /* calibration count */ double clock_skew_max; /* asynchronous max skew */ - double clock_start_gtime; /* reference instruction time for clock */ double clock_tick_size; /* 1/hz */ uint32 calib_initializations; /* Initialization Count */ double calib_tick_time; /* ticks time */ @@ -750,7 +751,7 @@ while (diff->tv_nsec >= 1000000000) { static double _timespec_to_double (struct timespec *time); static void _double_to_timespec (struct timespec *time, double dtime); -static t_bool _rtcn_tick_catchup_check (int32 tmr, int32 time); +static t_bool _rtcn_tick_catchup_check (RTC *rtc, int32 time); static void _rtcn_configure_calibrated_clock (int32 newtmr); static t_bool _sim_coschedule_cancel (UNIT *uptr); static t_bool _sim_wallclock_cancel (UNIT *uptr); @@ -837,10 +838,11 @@ void sim_rtcn_init_all (void) int32 tmr; RTC *rtc; -for (tmr = 0; tmr <= SIM_NTIMERS; tmr++) +for (tmr = 0; tmr <= SIM_NTIMERS; tmr++) { rtc = &rtcs[tmr]; if (rtc->initd != 0) sim_rtcn_init (rtc->initd, tmr); + } } int32 sim_rtcn_init (int32 time, int32 tmr) @@ -880,7 +882,7 @@ if (uptr) { if (!rtc->clock_unit) sim_register_clock_unit_tmr (uptr, tmr); } -rtc->clock_start_gtime = sim_gtime(); +rtc->gtime = sim_gtime(); rtc->rtime = sim_is_running ? sim_os_msec () : sim_stop_time; rtc->vtime = rtc->rtime; rtc->nxintv = 1000; @@ -916,7 +918,7 @@ RTC *rtc = &rtcs[tmr]; return sim_rtcn_calb (rtc->hz, tmr); } -int32 sim_rtcn_calb (int32 ticksper, int32 tmr) +int32 sim_rtcn_calb (uint32 ticksper, int32 tmr) { uint32 new_rtime, delta_rtime, last_idle_pct, catchup_ticks_curr; int32 delta_vtime; @@ -945,8 +947,16 @@ if (rtc->hz != ticksper) { /* changing tick rate? */ rtc->hz = ticksper; _rtcn_configure_calibrated_clock (tmr); if (ticksper != 0) { + RTC *crtc = &rtcs[sim_calb_tmr]; + rtc->clock_tick_size = 1.0 / ticksper; sim_debug (DBG_CAL, &sim_timer_dev, "sim_rtcn_calb(ticksper=%d,tmr=%d) currd=%d, prior_hz=%d\n", ticksper, tmr, rtc->currd, (int)prior_hz); + + if ((tmr != sim_calb_tmr) && rtc->clock_unit && (ticksper > crtc->hz)) { + sim_catchup_ticks = TRUE; + sim_debug (DBG_CAL, &sim_timer_dev, "sim_rtcn_calb(%d) - forcing catchup ticks for %s ticking at %d, host tick rate %ds\n", tmr, sim_uname (rtc->clock_unit), ticksper, sim_os_tick_hz); + _rtcn_tick_catchup_check (rtc, 0); + } } else sim_debug (DBG_CAL, &sim_timer_dev, "sim_rtcn_calb(ticksper=%d,tmr=%d) timer stopped currd was %d, prior_hz=%d\n", ticksper, tmr, rtc->currd, (int)prior_hz); @@ -987,6 +997,7 @@ if (new_rtime < rtc->rtime) { /* time running backwards? * sim_debug (DBG_CAL, &sim_timer_dev, "time running backwards - OldTime: %u, NewTime: %u, result: %d\n", rtc->rtime, new_rtime, rtc->currd); rtc->vtime = rtc->rtime = new_rtime; /* reset wall time */ rtc->nxintv = 1000; + rtc->based = rtc->currd; if (rtc->clock_catchup_eligible) { rtc->clock_catchup_base_time = sim_timenow_double(); rtc->calib_tick_time = 0.0; @@ -1007,6 +1018,7 @@ if (delta_rtime > 30000) { /* gap too big? */ rtc->vtime = rtc->rtime; /* sync virtual and real time */ rtc->nxintv = 1000; /* reset next interval */ rtc->gtime = sim_gtime(); /* save instruction time */ + rtc->based = rtc->currd; if (rtc->clock_catchup_eligible) rtc->calib_tick_time += ((double)delta_rtime / 1000.0);/* advance tick time */ sim_debug (DBG_CAL, &sim_timer_dev, "gap too big: delta = %d - result: %d\n", delta_rtime, rtc->currd); @@ -1021,7 +1033,7 @@ if (tmr != SIM_NTIMERS) { rtc->rtime = new_rtime; /* save wall time */ rtc->vtime += 1000; /* adv sim time */ rtc->gtime = sim_gtime(); /* save instruction time */ - rtc->based = rtc->initd; + rtc->based = rtc->currd; ++rtc->clock_calib_skip_idle; sim_debug (DBG_CAL, &sim_timer_dev, "skipping calibration due to idling (%d%%) - result: %d\n", last_idle_pct, rtc->currd); return rtc->currd; /* avoid calibrating idle checks */ @@ -1033,8 +1045,9 @@ if ((last_idle_pct == 0) && (delta_rtime != 0)) { if ((sim_idle_rate_ms != 0) && (delta_rtime > 1)) sim_idle_cyc_sleep = (uint32)((new_gtime - rtc->gtime) / (delta_rtime / sim_idle_rate_ms)); } -if (sim_asynch_timer) { - /* An asynchronous clock, merely needs to divide the number of */ +if (sim_asynch_timer || (catchup_ticks_curr > 0)) { + /* An asynchronous clock or when catchup ticks have */ + /* occurred, we merely needs to divide the number of */ /* instructions actually executed by the clock rate. */ new_currd = (int32)((new_gtime - rtc->gtime)/ticksper); /* avoid excessive swings in the calibrated result */ @@ -1044,9 +1057,10 @@ if (sim_asynch_timer) { if (new_currd < rtc->currd/10) /* don't swing small too fast */ new_currd = rtc->currd/10; } - rtc->currd = new_currd; + rtc->based = rtc->currd = new_currd; rtc->gtime = new_gtime; /* save instruction time */ - sim_debug (DBG_CAL, &sim_timer_dev, "asynch calibration result: %d\n", rtc->currd); + sim_debug (DBG_CAL, &sim_timer_dev, "sim_rtcn_calb(%s tmr=%d, tickper=%d) catchups=%u, idle=%d%% result: %d\n", + sim_asynch_timer ? "asynch" : "catchup", tmr, ticksper, catchup_ticks_curr, last_idle_pct, rtc->currd); return rtc->currd; /* calibrated result */ } rtc->gtime = new_gtime; /* save instruction time */ @@ -1072,7 +1086,7 @@ if (rtc->based <= 0) /* never negative or zero! * rtc->based = 1; if (rtc->currd <= 0) /* never negative or zero! */ rtc->currd = 1; -sim_debug (DBG_CAL, &sim_timer_dev, "sim_rtcn_calb(calibrated tmr=%d, tickper=%d) (delta_rtime=%d, delta_vtime=%d, base=%d, nxintv=%u, catchups=%u, idle=%d%%, result: %d)\n", +sim_debug (DBG_CAL, &sim_timer_dev, "sim_rtcn_calb(tmr=%d, tickper=%d) (delta_rtime=%d, delta_vtime=%d, base=%d, nxintv=%u, catchups=%u, idle=%d%%, result: %d)\n", tmr, ticksper, (int)delta_rtime, (int)delta_vtime, rtc->based, rtc->nxintv, catchup_ticks_curr, last_idle_pct, rtc->currd); /* Adjust calibration for other timers which depend on this timer's calibration */ for (itmr=0; itmr<=SIM_NTIMERS; itmr++) { @@ -1092,7 +1106,7 @@ int32 sim_rtc_init (int32 time) return sim_rtcn_init (time, 0); } -int32 sim_rtc_calb (int32 ticksper) +int32 sim_rtc_calb (uint32 ticksper) { return sim_rtcn_calb (ticksper, 0); } @@ -1108,8 +1122,9 @@ sim_debug (DBG_TRC, &sim_timer_dev, "sim_timer_init()\n"); for (tmr=0; tmr<=SIM_NTIMERS; tmr++) { RTC *rtc = &rtcs[tmr]; - sim_timer_units[tmr].action = &sim_timer_tick_svc; - sim_timer_units[tmr].flags = UNIT_DIS | UNIT_IDLE; + rtc->timer_unit = &sim_timer_units[tmr]; + rtc->timer_unit->action = &sim_timer_tick_svc; + rtc->timer_unit->flags = UNIT_DIS | UNIT_IDLE; rtc->clock_cosched_queue = QUEUE_LIST_END; } sim_stop_unit.action = &sim_timer_stop_svc; @@ -1189,6 +1204,13 @@ else #if defined(SIM_ASYNCH_CLOCKS) fprintf (st, "Asynchronous Clocks: %s\n", sim_asynch_timer ? "Active" : "Available"); #endif +if (sim_time_at_sim_prompt != 0.0) { + double prompt_time = 0.0; + if (!sim_is_running) + prompt_time = ((double)(sim_os_msec () - sim_stop_time)) / 1000.0; + fprintf (st, "Time at sim> prompt: %s\n", sim_fmt_secs (sim_time_at_sim_prompt + prompt_time)); + } + fprintf (st, "\n"); for (tmr=clocks=0; tmr<=SIM_NTIMERS; ++tmr) { RTC *rtc = &rtcs[tmr]; @@ -1265,7 +1287,7 @@ for (tmr=clocks=0; tmr<=SIM_NTIMERS; ++tmr) { clock_gettime (CLOCK_REALTIME, &now); time_t_now = (time_t)now.tv_sec; fprintf (st, " Wall Clock Time Now: %8.8s.%03d\n", 11+ctime(&time_t_now), (int)(now.tv_nsec/1000000)); - if (rtc->clock_catchup_eligible) { + if (sim_catchup_ticks && rtc->clock_catchup_eligible) { _double_to_timespec (&now, rtc->clock_catchup_base_time+rtc->calib_tick_time); time_t_now = (time_t)now.tv_sec; fprintf (st, " Catchup Tick Time: %8.8s.%03d\n", 11+ctime(&time_t_now), (int)(now.tv_nsec/1000000)); @@ -1595,12 +1617,16 @@ RTC *rtc = &rtcs[tmr]; if (rtc->hz == 0) /* specified timer is not running? */ tmr = sim_calb_tmr; /* use calibrated timer instead */ rtc = &rtcs[tmr]; -if (rtc->clock_catchup_pending) { /* Catchup clock tick pending? */ +if (rtc->clock_catchup_pending) { /* Catchup clock tick pending due to ack? */ sim_debug (DBG_TIK, &sim_timer_dev, "sim_idle(tmr=%d, sin_cyc=%d) - accelerating pending catch-up tick before idling %s\n", tmr, sin_cyc, sim_uname (rtc->clock_unit)); sim_activate_abs (&sim_timer_units[tmr], 0); sim_interval -= sin_cyc; return FALSE; } +if (_rtcn_tick_catchup_check (rtc, -1)) { /* Check for slow clock tick? */ + sim_interval -= sin_cyc; + return FALSE; + } if ((!sim_idle_enab) || /* idling disabled */ ((sim_clock_queue == QUEUE_LIST_END) && /* or clock queue empty? */ (!sim_asynch_timer))|| /* and not asynch? */ @@ -1614,14 +1640,9 @@ if ((!sim_idle_enab) || /* idling disabled */ sim_interval -= sin_cyc; return FALSE; } -if (_rtcn_tick_catchup_check (tmr, -1)) { - sim_debug (DBG_TIK, &sim_timer_dev, "sim_idle(tmr=%d, sin_cyc=%d) - rescheduling catchup tick %d for %s\n", tmr, sin_cyc, 1 + rtc->ticks, sim_uname (rtc->clock_unit)); - sim_interval -= sin_cyc; - return FALSE; - } /* When a simulator is in an instruction path (or under other conditions - which would indicate idling), the countdown of sim_interval will not + which would indicate idling), the countdown of sim_interval may not be happening at a pace which is consistent with the rate it happens when not in the 'idle capable' state. The consequence of this is that the clock calibration may produce calibrated results which vary much @@ -1646,7 +1667,7 @@ sim_debug (DBG_TRC, &sim_timer_dev, "sim_idle(tmr=%d, sin_cyc=%d)\n", tmr, sin_c if (sim_idle_cyc_ms == 0) { sim_idle_cyc_ms = (rtc->currd * rtc->hz) / 1000;/* cycles per msec */ if (sim_idle_rate_ms != 0) - sim_idle_cyc_sleep = (rtc->currd * rtc->hz) / (1000 / sim_idle_rate_ms);/* cycles per sleep */ + sim_idle_cyc_sleep = (rtc->currd * rtc->hz) / (1000 / sim_idle_rate_ms);/* cycles per minimum sleep */ } if ((sim_idle_rate_ms == 0) || (sim_idle_cyc_ms == 0)) {/* not possible? */ sim_interval -= sin_cyc; @@ -1660,19 +1681,18 @@ w_ms = (uint32) sim_interval / sim_idle_cyc_ms; /* ms to wait */ /* the simulator acknowledges the processing of clock ticks, then catchup */ /* ticks can be used to make up for missed ticks. */ if (rtc->clock_catchup_eligible) - w_idle = (sim_interval * 1000) / rtc->currd; /* 1000 * pending fraction of tick */ + w_idle = (sim_interval * 1000) / rtc->currd; /* 1000 * pending fraction of tick */ else w_idle = (w_ms * 1000) / sim_idle_rate_ms; /* 1000 * intervals to wait */ -if (w_idle < 500) { /* shorter than 1/2 the interval? */ - sim_interval -= sin_cyc; +if ((w_idle < 500) || (w_ms == 0)) { /* shorter than 1/2 the interval or */ + sim_interval -= sin_cyc; /* minimal sleep time? */ if (!in_nowait) sim_debug (DBG_IDL, &sim_timer_dev, "no wait, too short: %d usecs\n", w_idle); in_nowait = TRUE; return FALSE; } -if (w_ms > 1000) { /* too long a wait */ +if (w_ms > 1000) /* too long a wait (runaway calibration) */ sim_debug (DBG_TIK, &sim_timer_dev, "waiting too long: w_ms=%d usecs, w_idle=%d usecs, sim_interval=%d, rtc->currd=%d\n", w_ms, w_idle, sim_interval, rtc->currd); - } in_nowait = FALSE; if (sim_clock_queue == QUEUE_LIST_END) sim_debug (DBG_IDL, &sim_timer_dev, "sleeping for %d ms - pending event in %d instructions\n", w_ms, sim_interval); @@ -1991,6 +2011,7 @@ switch (sim_throt_state) { /* Run through all timers and adjust the calibration for each */ /* one that is running to reflect the throttle rate */ for (tmr=0; tmr<=SIM_NTIMERS; tmr++) { + rtc = &rtcs[tmr]; if (rtc->hz) { /* running? */ rtc->currd = (int32)(sim_throt_cps / rtc->hz);/* use throttle calibration */ rtc->ticks = rtc->hz - 1; /* force clock calibration on next tick */ @@ -2185,21 +2206,40 @@ clock_gettime (CLOCK_REALTIME, now); /* _rtcn_tick_catchup_check - idle simulator until next event or for specified interval Inputs: - tmr = calibrated timer to check/schedule + RTC = calibrated timer to check/schedule time = instruction delay for next tick Returns TRUE if a catchup tick has been scheduled */ -static t_bool _rtcn_tick_catchup_check (int32 tmr, int32 time) +static t_bool _rtcn_tick_catchup_check (RTC *rtc, int32 time) { -RTC *rtc; +int32 tmr; +t_bool bReturn = FALSE; -if ((!sim_catchup_ticks) || - ((tmr < 0) || (tmr >= SIM_NTIMERS))) +if (!sim_catchup_ticks) return FALSE; -rtc = &rtcs[tmr]; -if ((!rtc->clock_catchup_eligible) && /* not eligible yet? */ +if (time == -1) { + for (tmr=0; tmr<=SIM_NTIMERS; tmr++) { + rtc = &rtcs[tmr]; + if ((rtc->hz > 0) && rtc->clock_catchup_eligible) + { + double tnow = sim_timenow_double(); + + if (tnow > (rtc->clock_catchup_base_time + (rtc->calib_tick_time + rtc->clock_tick_size))) { + if (!rtc->clock_catchup_pending) { + sim_debug (DBG_TIK, &sim_timer_dev, "_rtcn_tick_catchup_check(%d) - scheduling catchup tick %d for %s which is behind %s\n", time, 1 + rtc->ticks, sim_uname (rtc->clock_unit), sim_fmt_secs (tnow - (rtc->clock_catchup_base_time + (rtc->calib_tick_time + rtc->clock_tick_size)))); + rtc->clock_catchup_pending = TRUE; + sim_activate_abs (rtc->timer_unit, 0); + bReturn = TRUE; + } + else + sim_debug (DBG_TIK, &sim_timer_dev, "_rtcn_tick_catchup_check(%d) - already pending catchup tick %d for %s which is behind %s\n", time, 1 + rtc->ticks, sim_uname (rtc->clock_unit), sim_fmt_secs (tnow - (rtc->clock_catchup_base_time + (rtc->calib_tick_time + rtc->clock_tick_size)))); + } + } + } + } +if ((!rtc->clock_catchup_eligible) && /* not eligible yet? */ (time != -1)) { /* called from ack? */ rtc->clock_catchup_base_time = sim_timenow_double(); rtc->clock_ticks_tot += rtc->clock_ticks; @@ -2212,7 +2252,7 @@ if ((!rtc->clock_catchup_eligible) && /* not eligible yet? */ rtc->calib_ticks_acked = 0; rtc->clock_catchup_eligible = TRUE; sim_debug (DBG_QUE, &sim_timer_dev, "_rtcn_tick_catchup_check() - Enabling catchup ticks for %s\n", sim_uname (rtc->clock_unit)); - return TRUE; + bReturn = TRUE; } if ((rtc->hz > 0) && rtc->clock_catchup_eligible) @@ -2223,25 +2263,25 @@ if ((rtc->hz > 0) && if (!rtc->clock_catchup_pending) { sim_debug (DBG_TIK, &sim_timer_dev, "_rtcn_tick_catchup_check(%d) - scheduling catchup tick %d for %s which is behind %s\n", time, 1 + rtc->ticks, sim_uname (rtc->clock_unit), sim_fmt_secs (tnow - (rtc->clock_catchup_base_time + (rtc->calib_tick_time + rtc->clock_tick_size)))); rtc->clock_catchup_pending = TRUE; - sim_activate_abs (&sim_timer_units[tmr], (time < 0) ? 0 : time); + sim_activate_abs (rtc->timer_unit, (time < 0) ? 0 : time); } else sim_debug (DBG_TIK, &sim_timer_dev, "_rtcn_tick_catchup_check(%d) - already pending catchup tick %d for %s which is behind %s\n", time, 1 + rtc->ticks, sim_uname (rtc->clock_unit), sim_fmt_secs (tnow - (rtc->clock_catchup_base_time + (rtc->calib_tick_time + rtc->clock_tick_size)))); return TRUE; } } -return FALSE; +return bReturn; } t_stat sim_rtcn_tick_ack (uint32 time, int32 tmr) { RTC *rtc; -if ((tmr < 0) || (tmr >= SIM_NTIMERS)) +if ((tmr < 0) || (tmr > SIM_NTIMERS)) return SCPE_TIMER; rtc = &rtcs[tmr]; sim_debug (DBG_ACK, &sim_timer_dev, "sim_rtcn_tick_ack - for %s\n", sim_uname (rtc->clock_unit)); -_rtcn_tick_catchup_check (tmr, (int32)time); +_rtcn_tick_catchup_check (rtc, (int32)time); ++rtc->calib_ticks_acked; return SCPE_OK; } @@ -2423,29 +2463,30 @@ for (tmr=0; tmrhz)) { /* now stopped? */ - sim_debug (DBG_CAL, &sim_timer_dev, "_rtcn_configure_calibrated_clock(newtmr=%d) - Cleaning up stopped timer %s support\n", newtmr, sim_uname(crtc->clock_unit)); - /* Migrate any coscheduled devices to the standard queue */ - /* with appropriate usecs_remaining reflecting their currently */ - /* scheduled firing time. sim_process_event() will coschedule */ - /* appropriately. */ - /* temporarily restore prior hz to get correct remaining time */ - crtc->hz = crtc->last_hz; - while (crtc->clock_cosched_queue != QUEUE_LIST_END) { - UNIT *uptr = crtc->clock_cosched_queue; - double usecs_remaining = sim_timer_activate_time_usecs (uptr) - 1; + (sim_calb_tmr != -1)) { /* previously active? */ + crtc = &rtcs[sim_calb_tmr]; + if (!crtc->hz) { /* now stopped? */ + sim_debug (DBG_CAL, &sim_timer_dev, "_rtcn_configure_calibrated_clock(newtmr=%d) - Cleaning up stopped timer %s support\n", newtmr, sim_uname(crtc->clock_unit)); + /* Migrate any coscheduled devices to the standard queue */ + /* with appropriate usecs_remaining reflecting their currently */ + /* scheduled firing time. sim_process_event() will coschedule */ + /* appropriately. */ + /* temporarily restore prior hz to get correct remaining time */ + crtc->hz = crtc->last_hz; + while (crtc->clock_cosched_queue != QUEUE_LIST_END) { + UNIT *uptr = crtc->clock_cosched_queue; + double usecs_remaining = sim_timer_activate_time_usecs (uptr) - 1; - _sim_coschedule_cancel (uptr); - _sim_activate (uptr, 1); - uptr->usecs_remaining = usecs_remaining; + _sim_coschedule_cancel (uptr); + _sim_activate (uptr, 1); + uptr->usecs_remaining = usecs_remaining; + } + crtc->hz = 0; /* back to 0 */ + if (crtc->clock_unit) + sim_cancel (crtc->clock_unit); + sim_cancel (crtc->timer_unit); } - crtc->hz = 0; /* back to 0 */ - if (crtc->clock_unit) - sim_cancel (crtc->clock_unit); - sim_cancel (&sim_timer_units[sim_calb_tmr]); } /* Start the internal timer */ sim_calb_tmr = SIM_NTIMERS; @@ -2470,26 +2511,27 @@ if (sim_calb_tmr == SIM_NTIMERS) { /* was old the internal timer? */ sim_cancel (&sim_timer_units[SIM_NTIMERS]); } else { - rtc = &rtcs[sim_calb_tmr]; - if ((sim_calb_tmr != -1) && - (rtc->hz == 0)) { - /* Migrate any coscheduled devices to the standard queue */ - /* with appropriate usecs_remaining reflecting their currently */ - /* scheduled firing time. sim_process_event() will coschedule */ - /* appropriately. */ - /* temporarily restore prior hz to get correct remaining time */ - rtc->hz = rtc->last_hz; - while (rtc->clock_cosched_queue != QUEUE_LIST_END) { - UNIT *uptr = rtc->clock_cosched_queue; - double usecs_remaining = sim_timer_activate_time_usecs (uptr) - 1; + if (sim_calb_tmr != -1) { + crtc = &rtcs[sim_calb_tmr]; + if (crtc->hz == 0) { + /* Migrate any coscheduled devices to the standard queue */ + /* with appropriate usecs_remaining reflecting their currently */ + /* scheduled firing time. sim_process_event() will coschedule */ + /* appropriately. */ + /* temporarily restore prior hz to get correct remaining time */ + crtc->hz = crtc->last_hz; + while (crtc->clock_cosched_queue != QUEUE_LIST_END) { + UNIT *uptr = crtc->clock_cosched_queue; + double usecs_remaining = sim_timer_activate_time_usecs (uptr) - 1; - _sim_coschedule_cancel (uptr); - _sim_activate (uptr, 1); - uptr->usecs_remaining = usecs_remaining; + _sim_coschedule_cancel (uptr); + _sim_activate (uptr, 1); + uptr->usecs_remaining = usecs_remaining; + } + crtc->hz = 0; /* back to 0 */ } - rtc->hz = 0; /* back to 0 */ } - sim_debug (DBG_CAL|DBG_INT, &sim_timer_dev, "_rtcn_configure_calibrated_clock(newtmr=%d) - Changing Calibrated Timer from %d (%dHz) to %d (%dHz)\n", newtmr, sim_calb_tmr, rtc->hz, tmr, rtc->hz); + sim_debug (DBG_CAL|DBG_INT, &sim_timer_dev, "_rtcn_configure_calibrated_clock(newtmr=%d) - Changing Calibrated Timer from %d (%dHz) to %d (%dHz)\n", newtmr, sim_calb_tmr, crtc->hz, tmr, crtc->hz); sim_calb_tmr = tmr; } sim_calb_tmr = tmr; @@ -2514,18 +2556,24 @@ void sim_start_timer_services (void) { int32 tmr; uint32 sim_prompt_time = sim_os_msec () - sim_stop_time; +int32 registered_units = 0; +sim_time_at_sim_prompt += (((double)sim_prompt_time) / 1000.0); for (tmr=0; tmr<=SIM_NTIMERS; tmr++) { RTC *rtc = &rtcs[tmr]; - if (rtc->hz) { /* calibrated clock running? */ + if (rtc->initd) { /* calibrated clock initialized? */ rtc->rtime += sim_prompt_time; rtc->vtime += sim_prompt_time; sim_debug (DBG_CAL, &sim_timer_dev, "sim_start_timer_services(tmr=%d) - adjusting calibration real time by %d ms\n", tmr, (int)sim_prompt_time); if (rtc->clock_catchup_eligible) rtc->calib_tick_time += (((double)sim_prompt_time) / 1000.0); + if (rtc->clock_unit) + ++registered_units; } } +if (registered_units == 1) + sim_catchup_ticks = FALSE; if (sim_calb_tmr == -1) { sim_debug (DBG_CAL, &sim_timer_dev, "sim_start_timer_services() - starting from scratch\n"); _rtcn_configure_calibrated_clock (sim_calb_tmr); @@ -2570,11 +2618,11 @@ for (tmr=0; tmr<=SIM_NTIMERS; tmr++) { RTC *rtc = &rtcs[tmr]; if (rtc->clock_unit) { - int32 clock_time = _sim_activate_time (&sim_timer_units[tmr]); + int32 clock_time = _sim_activate_time (rtc->timer_unit); /* Stop clock assist unit and make sure the clock unit has a tick queued */ - if (sim_is_active (&sim_timer_units[tmr])) { - sim_cancel (&sim_timer_units[tmr]); + if (sim_is_active (rtc->timer_unit)) { + sim_cancel (rtc->timer_unit); sim_debug (DBG_QUE, &sim_timer_dev, "sim_stop_timer_services() - tmr=%d scheduling %s after %d\n", tmr, sim_uname (rtc->clock_unit), clock_time); _sim_activate (rtc->clock_unit, clock_time); } @@ -2687,7 +2735,7 @@ for (tmr=0; tmr<=SIM_NTIMERS; tmr++) { RTC *rtc = &rtcs[tmr]; if (rtc->clock_unit == uptr) { - uptr = &sim_timer_units[tmr]; + uptr = rtc->timer_unit; break; } } @@ -2721,13 +2769,13 @@ if (uptr->usecs_remaining != 0.0) /* No calibrated timer yet, wait one cycle * inst_delay_d = inst_delay = 1; /* Minimum non-zero delay is 1 instruction */ crtc = &rtcs[sim_calb_tmr]; if ((sim_calb_tmr != -1) && (crtc->hz)) { /* Calibrated Timer available? */ - int32 inst_til_tick = sim_activate_time (&sim_timer_units[sim_calb_tmr]) - 1; + int32 inst_til_tick = sim_activate_time (crtc->timer_unit) - 1; int32 ticks_til_calib = crtc->hz - crtc->ticks; double usecs_per_tick = floor (1000000.0 / crtc->hz); int32 inst_til_calib = inst_til_tick + ((ticks_til_calib - 1) * crtc->currd); uint32 usecs_til_calib = (uint32)ceil(inst_til_calib / inst_per_usec); - if ((uptr != &sim_timer_units[sim_calb_tmr]) && /* Not scheduling calibrated timer */ + if ((uptr != crtc->timer_unit) && /* Not scheduling calibrated timer */ (inst_til_tick > 0)) { /* and tick not pending? */ if (inst_delay_d > (double)inst_til_calib) { /* long wait? */ stat = sim_clock_coschedule_tmr (uptr, sim_calb_tmr, ticks_til_calib - 1); @@ -2855,15 +2903,15 @@ if (NULL == uptr) { /* deregistering? */ rtc->clock_unit->dynflags &= ~UNIT_TMR_UNIT; } rtc->clock_unit = NULL; - sim_cancel (&sim_timer_units[tmr]); + sim_cancel (rtc->timer_unit); return SCPE_OK; } if (NULL == rtc->clock_unit) rtc->clock_cosched_queue = QUEUE_LIST_END; rtc->clock_unit = uptr; uptr->dynflags |= UNIT_TMR_UNIT; -sim_timer_units[tmr].flags = ((tmr == SIM_NTIMERS) ? 0 : UNIT_DIS) | - (rtc->clock_unit ? UNIT_IDLE : 0); +rtc->timer_unit->flags = ((tmr == SIM_NTIMERS) ? 0 : UNIT_DIS) | + (rtc->clock_unit ? UNIT_IDLE : 0); return SCPE_OK; } @@ -3391,4 +3439,5 @@ for (tmr=0; tmr<=SIM_NTIMERS; tmr++) { rtc->calib_initializations = 1; } sim_inst_per_sec_last = sim_precalibrate_ips; +sim_idle_stable = 0; } diff --git a/sim_timer.h b/sim_timer.h index 6793496..5ea2591 100644 --- a/sim_timer.h +++ b/sim_timer.h @@ -112,10 +112,10 @@ int32 sim_rtcn_init_unit_ticks (UNIT *uptr, int32 time, int32 tmr, int32 tickspe void sim_rtcn_get_time (struct timespec *now, int tmr); t_stat sim_rtcn_tick_ack (uint32 time, int32 tmr); void sim_rtcn_init_all (void); -int32 sim_rtcn_calb (int32 ticksper, int32 tmr); +int32 sim_rtcn_calb (uint32 ticksper, int32 tmr); int32 sim_rtcn_calb_tick (int32 tmr); int32 sim_rtc_init (int32 time); -int32 sim_rtc_calb (int32 ticksper); +int32 sim_rtc_calb (uint32 ticksper); t_stat sim_set_timers (int32 arg, CONST char *cptr); t_stat sim_show_timers (FILE* st, DEVICE *dptr, UNIT* uptr, int32 val, CONST char* desc); t_stat sim_show_clock_queues (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);