TIMER: Add calibrated ROM memory access support
This commit is contained in:
parent
9c89b0e08b
commit
b800587f34
3 changed files with 87 additions and 0 deletions
|
@ -267,10 +267,13 @@ typedef uint32 t_addr;
|
||||||
|
|
||||||
#if defined(_MSC_VER)
|
#if defined(_MSC_VER)
|
||||||
#define SIM_INLINE _inline
|
#define SIM_INLINE _inline
|
||||||
|
#define SIM_NOINLINE _declspec (noinline)
|
||||||
#elif defined(__GNUC__)
|
#elif defined(__GNUC__)
|
||||||
#define SIM_INLINE inline
|
#define SIM_INLINE inline
|
||||||
|
#define SIM_NOINLINE __attribute__ ((noinline))
|
||||||
#else
|
#else
|
||||||
#define SIM_INLINE
|
#define SIM_INLINE
|
||||||
|
#define SIM_NOINLINE
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Storage class modifier for weak link definition for sim_vm_init() */
|
/* Storage class modifier for weak link definition for sim_vm_init() */
|
||||||
|
|
81
sim_timer.c
81
sim_timer.c
|
@ -72,6 +72,11 @@
|
||||||
event
|
event
|
||||||
sim_timespec_diff subtract two timespec values
|
sim_timespec_diff subtract two timespec values
|
||||||
sim_timer_activate_after schedule unit for specific time
|
sim_timer_activate_after schedule unit for specific time
|
||||||
|
sim_timer_activate_time determine activation time
|
||||||
|
sim_timer_activate_time_usecs determine activation time in usecs
|
||||||
|
sim_rom_read_with_delay delay for default or specified delay
|
||||||
|
sim_get_rom_delay_factor get current or initialize 1usec delay factor
|
||||||
|
sim_set_rom_delay_factor set specific delay factor
|
||||||
|
|
||||||
|
|
||||||
The calibration, idle, and throttle routines are OS-independent; the _os_
|
The calibration, idle, and throttle routines are OS-independent; the _os_
|
||||||
|
@ -156,6 +161,7 @@ static uint32 sim_os_clock_resoluton_ms = 0;
|
||||||
static uint32 sim_os_tick_hz = 0;
|
static uint32 sim_os_tick_hz = 0;
|
||||||
static uint32 sim_idle_stable = SIM_IDLE_STDFLT;
|
static uint32 sim_idle_stable = SIM_IDLE_STDFLT;
|
||||||
static uint32 sim_idle_calib_pct = 0;
|
static uint32 sim_idle_calib_pct = 0;
|
||||||
|
static uint32 sim_rom_delay = 0;
|
||||||
static uint32 sim_throt_ms_start = 0;
|
static uint32 sim_throt_ms_start = 0;
|
||||||
static uint32 sim_throt_ms_stop = 0;
|
static uint32 sim_throt_ms_stop = 0;
|
||||||
static uint32 sim_throt_type = 0;
|
static uint32 sim_throt_type = 0;
|
||||||
|
@ -1023,6 +1029,7 @@ sim_throttle_unit.action = &sim_throt_svc;
|
||||||
sim_register_clock_unit_tmr (&SIM_INTERNAL_UNIT, SIM_INTERNAL_CLK);
|
sim_register_clock_unit_tmr (&SIM_INTERNAL_UNIT, SIM_INTERNAL_CLK);
|
||||||
sim_idle_enab = FALSE; /* init idle off */
|
sim_idle_enab = FALSE; /* init idle off */
|
||||||
sim_idle_rate_ms = sim_os_ms_sleep_init (); /* get OS timer rate */
|
sim_idle_rate_ms = sim_os_ms_sleep_init (); /* get OS timer rate */
|
||||||
|
sim_set_rom_delay_factor (sim_get_rom_delay_factor ()); /* initialize ROM delay factor */
|
||||||
|
|
||||||
clock_last = clock_start = sim_os_msec ();
|
clock_last = clock_start = sim_os_msec ();
|
||||||
sim_os_clock_resoluton_ms = 1000;
|
sim_os_clock_resoluton_ms = 1000;
|
||||||
|
@ -1235,6 +1242,7 @@ return SCPE_OK;
|
||||||
|
|
||||||
REG sim_timer_reg[] = {
|
REG sim_timer_reg[] = {
|
||||||
{ DRDATAD (IDLE_CYC_MS, sim_idle_cyc_ms, 32, "Cycles Per Millisecond"), PV_RSPC|REG_RO},
|
{ DRDATAD (IDLE_CYC_MS, sim_idle_cyc_ms, 32, "Cycles Per Millisecond"), PV_RSPC|REG_RO},
|
||||||
|
{ DRDATAD (ROM_DELAY, sim_rom_delay, 32, "ROM memory reference delay"), PV_RSPC|REG_RO},
|
||||||
{ NULL }
|
{ NULL }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -2779,3 +2787,76 @@ for (tmr=0; tmr<SIM_NTIMERS; tmr++)
|
||||||
return (1000000.0 * sim_activate_time (&sim_timer_units[tmr])) / sim_timer_inst_per_sec ();
|
return (1000000.0 * sim_activate_time (&sim_timer_units[tmr])) / sim_timer_inst_per_sec ();
|
||||||
return -1.0; /* Not found. */
|
return -1.0; /* Not found. */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* read only memory delayed support
|
||||||
|
|
||||||
|
Some simulation activities need a 'regulated' memory access
|
||||||
|
time to meet timing assumptions in the code being executed.
|
||||||
|
|
||||||
|
The default calibration determines a way to limit activities
|
||||||
|
to 1Mhz for each call to sim_rom_read_with_delay(). If a
|
||||||
|
simulator needs a different delay factor, the 1 Mhz initial
|
||||||
|
value can be queried with sim_get_rom_delay_factor() and the
|
||||||
|
result can be adjusted as nessary and the operating delay
|
||||||
|
can be set with sim_set_rom_delay_factor().
|
||||||
|
*/
|
||||||
|
|
||||||
|
SIM_NOINLINE static int32 _rom_swapb(int32 val)
|
||||||
|
{
|
||||||
|
return ((val << 24) & 0xff000000) | (( val << 8) & 0xff0000) |
|
||||||
|
((val >> 8) & 0xff00) | ((val >> 24) & 0xff);
|
||||||
|
}
|
||||||
|
|
||||||
|
static volatile int32 rom_loopval = 0;
|
||||||
|
|
||||||
|
SIM_NOINLINE int32 sim_rom_read_with_delay (int32 val)
|
||||||
|
{
|
||||||
|
uint32 i, l = sim_rom_delay;
|
||||||
|
|
||||||
|
for (i = 0; i < l; i++)
|
||||||
|
rom_loopval |= (rom_loopval + val) ^ _rom_swapb (_rom_swapb (rom_loopval + val));
|
||||||
|
return val + rom_loopval;
|
||||||
|
}
|
||||||
|
|
||||||
|
SIM_NOINLINE uint32 sim_get_rom_delay_factor (void)
|
||||||
|
{
|
||||||
|
/* Calibrate the loop delay factor at startup.
|
||||||
|
Do this 4 times and use the largest value computed.
|
||||||
|
The goal here is to come up with a delay factor which will throttle
|
||||||
|
a 6 byte delay loop running from ROM address space to execute
|
||||||
|
1 instruction per usec */
|
||||||
|
|
||||||
|
if (sim_rom_delay == 0) {
|
||||||
|
uint32 i, ts, te, c = 10000, samples = 0;
|
||||||
|
while (1) {
|
||||||
|
c = c * 2;
|
||||||
|
te = sim_os_msec();
|
||||||
|
while (te == (ts = sim_os_msec ())); /* align on ms tick */
|
||||||
|
|
||||||
|
/* This is merely a busy wait with some "work" that won't get optimized
|
||||||
|
away by a good compiler. loopval always is zero. To avoid smart compilers,
|
||||||
|
the loopval variable is referenced in the function arguments so that the
|
||||||
|
function expression is not loop invariant. It also must be referenced
|
||||||
|
by subsequent code to avoid the whole computation being eliminated. */
|
||||||
|
|
||||||
|
for (i = 0; i < c; i++)
|
||||||
|
rom_loopval |= (rom_loopval + ts) ^ _rom_swapb (_rom_swapb (rom_loopval + ts));
|
||||||
|
te = sim_os_msec ();
|
||||||
|
if ((te - ts) < 50) /* sample big enough? */
|
||||||
|
continue;
|
||||||
|
if (sim_rom_delay < (rom_loopval + (c / (te - ts) / 1000) + 1))
|
||||||
|
sim_rom_delay = rom_loopval + (c / (te - ts) / 1000) + 1;
|
||||||
|
if (++samples >= 4)
|
||||||
|
break;
|
||||||
|
c = c / 2;
|
||||||
|
}
|
||||||
|
if (sim_rom_delay < 5)
|
||||||
|
sim_rom_delay = 5;
|
||||||
|
}
|
||||||
|
return sim_rom_delay;
|
||||||
|
}
|
||||||
|
|
||||||
|
void sim_set_rom_delay_factor (uint32 delay)
|
||||||
|
{
|
||||||
|
sim_rom_delay = delay;
|
||||||
|
}
|
||||||
|
|
|
@ -151,6 +151,9 @@ t_bool sim_timer_idle_capable (uint32 *host_ms_sleep_1, uint32 *host_tick_ms);
|
||||||
#define PRIORITY_NORMAL 0
|
#define PRIORITY_NORMAL 0
|
||||||
#define PRIORITY_ABOVE_NORMAL 1
|
#define PRIORITY_ABOVE_NORMAL 1
|
||||||
t_stat sim_os_set_thread_priority (int below_normal_above);
|
t_stat sim_os_set_thread_priority (int below_normal_above);
|
||||||
|
uint32 sim_get_rom_delay_factor (void);
|
||||||
|
void sim_set_rom_delay_factor (uint32 delay);
|
||||||
|
int32 sim_rom_read_with_delay (int32 val);
|
||||||
|
|
||||||
extern t_bool sim_idle_enab; /* idle enabled flag */
|
extern t_bool sim_idle_enab; /* idle enabled flag */
|
||||||
extern volatile t_bool sim_idle_wait; /* idle waiting flag */
|
extern volatile t_bool sim_idle_wait; /* idle waiting flag */
|
||||||
|
|
Loading…
Add table
Reference in a new issue