From 5fdc1e6d0fdc1d8da9352b53572f7f7f1fe7e951 Mon Sep 17 00:00:00 2001 From: Mark Pizzolato Date: Mon, 8 Oct 2018 20:55:01 -0700 Subject: [PATCH] SCP: Add more clock adjustments while idling --- scp.c | 5 +++-- sim_timer.c | 33 +++++++++++++++++++++++++++++---- 2 files changed, 32 insertions(+), 6 deletions(-) diff --git a/scp.c b/scp.c index 8571919c..041f2cea 100644 --- a/scp.c +++ b/scp.c @@ -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 }, diff --git a/sim_timer.c b/sim_timer.c index 500326d3..7793639d 100644 --- a/sim_timer.c +++ b/sim_timer.c @@ -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