Lots of updates. Doesn't sync with real time yet.

This commit is contained in:
Gregory Alexander 2003-02-16 04:58:43 +00:00
parent b0e7f6d0c6
commit a0070f6c69
2 changed files with 155 additions and 43 deletions

View File

@ -2,33 +2,34 @@
bx_virt_timer_c bx_virt_timer; bx_virt_timer_c bx_virt_timer;
const Bit64u bx_pc_system_c::NullTimerInterval = BX_MAX_VIRTUAL_TIME;
static void static void
bx_virt_timer_c::nullTimer(void* this_ptr) { bx_virt_timer_c::nullTimer(void* this_ptr) {
UNUSED(this_ptr); UNUSED(this_ptr);
} }
Bit64u get_next_event_time(void) {
return next_event_time;
}
void periodic(Bit64u time_passed) { void periodic(Bit64u time_passed) {
//Assert that we haven't skipped any events. //Assert that we haven't skipped any events.
BX_ASSERT (time_passed <= next_event_time); BX_ASSERT (time_passed <= timers_next_event_time);
BX_ASSERT(!in_timer_handler);
//Update time variables. //Update time variables.
next_event_time -= time_passed; timers_next_event_time -= time_passed;
current_virtual_time += time_passed; current_timers_time += time_passed;
//If no events are occurring, just pass the time and we're done. //If no events are occurring, just pass the time and we're done.
if( time_passed < next_event_time ) { if( time_passed < timers_next_event_time ) {
return; return;
} }
//Starting timer handler calls.
in_timer_handler = 1;
//Otherwise, cause any events to occur that should. //Otherwise, cause any events to occur that should.
for(i=0;i<numTimers;i++) { for(i=0;i<numTimers;i++) {
if( timer[i].inUse && timer[i].active ) { if( timer[i].inUse && timer[i].active ) {
//Assert that we haven't skipped any timers. //Assert that we haven't skipped any timers.
BX_ASSERT(current_virtual_time <= timer[i].timeToFire); BX_ASSERT(current_timers_time <= timer[i].timeToFire);
if(timer[i].timeToFire == current_virtual_time) { if(timer[i].timeToFire == current_timers_time) {
if(timer[i].continuous) { if(timer[i].continuous) {
timer[i].timeToFire+=timer[i].period; timer[i].timeToFire+=timer[i].period;
} else { } else {
@ -40,18 +41,20 @@ void periodic(Bit64u time_passed) {
} }
} }
} }
//Finished timer handler calls.
in_timer_handler = 0;
//Use a second FOR loop so that a timer function call can //Use a second FOR loop so that a timer function call can
// change the behavior of another timer. // change the behavior of another timer.
//next_event_time normally contains a cycle count, not a cycle time. //timers_next_event_time normally contains a cycle count, not a cycle time.
// here we use it as a temporary variable that IS a cycle time, // here we use it as a temporary variable that IS a cycle time,
// but then convert it back to a cycle count afterwards. // but then convert it back to a cycle count afterwards.
next_event_time = current_virtual_time + BX_MAX_VIRTUAL_TIME; timers_next_event_time = current_timers_time + BX_MAX_VIRTUAL_TIME;
for(i=0;i<numTimers;i++) { for(i=0;i<numTimers;i++) {
if( timer[i].inUse && timer[i].active && ((timer[i].timeToFire)<next_event_time) ) { if( timer[i].inUse && timer[i].active && ((timer[i].timeToFire)<timers_next_event_time) ) {
next_event_time = timer[i].timeToFire; timers_next_event_time = timer[i].timeToFire;
} }
} }
next_event_time-=current_virtual_time; timers_next_event_time-=current_timers_time;
//FIXME //FIXME
} }
@ -59,14 +62,14 @@ void periodic(Bit64u time_passed) {
//Get the current virtual time. //Get the current virtual time.
// This may return the same value on subsequent calls. // This may return the same value on subsequent calls.
Bit64u Bit64u
bx_virt_timer_c::get_virtual_time(void) { bx_virt_timer_c::time_usec(void) {
if(!use_virtual_timers) { if(!use_virtual_timers) {
return bx_pc_system.time_usec(); return bx_pc_system.time_usec();
} }
//I might choose to update the time here, but this is //I might choose to update the time here, but this is
// safer, since it prevents call stack loops. // safer, since it prevents call stack loops.
return current_virtual_time; return current_timers_time;
} }
//Get the current virtual time. //Get the current virtual time.
@ -79,10 +82,15 @@ bx_virt_timer_c::time_usec_sequential(void) {
} }
//Can't prevent call stack loops here, so this //Can't prevent call stack loops here, so this
// MUST NOT be called from within a timer interrupt. // MUST NOT be called from within a timer handler.
BX_ASSERT(next_event_time>0); BX_ASSERT(timers_next_event_time>0);
periodic(1); BX_ASSERT(!in_timer_handler);
return current_virtual_time;
if(last_sequential_time >= current_timers_time) {
periodic(1);
last_sequential_time = current_timers_time;
}
return current_timers_time;
} }
@ -115,7 +123,7 @@ bx_virt_timer_c::register_timer( void *this_ptr, bx_timer_handler_t handler,
timer[i].inUse = 1; timer[i].inUse = 1;
timer[i].period = useconds; timer[i].period = useconds;
timer[i].timeToFire = current_virtual_time + (Bit64u)useconds; timer[i].timeToFire = current_timers_time + (Bit64u)useconds;
timer[i].active = active; timer[i].active = active;
timer[i].continuous = continuous; timer[i].continuous = continuous;
timer[i].funct = handler; timer[i].funct = handler;
@ -123,8 +131,8 @@ bx_virt_timer_c::register_timer( void *this_ptr, bx_timer_handler_t handler,
strncpy(timer[i].id, id, BxMaxTimerIDLen); strncpy(timer[i].id, id, BxMaxTimerIDLen);
id[BxMaxTimerIDLen]=0; //I like null terminated strings. id[BxMaxTimerIDLen]=0; //I like null terminated strings.
if(period < next_event_time) { if(period < timers_next_event_time) {
next_event_time = period; timers_next_event_time = period;
//FIXME //FIXME
} }
} }
@ -135,7 +143,11 @@ bx_virt_timer_c::unregisterTimer(int timerID) {
if(!use_virtual_timers) { if(!use_virtual_timers) {
return bx_pc_system.unregisterTimer(timerID); return bx_pc_system.unregisterTimer(timerID);
} }
//FIXME: Need error checking.
BX_ASSERT(timerID >= 0);
BX_ASSERT(timerID < BX_MAX_VIRTUAL_TIMERS);
//No need to prevent doing this to unused timers.
timer[timerID].inUse = 0; timer[timerID].inUse = 0;
} }
@ -154,7 +166,21 @@ bx_virt_timer_c::activate_timer( unsigned timer_index, Bit32u useconds,
if(!use_virtual_timers) { if(!use_virtual_timers) {
return bx_pc_system.activate_timer(timer_index, useconds, continuous); return bx_pc_system.activate_timer(timer_index, useconds, continuous);
} }
//FIXME
BX_ASSERT(timer_index >= 0);
BX_ASSERT(timer_index < BX_MAX_VIRTUAL_TIMERS);
BX_ASSERT(timer[timer_index].inUse);
timer[timer_index].period=useconds;
timer[timer_index].timeToFire = current_timers_time + (Bit64u)useconds;
timer[timer_index].active=1;
timer[timer_index].continuous=continuous;
if(period < timers_next_event_time) {
timers_next_event_time = period;
//FIXME
}
} }
//deactivate (but don't unregister) a currently registered timer. //deactivate (but don't unregister) a currently registered timer.
@ -163,7 +189,75 @@ bx_virt_timer_c::deactivate_timer( unsigned timer_index ) {
if(!use_virtual_timers) { if(!use_virtual_timers) {
return bx_pc_system.deactivate_timer(timer_index); return bx_pc_system.deactivate_timer(timer_index);
} }
//FIXME: Need error checking.
BX_ASSERT(timer_index >= 0);
BX_ASSERT(timer_index < BX_MAX_VIRTUAL_TIMERS);
//No need to prevent doing this to unused/inactive timers.
timer[timer_index].active = 0; timer[timer_index].active = 0;
} }
void
bx_virt_timer_c::advance_virtual_time(Bit64u time_passed) {
ASSERT(time_passed <= virtual_next_event_time);
current_virtual_time += time_passed;
virtual_next_event_time -= time_passed;
if(current_virtual_time > current_timers_time) {
periodic(current_virtual_time - current_timers_time);
}
}
//Called when next_event_time changes.
void
bx_virt_timer_c::next_event_time_update(void) {
virtual_next_event_time = timers_next_event_time + current_timers_time - current_virtual_time;
}
void
bx_virt_timer_c::init(void) {
numTimers = 0;
current_timers_time = 0;
timers_next_event_time = BX_MAX_VIRTUAL_TIME;
last_sequential_time = 0;
in_timer_handler = 0;
virtual_next_event_time = 0;
current_virtual_time = 0;
use_virtual_timers = BX_USE_VIRTUAL_TIMERS;
virtual_timers_realtime = BX_VIRTUAL_TIMERS_REALTIME;
register_timer(this, nullTimer, NullTimerInterval, 1, 1, "Null Timer");
system_timer_id = bx_pc_system.register_timer(this, pc_system_timer_handler, BX_MAX_VIRTUAL_TIME, 0, 1, "Virtual Timer");
}
void
bx_virt_timer_c::timer_handler(void) {
if(!virtual_timers_realtime) {
Bit64u temp_final_time = bx_pc_system.time_usec();
temp_final_time-=current_virtual_time;
while(temp_final_time) {
if((temp_final_time)>(virtual_next_event_time)) {
temp_final_time-=virtual_next_event_time;
advance_virtual_time(virtual_next_event_time);
} else {
advance_virtual_time(temp_final_time);
temp_final_time-=temp_final_time;
}
}
bx_pc_system.activate_timer(system_timer_id,
(virtual_next_event_time>2)?(virtual_next_event_time-2):1,
0);
return;
}
}
static void
bx_virt_timer_c::pc_system_timer_handler(void* this_ptr) {
((bx_virt_timer_c *)this_ptr)->timer_handler();
}

View File

@ -1,10 +1,11 @@
#define BX_USE_VIRTUAL_TIMERS 0 #define BX_USE_VIRTUAL_TIMERS 0
#define BX_VIRTUAL_TIMERS_REALTIME 0
#define BX_MAX_VIRTUAL_TIMERS (15+BX_SMP_PROCESSORS) #define BX_MAX_VIRTUAL_TIMERS (15+BX_SMP_PROCESSORS)
#define BX_NULL_VIRTUAL_TIMER_HANDLE 10000 #define BX_NULL_VIRTUAL_TIMER_HANDLE 10000
#define BX_MAX_VIRTUAL_TIME (100000) #define BX_MAX_VIRTUAL_TIME (0x7fffffff)
class bx_virt_timer_c { class bx_virt_timer_c {
private: private:
@ -26,24 +27,21 @@ class bx_virt_timer_c {
unsigned numTimers; // Number of currently allocated timers. unsigned numTimers; // Number of currently allocated timers.
//Variables for the timer subsystem: //Variables for the timer subsystem:
Bit64u current_virtual_time; Bit64u current_timers_time;
Bit64u next_event_time; Bit64u timers_next_event_time;
Bit64u last_sequential_time;
bx_bool in_timer_handler;
//Variables for the time sync subsystem: //Variables for the time sync subsystem:
Bit64u last_ips_time; Bit64u virtual_next_event_time;
Bit64u last_virtual_time; Bit64u current_virtual_time;
Bit64u last_host_time;
Bit64u initial_ips_time; int system_timer_id;
Bit64u initial_virtual_time;
Bit64u initial_host_time;
Bit64u next_virtual_time;
Bit64u next_ips_time;
Bit64u virtual_time_calls;
//Whether or not to use virtual timers.
bx_bool use_virtual_timers; bx_bool use_virtual_timers;
bx_bool virtual_timers_realtime;
// A special null timer is always inserted in the timer[0] slot. This // A special null timer is always inserted in the timer[0] slot. This
// make sure that at least one timer is always active, and that the // make sure that at least one timer is always active, and that the
@ -53,19 +51,35 @@ class bx_virt_timer_c {
static void nullTimer(void* this_ptr); static void nullTimer(void* this_ptr);
Bit64u get_next_event_time(void); //Cycle count until the next timer handler needs to be called.
void update_next_virtual_event_time(void){
return timers_next_event_time + current_timers_time - current_virtual_time;
}
//Step the given number of cycles, optionally calling any timer handlers.
void periodic(Bit64u time_passed); void periodic(Bit64u time_passed);
//Called when next_event_time changes.
void next_event_time_update(void);
//Called to advance the virtual time.
// calls periodic as needed.
void advance_virtual_time(Bit64u time_passed);
//The real timer handler.
void timer_handler();
public: public:
//Get the current virtual time. //Get the current virtual time.
// This may return the same value on subsequent calls. // This may return the same value on subsequent calls.
Bit64u time_usec(void); Bit64u time_usec(void);
//Get the current virtual time. //Get the current virtual time.
// This will return a monotonically increasing value. // This will return a monotonically increasing value.
// MUST NOT be called from within a timer interrupt. // MUST NOT be called from within a timer handler.
Bit64u time_usec_sequential(void); Bit64u time_usec_sequential(void);
//Register a timer handler to go off after a given interval. //Register a timer handler to go off after a given interval.
@ -86,6 +100,10 @@ class bx_virt_timer_c {
//deactivate (but don't unregister) a currently registered timer. //deactivate (but don't unregister) a currently registered timer.
void deactivate_timer( unsigned timer_index ); void deactivate_timer( unsigned timer_index );
//Timer handler passed to pc_system
void pc_system_timer_handler(void* this_ptr);
} }