TIMER: Accelerate catchup ticks while idling
- Avoid default idle stability wait when pre-calibrate has succeeded - Display time at sim> prompt in SHOW CLOCK output
This commit is contained in:
parent
b1fd80da64
commit
8c4f8b0bff
1 changed files with 35 additions and 28 deletions
63
sim_timer.c
63
sim_timer.c
|
@ -155,6 +155,7 @@ static int32 sim_calb_tmr = -1; /* the system calibrated tim
|
||||||
static int32 sim_calb_tmr_last = -1; /* shadow value when at sim> prompt */
|
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 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 */
|
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;
|
||||||
static uint32 sim_os_sleep_min_ms = 0;
|
static uint32 sim_os_sleep_min_ms = 0;
|
||||||
|
@ -182,7 +183,8 @@ static uint32 sim_throt_delay = 3;
|
||||||
static int32 sim_int_clk_tps;
|
static int32 sim_int_clk_tps;
|
||||||
|
|
||||||
typedef struct RTC {
|
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;
|
UNIT *clock_cosched_queue;
|
||||||
int32 cosched_interval;
|
int32 cosched_interval;
|
||||||
int32 ticks; /* ticks */
|
int32 ticks; /* ticks */
|
||||||
|
@ -750,7 +752,7 @@ while (diff->tv_nsec >= 1000000000) {
|
||||||
|
|
||||||
static double _timespec_to_double (struct timespec *time);
|
static double _timespec_to_double (struct timespec *time);
|
||||||
static void _double_to_timespec (struct timespec *time, double dtime);
|
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 void _rtcn_configure_calibrated_clock (int32 newtmr);
|
||||||
static t_bool _sim_coschedule_cancel (UNIT *uptr);
|
static t_bool _sim_coschedule_cancel (UNIT *uptr);
|
||||||
static t_bool _sim_wallclock_cancel (UNIT *uptr);
|
static t_bool _sim_wallclock_cancel (UNIT *uptr);
|
||||||
|
@ -1072,7 +1074,7 @@ if (rtc->based <= 0) /* never negative or zero! *
|
||||||
rtc->based = 1;
|
rtc->based = 1;
|
||||||
if (rtc->currd <= 0) /* never negative or zero! */
|
if (rtc->currd <= 0) /* never negative or zero! */
|
||||||
rtc->currd = 1;
|
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);
|
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 */
|
/* Adjust calibration for other timers which depend on this timer's calibration */
|
||||||
for (itmr=0; itmr<=SIM_NTIMERS; itmr++) {
|
for (itmr=0; itmr<=SIM_NTIMERS; itmr++) {
|
||||||
|
@ -1108,8 +1110,9 @@ sim_debug (DBG_TRC, &sim_timer_dev, "sim_timer_init()\n");
|
||||||
for (tmr=0; tmr<=SIM_NTIMERS; tmr++) {
|
for (tmr=0; tmr<=SIM_NTIMERS; tmr++) {
|
||||||
RTC *rtc = &rtcs[tmr];
|
RTC *rtc = &rtcs[tmr];
|
||||||
|
|
||||||
sim_timer_units[tmr].action = &sim_timer_tick_svc;
|
rtc->timer_unit = &sim_timer_units[tmr];
|
||||||
sim_timer_units[tmr].flags = UNIT_DIS | UNIT_IDLE;
|
rtc->timer_unit->action = &sim_timer_tick_svc;
|
||||||
|
rtc->timer_unit->flags = UNIT_DIS | UNIT_IDLE;
|
||||||
rtc->clock_cosched_queue = QUEUE_LIST_END;
|
rtc->clock_cosched_queue = QUEUE_LIST_END;
|
||||||
}
|
}
|
||||||
sim_stop_unit.action = &sim_timer_stop_svc;
|
sim_stop_unit.action = &sim_timer_stop_svc;
|
||||||
|
@ -1189,6 +1192,13 @@ else
|
||||||
#if defined(SIM_ASYNCH_CLOCKS)
|
#if defined(SIM_ASYNCH_CLOCKS)
|
||||||
fprintf (st, "Asynchronous Clocks: %s\n", sim_asynch_timer ? "Active" : "Available");
|
fprintf (st, "Asynchronous Clocks: %s\n", sim_asynch_timer ? "Active" : "Available");
|
||||||
#endif
|
#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");
|
fprintf (st, "\n");
|
||||||
for (tmr=clocks=0; tmr<=SIM_NTIMERS; ++tmr) {
|
for (tmr=clocks=0; tmr<=SIM_NTIMERS; ++tmr) {
|
||||||
RTC *rtc = &rtcs[tmr];
|
RTC *rtc = &rtcs[tmr];
|
||||||
|
@ -1614,9 +1624,8 @@ if ((!sim_idle_enab) || /* idling disabled */
|
||||||
sim_interval -= sin_cyc;
|
sim_interval -= sin_cyc;
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
if (_rtcn_tick_catchup_check (tmr, -1)) {
|
if (_rtcn_tick_catchup_check (rtc, -1)) { /* Pending catchup tick? */
|
||||||
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 = 0; /* Force it now */
|
||||||
sim_interval -= sin_cyc;
|
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
|
@ -1660,7 +1669,7 @@ w_ms = (uint32) sim_interval / sim_idle_cyc_ms; /* ms to wait */
|
||||||
/* the simulator acknowledges the processing of clock ticks, then catchup */
|
/* the simulator acknowledges the processing of clock ticks, then catchup */
|
||||||
/* ticks can be used to make up for missed ticks. */
|
/* ticks can be used to make up for missed ticks. */
|
||||||
if (rtc->clock_catchup_eligible)
|
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) { /* shorter than 1/2 the interval? */
|
||||||
|
@ -2191,15 +2200,11 @@ clock_gettime (CLOCK_REALTIME, now);
|
||||||
Returns TRUE if a catchup tick has been scheduled
|
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;
|
if (!sim_catchup_ticks)
|
||||||
|
|
||||||
if ((!sim_catchup_ticks) ||
|
|
||||||
((tmr < 0) || (tmr >= SIM_NTIMERS)))
|
|
||||||
return FALSE;
|
return FALSE;
|
||||||
rtc = &rtcs[tmr];
|
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();
|
||||||
rtc->clock_ticks_tot += rtc->clock_ticks;
|
rtc->clock_ticks_tot += rtc->clock_ticks;
|
||||||
|
@ -2223,7 +2228,7 @@ if ((rtc->hz > 0) &&
|
||||||
if (!rtc->clock_catchup_pending) {
|
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))));
|
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;
|
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
|
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))));
|
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))));
|
||||||
|
@ -2241,7 +2246,7 @@ 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));
|
||||||
_rtcn_tick_catchup_check (tmr, (int32)time);
|
_rtcn_tick_catchup_check (rtc, (int32)time);
|
||||||
++rtc->calib_ticks_acked;
|
++rtc->calib_ticks_acked;
|
||||||
return SCPE_OK;
|
return SCPE_OK;
|
||||||
}
|
}
|
||||||
|
@ -2445,7 +2450,7 @@ if (tmr == SIM_NTIMERS) { /* None found? */
|
||||||
crtc->hz = 0; /* back to 0 */
|
crtc->hz = 0; /* back to 0 */
|
||||||
if (crtc->clock_unit)
|
if (crtc->clock_unit)
|
||||||
sim_cancel (crtc->clock_unit);
|
sim_cancel (crtc->clock_unit);
|
||||||
sim_cancel (&sim_timer_units[sim_calb_tmr]);
|
sim_cancel (crtc->timer_unit);
|
||||||
}
|
}
|
||||||
/* Start the internal timer */
|
/* Start the internal timer */
|
||||||
sim_calb_tmr = SIM_NTIMERS;
|
sim_calb_tmr = SIM_NTIMERS;
|
||||||
|
@ -2515,6 +2520,7 @@ 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;
|
||||||
|
|
||||||
|
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];
|
||||||
|
|
||||||
|
@ -2570,11 +2576,11 @@ for (tmr=0; tmr<=SIM_NTIMERS; tmr++) {
|
||||||
RTC *rtc = &rtcs[tmr];
|
RTC *rtc = &rtcs[tmr];
|
||||||
|
|
||||||
if (rtc->clock_unit) {
|
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 */
|
/* Stop clock assist unit and make sure the clock unit has a tick queued */
|
||||||
if (sim_is_active (&sim_timer_units[tmr])) {
|
if (sim_is_active (rtc->timer_unit)) {
|
||||||
sim_cancel (&sim_timer_units[tmr]);
|
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_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);
|
_sim_activate (rtc->clock_unit, clock_time);
|
||||||
}
|
}
|
||||||
|
@ -2687,7 +2693,7 @@ for (tmr=0; tmr<=SIM_NTIMERS; tmr++) {
|
||||||
RTC *rtc = &rtcs[tmr];
|
RTC *rtc = &rtcs[tmr];
|
||||||
|
|
||||||
if (rtc->clock_unit == uptr) {
|
if (rtc->clock_unit == uptr) {
|
||||||
uptr = &sim_timer_units[tmr];
|
uptr = rtc->timer_unit;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2721,13 +2727,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 */
|
inst_delay_d = inst_delay = 1; /* Minimum non-zero delay is 1 instruction */
|
||||||
crtc = &rtcs[sim_calb_tmr];
|
crtc = &rtcs[sim_calb_tmr];
|
||||||
if ((sim_calb_tmr != -1) && (crtc->hz)) { /* Calibrated Timer available? */
|
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;
|
int32 ticks_til_calib = crtc->hz - crtc->ticks;
|
||||||
double usecs_per_tick = floor (1000000.0 / crtc->hz);
|
double usecs_per_tick = floor (1000000.0 / crtc->hz);
|
||||||
int32 inst_til_calib = inst_til_tick + ((ticks_til_calib - 1) * crtc->currd);
|
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);
|
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? */
|
(inst_til_tick > 0)) { /* and tick not pending? */
|
||||||
if (inst_delay_d > (double)inst_til_calib) { /* long wait? */
|
if (inst_delay_d > (double)inst_til_calib) { /* long wait? */
|
||||||
stat = sim_clock_coschedule_tmr (uptr, sim_calb_tmr, ticks_til_calib - 1);
|
stat = sim_clock_coschedule_tmr (uptr, sim_calb_tmr, ticks_til_calib - 1);
|
||||||
|
@ -2855,15 +2861,15 @@ if (NULL == uptr) { /* deregistering? */
|
||||||
rtc->clock_unit->dynflags &= ~UNIT_TMR_UNIT;
|
rtc->clock_unit->dynflags &= ~UNIT_TMR_UNIT;
|
||||||
}
|
}
|
||||||
rtc->clock_unit = NULL;
|
rtc->clock_unit = NULL;
|
||||||
sim_cancel (&sim_timer_units[tmr]);
|
sim_cancel (rtc->timer_unit);
|
||||||
return SCPE_OK;
|
return SCPE_OK;
|
||||||
}
|
}
|
||||||
if (NULL == rtc->clock_unit)
|
if (NULL == rtc->clock_unit)
|
||||||
rtc->clock_cosched_queue = QUEUE_LIST_END;
|
rtc->clock_cosched_queue = QUEUE_LIST_END;
|
||||||
rtc->clock_unit = uptr;
|
rtc->clock_unit = uptr;
|
||||||
uptr->dynflags |= UNIT_TMR_UNIT;
|
uptr->dynflags |= UNIT_TMR_UNIT;
|
||||||
sim_timer_units[tmr].flags = ((tmr == SIM_NTIMERS) ? 0 : UNIT_DIS) |
|
rtc->timer_unit->flags = ((tmr == SIM_NTIMERS) ? 0 : UNIT_DIS) |
|
||||||
(rtc->clock_unit ? UNIT_IDLE : 0);
|
(rtc->clock_unit ? UNIT_IDLE : 0);
|
||||||
return SCPE_OK;
|
return SCPE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3391,4 +3397,5 @@ for (tmr=0; tmr<=SIM_NTIMERS; tmr++) {
|
||||||
rtc->calib_initializations = 1;
|
rtc->calib_initializations = 1;
|
||||||
}
|
}
|
||||||
sim_inst_per_sec_last = sim_precalibrate_ips;
|
sim_inst_per_sec_last = sim_precalibrate_ips;
|
||||||
|
sim_idle_stable = 0;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue