TIMER: Stabilize timer behaviors

- Fix incomplete migration to RTC structures indicated by Coverity
  warnings.  Some Coverity were minor warnings and not real issues.
- Add calibration recovery parameters for idle and catchup ticks
- Aggressively perform catchup ticks when in simulated idle paths
  even when idling is disabled.
- All non internal clocks can have catch-up ticks triggered if they
  register a tick unit.
- Catch-up ticks will be delivered to non tick acking simulators when
  idling if regstered tick unit has been specified.
- Hosts with slow ticks can idle and keep sloppy OK time when
  simulators have faster ticks
- Default to active calibration (ALWAYS) while idling (no skipping)
This commit is contained in:
Mark Pizzolato 2019-06-18 08:01:45 -07:00
parent 5d747cc992
commit b3fa1f9fe8
2 changed files with 110 additions and 68 deletions

View file

@ -157,7 +157,7 @@ static double sim_inst_per_sec_last = 0; /* shadow value when at sim>
static uint32 sim_stop_time = 0; /* time when sim_stop_timer_services was called */ 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 */ 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_min_ms = 0;
static uint32 sim_os_sleep_inc_ms = 0; static uint32 sim_os_sleep_inc_ms = 0;
static uint32 sim_os_clock_resoluton_ms = 0; static uint32 sim_os_clock_resoluton_ms = 0;
@ -187,7 +187,7 @@ typedef struct RTC {
UNIT *timer_unit; /* points to related clock assist unit (sim_timer_units) */ UNIT *timer_unit; /* points to related clock assist unit (sim_timer_units) */
UNIT *clock_cosched_queue; UNIT *clock_cosched_queue;
int32 cosched_interval; int32 cosched_interval;
int32 ticks; /* ticks */ uint32 ticks; /* ticks */
uint32 hz; /* tick rate */ uint32 hz; /* tick rate */
uint32 last_hz; /* prior tick rate */ uint32 last_hz; /* prior tick rate */
uint32 rtime; /* real time (usecs) */ uint32 rtime; /* real time (usecs) */
@ -200,7 +200,6 @@ typedef struct RTC {
uint32 elapsed; /* seconds since init */ uint32 elapsed; /* seconds since init */
uint32 calibrations; /* calibration count */ uint32 calibrations; /* calibration count */
double clock_skew_max; /* asynchronous max skew */ double clock_skew_max; /* asynchronous max skew */
double clock_start_gtime; /* reference instruction time for clock */
double clock_tick_size; /* 1/hz */ double clock_tick_size; /* 1/hz */
uint32 calib_initializations; /* Initialization Count */ uint32 calib_initializations; /* Initialization Count */
double calib_tick_time; /* ticks time */ double calib_tick_time; /* ticks time */
@ -839,10 +838,11 @@ void sim_rtcn_init_all (void)
int32 tmr; int32 tmr;
RTC *rtc; RTC *rtc;
for (tmr = 0; tmr <= SIM_NTIMERS; tmr++) for (tmr = 0; tmr <= SIM_NTIMERS; tmr++) {
rtc = &rtcs[tmr]; rtc = &rtcs[tmr];
if (rtc->initd != 0) if (rtc->initd != 0)
sim_rtcn_init (rtc->initd, tmr); sim_rtcn_init (rtc->initd, tmr);
}
} }
int32 sim_rtcn_init (int32 time, int32 tmr) int32 sim_rtcn_init (int32 time, int32 tmr)
@ -882,7 +882,7 @@ if (uptr) {
if (!rtc->clock_unit) if (!rtc->clock_unit)
sim_register_clock_unit_tmr (uptr, tmr); 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->rtime = sim_is_running ? sim_os_msec () : sim_stop_time;
rtc->vtime = rtc->rtime; rtc->vtime = rtc->rtime;
rtc->nxintv = 1000; rtc->nxintv = 1000;
@ -918,7 +918,7 @@ RTC *rtc = &rtcs[tmr];
return sim_rtcn_calb (rtc->hz, 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; uint32 new_rtime, delta_rtime, last_idle_pct, catchup_ticks_curr;
int32 delta_vtime; int32 delta_vtime;
@ -947,8 +947,16 @@ if (rtc->hz != ticksper) { /* changing tick rate? */
rtc->hz = ticksper; rtc->hz = ticksper;
_rtcn_configure_calibrated_clock (tmr); _rtcn_configure_calibrated_clock (tmr);
if (ticksper != 0) { if (ticksper != 0) {
RTC *crtc = &rtcs[sim_calb_tmr];
rtc->clock_tick_size = 1.0 / ticksper; 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); 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 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); 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);
@ -989,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); 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->vtime = rtc->rtime = new_rtime; /* reset wall time */
rtc->nxintv = 1000; rtc->nxintv = 1000;
rtc->based = rtc->currd;
if (rtc->clock_catchup_eligible) { if (rtc->clock_catchup_eligible) {
rtc->clock_catchup_base_time = sim_timenow_double(); rtc->clock_catchup_base_time = sim_timenow_double();
rtc->calib_tick_time = 0.0; rtc->calib_tick_time = 0.0;
@ -1009,6 +1018,7 @@ if (delta_rtime > 30000) { /* gap too big? */
rtc->vtime = rtc->rtime; /* sync virtual and real time */ rtc->vtime = rtc->rtime; /* sync virtual and real time */
rtc->nxintv = 1000; /* reset next interval */ rtc->nxintv = 1000; /* reset next interval */
rtc->gtime = sim_gtime(); /* save instruction time */ rtc->gtime = sim_gtime(); /* save instruction time */
rtc->based = rtc->currd;
if (rtc->clock_catchup_eligible) if (rtc->clock_catchup_eligible)
rtc->calib_tick_time += ((double)delta_rtime / 1000.0);/* advance tick time */ 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); sim_debug (DBG_CAL, &sim_timer_dev, "gap too big: delta = %d - result: %d\n", delta_rtime, rtc->currd);
@ -1023,7 +1033,7 @@ if (tmr != SIM_NTIMERS) {
rtc->rtime = new_rtime; /* save wall time */ rtc->rtime = new_rtime; /* save wall time */
rtc->vtime += 1000; /* adv sim time */ rtc->vtime += 1000; /* adv sim time */
rtc->gtime = sim_gtime(); /* save instruction time */ rtc->gtime = sim_gtime(); /* save instruction time */
rtc->based = rtc->initd; rtc->based = rtc->currd;
++rtc->clock_calib_skip_idle; ++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); 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 */ return rtc->currd; /* avoid calibrating idle checks */
@ -1035,8 +1045,9 @@ if ((last_idle_pct == 0) && (delta_rtime != 0)) {
if ((sim_idle_rate_ms != 0) && (delta_rtime > 1)) if ((sim_idle_rate_ms != 0) && (delta_rtime > 1))
sim_idle_cyc_sleep = (uint32)((new_gtime - rtc->gtime) / (delta_rtime / sim_idle_rate_ms)); sim_idle_cyc_sleep = (uint32)((new_gtime - rtc->gtime) / (delta_rtime / sim_idle_rate_ms));
} }
if (sim_asynch_timer) { if (sim_asynch_timer || (catchup_ticks_curr > 0)) {
/* An asynchronous clock, merely needs to divide the number of */ /* An asynchronous clock or when catchup ticks have */
/* occurred, we merely needs to divide the number of */
/* instructions actually executed by the clock rate. */ /* instructions actually executed by the clock rate. */
new_currd = (int32)((new_gtime - rtc->gtime)/ticksper); new_currd = (int32)((new_gtime - rtc->gtime)/ticksper);
/* avoid excessive swings in the calibrated result */ /* avoid excessive swings in the calibrated result */
@ -1046,9 +1057,10 @@ if (sim_asynch_timer) {
if (new_currd < rtc->currd/10) /* don't swing small too fast */ if (new_currd < rtc->currd/10) /* don't swing small too fast */
new_currd = rtc->currd/10; new_currd = rtc->currd/10;
} }
rtc->currd = new_currd; rtc->based = rtc->currd = new_currd;
rtc->gtime = new_gtime; /* save instruction time */ 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 */ return rtc->currd; /* calibrated result */
} }
rtc->gtime = new_gtime; /* save instruction time */ rtc->gtime = new_gtime; /* save instruction time */
@ -1094,7 +1106,7 @@ int32 sim_rtc_init (int32 time)
return sim_rtcn_init (time, 0); return sim_rtcn_init (time, 0);
} }
int32 sim_rtc_calb (int32 ticksper) int32 sim_rtc_calb (uint32 ticksper)
{ {
return sim_rtcn_calb (ticksper, 0); return sim_rtcn_calb (ticksper, 0);
} }
@ -1275,7 +1287,7 @@ for (tmr=clocks=0; tmr<=SIM_NTIMERS; ++tmr) {
clock_gettime (CLOCK_REALTIME, &now); clock_gettime (CLOCK_REALTIME, &now);
time_t_now = (time_t)now.tv_sec; 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)); 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); _double_to_timespec (&now, rtc->clock_catchup_base_time+rtc->calib_tick_time);
time_t_now = (time_t)now.tv_sec; 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)); fprintf (st, " Catchup Tick Time: %8.8s.%03d\n", 11+ctime(&time_t_now), (int)(now.tv_nsec/1000000));
@ -1605,12 +1617,16 @@ RTC *rtc = &rtcs[tmr];
if (rtc->hz == 0) /* specified timer is not running? */ if (rtc->hz == 0) /* specified timer is not running? */
tmr = sim_calb_tmr; /* use calibrated timer instead */ tmr = sim_calb_tmr; /* use calibrated timer instead */
rtc = &rtcs[tmr]; 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_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_activate_abs (&sim_timer_units[tmr], 0);
sim_interval -= sin_cyc; sim_interval -= sin_cyc;
return FALSE; 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 */ if ((!sim_idle_enab) || /* idling disabled */
((sim_clock_queue == QUEUE_LIST_END) && /* or clock queue empty? */ ((sim_clock_queue == QUEUE_LIST_END) && /* or clock queue empty? */
(!sim_asynch_timer))|| /* and not asynch? */ (!sim_asynch_timer))|| /* and not asynch? */
@ -1624,13 +1640,9 @@ if ((!sim_idle_enab) || /* idling disabled */
sim_interval -= sin_cyc; sim_interval -= sin_cyc;
return FALSE; return FALSE;
} }
if (_rtcn_tick_catchup_check (rtc, -1)) { /* Pending catchup tick? */
sim_interval = 0; /* Force it now */
return FALSE;
}
/* /*
When a simulator is in an instruction path (or under other conditions 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 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 when not in the 'idle capable' state. The consequence of this is that
the clock calibration may produce calibrated results which vary much the clock calibration may produce calibrated results which vary much
@ -1655,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) { if (sim_idle_cyc_ms == 0) {
sim_idle_cyc_ms = (rtc->currd * rtc->hz) / 1000;/* cycles per msec */ sim_idle_cyc_ms = (rtc->currd * rtc->hz) / 1000;/* cycles per msec */
if (sim_idle_rate_ms != 0) 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? */ if ((sim_idle_rate_ms == 0) || (sim_idle_cyc_ms == 0)) {/* not possible? */
sim_interval -= sin_cyc; sim_interval -= sin_cyc;
@ -1672,16 +1684,15 @@ 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 else
w_idle = (w_ms * 1000) / sim_idle_rate_ms; /* 1000 * intervals to wait */ w_idle = (w_ms * 1000) / sim_idle_rate_ms; /* 1000 * intervals to wait */
if (w_idle < 500) { /* shorter than 1/2 the interval? */ if ((w_idle < 500) || (w_ms == 0)) { /* shorter than 1/2 the interval or */
sim_interval -= sin_cyc; sim_interval -= sin_cyc; /* minimal sleep time? */
if (!in_nowait) if (!in_nowait)
sim_debug (DBG_IDL, &sim_timer_dev, "no wait, too short: %d usecs\n", w_idle); sim_debug (DBG_IDL, &sim_timer_dev, "no wait, too short: %d usecs\n", w_idle);
in_nowait = TRUE; in_nowait = TRUE;
return FALSE; 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); 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; in_nowait = FALSE;
if (sim_clock_queue == QUEUE_LIST_END) 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); sim_debug (DBG_IDL, &sim_timer_dev, "sleeping for %d ms - pending event in %d instructions\n", w_ms, sim_interval);
@ -2000,6 +2011,7 @@ switch (sim_throt_state) {
/* Run through all timers and adjust the calibration for each */ /* Run through all timers and adjust the calibration for each */
/* one that is running to reflect the throttle rate */ /* one that is running to reflect the throttle rate */
for (tmr=0; tmr<=SIM_NTIMERS; tmr++) { for (tmr=0; tmr<=SIM_NTIMERS; tmr++) {
rtc = &rtcs[tmr];
if (rtc->hz) { /* running? */ if (rtc->hz) { /* running? */
rtc->currd = (int32)(sim_throt_cps / rtc->hz);/* use throttle calibration */ rtc->currd = (int32)(sim_throt_cps / rtc->hz);/* use throttle calibration */
rtc->ticks = rtc->hz - 1; /* force clock calibration on next tick */ rtc->ticks = rtc->hz - 1; /* force clock calibration on next tick */
@ -2194,7 +2206,7 @@ clock_gettime (CLOCK_REALTIME, now);
/* _rtcn_tick_catchup_check - idle simulator until next event or for specified interval /* _rtcn_tick_catchup_check - idle simulator until next event or for specified interval
Inputs: Inputs:
tmr = calibrated timer to check/schedule RTC = calibrated timer to check/schedule
time = instruction delay for next tick time = instruction delay for next tick
Returns TRUE if a catchup tick has been scheduled Returns TRUE if a catchup tick has been scheduled
@ -2202,8 +2214,31 @@ clock_gettime (CLOCK_REALTIME, now);
static t_bool _rtcn_tick_catchup_check (RTC *rtc, int32 time) static t_bool _rtcn_tick_catchup_check (RTC *rtc, int32 time)
{ {
int32 tmr;
t_bool bReturn = FALSE;
if (!sim_catchup_ticks) if (!sim_catchup_ticks)
return FALSE; return FALSE;
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? */ if ((!rtc->clock_catchup_eligible) && /* not eligible yet? */
(time != -1)) { /* called from ack? */ (time != -1)) { /* called from ack? */
rtc->clock_catchup_base_time = sim_timenow_double(); rtc->clock_catchup_base_time = sim_timenow_double();
@ -2217,7 +2252,7 @@ if ((!rtc->clock_catchup_eligible) && /* not eligible yet? */
rtc->calib_ticks_acked = 0; rtc->calib_ticks_acked = 0;
rtc->clock_catchup_eligible = TRUE; 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)); 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) && if ((rtc->hz > 0) &&
rtc->clock_catchup_eligible) rtc->clock_catchup_eligible)
@ -2235,14 +2270,14 @@ if ((rtc->hz > 0) &&
return TRUE; return TRUE;
} }
} }
return FALSE; return bReturn;
} }
t_stat sim_rtcn_tick_ack (uint32 time, int32 tmr) t_stat sim_rtcn_tick_ack (uint32 time, int32 tmr)
{ {
RTC *rtc; RTC *rtc;
if ((tmr < 0) || (tmr >= SIM_NTIMERS)) if ((tmr < 0) || (tmr > SIM_NTIMERS))
return SCPE_TIMER; return SCPE_TIMER;
rtc = &rtcs[tmr]; rtc = &rtcs[tmr];
sim_debug (DBG_ACK, &sim_timer_dev, "sim_rtcn_tick_ack - for %s\n", sim_uname (rtc->clock_unit)); sim_debug (DBG_ACK, &sim_timer_dev, "sim_rtcn_tick_ack - for %s\n", sim_uname (rtc->clock_unit));
@ -2428,29 +2463,30 @@ for (tmr=0; tmr<SIM_NTIMERS; tmr++) {
} }
if (tmr == SIM_NTIMERS) { /* None found? */ if (tmr == SIM_NTIMERS) { /* None found? */
if ((tmr != newtmr) && (!sim_is_active (&SIM_INTERNAL_UNIT))) { if ((tmr != newtmr) && (!sim_is_active (&SIM_INTERNAL_UNIT))) {
crtc = &rtcs[sim_calb_tmr];
if ((sim_calb_tmr != SIM_NTIMERS) &&/* not internal timer? */ if ((sim_calb_tmr != SIM_NTIMERS) &&/* not internal timer? */
(sim_calb_tmr != -1) && /* previously active? */ (sim_calb_tmr != -1)) { /* previously active? */
(!crtc->hz)) { /* now stopped? */ crtc = &rtcs[sim_calb_tmr];
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)); if (!crtc->hz) { /* now stopped? */
/* Migrate any coscheduled devices to the standard queue */ 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));
/* with appropriate usecs_remaining reflecting their currently */ /* Migrate any coscheduled devices to the standard queue */
/* scheduled firing time. sim_process_event() will coschedule */ /* with appropriate usecs_remaining reflecting their currently */
/* appropriately. */ /* scheduled firing time. sim_process_event() will coschedule */
/* temporarily restore prior hz to get correct remaining time */ /* appropriately. */
crtc->hz = crtc->last_hz; /* temporarily restore prior hz to get correct remaining time */
while (crtc->clock_cosched_queue != QUEUE_LIST_END) { crtc->hz = crtc->last_hz;
UNIT *uptr = crtc->clock_cosched_queue; while (crtc->clock_cosched_queue != QUEUE_LIST_END) {
double usecs_remaining = sim_timer_activate_time_usecs (uptr) - 1; UNIT *uptr = crtc->clock_cosched_queue;
double usecs_remaining = sim_timer_activate_time_usecs (uptr) - 1;
_sim_coschedule_cancel (uptr); _sim_coschedule_cancel (uptr);
_sim_activate (uptr, 1); _sim_activate (uptr, 1);
uptr->usecs_remaining = usecs_remaining; 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 (crtc->timer_unit);
} }
/* Start the internal timer */ /* Start the internal timer */
sim_calb_tmr = SIM_NTIMERS; sim_calb_tmr = SIM_NTIMERS;
@ -2475,26 +2511,27 @@ if (sim_calb_tmr == SIM_NTIMERS) { /* was old the internal timer? */
sim_cancel (&sim_timer_units[SIM_NTIMERS]); sim_cancel (&sim_timer_units[SIM_NTIMERS]);
} }
else { else {
rtc = &rtcs[sim_calb_tmr]; if (sim_calb_tmr != -1) {
if ((sim_calb_tmr != -1) && crtc = &rtcs[sim_calb_tmr];
(rtc->hz == 0)) { if (crtc->hz == 0) {
/* Migrate any coscheduled devices to the standard queue */ /* Migrate any coscheduled devices to the standard queue */
/* with appropriate usecs_remaining reflecting their currently */ /* with appropriate usecs_remaining reflecting their currently */
/* scheduled firing time. sim_process_event() will coschedule */ /* scheduled firing time. sim_process_event() will coschedule */
/* appropriately. */ /* appropriately. */
/* temporarily restore prior hz to get correct remaining time */ /* temporarily restore prior hz to get correct remaining time */
rtc->hz = rtc->last_hz; crtc->hz = crtc->last_hz;
while (rtc->clock_cosched_queue != QUEUE_LIST_END) { while (crtc->clock_cosched_queue != QUEUE_LIST_END) {
UNIT *uptr = rtc->clock_cosched_queue; UNIT *uptr = crtc->clock_cosched_queue;
double usecs_remaining = sim_timer_activate_time_usecs (uptr) - 1; double usecs_remaining = sim_timer_activate_time_usecs (uptr) - 1;
_sim_coschedule_cancel (uptr); _sim_coschedule_cancel (uptr);
_sim_activate (uptr, 1); _sim_activate (uptr, 1);
uptr->usecs_remaining = usecs_remaining; 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;
} }
sim_calb_tmr = tmr; sim_calb_tmr = tmr;
@ -2519,19 +2556,24 @@ void sim_start_timer_services (void)
{ {
int32 tmr; int32 tmr;
uint32 sim_prompt_time = sim_os_msec () - sim_stop_time; 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); sim_time_at_sim_prompt += (((double)sim_prompt_time) / 1000.0);
for (tmr=0; tmr<=SIM_NTIMERS; tmr++) { for (tmr=0; tmr<=SIM_NTIMERS; tmr++) {
RTC *rtc = &rtcs[tmr]; RTC *rtc = &rtcs[tmr];
if (rtc->hz) { /* calibrated clock running? */ if (rtc->initd) { /* calibrated clock initialized? */
rtc->rtime += sim_prompt_time; rtc->rtime += sim_prompt_time;
rtc->vtime += 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); 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) if (rtc->clock_catchup_eligible)
rtc->calib_tick_time += (((double)sim_prompt_time) / 1000.0); 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) { if (sim_calb_tmr == -1) {
sim_debug (DBG_CAL, &sim_timer_dev, "sim_start_timer_services() - starting from scratch\n"); sim_debug (DBG_CAL, &sim_timer_dev, "sim_start_timer_services() - starting from scratch\n");
_rtcn_configure_calibrated_clock (sim_calb_tmr); _rtcn_configure_calibrated_clock (sim_calb_tmr);

View file

@ -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); void sim_rtcn_get_time (struct timespec *now, int tmr);
t_stat sim_rtcn_tick_ack (uint32 time, int32 tmr); t_stat sim_rtcn_tick_ack (uint32 time, int32 tmr);
void sim_rtcn_init_all (void); 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_rtcn_calb_tick (int32 tmr);
int32 sim_rtc_init (int32 time); 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_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_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); t_stat sim_show_clock_queues (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);