1
0
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:
Mark Pizzolato 2024-04-04 10:09:57 -10:00
parent b404ccd050
commit 81e2719d90

View File

@ -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