mirror of
https://github.com/simh/simh.git
synced 2026-01-11 23:52:58 +00:00
TIMER: Cleanup Inconsistencies and Throttling and IDLE activities
- Make time at sim> prompt consistent when in nocalibrate mode. - Disable asynch operations when in nocalibrate mode so that all events occur consistently. - Make sure that all throttling modes produce consistent behavior related to all timing activities including clock ticks and TMXR port speed timing. - Expose all timer and throttling state variables via simh REGisters - Only allow throttling to start execution one time. Throttling can't be changed once instruction execution has started. - Clarification of SHOW CLOCK variable units - Avoid competing gratuitous keyboard polls with simulators - Properly enable catchup ticks - Fix second boot while idling - Improve calibration while idling - Report complete timer state when impossible timer conditions exist that will cause a simulator abort. - Leave memory 0 after pre-calibration instruction execution rate.
This commit is contained in:
parent
b404ccd050
commit
81e2719d90
233
sim_timer.c
233
sim_timer.c
@ -158,7 +158,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 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 */
|
||||
double sim_time_at_sim_prompt = 0; /* time spent processing commands from sim> prompt */
|
||||
double sim_time_at_sim_prompt = 0.0; /* time spent processing commands from sim> prompt */
|
||||
|
||||
static uint32 sim_idle_rate_ms = 0; /* Minimum Sleep time */
|
||||
static uint32 sim_os_sleep_min_ms = 0;
|
||||
@ -186,7 +186,7 @@ static uint32 sim_throt_delay = 3;
|
||||
static int32 sim_int_clk_tps;
|
||||
static t_bool sim_timer_calib_enabled = TRUE;
|
||||
static struct timespec sim_timer_uncalib_base_time = {0, 0};
|
||||
static t_bool sim_throttle_has_been_enabled = FALSE;
|
||||
static t_bool sim_throttle_has_been_active = FALSE;
|
||||
|
||||
typedef struct RTC {
|
||||
UNIT *clock_unit; /* registered ticking clock unit */
|
||||
@ -323,10 +323,10 @@ pthread_mutex_lock (&sim_asynch_lock);
|
||||
sim_idle_wait = TRUE;
|
||||
if (pthread_cond_timedwait (&sim_asynch_wake, &sim_asynch_lock, &end_time))
|
||||
timedout = TRUE;
|
||||
else
|
||||
sim_asynch_check = 0; /* force check of asynch queue now */
|
||||
sim_idle_wait = FALSE;
|
||||
pthread_mutex_unlock (&sim_asynch_lock);
|
||||
if (!timedout)
|
||||
sim_asynch_check = 0; /* force check of asynch queue now */
|
||||
clock_gettime(CLOCK_REALTIME, &done_time);
|
||||
if (!timedout) {
|
||||
AIO_UPDATE_QUEUE;
|
||||
@ -983,8 +983,8 @@ if (sim_calb_tmr != tmr) {
|
||||
}
|
||||
new_rtime = sim_os_msec (); /* wall time */
|
||||
if (!sim_signaled_int_char &&
|
||||
((new_rtime - sim_last_poll_kbd_time) > 500)) {
|
||||
sim_debug (DBG_CAL, &sim_timer_dev, "sim_rtcn_calb(tmr=%d) gratuitious keyboard poll after %d msecs\n", tmr, (int)(new_rtime - sim_last_poll_kbd_time));
|
||||
((new_rtime - sim_last_poll_kbd_time) > 1000)) {
|
||||
sim_debug (DBG_CAL, &sim_timer_dev, "sim_rtcn_calb(tmr=%d) gratuitous keyboard poll after %d msecs\n", tmr, (int)(new_rtime - sim_last_poll_kbd_time));
|
||||
(void)sim_poll_kbd ();
|
||||
}
|
||||
++rtc->calibrations; /* count calibrations */
|
||||
@ -1203,9 +1203,9 @@ if (sim_timer_calib_enabled) {
|
||||
fprintf (st, "Calibrated Timer: %s\n", (calb_tmr == -1) ? "Undetermined" :
|
||||
((calb_tmr == SIM_NTIMERS) ? "Internal Timer" :
|
||||
(rtcs[calb_tmr].clock_unit ? sim_uname(rtcs[calb_tmr].clock_unit) : "")));
|
||||
if (calb_tmr == SIM_NTIMERS)
|
||||
if (calb_tmr != SIM_NTIMERS)
|
||||
fprintf (st, "Catchup Ticks: %s\n", sim_catchup_ticks ? "Enabled" : "Disabled");
|
||||
fprintf (st, "Pre-Calibration Estimated Rate: %s\n", sim_fmt_numeric ((double)sim_precalibrate_ips));
|
||||
fprintf (st, "Pre-Calibration Estimated Rate: %s %s/sec\n", sim_fmt_numeric ((double)sim_precalibrate_ips), sim_vm_interval_units);
|
||||
if (sim_idle_calib_pct == 100)
|
||||
fprintf (st, "Calibration: Always\n");
|
||||
else
|
||||
@ -1302,16 +1302,29 @@ for (tmr=clocks=0; tmr<=SIM_NTIMERS; ++tmr) {
|
||||
if (rtc->clock_calib_gap2big)
|
||||
fprintf (st, " Calibs Skip Gap Too Big: %s\n", sim_fmt_numeric ((double)rtc->clock_calib_gap2big));
|
||||
}
|
||||
if (rtc->gtime)
|
||||
fprintf (st, " Instruction Time: %.0f\n", rtc->gtime);
|
||||
if ((!sim_asynch_timer) && (sim_throt_type == SIM_THROT_NONE)) {
|
||||
fprintf (st, " Real Time: %u\n", rtc->rtime);
|
||||
fprintf (st, " Virtual Time: %u\n", rtc->vtime);
|
||||
fprintf (st, " Next Interval: %s\n", sim_fmt_numeric ((double)rtc->nxintv));
|
||||
fprintf (st, " Base Tick Delay: %s\n", sim_fmt_numeric ((double)rtc->based));
|
||||
fprintf (st, " Initial Insts Per Tick: %s\n", sim_fmt_numeric ((double)rtc->initd));
|
||||
if (rtc->gtime) {
|
||||
if (strcmp (sim_vm_interval_units, "instructions") == 0)
|
||||
fprintf (st, " Instructions Since Init: %s\n", sim_fmt_numeric (rtc->gtime));
|
||||
else
|
||||
fprintf (st, " Cycles Since Init: %s\n", sim_fmt_numeric (rtc->gtime));
|
||||
}
|
||||
fprintf (st, " Current Insts Per Tick: %s\n", sim_fmt_numeric ((double)rtc->currd));
|
||||
if ((!sim_asynch_timer) && (sim_throt_type == SIM_THROT_NONE)) {
|
||||
fprintf (st, " Host Real Time: %s msecs\n", sim_fmt_numeric ((double)rtc->rtime));
|
||||
fprintf (st, " Simulated Virtual Time: %s msecs\n", sim_fmt_numeric ((double)rtc->vtime));
|
||||
fprintf (st, " Next Calibration Interval: %s msecs\n", sim_fmt_numeric ((double)rtc->nxintv));
|
||||
if (strcmp (sim_vm_interval_units, "instructions") == 0) {
|
||||
fprintf (st, " Previous Insts Per Tick: %s\n", sim_fmt_numeric ((double)rtc->based));
|
||||
fprintf (st, " Initial Insts Per Tick: %s\n", sim_fmt_numeric ((double)rtc->initd));
|
||||
}
|
||||
else {
|
||||
fprintf (st, " Previous Cycles Per Tick: %s\n", sim_fmt_numeric ((double)rtc->based));
|
||||
fprintf (st, " Initial Cycles Per Tick: %s\n", sim_fmt_numeric ((double)rtc->initd));
|
||||
}
|
||||
}
|
||||
if (strcmp (sim_vm_interval_units, "instructions") == 0)
|
||||
fprintf (st, " Current Insts Per Tick: %s\n", sim_fmt_numeric ((double)rtc->currd));
|
||||
else
|
||||
fprintf (st, " Current Cycles Per Tick: %s\n", sim_fmt_numeric ((double)rtc->currd));
|
||||
fprintf (st, " Initializations: %d\n", rtc->calib_initializations);
|
||||
fprintf (st, " Ticks: %s\n", sim_fmt_numeric ((double)(rtc->clock_ticks)));
|
||||
if (rtc->clock_ticks_tot+rtc->clock_ticks != rtc->clock_ticks)
|
||||
@ -1431,7 +1444,17 @@ 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},
|
||||
{ DBRDATAD (IDLE_END_TIME, sim_idle_end_time, "Time when last idle completed") },
|
||||
{ DRDATAD (IDLE_STABLE, sim_idle_stable, 32, "IDLE stability delay"), PV_RSPC},
|
||||
{ FLDATAD (IDLE_ENABLED, sim_idle_enab, 0, "Idle Enabled"), REG_RO},
|
||||
{ DRDATAD (IDLE_MIN_SLEEP, sim_idle_rate_ms, 32, "Idle Minimum Sleep Time"), PV_RSPC|REG_RO},
|
||||
{ DRDATAD (IDLE_STABLE_TIME, sim_idle_stable, 32, "Idle Skip before Stability Seconds"), PV_RSPC|REG_RO},
|
||||
{ DRDATAD (IDLE_SKIP_CAL_PCT,sim_idle_calib_pct, 32, "Idle Skip Calibration Percentage"), PV_RSPC|REG_RO},
|
||||
{ DBRDATAD (TIMER_STOP_TIME, sim_timer_stop_time, "Execution Stop Time") },
|
||||
{ DRDATAD (OS_SLEEP_MIN_MS, sim_os_sleep_min_ms, 32, "Minimum Host Sleep Time"), PV_RSPC|REG_RO},
|
||||
{ DRDATAD (OS_SLEEP_INC_MS, sim_os_sleep_inc_ms, 32, "Minimum Host Sleep Increment Time"), PV_RSPC|REG_RO},
|
||||
{ DRDATAD (OS_CLOCK_RES_MS, sim_os_clock_resoluton_ms, 32, "Host Clock Resolution"), PV_RSPC|REG_RO},
|
||||
{ DRDATAD (OS_TICK_HZ, sim_os_tick_hz, 32, "OS Tick Rate (HZ)"), PV_RSPC|REG_RO},
|
||||
{ DRDATAD (ROM_DELAY, sim_rom_delay, 32, "ROM memory reference delay"), PV_RSPC|REG_RO},
|
||||
{ DRDATAD (TICK_RATE_0, rtcs[0].hz, 32, "Timer 0 Ticks Per Second") },
|
||||
{ DRDATAD (TICK_SIZE_0, rtcs[0].currd, 32, "Timer 0 Tick Size") },
|
||||
@ -1451,6 +1474,18 @@ REG sim_timer_reg[] = {
|
||||
{ DRDATAD (TICK_SIZE_7, rtcs[7].currd, 32, "Timer 7 Tick Size") },
|
||||
{ DRDATAD (INTERNAL_TICK_RATE,sim_int_clk_tps, 32, "Internal Timer Ticks Per Second") },
|
||||
{ DRDATAD (INTERNAL_TICK_SIZE,rtcs[SIM_NTIMERS].currd,32, "Internal Timer Tick Size") },
|
||||
{ DRDATAD (CALIB_TIMR, sim_calb_tmr, 32, "System Calibrated Timer"), PV_RSPC|REG_RO},
|
||||
{ DRDATAD (CALIB_TIMR_LAST, sim_calb_tmr_last, 32, "Previous Calibrated Timer before sim>"), PV_RSPC|REG_RO},
|
||||
{ DBRDATAD (INST_PER_SEC_LAST,sim_inst_per_sec_last, "Previous Instructions Per Sec before sim>") },
|
||||
{ DRDATAD (STOP_TIME, sim_stop_time, 32, "Time when siminst() exited"), PV_RSPC|REG_RO},
|
||||
{ DBRDATAD (SIM_PROMPT_TIME, sim_time_at_sim_prompt, "time spent processing commands from sim> prompt") },
|
||||
{ DRDATAD (VM_INITIAL_IPS, sim_vm_initial_ips, 32, "Initial Instructions Per Second"), PV_RSPC|REG_RO},
|
||||
{ DRDATAD (PRECALIBRATE_IPS, sim_precalibrate_ips, 32, "Precalibrate Instructions Per Second"), PV_RSPC|REG_RO},
|
||||
{ DRDATAD (INTER_CLK_TPS, sim_int_clk_tps, 32, "Internal Clock Ticks Per Second") },
|
||||
{ FLDATAD (TIMER_CALIB_ENABLED, sim_timer_calib_enabled, 0, "Timer Calibration Enabled"), },
|
||||
{ FLDATAD (THROT_WAS_ACTIVE, sim_throttle_has_been_active, 0, "Throttle has been Active"), },
|
||||
{ FLDATAD (CATCHUP_TICKS, sim_catchup_ticks, 0, "Catchup Ticks Enabled"), REG_RO},
|
||||
{ FLDATAD (ASYNC_TIMER, sim_asynch_timer, 0, "Asynchronous Clocks Enabled"), REG_RO},
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
@ -1462,6 +1497,9 @@ REG sim_throttle_reg[] = {
|
||||
{ DRDATAD (THROT_STATE, sim_throt_state, 32, "Throttle state"), PV_RSPC|REG_RO},
|
||||
{ DRDATAD (THROT_SLEEP_TIME, sim_throt_sleep_time, 32, "Throttle sleep time"), PV_RSPC|REG_RO},
|
||||
{ DRDATAD (THROT_WAIT, sim_throt_wait, 32, "Throttle execution interval before sleep"), PV_RSPC|REG_RO},
|
||||
{ DBRDATAD (THROT_CPS, sim_throt_cps, "Desired throttling Cycles per second") },
|
||||
{ DBRDATAD (THROT_PEAK_CPS, sim_throt_peak_cps, "Peak cycles per second rate") },
|
||||
{ DBRDATAD (THROT_START_TIME,sim_throt_inst_start, "Time when actual throttling started") },
|
||||
{ DRDATAD (THROT_DELAY, sim_throt_delay, 32, "Seconds before throttling starts"), PV_RSPC},
|
||||
{ DRDATAD (THROT_DRIFT_PCT, sim_throt_drift_pct, 32, "Percent of throttle drift before correction"), PV_RSPC},
|
||||
{ NULL }
|
||||
@ -1537,7 +1575,11 @@ if ((cptr == NULL) || (*cptr == '\0')) {
|
||||
if (sim_timer_uncalib_base_time.tv_sec == 0)
|
||||
sim_rtcn_get_time (&sim_timer_uncalib_base_time, 0);
|
||||
sim_timer_calib_enabled = FALSE;
|
||||
sim_time_at_sim_prompt = 0.0;
|
||||
sim_reset_time ();
|
||||
reset_all_p (0);
|
||||
sim_stop_time = sim_os_msec ();
|
||||
set_cmd (0, "NOASYNC");
|
||||
return sim_messagef (SCPE_OK, "calibration disabled running at %s %s per pseudo second\n",
|
||||
sim_fmt_numeric ((double)sim_precalibrate_ips), sim_vm_interval_units);
|
||||
}
|
||||
@ -1557,6 +1599,7 @@ sim_timer_set_async (0, NULL);
|
||||
if (sim_timer_uncalib_base_time.tv_sec == 0)
|
||||
sim_rtcn_get_time (&sim_timer_uncalib_base_time, 0);
|
||||
sim_timer_calib_enabled = FALSE;
|
||||
sim_time_at_sim_prompt = 0.0;
|
||||
sim_reset_time ();
|
||||
sim_precalibrate_ips = (uint32)(val * units);
|
||||
for (tmr=clocks=0; tmr<=SIM_NTIMERS; ++tmr) {
|
||||
@ -1568,6 +1611,8 @@ for (tmr=clocks=0; tmr<=SIM_NTIMERS; ++tmr) {
|
||||
rtc->initd = rtc->based = rtc->currd = sim_precalibrate_ips / rtc->last_hz;
|
||||
}
|
||||
reset_all_p (0);
|
||||
sim_stop_time = sim_os_msec ();
|
||||
set_cmd (0, "NOASYNC");
|
||||
return sim_messagef (SCPE_OK, "calibration disabled running at %s %s per pseudo second\n",
|
||||
sim_fmt_numeric ((double)sim_precalibrate_ips), sim_vm_interval_units);
|
||||
}
|
||||
@ -1841,12 +1886,14 @@ else
|
||||
if ((w_idle < 500) || (w_ms == 0)) { /* shorter than 1/2 the interval or */
|
||||
sim_interval -= sin_cyc; /* minimal sleep time? */
|
||||
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 msecs\n", w_idle);
|
||||
in_nowait = TRUE;
|
||||
return FALSE;
|
||||
}
|
||||
if (w_ms > 1000) { /* too long a wait (runaway calibration) */
|
||||
sim_printf ("sim_idle() - 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_printf ("sim_idle() - waiting too long: w_ms=%d msecs, w_idle=%d msecs, sim_interval=%d, rtc->currd=%d, sim_idle_cyc_ms=%d\n", w_ms, w_idle, sim_interval, rtc->currd, sim_idle_cyc_ms);
|
||||
exdep_cmd (EX_E, "INT-CLOCK STATE");
|
||||
sim_show_timers (stdout, NULL, NULL, 0, "");
|
||||
SIM_SCP_ABORT ("sim_idle() - waiting too long");
|
||||
}
|
||||
in_nowait = FALSE;
|
||||
@ -1854,14 +1901,15 @@ if (sim_clock_queue == QUEUE_LIST_END)
|
||||
sim_debug (DBG_IDL, &sim_timer_dev, "sleeping for %d ms - pending event in %d %s\n", w_ms, sim_interval, sim_vm_interval_units);
|
||||
else
|
||||
sim_debug (DBG_IDL, &sim_timer_dev, "sleeping for %d ms - pending event on %s in %d %s\n", w_ms, sim_uname(sim_clock_queue), sim_interval, sim_vm_interval_units);
|
||||
cyc_since_idle = sim_gtime() - sim_idle_end_time; /* time since prior idle */
|
||||
cyc_since_idle = sim_gtime() - sim_idle_end_time; /* time since prior idle completed */
|
||||
act_ms = sim_idle_ms_sleep (w_ms); /* wait */
|
||||
rtc->clock_time_idled += 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 */
|
||||
act_cyc = act_ms * sim_idle_cyc_ms; /* Total potential cycles executed while sleeping */
|
||||
/* In general, sleeps will end at the boundary of host OS ticks */
|
||||
if (cyc_since_idle > sim_idle_cyc_sleep) /* executed more than a sleep interval's cycles */
|
||||
act_cyc -= sim_idle_cyc_sleep / 2; /* adjust for half a sleep interval's worth of cycles */
|
||||
else
|
||||
act_cyc -= (int32)cyc_since_idle; /* acount for cycles executed */
|
||||
act_cyc -= (int32)cyc_since_idle; /* adjust 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)
|
||||
@ -1923,50 +1971,75 @@ CONST char *tptr;
|
||||
char c;
|
||||
uint32 saved_throt_type = sim_throt_type;
|
||||
t_value val, val2 = 0;
|
||||
double d_cps = 0.0;
|
||||
|
||||
if (arg == 0) {
|
||||
if ((cptr != NULL) && (*cptr != 0))
|
||||
return sim_messagef (SCPE_ARG, "Unexpected NOTHROTTLE argument: %s\n", cptr);
|
||||
sim_throt_type = SIM_THROT_NONE;
|
||||
sim_throt_cancel ();
|
||||
return SCPE_OK;
|
||||
}
|
||||
else if (sim_timer_calib_enabled == FALSE) {
|
||||
if (sim_timer_calib_enabled == FALSE)
|
||||
return sim_messagef (SCPE_NOFNC, "Throttling is not available when calibration is disabled\n");
|
||||
}
|
||||
else if (sim_idle_rate_ms == 0) {
|
||||
if (sim_idle_rate_ms == 0)
|
||||
return sim_messagef (SCPE_NOFNC, "Throttling is not available, Minimum OS sleep time is %dms\n", sim_os_sleep_min_ms);
|
||||
if (*cptr == '\0')
|
||||
return sim_messagef (SCPE_ARG, "Missing throttle mode specification\n");
|
||||
val = strtotv (cptr, &tptr, 10);
|
||||
if (cptr == tptr)
|
||||
return sim_messagef (SCPE_ARG, "Invalid throttle specification: %s\n", cptr);
|
||||
sim_throt_sleep_time = sim_idle_rate_ms;
|
||||
c = (char)toupper (*tptr++);
|
||||
if (c == '/') {
|
||||
if (val == 0)
|
||||
return sim_messagef (SCPE_ARG, "Invalid %s count specifier: %s\n", cptr, sim_vm_interval_units);
|
||||
val2 = strtotv (tptr, &tptr, 10);
|
||||
if (val2 == 0)
|
||||
return sim_messagef (SCPE_ARG, "Invalid throttle delay specifier: %s\n", cptr);
|
||||
if ((*tptr != '\0') && (*tptr != '='))
|
||||
return sim_messagef (SCPE_ARG, "Invalid throttle delay specifier: %s\n", cptr);
|
||||
}
|
||||
if (c == 'M') {
|
||||
sim_throt_type = SIM_THROT_MCYC;
|
||||
d_cps = val * 1000000.0;
|
||||
}
|
||||
else {
|
||||
if (*cptr == '\0')
|
||||
return sim_messagef (SCPE_ARG, "Missing throttle mode specification\n");
|
||||
val = strtotv (cptr, &tptr, 10);
|
||||
if (cptr == tptr)
|
||||
return sim_messagef (SCPE_ARG, "Invalid throttle specification: %s\n", cptr);
|
||||
sim_throt_sleep_time = sim_idle_rate_ms;
|
||||
c = (char)toupper (*tptr++);
|
||||
if (c == '/') {
|
||||
val2 = strtotv (tptr, &tptr, 10);
|
||||
if ((*tptr != '\0') || (val == 0))
|
||||
return sim_messagef (SCPE_ARG, "Invalid throttle delay specifier: %s\n", cptr);
|
||||
}
|
||||
if (c == 'M')
|
||||
sim_throt_type = SIM_THROT_MCYC;
|
||||
else if (c == 'K')
|
||||
if (c == 'K') {
|
||||
sim_throt_type = SIM_THROT_KCYC;
|
||||
else if ((c == '%') && (val > 0) && (val < 100))
|
||||
sim_throt_type = SIM_THROT_PCT;
|
||||
else if ((c == '/') && (val2 != 0))
|
||||
sim_throt_type = SIM_THROT_SPC;
|
||||
else return sim_messagef (SCPE_ARG, "Invalid throttle specification: %s\n", cptr);
|
||||
if (sim_throttle_has_been_enabled) {
|
||||
sim_throt_type = saved_throt_type;
|
||||
return sim_messagef (SCPE_ARG, "Throttling was previously enabled. Restart to change throttling\n");
|
||||
d_cps = val * 1000.0;
|
||||
}
|
||||
if (sim_idle_enab) {
|
||||
sim_printf ("Idling disabled\n");
|
||||
sim_clr_idle (NULL, 0, NULL, NULL);
|
||||
else {
|
||||
if ((c == '%') && (val > 0) && (val < 100))
|
||||
sim_throt_type = SIM_THROT_PCT;
|
||||
else {
|
||||
if ((c == '/') && (val2 != 0))
|
||||
sim_throt_type = SIM_THROT_SPC;
|
||||
else
|
||||
return sim_messagef (SCPE_ARG, "Invalid throttle specification: %s\n", cptr);
|
||||
}
|
||||
}
|
||||
sim_throt_val = (uint32) val;
|
||||
}
|
||||
if (sim_throttle_has_been_active) {
|
||||
sim_throt_type = saved_throt_type;
|
||||
sim_messagef (SCPE_ARG, "Throttling was previously active.\n");
|
||||
return sim_messagef (SCPE_ARG, "Restart the simulator to change the throttling mode\n");
|
||||
}
|
||||
if ((sim_precalibrate_ips != SIM_INITIAL_IPS) && (d_cps > sim_precalibrate_ips)) {
|
||||
return sim_messagef (SCPE_ARG, "The current host CPU is too slow to simulate at %s %s per sec.\n", cptr, sim_vm_interval_units);
|
||||
}
|
||||
if (sim_idle_enab) {
|
||||
sim_printf ("Idling disabled\n");
|
||||
sim_clr_idle (NULL, 0, NULL, NULL);
|
||||
}
|
||||
sim_throt_val = (uint32) val;
|
||||
if ((sim_throt_type != SIM_THROT_SPC) &&
|
||||
(sim_precalibrate_ips == SIM_INITIAL_IPS))
|
||||
sim_throt_cps = sim_precalibrate_ips; /* Set initial value while correct one is determined */
|
||||
else { /* otherwise use best guess based on measured execution and sleep times */
|
||||
int32 tmr;
|
||||
RTC *rtc = NULL;
|
||||
|
||||
if (sim_throt_type == SIM_THROT_SPC) {
|
||||
if (val2 >= sim_idle_rate_ms)
|
||||
sim_throt_sleep_time = (uint32) val2;
|
||||
@ -1980,15 +2053,29 @@ else {
|
||||
sim_throt_val = (uint32) (val * (1 + (sim_idle_rate_ms / val2)));
|
||||
}
|
||||
}
|
||||
sim_throt_state = SIM_THROT_STATE_THROTTLE; /* force state */
|
||||
sim_throt_state = SIM_THROT_STATE_THROTTLE; /* force state */
|
||||
sim_throt_wait = sim_throt_val;
|
||||
}
|
||||
}
|
||||
if (sim_throt_type == SIM_THROT_SPC) /* Set initial value while correct one is determined */
|
||||
|
||||
sim_throt_delay = 1;
|
||||
sim_throt_cps = (int32)((1000.0 * sim_throt_val) / (double)sim_throt_sleep_time);
|
||||
else
|
||||
sim_throt_cps = sim_precalibrate_ips;
|
||||
sim_throttle_has_been_enabled = TRUE;
|
||||
sim_inst_per_sec_last = sim_throt_cps; /* Reflect the throttle rate for where cps is needed */
|
||||
/* Run through all timers and adjust the calibration for each */
|
||||
/* one that is running to reflect the throttle specified rate */
|
||||
for (tmr=0; tmr<=SIM_NTIMERS; tmr++) {
|
||||
rtc = &rtcs[tmr];
|
||||
if (rtc->hz) { /* running? */
|
||||
rtc->currd = (int32)(sim_throt_cps / rtc->hz);/* use throttle calibration */
|
||||
rtc->ticks = rtc->hz - 1; /* force clock calibration on next tick */
|
||||
rtc->rtime = sim_throt_ms_start - 1000 + 1000/rtc->hz;/* adjust calibration parameters to reflect throttled rate */
|
||||
rtc->gtime = sim_throt_inst_start - sim_throt_cps + sim_throt_cps/rtc->hz;
|
||||
rtc->nxintv = 1000;
|
||||
rtc->based = rtc->currd;
|
||||
if (rtc->clock_unit)
|
||||
sim_activate_abs (rtc->clock_unit, rtc->currd);/* reschedule next tick */
|
||||
}
|
||||
}
|
||||
}
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
@ -2000,13 +2087,13 @@ else {
|
||||
switch (sim_throt_type) {
|
||||
|
||||
case SIM_THROT_MCYC:
|
||||
fprintf (st, "Throttle: %d mega%s\n", sim_throt_val, sim_vm_interval_units);
|
||||
fprintf (st, "Throttle: %d mega %s per second\n", sim_throt_val, sim_vm_interval_units);
|
||||
if (sim_throt_wait)
|
||||
fprintf (st, "Throttling by sleeping for: %d ms every %d %s\n", sim_throt_sleep_time, sim_throt_wait, sim_vm_interval_units);
|
||||
break;
|
||||
|
||||
case SIM_THROT_KCYC:
|
||||
fprintf (st, "Throttle: %d kilo%s\n", sim_throt_val, sim_vm_interval_units);
|
||||
fprintf (st, "Throttle: %d kilo %s per second\n", sim_throt_val, sim_vm_interval_units);
|
||||
if (sim_throt_wait)
|
||||
fprintf (st, "Throttling by sleeping for: %d ms every %d %s\n", sim_throt_sleep_time, sim_throt_wait, sim_vm_interval_units);
|
||||
break;
|
||||
@ -2021,7 +2108,10 @@ else {
|
||||
break;
|
||||
|
||||
case SIM_THROT_SPC:
|
||||
fprintf (st, "Throttle: %d/%d\n", sim_throt_val, sim_throt_sleep_time);
|
||||
if (sim_throt_cps > 0.0)
|
||||
fprintf (st, "Throttle: %d/%d (~%.0f %s per second)\n", sim_throt_val, sim_throt_sleep_time, sim_throt_cps, sim_vm_interval_units);
|
||||
else
|
||||
fprintf (st, "Throttle: %d/%d\n", sim_throt_val, sim_throt_sleep_time);
|
||||
fprintf (st, "Throttling by sleeping for: %d ms every %d %s\n", sim_throt_sleep_time, sim_throt_val, sim_vm_interval_units);
|
||||
break;
|
||||
|
||||
@ -2052,6 +2142,7 @@ if (sim_throt_type != SIM_THROT_NONE) {
|
||||
sim_throt_state = SIM_THROT_STATE_INIT;
|
||||
sim_activate (&sim_throttle_unit, SIM_THROT_WINIT);
|
||||
}
|
||||
sim_throttle_has_been_active = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
@ -2193,7 +2284,7 @@ switch (sim_throt_state) {
|
||||
a_cps, d_cps, sim_throt_wait, sim_throt_sleep_time);
|
||||
sim_throt_cps = d_cps; /* save the desired rate */
|
||||
/* 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 specified rate */
|
||||
for (tmr=0; tmr<=SIM_NTIMERS; tmr++) {
|
||||
rtc = &rtcs[tmr];
|
||||
if (rtc->hz) { /* running? */
|
||||
@ -2779,7 +2870,11 @@ return SCPE_OK;
|
||||
void sim_start_timer_services (void)
|
||||
{
|
||||
int32 tmr;
|
||||
uint32 sim_prompt_time = (sim_gtime () > 0) ? (sim_os_msec () - sim_stop_time) : 0;
|
||||
uint32 sim_prompt_time = (sim_gtime () > 0) ? /* running? */
|
||||
(sim_timer_calib_enabled ? /* with calibrated clocks? */
|
||||
(sim_os_msec () - sim_stop_time) : /* yes, delta time since stopped */
|
||||
100) : /* 100ms prompt time without calibration */
|
||||
0; /* not running yet so count as 0 */
|
||||
int32 registered_units = 0;
|
||||
|
||||
sim_time_at_sim_prompt += (((double)sim_prompt_time) / 1000.0);
|
||||
@ -2796,8 +2891,6 @@ for (tmr=0; tmr<=SIM_NTIMERS; tmr++) {
|
||||
++registered_units;
|
||||
}
|
||||
}
|
||||
if (registered_units == 1)
|
||||
sim_catchup_ticks = FALSE;
|
||||
if (sim_calb_tmr == -1) {
|
||||
sim_debug (DBG_CAL, &sim_timer_dev, "sim_start_timer_services() - starting from scratch\n");
|
||||
_rtcn_configure_calibrated_clock (sim_calb_tmr);
|
||||
@ -2811,6 +2904,7 @@ else {
|
||||
}
|
||||
if (sim_timer_stop_time > sim_gtime())
|
||||
sim_activate_abs (&sim_stop_unit, (int32)(sim_timer_stop_time - sim_gtime()));
|
||||
sim_idle_end_time = sim_gtime();
|
||||
#if defined(SIM_ASYNCH_CLOCKS)
|
||||
pthread_mutex_lock (&sim_timer_lock);
|
||||
if (sim_asynch_timer) {
|
||||
@ -3636,8 +3730,8 @@ sim_rom_delay = delay;
|
||||
* instructions that don't do anything, but run in an effective loop.
|
||||
* That loop is run for some 5 million instructions and based on
|
||||
* the time those 5 million instructions take to execute the effective
|
||||
* execution rate. That rate is used to avoid the initial 3 to 5
|
||||
* seconds that normal clock calibration takes.
|
||||
* execution rate is determined. That rate is used to avoid the initial
|
||||
* 3 to 5 seconds that normal clock calibration takes.
|
||||
*
|
||||
*/
|
||||
void sim_timer_precalibrate_execution_rate (void)
|
||||
@ -3681,6 +3775,7 @@ for (tmr=0; tmr<=SIM_NTIMERS; tmr++) {
|
||||
}
|
||||
sim_inst_per_sec_last = sim_precalibrate_ips;
|
||||
sim_idle_stable = 0;
|
||||
exdep_cmd (EX_D, "ALL 0"); /* Leave memory in its initial state */
|
||||
}
|
||||
|
||||
double
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user