TIMER: Fixed calibration idle skip percent logic
Also: - Added more statistics - Made sleep measurements more precise - Correct idle sleep decision logic without regard to host tick size - Fix calibration setup/teardown when host tick size is large (>10ms) - Generalized large host tick test capability (MS_MIN_GRANULARITY) - Fixed Windows sim_os_msec() to always use timeGetTime() - Fixed coschedule routines (that don't mentoin a tmr) to default to timer 0 and fallback to the internal timer otherwise. - Removed dependency on sizeof(tv_sec) in timespec structure for MinGW
This commit is contained in:
parent
7498f183d2
commit
eb333a845e
2 changed files with 192 additions and 125 deletions
315
sim_timer.c
315
sim_timer.c
|
@ -93,8 +93,54 @@
|
||||||
#define MAX(a,b) (((a) > (b)) ? (a) : (b))
|
#define MAX(a,b) (((a) > (b)) ? (a) : (b))
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
//#define MS_MIN_GRANULARITY 20
|
uint32 sim_idle_ms_sleep (unsigned int msec);
|
||||||
#define MS_MIN_GRANULARITY 1
|
|
||||||
|
/* MS_MIN_GRANULARITY exists here so that timing behavior for hosts systems */
|
||||||
|
/* with slow clock ticks can be assessed and tested without actually having */
|
||||||
|
/* that slow a clock tick on the development platform */
|
||||||
|
//#define MS_MIN_GRANULARITY 20 /* Uncomment to simulate 20ms host tick size.*/
|
||||||
|
/* some Solaris and BSD hosts come this way */
|
||||||
|
|
||||||
|
#if defined(MS_MIN_GRANULARITY) && (MS_MIN_GRANULARITY != 1)
|
||||||
|
uint32 real_sim_idle_ms_sleep (unsigned int msec);
|
||||||
|
uint32 real_sim_os_msec (void);
|
||||||
|
uint32 real_sim_os_ms_sleep (unsigned int msec);
|
||||||
|
static uint32 real_sim_os_sleep_min_ms = 0;
|
||||||
|
static uint32 real_sim_os_sleep_inc_ms = 0;
|
||||||
|
|
||||||
|
uint32 sim_idle_ms_sleep (unsigned int msec)
|
||||||
|
{
|
||||||
|
uint32 real_start = real_sim_os_msec ();
|
||||||
|
uint32 start = (real_start / MS_MIN_GRANULARITY) * MS_MIN_GRANULARITY;
|
||||||
|
uint32 tick_left;
|
||||||
|
|
||||||
|
if (msec == 0)
|
||||||
|
return 0;
|
||||||
|
if (real_start == start)
|
||||||
|
tick_left = 0;
|
||||||
|
else
|
||||||
|
tick_left = MS_MIN_GRANULARITY - (real_start - start);
|
||||||
|
if (msec <= tick_left)
|
||||||
|
real_sim_idle_ms_sleep (tick_left);
|
||||||
|
else
|
||||||
|
real_sim_idle_ms_sleep (((msec + MS_MIN_GRANULARITY - 1) / MS_MIN_GRANULARITY) * MS_MIN_GRANULARITY);
|
||||||
|
|
||||||
|
return (sim_os_msec () - start);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32 sim_os_msec (void)
|
||||||
|
{
|
||||||
|
return (real_sim_os_msec ()/MS_MIN_GRANULARITY)*MS_MIN_GRANULARITY;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32 sim_os_ms_sleep (unsigned int msec)
|
||||||
|
{
|
||||||
|
msec = MS_MIN_GRANULARITY*((msec+MS_MIN_GRANULARITY-1)/MS_MIN_GRANULARITY);
|
||||||
|
|
||||||
|
return real_sim_os_ms_sleep (msec);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* defined(MS_MIN_GRANULARITY) && (MS_MIN_GRANULARITY != 1) */
|
||||||
|
|
||||||
t_bool sim_idle_enab = FALSE; /* global flag */
|
t_bool sim_idle_enab = FALSE; /* global flag */
|
||||||
volatile t_bool sim_idle_wait = FALSE; /* global flag */
|
volatile t_bool sim_idle_wait = FALSE; /* global flag */
|
||||||
|
@ -131,28 +177,46 @@ UNIT * volatile sim_wallclock_queue = QUEUE_LIST_END;
|
||||||
UNIT * volatile sim_wallclock_entry = NULL;
|
UNIT * volatile sim_wallclock_entry = NULL;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
t_stat sim_throt_svc (UNIT *uptr);
|
#define sleep1Samples 100
|
||||||
t_stat sim_timer_tick_svc (UNIT *uptr);
|
|
||||||
|
|
||||||
#define DBG_IDL TIMER_DBG_IDLE /* idling */
|
static uint32 _compute_minimum_sleep (void)
|
||||||
#define DBG_QUE TIMER_DBG_QUEUE /* queue activities */
|
{
|
||||||
#define DBG_MUX TIMER_DBG_MUX /* tmxr queue activities */
|
uint32 i, tot, tim;
|
||||||
#define DBG_TRC 0x008 /* tracing */
|
|
||||||
#define DBG_CAL 0x010 /* calibration activities */
|
sim_os_set_thread_priority (PRIORITY_ABOVE_NORMAL);
|
||||||
#define DBG_TIM 0x020 /* timer thread activities */
|
#if defined(MS_MIN_GRANULARITY) && (MS_MIN_GRANULARITY != 1)
|
||||||
#define DBG_THR 0x040 /* throttle activities */
|
real_sim_idle_ms_sleep (1); /* Start sampling on a tick boundary */
|
||||||
#define DBG_ACK 0x080 /* interrupt acknowledgement activities */
|
for (i = 0, tot = 0; i < sleep1Samples; i++)
|
||||||
DEBTAB sim_timer_debug[] = {
|
tot += real_sim_idle_ms_sleep (1);
|
||||||
{"TRACE", DBG_TRC, "Trace routine calls"},
|
tim = tot / sleep1Samples; /* Truncated average */
|
||||||
{"IDLE", DBG_IDL, "Idling activities"},
|
real_sim_os_sleep_min_ms = tim;
|
||||||
{"QUEUE", DBG_QUE, "Event queuing activities"},
|
real_sim_idle_ms_sleep (1); /* Start sampling on a tick boundary */
|
||||||
{"IACK", DBG_ACK, "interrupt acknowledgement activities"},
|
for (i = 0, tot = 0; i < sleep1Samples; i++)
|
||||||
{"CALIB", DBG_CAL, "Calibration activities"},
|
tot += real_sim_idle_ms_sleep (real_sim_os_sleep_min_ms + 1);
|
||||||
{"TIME", DBG_TIM, "Activation and scheduling activities"},
|
tim = tot / sleep1Samples; /* Truncated average */
|
||||||
{"THROT", DBG_THR, "Throttling activities"},
|
real_sim_os_sleep_inc_ms = tim - real_sim_os_sleep_min_ms;
|
||||||
{"MUX", DBG_MUX, "Tmxr scheduling activities"},
|
#endif /* defined(MS_MIN_GRANULARITY) && (MS_MIN_GRANULARITY != 1) */
|
||||||
{0}
|
sim_idle_ms_sleep (1); /* Start sampling on a tick boundary */
|
||||||
};
|
for (i = 0, tot = 0; i < sleep1Samples; i++)
|
||||||
|
tot += sim_idle_ms_sleep (1);
|
||||||
|
tim = tot / sleep1Samples; /* Truncated average */
|
||||||
|
sim_os_sleep_min_ms = tim;
|
||||||
|
sim_idle_ms_sleep (1); /* Start sampling on a tick boundary */
|
||||||
|
for (i = 0, tot = 0; i < sleep1Samples; i++)
|
||||||
|
tot += sim_idle_ms_sleep (sim_os_sleep_min_ms + 1);
|
||||||
|
tim = tot / sleep1Samples; /* Truncated average */
|
||||||
|
sim_os_sleep_inc_ms = tim - sim_os_sleep_min_ms;
|
||||||
|
sim_os_set_thread_priority (PRIORITY_NORMAL);
|
||||||
|
return sim_os_sleep_min_ms;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(MS_MIN_GRANULARITY) && (MS_MIN_GRANULARITY != 1)
|
||||||
|
|
||||||
|
#define sim_idle_ms_sleep real_sim_idle_ms_sleep
|
||||||
|
#define sim_os_msec real_sim_os_msec
|
||||||
|
#define sim_os_ms_sleep real_sim_os_ms_sleep
|
||||||
|
|
||||||
|
#endif /* defined(MS_MIN_GRANULARITY) && (MS_MIN_GRANULARITY != 1) */
|
||||||
|
|
||||||
#if defined(SIM_ASYNCH_IO)
|
#if defined(SIM_ASYNCH_IO)
|
||||||
uint32 sim_idle_ms_sleep (unsigned int msec)
|
uint32 sim_idle_ms_sleep (unsigned int msec)
|
||||||
|
@ -161,10 +225,6 @@ uint32 start_time = sim_os_msec();
|
||||||
struct timespec done_time;
|
struct timespec done_time;
|
||||||
t_bool timedout = FALSE;
|
t_bool timedout = FALSE;
|
||||||
|
|
||||||
#if defined(MS_MIN_GRANULARITY) && (MS_MIN_GRANULARITY != 1)
|
|
||||||
msec = MS_MIN_GRANULARITY*((msec+MS_MIN_GRANULARITY-1)/MS_MIN_GRANULARITY);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
clock_gettime(CLOCK_REALTIME, &done_time);
|
clock_gettime(CLOCK_REALTIME, &done_time);
|
||||||
done_time.tv_sec += (msec/1000);
|
done_time.tv_sec += (msec/1000);
|
||||||
done_time.tv_nsec += 1000000*(msec%1000);
|
done_time.tv_nsec += 1000000*(msec%1000);
|
||||||
|
@ -185,9 +245,11 @@ if (!timedout) {
|
||||||
}
|
}
|
||||||
return sim_os_msec() - start_time;
|
return sim_os_msec() - start_time;
|
||||||
}
|
}
|
||||||
#define SIM_IDLE_MS_SLEEP sim_idle_ms_sleep
|
|
||||||
#else
|
#else
|
||||||
#define SIM_IDLE_MS_SLEEP sim_os_ms_sleep
|
uint32 sim_idle_ms_sleep (unsigned int msec)
|
||||||
|
{
|
||||||
|
return sim_os_ms_sleep (msec);
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Mark the need for the sim_os_set_thread_priority routine, */
|
/* Mark the need for the sim_os_set_thread_priority routine, */
|
||||||
|
@ -243,25 +305,6 @@ return SCPE_OK;
|
||||||
#endif
|
#endif
|
||||||
#endif /* defined(USE_READER_THREAD) */
|
#endif /* defined(USE_READER_THREAD) */
|
||||||
|
|
||||||
#define sleep1Samples 100
|
|
||||||
|
|
||||||
static uint32 _compute_minimum_sleep (void)
|
|
||||||
{
|
|
||||||
uint32 i, tot, tim;
|
|
||||||
|
|
||||||
SIM_IDLE_MS_SLEEP (1); /* Start sampling on a tick boundary */
|
|
||||||
for (i = 0, tot = 0; i < sleep1Samples; i++)
|
|
||||||
tot += SIM_IDLE_MS_SLEEP (1);
|
|
||||||
tim = (tot + (sleep1Samples - 1)) / sleep1Samples;
|
|
||||||
sim_os_sleep_min_ms = tim;
|
|
||||||
SIM_IDLE_MS_SLEEP (1); /* Start sampling on a tick boundary */
|
|
||||||
for (i = 0, tot = 0; i < sleep1Samples; i++)
|
|
||||||
tot += SIM_IDLE_MS_SLEEP (sim_os_sleep_min_ms + 1);
|
|
||||||
tim = (tot + (sleep1Samples - 1)) / sleep1Samples;
|
|
||||||
sim_os_sleep_inc_ms = tim - sim_os_sleep_min_ms;
|
|
||||||
return sim_os_sleep_min_ms;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* OS-dependent timer and clock routines */
|
/* OS-dependent timer and clock routines */
|
||||||
|
|
||||||
/* VMS */
|
/* VMS */
|
||||||
|
@ -306,9 +349,6 @@ for (i = 0; i < 64; i++) { /* 64b quo */
|
||||||
quo = quo | 1; /* set quo bit */
|
quo = quo | 1; /* set quo bit */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#if defined(MS_MIN_GRANULARITY) && (MS_MIN_GRANULARITY != 1)
|
|
||||||
quo = (quo/MS_MIN_GRANULARITY)*MS_MIN_GRANULARITY;
|
|
||||||
#endif
|
|
||||||
return quo;
|
return quo;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -330,10 +370,6 @@ uint32 qtime[2];
|
||||||
int32 nsfactor = -10000;
|
int32 nsfactor = -10000;
|
||||||
static int32 zero = 0;
|
static int32 zero = 0;
|
||||||
|
|
||||||
#if defined(MS_MIN_GRANULARITY) && (MS_MIN_GRANULARITY != 1)
|
|
||||||
msec = MS_MIN_GRANULARITY*((msec+MS_MIN_GRANULARITY-1)/MS_MIN_GRANULARITY);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
lib$emul (&msec, &nsfactor, &zero, qtime);
|
lib$emul (&msec, &nsfactor, &zero, qtime);
|
||||||
sys$setimr (2, qtime, 0, 0);
|
sys$setimr (2, qtime, 0, 0);
|
||||||
sys$waitfr (2);
|
sys$waitfr (2);
|
||||||
|
@ -365,13 +401,7 @@ const t_bool rtc_avail = TRUE;
|
||||||
|
|
||||||
uint32 sim_os_msec (void)
|
uint32 sim_os_msec (void)
|
||||||
{
|
{
|
||||||
uint32 t = (sim_idle_rate_ms ? timeGetTime () : GetTickCount ());
|
return timeGetTime ();
|
||||||
|
|
||||||
#if defined(MS_MIN_GRANULARITY) && (MS_MIN_GRANULARITY != 1)
|
|
||||||
t = (t/MS_MIN_GRANULARITY)*MS_MIN_GRANULARITY;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return t;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void sim_os_sleep (unsigned int sec)
|
void sim_os_sleep (unsigned int sec)
|
||||||
|
@ -405,10 +435,6 @@ uint32 sim_os_ms_sleep (unsigned int msec)
|
||||||
{
|
{
|
||||||
uint32 stime = sim_os_msec();
|
uint32 stime = sim_os_msec();
|
||||||
|
|
||||||
#if defined(MS_MIN_GRANULARITY) && (MS_MIN_GRANULARITY != 1)
|
|
||||||
msec = MS_MIN_GRANULARITY*((msec+MS_MIN_GRANULARITY-1)/MS_MIN_GRANULARITY);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
Sleep (msec);
|
Sleep (msec);
|
||||||
return sim_os_msec () - stime;
|
return sim_os_msec () - stime;
|
||||||
}
|
}
|
||||||
|
@ -479,9 +505,6 @@ unsigned long millis;
|
||||||
Microseconds (&macMicros);
|
Microseconds (&macMicros);
|
||||||
micros = *((unsigned long long *) &macMicros);
|
micros = *((unsigned long long *) &macMicros);
|
||||||
millis = micros / 1000LL;
|
millis = micros / 1000LL;
|
||||||
#if defined(MS_MIN_GRANULARITY) && (MS_MIN_GRANULARITY != 1)
|
|
||||||
millis = (millis/MS_MIN_GRANULARITY)*MS_MIN_GRANULARITY;
|
|
||||||
#endif
|
|
||||||
return (uint32) millis;
|
return (uint32) millis;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -501,10 +524,6 @@ uint32 sim_os_ms_sleep (unsigned int milliseconds)
|
||||||
uint32 stime = sim_os_msec ();
|
uint32 stime = sim_os_msec ();
|
||||||
struct timespec treq;
|
struct timespec treq;
|
||||||
|
|
||||||
#if defined(MS_MIN_GRANULARITY) && (MS_MIN_GRANULARITY != 1)
|
|
||||||
milliseconds = MS_MIN_GRANULARITY*((milliseconds+MS_MIN_GRANULARITY-1)/MS_MIN_GRANULARITY);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
treq.tv_sec = milliseconds / MILLIS_PER_SEC;
|
treq.tv_sec = milliseconds / MILLIS_PER_SEC;
|
||||||
treq.tv_nsec = (milliseconds % MILLIS_PER_SEC) * NANOS_PER_MILLI;
|
treq.tv_nsec = (milliseconds % MILLIS_PER_SEC) * NANOS_PER_MILLI;
|
||||||
(void) nanosleep (&treq, NULL);
|
(void) nanosleep (&treq, NULL);
|
||||||
|
@ -545,9 +564,6 @@ uint32 msec;
|
||||||
|
|
||||||
gettimeofday (&cur, &foo);
|
gettimeofday (&cur, &foo);
|
||||||
msec = (((uint32) cur.tv_sec) * 1000) + (((uint32) cur.tv_usec) / 1000);
|
msec = (((uint32) cur.tv_sec) * 1000) + (((uint32) cur.tv_usec) / 1000);
|
||||||
#if defined(MS_MIN_GRANULARITY) && (MS_MIN_GRANULARITY != 1)
|
|
||||||
msec = (msec/MS_MIN_GRANULARITY)*MS_MIN_GRANULARITY;
|
|
||||||
#endif
|
|
||||||
return msec;
|
return msec;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -585,10 +601,6 @@ uint32 sim_os_ms_sleep (unsigned int milliseconds)
|
||||||
uint32 stime = sim_os_msec ();
|
uint32 stime = sim_os_msec ();
|
||||||
struct timespec treq;
|
struct timespec treq;
|
||||||
|
|
||||||
#if defined(MS_MIN_GRANULARITY) && (MS_MIN_GRANULARITY != 1)
|
|
||||||
milliseconds = MS_MIN_GRANULARITY*((milliseconds+MS_MIN_GRANULARITY-1)/MS_MIN_GRANULARITY);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
treq.tv_sec = milliseconds / MILLIS_PER_SEC;
|
treq.tv_sec = milliseconds / MILLIS_PER_SEC;
|
||||||
treq.tv_nsec = (milliseconds % MILLIS_PER_SEC) * NANOS_PER_MILLI;
|
treq.tv_nsec = (milliseconds % MILLIS_PER_SEC) * NANOS_PER_MILLI;
|
||||||
(void) nanosleep (&treq, NULL);
|
(void) nanosleep (&treq, NULL);
|
||||||
|
@ -636,6 +648,13 @@ return SCPE_OK;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined(MS_MIN_GRANULARITY) && (MS_MIN_GRANULARITY != 1)
|
||||||
|
/* Make sure to use the substitute routines */
|
||||||
|
#undef sim_idle_ms_sleep
|
||||||
|
#undef sim_os_msec
|
||||||
|
#undef sim_os_ms_sleep
|
||||||
|
#endif /* defined(MS_MIN_GRANULARITY) && (MS_MIN_GRANULARITY != 1) */
|
||||||
|
|
||||||
/* diff = min - sub */
|
/* diff = min - sub */
|
||||||
void
|
void
|
||||||
sim_timespec_diff (struct timespec *diff, struct timespec *min, struct timespec *sub)
|
sim_timespec_diff (struct timespec *diff, struct timespec *min, struct timespec *sub)
|
||||||
|
@ -721,11 +740,36 @@ static t_bool rtc_clock_catchup_eligible[SIM_NTIMERS+1] = { 0 };/* clock tick ca
|
||||||
static uint32 rtc_clock_time_idled[SIM_NTIMERS+1] = { 0 };/* total time idled */
|
static uint32 rtc_clock_time_idled[SIM_NTIMERS+1] = { 0 };/* total time idled */
|
||||||
static uint32 rtc_clock_time_idled_last[SIM_NTIMERS+1] = { 0 };/* total time idled */
|
static uint32 rtc_clock_time_idled_last[SIM_NTIMERS+1] = { 0 };/* total time idled */
|
||||||
static uint32 rtc_clock_calib_skip_idle[SIM_NTIMERS+1] = { 0 };/* Calibrations skipped due to idling */
|
static uint32 rtc_clock_calib_skip_idle[SIM_NTIMERS+1] = { 0 };/* Calibrations skipped due to idling */
|
||||||
|
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 */
|
||||||
|
|
||||||
UNIT sim_timer_units[SIM_NTIMERS+1]; /* one for each timer and one for an */
|
UNIT sim_timer_units[SIM_NTIMERS+1]; /* one for each timer and one for an */
|
||||||
/* internal clock if no clocks are registered */
|
/* internal clock if no clocks are registered */
|
||||||
UNIT sim_throttle_unit; /* one for throttle */
|
UNIT sim_throttle_unit; /* one for throttle */
|
||||||
|
|
||||||
|
t_stat sim_throt_svc (UNIT *uptr);
|
||||||
|
t_stat sim_timer_tick_svc (UNIT *uptr);
|
||||||
|
|
||||||
|
#define DBG_IDL TIMER_DBG_IDLE /* idling */
|
||||||
|
#define DBG_QUE TIMER_DBG_QUEUE /* queue activities */
|
||||||
|
#define DBG_MUX TIMER_DBG_MUX /* tmxr queue activities */
|
||||||
|
#define DBG_TRC 0x008 /* tracing */
|
||||||
|
#define DBG_CAL 0x010 /* calibration activities */
|
||||||
|
#define DBG_TIM 0x020 /* timer thread activities */
|
||||||
|
#define DBG_THR 0x040 /* throttle activities */
|
||||||
|
#define DBG_ACK 0x080 /* interrupt acknowledgement activities */
|
||||||
|
DEBTAB sim_timer_debug[] = {
|
||||||
|
{"TRACE", DBG_TRC, "Trace routine calls"},
|
||||||
|
{"IDLE", DBG_IDL, "Idling activities"},
|
||||||
|
{"QUEUE", DBG_QUE, "Event queuing activities"},
|
||||||
|
{"IACK", DBG_ACK, "interrupt acknowledgement activities"},
|
||||||
|
{"CALIB", DBG_CAL, "Calibration activities"},
|
||||||
|
{"TIME", DBG_TIM, "Activation and scheduling activities"},
|
||||||
|
{"THROT", DBG_THR, "Throttling activities"},
|
||||||
|
{"MUX", DBG_MUX, "Tmxr scheduling activities"},
|
||||||
|
{0}
|
||||||
|
};
|
||||||
|
|
||||||
/* Forward device declarations */
|
/* Forward device declarations */
|
||||||
extern DEVICE sim_timer_dev;
|
extern DEVICE sim_timer_dev;
|
||||||
extern DEVICE sim_throttle_dev;
|
extern DEVICE sim_throttle_dev;
|
||||||
|
@ -849,23 +893,17 @@ if (sim_calb_tmr != tmr) {
|
||||||
return rtc_currd[tmr];
|
return rtc_currd[tmr];
|
||||||
}
|
}
|
||||||
new_rtime = sim_os_msec (); /* wall time */
|
new_rtime = sim_os_msec (); /* wall time */
|
||||||
|
++rtc_calibrations[tmr]; /* count calibrations */
|
||||||
sim_debug (DBG_TRC, &sim_timer_dev, "sim_rtcn_calb(ticksper=%d, tmr=%d)\n", ticksper, tmr);
|
sim_debug (DBG_TRC, &sim_timer_dev, "sim_rtcn_calb(ticksper=%d, tmr=%d)\n", ticksper, tmr);
|
||||||
last_idle_pct = MIN(100,(uint32)(((double)(rtc_clock_time_idled[tmr] - rtc_clock_time_idled_last[tmr])) / 10.0));
|
|
||||||
rtc_clock_time_idled_last[tmr] = rtc_clock_time_idled[tmr];
|
|
||||||
if (last_idle_pct > (100 - sim_idle_calib_pct)) {
|
|
||||||
rtc_rtime[tmr] = new_rtime; /* save wall time */
|
|
||||||
rtc_vtime[tmr] = rtc_vtime[tmr] + 1000; /* adv sim time */
|
|
||||||
rtc_gtime[tmr] = sim_gtime(); /* save instruction time */
|
|
||||||
++rtc_clock_calib_skip_idle[tmr];
|
|
||||||
sim_debug (DBG_CAL, &sim_timer_dev, "skipping calibration due to idling - result: %d\n", rtc_currd[tmr]);
|
|
||||||
return rtc_currd[tmr]; /* avoid calibrating idle checks */
|
|
||||||
}
|
|
||||||
if (new_rtime < rtc_rtime[tmr]) { /* time running backwards? */
|
if (new_rtime < rtc_rtime[tmr]) { /* time running backwards? */
|
||||||
|
/* This happens when the value returned by sim_os_msec wraps (as an uint32) */
|
||||||
|
/* Wrapping will happen initially sometime before a simulator has been running */
|
||||||
|
/* for 49 days approximately every 49 days thereafter. */
|
||||||
|
++rtc_clock_calib_backwards[tmr]; /* Count statistic */
|
||||||
|
sim_debug (DBG_CAL, &sim_timer_dev, "time running backwards - OldTime: %u, NewTime: %u, result: %d\n", rtc_rtime[tmr], new_rtime, rtc_currd[tmr]);
|
||||||
rtc_rtime[tmr] = new_rtime; /* reset wall time */
|
rtc_rtime[tmr] = new_rtime; /* reset wall time */
|
||||||
sim_debug (DBG_CAL, &sim_timer_dev, "time running backwards - result: %d\n", rtc_currd[tmr]);
|
|
||||||
return rtc_currd[tmr]; /* can't calibrate */
|
return rtc_currd[tmr]; /* can't calibrate */
|
||||||
}
|
}
|
||||||
++rtc_calibrations[tmr]; /* count calibrations */
|
|
||||||
delta_rtime = new_rtime - rtc_rtime[tmr]; /* elapsed wtime */
|
delta_rtime = new_rtime - rtc_rtime[tmr]; /* elapsed wtime */
|
||||||
rtc_rtime[tmr] = new_rtime; /* adv wall time */
|
rtc_rtime[tmr] = new_rtime; /* adv wall time */
|
||||||
rtc_vtime[tmr] = rtc_vtime[tmr] + 1000; /* adv sim time */
|
rtc_vtime[tmr] = rtc_vtime[tmr] + 1000; /* adv sim time */
|
||||||
|
@ -876,12 +914,26 @@ if (delta_rtime > 30000) { /* gap too big? */
|
||||||
/* developer stops the simulator at a breakpoint (a process, not simh */
|
/* developer stops the simulator at a breakpoint (a process, not simh */
|
||||||
/* breakpoint). To accomodate this, we set the calibration state to */
|
/* breakpoint). To accomodate this, we set the calibration state to */
|
||||||
/* ignore what happened and proceed from here. */
|
/* ignore what happened and proceed from here. */
|
||||||
|
++rtc_clock_calib_gap2big[tmr]; /* Count statistic */
|
||||||
rtc_vtime[tmr] = rtc_rtime[tmr]; /* sync virtual and real time */
|
rtc_vtime[tmr] = rtc_rtime[tmr]; /* sync virtual and real time */
|
||||||
rtc_nxintv[tmr] = 1000; /* reset next interval */
|
rtc_nxintv[tmr] = 1000; /* reset next interval */
|
||||||
rtc_gtime[tmr] = sim_gtime(); /* save instruction time */
|
rtc_gtime[tmr] = sim_gtime(); /* save instruction time */
|
||||||
sim_debug (DBG_CAL, &sim_timer_dev, "gap too big: delta = %d - result: %d\n", delta_rtime, rtc_currd[tmr]);
|
sim_debug (DBG_CAL, &sim_timer_dev, "gap too big: delta = %d - result: %d\n", delta_rtime, rtc_currd[tmr]);
|
||||||
return rtc_currd[tmr]; /* can't calibr */
|
return rtc_currd[tmr]; /* can't calibr */
|
||||||
}
|
}
|
||||||
|
if (delta_rtime == 0) /* avoid divide by zero */
|
||||||
|
last_idle_pct = 0; /* force calibration */
|
||||||
|
else
|
||||||
|
last_idle_pct = MIN(100, (uint32)(100.0 * (((double)(rtc_clock_time_idled[tmr] - rtc_clock_time_idled_last[tmr])) / ((double)delta_rtime))));
|
||||||
|
rtc_clock_time_idled_last[tmr] = rtc_clock_time_idled[tmr];
|
||||||
|
if (last_idle_pct > (100 - sim_idle_calib_pct)) {
|
||||||
|
rtc_rtime[tmr] = new_rtime; /* save wall time */
|
||||||
|
rtc_vtime[tmr] = rtc_vtime[tmr] + 1000; /* adv sim time */
|
||||||
|
rtc_gtime[tmr] = sim_gtime(); /* save instruction time */
|
||||||
|
++rtc_clock_calib_skip_idle[tmr];
|
||||||
|
sim_debug (DBG_CAL, &sim_timer_dev, "skipping calibration due to idling (%d%%) - result: %d\n", last_idle_pct, rtc_currd[tmr]);
|
||||||
|
return rtc_currd[tmr]; /* avoid calibrating idle checks */
|
||||||
|
}
|
||||||
new_gtime = sim_gtime();
|
new_gtime = sim_gtime();
|
||||||
if (sim_asynch_timer) {
|
if (sim_asynch_timer) {
|
||||||
/* An asynchronous clock, merely needs to divide the number of */
|
/* An asynchronous clock, merely needs to divide the number of */
|
||||||
|
@ -987,6 +1039,7 @@ t_stat sim_show_timers (FILE* st, DEVICE *dptr, UNIT* uptr, int32 val, CONST cha
|
||||||
{
|
{
|
||||||
int tmr, clocks;
|
int tmr, clocks;
|
||||||
struct timespec now;
|
struct timespec now;
|
||||||
|
time_t time_t_now;
|
||||||
|
|
||||||
fprintf (st, "Minimum Host Sleep Time: %d ms (%dHz)\n", sim_os_sleep_min_ms, sim_os_tick_hz);
|
fprintf (st, "Minimum Host Sleep Time: %d ms (%dHz)\n", sim_os_sleep_min_ms, sim_os_tick_hz);
|
||||||
if (sim_os_sleep_min_ms != sim_os_sleep_inc_ms)
|
if (sim_os_sleep_min_ms != sim_os_sleep_inc_ms)
|
||||||
|
@ -1005,11 +1058,10 @@ for (tmr=clocks=0; tmr<=SIM_NTIMERS; ++tmr) {
|
||||||
|
|
||||||
if (sim_clock_unit[tmr]) {
|
if (sim_clock_unit[tmr]) {
|
||||||
++clocks;
|
++clocks;
|
||||||
fprintf (st, "%s clock device is %s\n", sim_name, sim_uname(sim_clock_unit[tmr]));
|
fprintf (st, "%s clock device is %s%s%s\n", sim_name,
|
||||||
}
|
(tmr == SIM_NTIMERS) ? "Internal Calibrated Timer(" : "",
|
||||||
else {
|
sim_uname(sim_clock_unit[tmr]),
|
||||||
if (tmr == SIM_NTIMERS)
|
(tmr == SIM_NTIMERS) ? ")" : "");
|
||||||
fprintf (st, "Internal Calibrated Timer\n");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fprintf (st, "%s%sTimer %d:\n", sim_asynch_timer ? "Asynchronous " : "", rtc_hz[tmr] ? "Calibrated " : "Uncalibrated ", tmr);
|
fprintf (st, "%s%sTimer %d:\n", sim_asynch_timer ? "Asynchronous " : "", rtc_hz[tmr] ? "Calibrated " : "Uncalibrated ", tmr);
|
||||||
|
@ -1019,9 +1071,17 @@ for (tmr=clocks=0; tmr<=SIM_NTIMERS; ++tmr) {
|
||||||
fprintf (st, " Ticks in current second: %d\n", rtc_ticks[tmr]);
|
fprintf (st, " Ticks in current second: %d\n", rtc_ticks[tmr]);
|
||||||
}
|
}
|
||||||
fprintf (st, " Seconds Running: %u (%s)\n", rtc_elapsed[tmr], sim_fmt_secs ((double)rtc_elapsed[tmr]));
|
fprintf (st, " Seconds Running: %u (%s)\n", rtc_elapsed[tmr], sim_fmt_secs ((double)rtc_elapsed[tmr]));
|
||||||
fprintf (st, " Calibration Opportunities: %u\n", rtc_calibrations[tmr]);
|
if (tmr == sim_calb_tmr) {
|
||||||
if (rtc_clock_calib_skip_idle[tmr])
|
fprintf (st, " Calibration Opportunities: %u\n", rtc_calibrations[tmr]);
|
||||||
fprintf (st, " Calibs Skipped While Idle: %u\n", rtc_clock_calib_skip_idle[tmr]);
|
if (sim_idle_calib_pct)
|
||||||
|
fprintf (st, " Calib Skip Idle Thresh %%: %u\n", sim_idle_calib_pct);
|
||||||
|
if (rtc_clock_calib_skip_idle[tmr])
|
||||||
|
fprintf (st, " Calibs Skip While Idle: %u\n", rtc_clock_calib_skip_idle[tmr]);
|
||||||
|
if (rtc_clock_calib_backwards[tmr])
|
||||||
|
fprintf (st, " Calibs Skip Backwards: %u\n", rtc_clock_calib_backwards[tmr]);
|
||||||
|
if (rtc_clock_calib_gap2big[tmr])
|
||||||
|
fprintf (st, " Calibs Skip Gap Too Big: %u\n", rtc_clock_calib_gap2big[tmr]);
|
||||||
|
}
|
||||||
if (rtc_gtime[tmr])
|
if (rtc_gtime[tmr])
|
||||||
fprintf (st, " Instruction Time: %.0f\n", rtc_gtime[tmr]);
|
fprintf (st, " Instruction Time: %.0f\n", rtc_gtime[tmr]);
|
||||||
if ((!sim_asynch_timer) && (sim_throt_type == SIM_THROT_NONE)) {
|
if ((!sim_asynch_timer) && (sim_throt_type == SIM_THROT_NONE)) {
|
||||||
|
@ -1049,12 +1109,15 @@ for (tmr=clocks=0; tmr<=SIM_NTIMERS; ++tmr) {
|
||||||
if (rtc_clock_catchup_ticks_tot[tmr]+rtc_clock_catchup_ticks[tmr] != rtc_clock_catchup_ticks[tmr])
|
if (rtc_clock_catchup_ticks_tot[tmr]+rtc_clock_catchup_ticks[tmr] != rtc_clock_catchup_ticks[tmr])
|
||||||
fprintf (st, " Total Catchup Ticks Sched: %u\n", rtc_clock_catchup_ticks_tot[tmr]+rtc_clock_catchup_ticks[tmr]);
|
fprintf (st, " Total Catchup Ticks Sched: %u\n", rtc_clock_catchup_ticks_tot[tmr]+rtc_clock_catchup_ticks[tmr]);
|
||||||
clock_gettime (CLOCK_REALTIME, &now);
|
clock_gettime (CLOCK_REALTIME, &now);
|
||||||
fprintf (st, " Wall Clock Time Now: %8.8s.%03d\n", 11+ctime(&now.tv_sec), (int)(now.tv_nsec/1000000));
|
time_t_now = (time_t)now.tv_sec;
|
||||||
|
fprintf (st, " Wall Clock Time Now: %8.8s.%03d\n", 11+ctime(&time_t_now), (int)(now.tv_nsec/1000000));
|
||||||
if (rtc_clock_catchup_eligible[tmr]) {
|
if (rtc_clock_catchup_eligible[tmr]) {
|
||||||
_double_to_timespec (&now, rtc_clock_catchup_base_time[tmr]+rtc_calib_tick_time[tmr]);
|
_double_to_timespec (&now, rtc_clock_catchup_base_time[tmr]+rtc_calib_tick_time[tmr]);
|
||||||
fprintf (st, " Catchup Tick Time: %8.8s.%03d\n", 11+ctime(&now.tv_sec), (int)(now.tv_nsec/1000000));
|
time_t_now = (time_t)now.tv_sec;
|
||||||
|
fprintf (st, " Catchup Tick Time: %8.8s.%03d\n", 11+ctime(&time_t_now), (int)(now.tv_nsec/1000000));
|
||||||
_double_to_timespec (&now, rtc_clock_catchup_base_time[tmr]);
|
_double_to_timespec (&now, rtc_clock_catchup_base_time[tmr]);
|
||||||
fprintf (st, " Catchup Base Time: %8.8s.%03d\n", 11+ctime(&now.tv_sec), (int)(now.tv_nsec/1000000));
|
time_t_now = (time_t)now.tv_sec;
|
||||||
|
fprintf (st, " Catchup Base Time: %8.8s.%03d\n", 11+ctime(&time_t_now), (int)(now.tv_nsec/1000000));
|
||||||
}
|
}
|
||||||
if (rtc_clock_time_idled[tmr])
|
if (rtc_clock_time_idled[tmr])
|
||||||
fprintf (st, " Total Time Idled: %s\n", sim_fmt_secs (rtc_clock_time_idled[tmr]/1000.0));
|
fprintf (st, " Total Time Idled: %s\n", sim_fmt_secs (rtc_clock_time_idled[tmr]/1000.0));
|
||||||
|
@ -1325,10 +1388,7 @@ 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 */
|
||||||
if (sim_os_tick_hz < rtc_hz[tmr])
|
w_idle = (w_ms * 1000) / sim_idle_rate_ms; /* intervals to wait * 1000 */
|
||||||
w_idle = (w_ms * 1000); /* intervals to wait * 1000 */
|
|
||||||
else
|
|
||||||
w_idle = (w_ms * 1000) / sim_idle_rate_ms; /* intervals to wait * 1000 */
|
|
||||||
if (w_idle < 500) { /* shorter than 1/2 a minimum sleep? */
|
if (w_idle < 500) { /* shorter than 1/2 a minimum sleep? */
|
||||||
if (sin_cyc)
|
if (sin_cyc)
|
||||||
sim_interval = sim_interval - 1;
|
sim_interval = sim_interval - 1;
|
||||||
|
@ -1339,7 +1399,7 @@ 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);
|
sim_debug (DBG_IDL, &sim_timer_dev, "sleeping for %d ms - pending event in %d instructions\n", w_ms, sim_interval);
|
||||||
else
|
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);
|
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);
|
||||||
act_ms = SIM_IDLE_MS_SLEEP (w_ms); /* wait */
|
act_ms = sim_idle_ms_sleep (w_ms); /* wait */
|
||||||
rtc_clock_time_idled[tmr] += act_ms;
|
rtc_clock_time_idled[tmr] += act_ms;
|
||||||
act_cyc = act_ms * cyc_ms;
|
act_cyc = act_ms * cyc_ms;
|
||||||
if (act_ms < w_ms) /* awakened early? */
|
if (act_ms < w_ms) /* awakened early? */
|
||||||
|
@ -1575,7 +1635,7 @@ switch (sim_throt_state) {
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 2: /* throttling */
|
case 2: /* throttling */
|
||||||
SIM_IDLE_MS_SLEEP (sim_throt_sleep_time);
|
sim_idle_ms_sleep (sim_throt_sleep_time);
|
||||||
delta_ms = sim_os_msec () - sim_throt_ms_start;
|
delta_ms = sim_os_msec () - sim_throt_ms_start;
|
||||||
if (sim_throt_type != SIM_THROT_SPC) { /* when not dynamic throttling */
|
if (sim_throt_type != SIM_THROT_SPC) { /* when not dynamic throttling */
|
||||||
if (delta_ms >= 10000) { /* recompute every 10 sec */
|
if (delta_ms >= 10000) { /* recompute every 10 sec */
|
||||||
|
@ -1879,7 +1939,7 @@ return NULL;
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define CLK_TPS 10
|
#define CLK_TPS 10
|
||||||
#define CLK_INIT 100000
|
#define CLK_INIT (SIM_INITIAL_IPS/CLK_TPS)
|
||||||
static int32 sim_int_clk_tps;
|
static int32 sim_int_clk_tps;
|
||||||
|
|
||||||
static t_stat sim_timer_clock_tick_svc (UNIT *uptr)
|
static t_stat sim_timer_clock_tick_svc (UNIT *uptr)
|
||||||
|
@ -1902,6 +1962,7 @@ static void _rtcn_configure_calibrated_clock (int32 newtmr)
|
||||||
{
|
{
|
||||||
int32 tmr;
|
int32 tmr;
|
||||||
|
|
||||||
|
/* Look for a timer running slower than the host system clock */
|
||||||
sim_int_clk_tps = MIN(CLK_TPS, sim_os_tick_hz);
|
sim_int_clk_tps = MIN(CLK_TPS, sim_os_tick_hz);
|
||||||
for (tmr=0; tmr<SIM_NTIMERS; tmr++) {
|
for (tmr=0; tmr<SIM_NTIMERS; tmr++) {
|
||||||
if ((rtc_hz[tmr]) &&
|
if ((rtc_hz[tmr]) &&
|
||||||
|
@ -1909,14 +1970,13 @@ for (tmr=0; tmr<SIM_NTIMERS; tmr++) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (tmr == SIM_NTIMERS) { /* None found? */
|
if (tmr == SIM_NTIMERS) { /* None found? */
|
||||||
if ((!sim_is_active (&SIM_INTERNAL_UNIT)) &&
|
if ((tmr != newtmr) && (!sim_is_active (&SIM_INTERNAL_UNIT))) {
|
||||||
(0 == rtc_hz[tmr])) {
|
|
||||||
/* Start the internal timer */
|
/* Start the internal timer */
|
||||||
sim_calb_tmr = SIM_NTIMERS;
|
sim_calb_tmr = SIM_NTIMERS;
|
||||||
sim_debug (DBG_TRC, &sim_timer_dev, "_rtcn_configure_calibrated_clock() - Starting Internal Calibrated Timer at %dHz\n", sim_int_clk_tps);
|
sim_debug (DBG_CAL, &sim_timer_dev, "_rtcn_configure_calibrated_clock() - Starting Internal Calibrated Timer at %dHz\n", sim_int_clk_tps);
|
||||||
SIM_INTERNAL_UNIT.action = &sim_timer_clock_tick_svc;
|
SIM_INTERNAL_UNIT.action = &sim_timer_clock_tick_svc;
|
||||||
sim_activate_abs (&SIM_INTERNAL_UNIT, CLK_INIT);
|
sim_activate_abs (&SIM_INTERNAL_UNIT, 0);
|
||||||
sim_rtcn_init_unit (&SIM_INTERNAL_UNIT, CLK_INIT, SIM_INTERNAL_CLK);
|
sim_rtcn_init_unit (&SIM_INTERNAL_UNIT, (CLK_INIT*CLK_TPS)/sim_int_clk_tps, SIM_INTERNAL_CLK);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -1924,7 +1984,7 @@ if ((tmr == newtmr) &&
|
||||||
(sim_calb_tmr == newtmr)) /* already set? */
|
(sim_calb_tmr == newtmr)) /* already set? */
|
||||||
return;
|
return;
|
||||||
if (sim_calb_tmr == SIM_NTIMERS) { /* was old the internal timer? */
|
if (sim_calb_tmr == SIM_NTIMERS) { /* was old the internal timer? */
|
||||||
sim_debug (DBG_TRC, &sim_timer_dev, "_rtcn_configure_calibrated_clock() - Stopping Internal Calibrated Timer, New Timer = %d (%dHz)\n", tmr, rtc_hz[tmr]);
|
sim_debug (DBG_CAL, &sim_timer_dev, "_rtcn_configure_calibrated_clock() - Stopping Internal Calibrated Timer, New Timer = %d (%dHz)\n", tmr, rtc_hz[tmr]);
|
||||||
rtc_initd[SIM_NTIMERS] = 0;
|
rtc_initd[SIM_NTIMERS] = 0;
|
||||||
rtc_hz[SIM_NTIMERS] = 0;
|
rtc_hz[SIM_NTIMERS] = 0;
|
||||||
sim_cancel (&SIM_INTERNAL_UNIT);
|
sim_cancel (&SIM_INTERNAL_UNIT);
|
||||||
|
@ -1937,7 +1997,7 @@ if (sim_calb_tmr == SIM_NTIMERS) { /* was old the internal timer? */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
sim_debug (DBG_TRC, &sim_timer_dev, "_rtcn_configure_calibrated_clock() - Changing Calibrated Timer from %d (%dHz) to %d (%dHz)\n", sim_calb_tmr, rtc_hz[sim_calb_tmr], tmr, rtc_hz[tmr]);
|
sim_debug (DBG_CAL, &sim_timer_dev, "_rtcn_configure_calibrated_clock() - Changing Calibrated Timer from %d (%dHz) to %d (%dHz)\n", sim_calb_tmr, rtc_hz[sim_calb_tmr], tmr, rtc_hz[tmr]);
|
||||||
sim_calb_tmr = tmr;
|
sim_calb_tmr = tmr;
|
||||||
}
|
}
|
||||||
sim_calb_tmr = tmr;
|
sim_calb_tmr = tmr;
|
||||||
|
@ -2001,7 +2061,8 @@ for (tmr=0; tmr<=SIM_NTIMERS; tmr++) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
rtc_hz[SIM_NTIMERS] = 0; /* Make sure Internal Timer is stopped */
|
sim_cancel (&SIM_INTERNAL_UNIT); /* Make sure Internal Timer is stopped */
|
||||||
|
sim_calb_tmr = -1;
|
||||||
#if defined(SIM_ASYNCH_CLOCKS)
|
#if defined(SIM_ASYNCH_CLOCKS)
|
||||||
pthread_mutex_lock (&sim_timer_lock);
|
pthread_mutex_lock (&sim_timer_lock);
|
||||||
if (sim_timer_thread_running) {
|
if (sim_timer_thread_running) {
|
||||||
|
@ -2057,7 +2118,7 @@ if (sim_calb_tmr == -1)
|
||||||
return inst_per_sec;
|
return inst_per_sec;
|
||||||
inst_per_sec = ((double)rtc_currd[sim_calb_tmr])*rtc_hz[sim_calb_tmr];
|
inst_per_sec = ((double)rtc_currd[sim_calb_tmr])*rtc_hz[sim_calb_tmr];
|
||||||
if (0 == inst_per_sec)
|
if (0 == inst_per_sec)
|
||||||
inst_per_sec = SIM_INITIAL_IPS;
|
inst_per_sec = ((double)rtc_currd[sim_calb_tmr])*sim_int_clk_tps;
|
||||||
return inst_per_sec;
|
return inst_per_sec;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2158,9 +2219,15 @@ sim_timer_units[tmr].flags = UNIT_DIS | (sim_clock_unit[tmr] ? UNIT_IDLE : 0);
|
||||||
return SCPE_OK;
|
return SCPE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Default timer is 0, otherwise use a calibrated one if it exists */
|
||||||
|
static int32 _default_tmr ()
|
||||||
|
{
|
||||||
|
return (rtc_currd[0] ? 0 : ((sim_calb_tmr != -1) ? rtc_currd[sim_calb_tmr] : 0));
|
||||||
|
}
|
||||||
|
|
||||||
static int32 _tick_size ()
|
static int32 _tick_size ()
|
||||||
{
|
{
|
||||||
return (sim_calb_tmr != -1) ? rtc_currd[sim_calb_tmr] : 10000;
|
return (rtc_currd[_default_tmr ()] ? rtc_currd[_default_tmr ()] : 10000);
|
||||||
}
|
}
|
||||||
|
|
||||||
int32 sim_rtcn_tick_size (int32 tmr)
|
int32 sim_rtcn_tick_size (int32 tmr)
|
||||||
|
@ -2177,17 +2244,17 @@ t_stat sim_clock_coschedule (UNIT *uptr, int32 interval)
|
||||||
{
|
{
|
||||||
int32 ticks = (interval + (_tick_size ()/2))/_tick_size ();/* Convert to ticks */
|
int32 ticks = (interval + (_tick_size ()/2))/_tick_size ();/* Convert to ticks */
|
||||||
|
|
||||||
sim_debug (DBG_QUE, &sim_timer_dev, "sim_clock_coschedule(interval=%d, ticks=%d)\n", interval, ticks);
|
sim_debug (DBG_QUE, &sim_timer_dev, "sim_clock_coschedule(%s, interval=%d, ticks=%d)\n", sim_uname(uptr), interval, ticks);
|
||||||
return sim_clock_coschedule_tmr (uptr, sim_calb_tmr, ticks);
|
return sim_clock_coschedule_tmr (uptr, _default_tmr (), ticks);
|
||||||
}
|
}
|
||||||
|
|
||||||
t_stat sim_clock_coschedule_abs (UNIT *uptr, int32 interval)
|
t_stat sim_clock_coschedule_abs (UNIT *uptr, int32 interval)
|
||||||
{
|
{
|
||||||
int32 ticks = (interval + (_tick_size ()/2))/_tick_size ();/* Convert to ticks */
|
int32 ticks = (interval + (_tick_size ()/2))/_tick_size ();/* Convert to ticks */
|
||||||
|
|
||||||
sim_debug (DBG_QUE, &sim_timer_dev, "sim_clock_coschedule_abs(interval=%d, ticks=%d)\n", interval, ticks);
|
sim_debug (DBG_QUE, &sim_timer_dev, "sim_clock_coschedule_abs(%s, interval=%d, ticks=%d)\n", sim_uname(uptr), interval, ticks);
|
||||||
sim_cancel (uptr);
|
sim_cancel (uptr);
|
||||||
return sim_clock_coschedule_tmr (uptr, sim_calb_tmr, ticks);
|
return sim_clock_coschedule_tmr (uptr, _default_tmr (), ticks);
|
||||||
}
|
}
|
||||||
|
|
||||||
t_stat sim_clock_coschedule_tmr (UNIT *uptr, int32 tmr, int32 ticks)
|
t_stat sim_clock_coschedule_tmr (UNIT *uptr, int32 tmr, int32 ticks)
|
||||||
|
|
|
@ -76,7 +76,7 @@ int clock_gettime(int clock_id, struct timespec *tp);
|
||||||
#define SIM_NTIMERS 8 /* # timers */
|
#define SIM_NTIMERS 8 /* # timers */
|
||||||
#define SIM_TMAX 500 /* max timer makeup */
|
#define SIM_TMAX 500 /* max timer makeup */
|
||||||
|
|
||||||
#define SIM_INITIAL_IPS 50000 /* uncalibrated assumption */
|
#define SIM_INITIAL_IPS 500000 /* uncalibrated assumption */
|
||||||
/* about instructions per second */
|
/* about instructions per second */
|
||||||
|
|
||||||
#define SIM_IDLE_CAL 10 /* ms to calibrate */
|
#define SIM_IDLE_CAL 10 /* ms to calibrate */
|
||||||
|
|
Loading…
Add table
Reference in a new issue