SCP: Add more clock adjustments while idling

This commit is contained in:
Mark Pizzolato 2018-10-08 20:55:01 -07:00
parent 6a3424df86
commit 5fdc1e6d0f
2 changed files with 32 additions and 6 deletions

5
scp.c
View file

@ -1266,7 +1266,7 @@ static const char simh_help[] =
" running in the simulator is doing nothing, and runs the simulator at full\n"
" speed when there is work to do. Throttling and idling are mutually\n"
" exclusive.\n"
#define HLP_SET_CLOCKS "*Commands SET Clocks"
#define HLP_SET_CLOCK "*Commands SET Clock"
"3Clock\n"
#if defined (SIM_ASYNCH_CLOCKS)
"+SET CLOCK asynch enable asynchronous clocks\n"
@ -1275,6 +1275,7 @@ static const char simh_help[] =
"+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"
"+SET CLOCK calib=ALWAYS specify calibration independent of idle\n"
"+SET CLOCK stop=n stop execution after n instructions\n\n"
" The SET CLOCK STOP command allows execution to have a bound when\n"
" execution starts with a BOOT, NEXT or CONTINUE command.\n"
@ -2313,7 +2314,7 @@ static CTAB set_glob_tab[] = {
{ "NODEBUG", &sim_set_deboff, 0, HLP_SET_DEBUG },
{ "THROTTLE", &sim_set_throt, 1, HLP_SET_THROTTLE },
{ "NOTHROTTLE", &sim_set_throt, 0, HLP_SET_THROTTLE },
{ "CLOCKS", &sim_set_timers, 1, HLP_SET_CLOCKS },
{ "CLOCKS", &sim_set_timers, 1, HLP_SET_CLOCK },
{ "ASYNCH", &sim_set_asynch, 1, HLP_SET_ASYNCH },
{ "NOASYNCH", &sim_set_asynch, 0, HLP_SET_ASYNCH },
{ "ENVIRONMENT", &sim_set_environment, 1, HLP_SET_ENVIRON },

View file

@ -773,6 +773,8 @@ static uint32 rtc_clock_calib_skip_idle[SIM_NTIMERS+1] = { 0 };/* Calibrations s
static uint32 rtc_clock_calib_gap2big[SIM_NTIMERS+1] = { 0 };/* Calibrations skipped Gap Too Big */
static uint32 rtc_clock_calib_backwards[SIM_NTIMERS+1] = { 0 };/* Calibrations skipped Clock Running Backwards */
static uint32 sim_idle_cyc_ms = 0; /* Cycles per millisecond while not idling */
static uint32 sim_idle_cyc_sleep = 0; /* Cycles per minimum sleep interval */
static double sim_idle_end_time = 0.0; /* Time when last idle completed */
UNIT sim_timer_units[SIM_NTIMERS+1]; /* Clock assist units */
/* one for each timer and one for an internal */
@ -979,8 +981,11 @@ if (last_idle_pct > (100 - sim_idle_calib_pct)) {
return rtc_currd[tmr]; /* avoid calibrating idle checks */
}
new_gtime = sim_gtime();
if ((last_idle_pct == 0) && (delta_rtime != 0))
if ((last_idle_pct == 0) && (delta_rtime != 0)) {
sim_idle_cyc_ms = (uint32)((new_gtime - rtc_gtime[tmr]) / delta_rtime);
if ((sim_idle_rate_ms != 0) && (delta_rtime > 1))
sim_idle_cyc_sleep = (uint32)((new_gtime - rtc_gtime[tmr]) / (delta_rtime / sim_idle_rate_ms));
}
if (sim_asynch_timer) {
/* An asynchronous clock, merely needs to divide the number of */
/* instructions actually executed by the clock rate. */
@ -1279,6 +1284,7 @@ return SCPE_OK;
REG sim_timer_reg[] = {
{ DRDATAD (IDLE_CYC_MS, sim_idle_cyc_ms, 32, "Cycles Per Millisecond"), PV_RSPC|REG_RO},
{ DRDATAD (IDLE_CYC_SLEEP, sim_idle_cyc_sleep, 32, "Cycles Per Minimum Sleep"), PV_RSPC|REG_RO},
{ DRDATAD (IDLE_STABLE, sim_idle_stable, 32, "IDLE stability delay"), PV_RSPC},
{ DRDATAD (ROM_DELAY, sim_rom_delay, 32, "ROM memory reference delay"), PV_RSPC|REG_RO},
{ DRDATAD (TICK_RATE_0, rtc_hz[0], 32, "Timer 0 Ticks Per Second") },
@ -1342,12 +1348,21 @@ return SCPE_OK;
t_stat sim_timer_set_idle_pct (int32 flag, CONST char *cptr)
{
t_stat r;
t_stat r = SCPE_OK;
int32 newpct;
char gbuf[CBUFSIZE];
if (cptr == NULL)
return SCPE_ARG;
newpct = (int32) get_uint (cptr, 10, 100, &r);
cptr = get_glyph_nc (cptr, gbuf, 0); /* get argument */
if (isdigit (gbuf[0]))
newpct = (int32) get_uint (cptr, 10, 100, &r);
else {
if (MATCH_CMD (gbuf, "ALWAYS") == 0)
newpct = 0;
else
r = SCPE_ARG;
}
if ((r != SCPE_OK) || (newpct == (int32)(sim_idle_calib_pct)))
return r;
if (newpct == 0)
@ -1504,6 +1519,7 @@ t_bool sim_idle (uint32 tmr, int sin_cyc)
uint32 w_ms, w_idle, act_ms;
int32 act_cyc;
static t_bool in_nowait = FALSE;
double cyc_since_idle;
if (rtc_clock_catchup_pending[tmr]) { /* Catchup clock tick pending? */
sim_debug (DBG_CAL, &sim_timer_dev, "sim_idle(tmr=%d, sin_cyc=%d) - accelerating pending catch-up tick before idling %s\n", tmr, sin_cyc, sim_uname (sim_clock_unit[tmr]));
@ -1553,8 +1569,11 @@ if (_rtcn_tick_catchup_check(tmr, 0)) {
means something, while not idling when it isn't enabled.
*/
sim_debug (DBG_TRC, &sim_timer_dev, "sim_idle(tmr=%d, sin_cyc=%d)\n", tmr, sin_cyc);
if (sim_idle_cyc_ms == 0)
if (sim_idle_cyc_ms == 0) {
sim_idle_cyc_ms = (rtc_currd[tmr] * rtc_hz[tmr]) / 1000;/* cycles per msec */
if (sim_idle_rate_ms != 0)
sim_idle_cyc_sleep = (rtc_currd[tmr] * rtc_hz[tmr]) / (1000 / sim_idle_rate_ms);/* cycles per sleep */
}
if ((sim_idle_rate_ms == 0) || (sim_idle_cyc_ms == 0)) {/* not possible? */
sim_interval -= sin_cyc;
sim_debug (DBG_IDL, &sim_timer_dev, "not possible idle_rate_ms=%d - cyc/ms=%d\n", sim_idle_rate_ms, sim_idle_cyc_ms);
@ -1582,10 +1601,16 @@ 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);
else
sim_debug (DBG_IDL, &sim_timer_dev, "sleeping for %d ms - pending event on %s in %d instructions\n", w_ms, sim_uname(sim_clock_queue), sim_interval);
cyc_since_idle = sim_gtime() - sim_idle_end_time; /* time since prior idle */
act_ms = sim_idle_ms_sleep (w_ms); /* wait */
rtc_clock_time_idled[tmr] += act_ms;
act_cyc = act_ms * sim_idle_cyc_ms;
if (cyc_since_idle > sim_idle_cyc_sleep)
act_cyc -= sim_idle_cyc_sleep / 2; /* account for half an interval's worth of cycles */
else
act_cyc -= (int32)cyc_since_idle; /* acount for cycles executed */
sim_interval = sim_interval - act_cyc; /* count down sim_interval to reflect idle period */
sim_idle_end_time = sim_gtime(); /* save idle completed time */
if (sim_clock_queue == QUEUE_LIST_END)
sim_debug (DBG_IDL, &sim_timer_dev, "slept for %d ms - pending event in %d instructions\n", act_ms, sim_interval);
else