TIMER: Enabled catchup clock ticks

Historically, hosts which have a tick size slower than the tick a simulator
wants to implement can't idle effectively and keep good time.

This change allows simulators which call sim_rtcn_tick_ack() to provide
useful idling behavior while still keeping the passage of wall clock time
to time in the simulator accurate.
This commit is contained in:
Mark Pizzolato 2016-12-10 11:59:49 -08:00
parent 1c3c50fd26
commit 5d8553e24c
3 changed files with 121 additions and 91 deletions

14
scp.c
View file

@ -1115,6 +1115,15 @@ static const char simh_help[] =
"+set throttle {x{M|K|%%}}|{x/t}\n" "+set throttle {x{M|K|%%}}|{x/t}\n"
"++++++++ set simulation rate\n" "++++++++ set simulation rate\n"
"+set nothrottle set simulation rate to maximum\n" "+set nothrottle set simulation rate to maximum\n"
#define HLP_SET_CLOCKS "*Commands SET Clocks"
"3Clock\n"
#if defined (SIM_ASYNCH_CLOCKS)
"+set clock asynch enable asynchronous clocks\n"
"+set clock noasynch disable asynchronous clocks\n"
#endif
"+set clock nocatchup disable catchup clock ticks\n"
"+set clock catchup enable catchup clock ticks\n"
"+set clock calib=n%% specify idle calibration skip %%\n"
#define HLP_SET_ASYNCH "*Commands SET Asynch" #define HLP_SET_ASYNCH "*Commands SET Asynch"
"3Asynch\n" "3Asynch\n"
"+set asynch enable asynchronous I/O\n" "+set asynch enable asynchronous I/O\n"
@ -1202,7 +1211,7 @@ static const char simh_help[] =
#if defined(USE_SIM_VIDEO) #if defined(USE_SIM_VIDEO)
"+sh{ow} video show video capabilities\n" "+sh{ow} video show video capabilities\n"
#endif #endif
"+sh{ow} clocks show calibrated timers\n" "+sh{ow} clocks show calibrated timer information\n"
"+sh{ow} throttle show throttle info\n" "+sh{ow} throttle show throttle info\n"
"+sh{ow} on show on condition actions\n" "+sh{ow} on show on condition actions\n"
"+h{elp} <dev> show displays the device specific show commands\n" "+h{elp} <dev> show displays the device specific show commands\n"
@ -1839,6 +1848,7 @@ static CTAB set_glob_tab[] = {
{ "NODEBUG", &sim_set_deboff, 0, HLP_SET_DEBUG }, { "NODEBUG", &sim_set_deboff, 0, HLP_SET_DEBUG },
{ "THROTTLE", &sim_set_throt, 1, HLP_SET_THROTTLE }, { "THROTTLE", &sim_set_throt, 1, HLP_SET_THROTTLE },
{ "NOTHROTTLE", &sim_set_throt, 0, HLP_SET_THROTTLE }, { "NOTHROTTLE", &sim_set_throt, 0, HLP_SET_THROTTLE },
{ "CLOCKS", &sim_set_timers, 1, HLP_SET_CLOCKS },
{ "ASYNCH", &sim_set_asynch, 1, HLP_SET_ASYNCH }, { "ASYNCH", &sim_set_asynch, 1, HLP_SET_ASYNCH },
{ "NOASYNCH", &sim_set_asynch, 0, HLP_SET_ASYNCH }, { "NOASYNCH", &sim_set_asynch, 0, HLP_SET_ASYNCH },
{ "ENVIRONMENT", &sim_set_environment, 1, HLP_SET_ENVIRON }, { "ENVIRONMENT", &sim_set_environment, 1, HLP_SET_ENVIRON },
@ -4427,7 +4437,7 @@ static char capac_buf[((CHAR_BIT * sizeof (t_value) * 4 + 3)/3) + 8];
t_addr kval = (uptr->flags & UNIT_BINK)? 1024: 1000; t_addr kval = (uptr->flags & UNIT_BINK)? 1024: 1000;
t_addr mval; t_addr mval;
t_addr psize = uptr->capac; t_addr psize = uptr->capac;
char *scale, *width; const char *scale, *width;
if (sim_switches & SWMASK ('B')) if (sim_switches & SWMASK ('B'))
kval = 1024; kval = 1024;

View file

@ -168,7 +168,7 @@ static int32 sim_throt_wait = 0;
static UNIT *sim_clock_unit[SIM_NTIMERS+1] = {NULL}; static UNIT *sim_clock_unit[SIM_NTIMERS+1] = {NULL};
UNIT * volatile sim_clock_cosched_queue[SIM_NTIMERS+1] = {NULL}; UNIT * volatile sim_clock_cosched_queue[SIM_NTIMERS+1] = {NULL};
static int32 sim_cosched_interval[SIM_NTIMERS+1]; static int32 sim_cosched_interval[SIM_NTIMERS+1];
static t_bool sim_catchup_ticks = FALSE; static t_bool sim_catchup_ticks = TRUE;
#if defined (SIM_ASYNCH_CLOCKS) && !defined (SIM_ASYNCH_IO) #if defined (SIM_ASYNCH_CLOCKS) && !defined (SIM_ASYNCH_IO)
#undef SIM_ASYNCH_CLOCKS #undef SIM_ASYNCH_CLOCKS
#endif #endif
@ -686,6 +686,8 @@ static void _rtcn_configure_calibrated_clock (int32 newtmr);
static void _sim_coschedule_cancel(UNIT *uptr); static void _sim_coschedule_cancel(UNIT *uptr);
static void _sim_wallclock_cancel (UNIT *uptr); static void _sim_wallclock_cancel (UNIT *uptr);
static t_bool _sim_wallclock_is_active (UNIT *uptr); static t_bool _sim_wallclock_is_active (UNIT *uptr);
t_stat sim_timer_show_idle_mode (FILE* st, UNIT* uptr, int32 val, CONST void * desc);
#if defined(SIM_ASYNCH_CLOCKS) #if defined(SIM_ASYNCH_CLOCKS)
static int sim_timespec_compare (struct timespec *a, struct timespec *b) static int sim_timespec_compare (struct timespec *a, struct timespec *b)
@ -869,13 +871,10 @@ if (sim_clock_unit[tmr] == NULL) { /* Not using TIMER units
if (rtc_clock_catchup_pending[tmr]) { /* catchup tick? */ if (rtc_clock_catchup_pending[tmr]) { /* catchup tick? */
++rtc_clock_catchup_ticks[tmr]; /* accumulating which were catchups */ ++rtc_clock_catchup_ticks[tmr]; /* accumulating which were catchups */
rtc_clock_catchup_pending[tmr] = FALSE; rtc_clock_catchup_pending[tmr] = FALSE;
if (!sim_asynch_timer) /* non asynch timers? */
return rtc_currd[tmr]; /* return now avoiding counting catchup tick in calibration */
} }
rtc_ticks[tmr] = rtc_ticks[tmr] + 1; /* count ticks */ rtc_ticks[tmr] = rtc_ticks[tmr] + 1; /* count ticks */
if (rtc_ticks[tmr] < ticksper) { /* 1 sec yet? */ if (rtc_ticks[tmr] < ticksper) /* 1 sec yet? */
return rtc_currd[tmr]; return rtc_currd[tmr];
}
rtc_ticks[tmr] = 0; /* reset ticks */ rtc_ticks[tmr] = 0; /* reset ticks */
rtc_elapsed[tmr] = rtc_elapsed[tmr] + 1; /* count sec */ rtc_elapsed[tmr] = rtc_elapsed[tmr] + 1; /* count sec */
if (sim_throt_type != SIM_THROT_NONE) { if (sim_throt_type != SIM_THROT_NONE) {
@ -885,9 +884,8 @@ if (sim_throt_type != SIM_THROT_NONE) {
sim_debug (DBG_CAL, &sim_timer_dev, "using throttle calibrated value - result: %d\n", rtc_currd[tmr]); sim_debug (DBG_CAL, &sim_timer_dev, "using throttle calibrated value - result: %d\n", rtc_currd[tmr]);
return rtc_currd[tmr]; return rtc_currd[tmr];
} }
if (!rtc_avail) { /* no timer? */ if (!rtc_avail) /* no timer? */
return rtc_currd[tmr]; return rtc_currd[tmr];
}
if (sim_calb_tmr != tmr) { if (sim_calb_tmr != tmr) {
rtc_currd[tmr] = (int32)(sim_timer_inst_per_sec()/ticksper); rtc_currd[tmr] = (int32)(sim_timer_inst_per_sec()/ticksper);
sim_debug (DBG_CAL, &sim_timer_dev, "calibrated calibrated tmr=%d against system tmr=%d, tickper=%d (result: %d)\n", tmr, sim_calb_tmr, ticksper, rtc_currd[tmr]); sim_debug (DBG_CAL, &sim_timer_dev, "calibrated calibrated tmr=%d against system tmr=%d, tickper=%d (result: %d)\n", tmr, sim_calb_tmr, ticksper, rtc_currd[tmr]);
@ -1048,12 +1046,23 @@ fprintf (st, "Minimum Host Sleep Time: %d ms (%dHz)\n", sim_os_sleep_min_m
if (sim_os_sleep_min_ms != sim_os_sleep_inc_ms) if (sim_os_sleep_min_ms != sim_os_sleep_inc_ms)
fprintf (st, "Minimum Host Sleep Incr Time: %d ms\n", sim_os_sleep_inc_ms); fprintf (st, "Minimum Host Sleep Incr Time: %d ms\n", sim_os_sleep_inc_ms);
fprintf (st, "Host Clock Resolution: %d ms\n", sim_os_clock_resoluton_ms); fprintf (st, "Host Clock Resolution: %d ms\n", sim_os_clock_resoluton_ms);
if (sim_idle_enab)
fprintf (st, "Time before Idling starts: %d seconds\n", sim_idle_stable);
fprintf (st, "Execution Rate: %.0f instructions/sec\n", inst_per_sec); fprintf (st, "Execution Rate: %.0f instructions/sec\n", inst_per_sec);
if (sim_idle_enab) {
fprintf (st, "Idling: Enabled\n");
fprintf (st, "Time before Idling starts: %d seconds\n", sim_idle_stable);
}
if (sim_throt_type != SIM_THROT_NONE) {
sim_show_throt (st, NULL, uptr, val, desc);
}
fprintf (st, "Calibrated Timer: %s\n", (calb_tmr == -1) ? "Undetermined" : fprintf (st, "Calibrated Timer: %s\n", (calb_tmr == -1) ? "Undetermined" :
((calb_tmr == SIM_NTIMERS) ? "Internal Timer" : ((calb_tmr == SIM_NTIMERS) ? "Internal Timer" :
(sim_clock_unit[calb_tmr] ? sim_uname(sim_clock_unit[calb_tmr]) : ""))); (sim_clock_unit[calb_tmr] ? sim_uname(sim_clock_unit[calb_tmr]) : "")));
if (calb_tmr == SIM_NTIMERS)
fprintf (st, "Catchup Ticks: %s for clocks ticking faster than %d Hz\n", sim_catchup_ticks ? "Enabled" : "Disabled", sim_os_tick_hz);
if (sim_idle_calib_pct == 0)
fprintf (st, "Calibration: Always\n");
else
fprintf (st, "Calibration: Skipped when Idle exceeds %d%%\n", sim_idle_calib_pct);
fprintf (st, "\n"); fprintf (st, "\n");
for (tmr=clocks=0; tmr<=SIM_NTIMERS; ++tmr) { for (tmr=clocks=0; tmr<=SIM_NTIMERS; ++tmr) {
if (0 == rtc_initd[tmr]) if (0 == rtc_initd[tmr])
@ -1187,13 +1196,6 @@ pthread_mutex_unlock (&sim_timer_lock);
return SCPE_OK; return SCPE_OK;
} }
t_stat sim_timer_show_idle_mode (FILE* st, UNIT* uptr, int32 val, CONST void * desc)
{
if (sim_throt_type != SIM_THROT_NONE)
return sim_show_throt (st, NULL, uptr, val, desc);
return sim_show_idle (st, uptr, val, desc);
}
REG sim_timer_reg[] = { REG sim_timer_reg[] = {
{ NULL } { NULL }
}; };
@ -1211,19 +1213,18 @@ REG sim_throttle_reg[] = {
/* Clear, Set and show catchup */ /* Clear, Set and show catchup */
/* Clear catchup */ /* Set/Clear catchup */
t_stat sim_timer_clr_catchup (UNIT *uptr, int32 val, CONST char *cptr, void *desc) t_stat sim_timer_set_catchup (int32 flag, CONST char *cptr)
{
if (sim_catchup_ticks)
sim_catchup_ticks = FALSE;
return SCPE_OK;
}
t_stat sim_timer_set_catchup (UNIT *uptr, int32 val, CONST char *cptr, void *desc)
{ {
if (flag) {
if (!sim_catchup_ticks) if (!sim_catchup_ticks)
sim_catchup_ticks = TRUE; sim_catchup_ticks = TRUE;
}
else {
if (sim_catchup_ticks)
sim_catchup_ticks = FALSE;
}
return SCPE_OK; return SCPE_OK;
} }
@ -1233,9 +1234,9 @@ fprintf (st, "Calibrated Ticks%s", sim_catchup_ticks ? " with Catchup Ticks" : "
return SCPE_OK; return SCPE_OK;
} }
/* Set and show idle calibration threshold */ /* Set idle calibration threshold */
t_stat sim_timer_set_idle_pct (UNIT *uptr, int32 val, CONST char *cptr, void *desc) t_stat sim_timer_set_idle_pct (int32 flag, CONST char *cptr)
{ {
t_stat r; t_stat r;
int32 newpct; int32 newpct;
@ -1251,52 +1252,37 @@ sim_idle_calib_pct = (uint32)newpct;
return SCPE_OK; return SCPE_OK;
} }
t_stat sim_timer_show_idle_pct (FILE *st, UNIT *uptr, int32 val, CONST void *desc) /* Set/Clear asynch */
{
if (sim_idle_calib_pct == 0) t_stat sim_timer_set_async (int32 flag, CONST char *cptr)
fprintf (st, "Calibration Always");
else
fprintf (st, "Calibration Skipped when Idle exceeds %d%%", sim_idle_calib_pct);
return SCPE_OK;
}
/* Clear, Set and show asynch */
/* Clear asynch */
t_stat sim_timer_clr_async (UNIT *uptr, int32 val, CONST char *cptr, void *desc)
{
if (sim_asynch_timer) {
sim_asynch_timer = FALSE;
sim_timer_change_asynch ();
}
return SCPE_OK;
}
t_stat sim_timer_set_async (UNIT *uptr, int32 val, CONST char *cptr, void *desc)
{ {
if (flag) {
if (sim_asynch_enabled && (!sim_asynch_timer)) { if (sim_asynch_enabled && (!sim_asynch_timer)) {
sim_asynch_timer = TRUE; sim_asynch_timer = TRUE;
sim_timer_change_asynch (); sim_timer_change_asynch ();
} }
}
else {
if (sim_asynch_timer) {
sim_asynch_timer = FALSE;
sim_timer_change_asynch ();
}
}
return SCPE_OK; return SCPE_OK;
} }
t_stat sim_timer_show_async (FILE *st, UNIT *uptr, int32 val, CONST void *desc) static CTAB set_timer_tab[] = {
{ #if defined (SIM_ASYNCH_CLOCKS)
fprintf (st, "%s", sim_asynch_timer ? "Asynchronous" : "Synchronous"); { "ASYNCH", &sim_timer_set_async, 1 },
return SCPE_OK; { "NOASYNCH", &sim_timer_set_async, 0 },
} #endif
{ "CATCHUP", &sim_timer_set_catchup, 1 },
{ "NOCATCHUP", &sim_timer_set_catchup, 0 },
{ "CALIB", &sim_timer_set_idle_pct, 0 },
{ NULL, NULL, 0 }
};
MTAB sim_timer_mod[] = { MTAB sim_timer_mod[] = {
#if defined (SIM_ASYNCH_CLOCKS)
{ MTAB_VDV, MTAB_VDV, "ASYNCH", "ASYNCH", &sim_timer_set_async, &sim_timer_show_async, NULL, "Enables/Displays Asynchronous Timer mode" },
{ MTAB_VDV, 0, NULL, "NOASYNCH", &sim_timer_clr_async, NULL, NULL, "Disables Asynchronous Timer operation" },
#endif
{ MTAB_VDV, MTAB_VDV, "CATCHUP", "CATCHUP", &sim_timer_set_catchup, &sim_timer_show_catchup, NULL, "Enables/Displays Clock Tick catchup mode" },
{ MTAB_VDV, 0, NULL, "NOCATCHUP", &sim_timer_clr_catchup, NULL, NULL, "Disables Clock Tick catchup mode" },
{ MTAB_VDV|MTAB_VALR, 0, "CALIB", "CALIB=nn", &sim_timer_set_idle_pct, &sim_timer_show_idle_pct, NULL, "Configure/Display Calibration Idle Suppression %" },
{ MTAB_VDV, 0, "IDLE", NULL, NULL, &sim_timer_show_idle_mode, NULL, "Display Idle/Throttle mode" },
{ 0 }, { 0 },
}; };
@ -1312,6 +1298,31 @@ DEVICE sim_throttle_dev = {
"THROT-TLE", &sim_throttle_unit, sim_throttle_reg, NULL, 1}; "THROT-TLE", &sim_throttle_unit, sim_throttle_reg, NULL, 1};
/* SET CLOCK command */
t_stat sim_set_timers (int32 arg, CONST char *cptr)
{
char *cvptr, gbuf[CBUFSIZE];
CTAB *ctptr;
t_stat r;
if ((cptr == NULL) || (*cptr == 0))
return SCPE_2FARG;
while (*cptr != 0) { /* do all mods */
cptr = get_glyph_nc (cptr, gbuf, ','); /* get modifier */
if ((cvptr = strchr (gbuf, '='))) /* = value? */
*cvptr++ = 0;
get_glyph (gbuf, gbuf, 0); /* modifier to UC */
if ((ctptr = find_ctab (set_timer_tab, gbuf))) { /* match? */
r = ctptr->action (ctptr->arg, cvptr); /* do the rest */
if (r != SCPE_OK)
return r;
}
else return SCPE_NOPARAM;
}
return SCPE_OK;
}
/* sim_idle - idle simulator until next event or for specified interval /* sim_idle - idle simulator until next event or for specified interval
Inputs: Inputs:
@ -1390,8 +1401,16 @@ if ((sim_idle_rate_ms == 0) || (cyc_ms == 0)) { /* not possible? */
return FALSE; return FALSE;
} }
w_ms = (uint32) sim_interval / cyc_ms; /* ms to wait */ w_ms = (uint32) sim_interval / cyc_ms; /* ms to wait */
w_idle = (w_ms * 1000) / sim_idle_rate_ms; /* intervals to wait * 1000 */ /* When the host system has a clock tick which is less frequent than the */
if (w_idle < 500) { /* shorter than 1/2 a minimum sleep? */ /* simulated system's clock, idling will cause delays which will miss */
/* simulated clock ticks. To accomodate this, and still allow idling, if */
/* 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[tmr])
w_idle = (sim_interval * 1000) / rtc_currd[tmr]; /* 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? */
if (sin_cyc) if (sin_cyc)
sim_interval = sim_interval - 1; sim_interval = sim_interval - 1;
sim_debug (DBG_IDL, &sim_timer_dev, "no wait\n"); sim_debug (DBG_IDL, &sim_timer_dev, "no wait\n");
@ -1524,34 +1543,34 @@ return SCPE_OK;
t_stat sim_show_throt (FILE *st, DEVICE *dnotused, UNIT *unotused, int32 flag, CONST char *cptr) t_stat sim_show_throt (FILE *st, DEVICE *dnotused, UNIT *unotused, int32 flag, CONST char *cptr)
{ {
if (sim_idle_rate_ms == 0) if (sim_idle_rate_ms == 0)
fprintf (st, "Throttling not available\n"); fprintf (st, "Throttling: Not Available\n");
else { else {
switch (sim_throt_type) { switch (sim_throt_type) {
case SIM_THROT_MCYC: case SIM_THROT_MCYC:
fprintf (st, "Throttle = %d megacycles\n", sim_throt_val); fprintf (st, "Throttle: %d megacycles\n", sim_throt_val);
if (sim_throt_wait) if (sim_throt_wait)
fprintf (st, "Throttling achieved by sleeping for %d ms every %d cycles\n", sim_throt_sleep_time, sim_throt_wait); fprintf (st, "Throttling by sleeping for: %d ms every %d cycles\n", sim_throt_sleep_time, sim_throt_wait);
break; break;
case SIM_THROT_KCYC: case SIM_THROT_KCYC:
fprintf (st, "Throttle = %d kilocycles\n", sim_throt_val); fprintf (st, "Throttle: %d kilocycles\n", sim_throt_val);
if (sim_throt_wait) if (sim_throt_wait)
fprintf (st, "Throttling achieved by sleeping for %d ms every %d cycles\n", sim_throt_sleep_time, sim_throt_wait); fprintf (st, "Throttling by sleeping for: %d ms every %d cycles\n", sim_throt_sleep_time, sim_throt_wait);
break; break;
case SIM_THROT_PCT: case SIM_THROT_PCT:
fprintf (st, "Throttle = %d%%\n", sim_throt_val); fprintf (st, "Throttle: %d%%\n", sim_throt_val);
if (sim_throt_wait) if (sim_throt_wait)
fprintf (st, "Throttling achieved by sleeping for %d ms every %d cycles\n", sim_throt_sleep_time, sim_throt_wait); fprintf (st, "Throttling by sleeping for: %d ms every %d cycles\n", sim_throt_sleep_time, sim_throt_wait);
break; break;
case SIM_THROT_SPC: case SIM_THROT_SPC:
fprintf (st, "Throttle = %d ms every %d cycles\n", sim_throt_sleep_time, sim_throt_val); fprintf (st, "Throttle: sleep %d ms every %d cycles\n", sim_throt_sleep_time, sim_throt_val);
break; break;
default: default:
fprintf (st, "Throttling disabled\n"); fprintf (st, "Throttling: Disabled\n");
break; break;
} }
} }
@ -1736,11 +1755,6 @@ clock_gettime (CLOCK_REALTIME, now);
* We accomodate these problems and make up for lost ticks by injecting * We accomodate these problems and make up for lost ticks by injecting
* catch-up ticks to the simulator. * catch-up ticks to the simulator.
* *
* We avoid excessive co-scheduled polling during these catch-up ticks
* to minimize what is likely excessive overhead, thus 'coschedule
* polling' only occurs on every fourth clock tick when processing
* catch-up ticks.
*
* When necessary, catch-up ticks are scheduled to run under one * When necessary, catch-up ticks are scheduled to run under one
* of two conditions: * of two conditions:
* 1) after indicated number of instructions in a call by the simulator * 1) after indicated number of instructions in a call by the simulator
@ -1748,6 +1762,9 @@ clock_gettime (CLOCK_REALTIME, now);
* mechanism to inform the simh timer facilities when the simulated * mechanism to inform the simh timer facilities when the simulated
* system has accepted the most recent clock tick interrupt. * system has accepted the most recent clock tick interrupt.
* 2) immediately when the simulator calls sim_idle * 2) immediately when the simulator calls sim_idle
*
* catchup ticks are only scheduled (eligible to happen) under these
* conditions after at least one tick has been acknowledged.
*/ */
/* _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
@ -1767,7 +1784,9 @@ if ((!sim_catchup_ticks) ||
((tmr < 0) || (tmr >= SIM_NTIMERS))) ((tmr < 0) || (tmr >= SIM_NTIMERS)))
return FALSE; return FALSE;
tnow = sim_timenow_double(); tnow = sim_timenow_double();
if (!rtc_clock_catchup_eligible[tmr]) { if ((rtc_hz[tmr] > sim_os_tick_hz) && /* faster than host tick */
(!rtc_clock_catchup_eligible[tmr]) && /* not eligible yet? */
(time != -1)) { /* called from ack? */
rtc_clock_catchup_base_time[tmr] = tnow; rtc_clock_catchup_base_time[tmr] = tnow;
rtc_clock_ticks_tot[tmr] += rtc_clock_ticks[tmr]; rtc_clock_ticks_tot[tmr] += rtc_clock_ticks[tmr];
rtc_clock_ticks[tmr] = 0; rtc_clock_ticks[tmr] = 0;
@ -1785,18 +1804,18 @@ if (rtc_clock_catchup_eligible[tmr] &&
(tnow > (rtc_clock_catchup_base_time[tmr] + (rtc_calib_tick_time[tmr] + rtc_clock_tick_size[tmr])))) { (tnow > (rtc_clock_catchup_base_time[tmr] + (rtc_calib_tick_time[tmr] + rtc_clock_tick_size[tmr])))) {
sim_debug (DBG_QUE, &sim_timer_dev, "_rtcn_tick_catchup_check(%d) - scheduling catchup tick for %s which is behind %s\n", time, sim_uname (sim_clock_unit[tmr]), sim_fmt_secs (tnow > (rtc_clock_catchup_base_time[tmr] + (rtc_calib_tick_time[tmr] + rtc_clock_tick_size[tmr])))); sim_debug (DBG_QUE, &sim_timer_dev, "_rtcn_tick_catchup_check(%d) - scheduling catchup tick for %s which is behind %s\n", time, sim_uname (sim_clock_unit[tmr]), sim_fmt_secs (tnow > (rtc_clock_catchup_base_time[tmr] + (rtc_calib_tick_time[tmr] + rtc_clock_tick_size[tmr]))));
rtc_clock_catchup_pending[tmr] = TRUE; rtc_clock_catchup_pending[tmr] = TRUE;
sim_activate_abs (&sim_timer_units[tmr], time); sim_activate_abs (&sim_timer_units[tmr], (time < 0) ? 0 : time);
return TRUE; return TRUE;
} }
return FALSE; return FALSE;
} }
t_stat sim_rtcn_tick_ack (int32 time, int32 tmr) t_stat sim_rtcn_tick_ack (uint32 time, int32 tmr)
{ {
if ((tmr < 0) || (tmr >= SIM_NTIMERS)) if ((tmr < 0) || (tmr >= SIM_NTIMERS))
return SCPE_TIMER; return SCPE_TIMER;
sim_debug (DBG_ACK, &sim_timer_dev, "sim_rtcn_tick_ack - for %s\n", sim_uname (sim_clock_unit[tmr])); sim_debug (DBG_ACK, &sim_timer_dev, "sim_rtcn_tick_ack - for %s\n", sim_uname (sim_clock_unit[tmr]));
_rtcn_tick_catchup_check (tmr, time); _rtcn_tick_catchup_check (tmr, (int32)time);
++rtc_calib_ticks_acked[tmr]; ++rtc_calib_ticks_acked[tmr];
return SCPE_OK; return SCPE_OK;
} }

View file

@ -106,11 +106,12 @@ double sim_timenow_double (void);
int32 sim_rtcn_init (int32 time, int32 tmr); int32 sim_rtcn_init (int32 time, int32 tmr);
int32 sim_rtcn_init_unit (UNIT *uptr, int32 time, int32 tmr); int32 sim_rtcn_init_unit (UNIT *uptr, int32 time, int32 tmr);
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 (int32 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 (int32 ticksper, int32 tmr);
int32 sim_rtc_init (int32 time); int32 sim_rtc_init (int32 time);
int32 sim_rtc_calb (int32 ticksper); int32 sim_rtc_calb (int32 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_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);
t_bool sim_idle (uint32 tmr, t_bool sin_cyc); t_bool sim_idle (uint32 tmr, t_bool sin_cyc);