Working on timer part.

This commit is contained in:
Gregory Alexander 2003-02-15 23:39:41 +00:00
parent c0d7138924
commit b0e7f6d0c6
2 changed files with 106 additions and 2 deletions

View File

@ -7,6 +7,54 @@ bx_virt_timer_c::nullTimer(void* this_ptr) {
UNUSED(this_ptr);
}
Bit64u get_next_event_time(void) {
return next_event_time;
}
void periodic(Bit64u time_passed) {
//Assert that we haven't skipped any events.
BX_ASSERT (time_passed <= next_event_time);
//Update time variables.
next_event_time -= time_passed;
current_virtual_time += time_passed;
//If no events are occurring, just pass the time and we're done.
if( time_passed < next_event_time ) {
return;
}
//Otherwise, cause any events to occur that should.
for(i=0;i<numTimers;i++) {
if( timer[i].inUse && timer[i].active ) {
//Assert that we haven't skipped any timers.
BX_ASSERT(current_virtual_time <= timer[i].timeToFire);
if(timer[i].timeToFire == current_virtual_time) {
if(timer[i].continuous) {
timer[i].timeToFire+=timer[i].period;
} else {
timer[i].active = 0;
}
//This function MUST return, or the timer mechanism
// will be broken.
timer[i].funct(this_ptr);
}
}
}
//Use a second FOR loop so that a timer function call can
// change the behavior of another timer.
//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,
// but then convert it back to a cycle count afterwards.
next_event_time = current_virtual_time + BX_MAX_VIRTUAL_TIME;
for(i=0;i<numTimers;i++) {
if( timer[i].inUse && timer[i].active && ((timer[i].timeToFire)<next_event_time) ) {
next_event_time = timer[i].timeToFire;
}
}
next_event_time-=current_virtual_time;
//FIXME
}
//Get the current virtual time.
// This may return the same value on subsequent calls.
@ -15,15 +63,26 @@ bx_virt_timer_c::get_virtual_time(void) {
if(!use_virtual_timers) {
return bx_pc_system.time_usec();
}
//I might choose to update the time here, but this is
// safer, since it prevents call stack loops.
return current_virtual_time;
}
//Get the current virtual time.
// This will return a monotonically increasing value.
// MUST NOT be called from within a timer interrupt.
Bit64u
bx_virt_timer_c::time_usec_sequential(void) {
if(!use_virtual_timers) {
return bx_pc_system.time_usec_sequential();
}
//Can't prevent call stack loops here, so this
// MUST NOT be called from within a timer interrupt.
BX_ASSERT(next_event_time>0);
periodic(1);
return current_virtual_time;
}
@ -39,6 +98,35 @@ bx_virt_timer_c::register_timer( void *this_ptr, bx_timer_handler_t handler,
return bx_pc_system.register_timer(this_ptr, handler, useconds,
continuous, active, id);
}
//We don't like starting with a zero period timer.
BX_ASSERT((!active) || (period>0));
//Search for an unused timer.
int i;
for (i=0; i < numTimers; i++) {
if (timer[i].inUse == 0 || i==numTimers)
break;
}
// If we didn't find a free slot, increment the bound, numTimers.
if (i==numTimers)
numTimers++; // One new timer installed.
BX_ASSERT(numTimers<BX_MAX_VIRTUAL_TIMERS);
timer[i].inUse = 1;
timer[i].period = useconds;
timer[i].timeToFire = current_virtual_time + (Bit64u)useconds;
timer[i].active = active;
timer[i].continuous = continuous;
timer[i].funct = handler;
timer[i].this_ptr = this_ptr;
strncpy(timer[i].id, id, BxMaxTimerIDLen);
id[BxMaxTimerIDLen]=0; //I like null terminated strings.
if(period < next_event_time) {
next_event_time = period;
//FIXME
}
}
//unregister a previously registered timer.
@ -47,6 +135,8 @@ bx_virt_timer_c::unregisterTimer(int timerID) {
if(!use_virtual_timers) {
return bx_pc_system.unregisterTimer(timerID);
}
//FIXME: Need error checking.
timer[timerID].inUse = 0;
}
void
@ -54,6 +144,7 @@ bx_virt_timer_c::start_timers(void) {
if(!use_virtual_timers) {
return bx_pc_system.start_timers();
}
//FIXME
}
//activate a deactivated but registered timer.
@ -63,6 +154,7 @@ bx_virt_timer_c::activate_timer( unsigned timer_index, Bit32u useconds,
if(!use_virtual_timers) {
return bx_pc_system.activate_timer(timer_index, useconds, continuous);
}
//FIXME
}
//deactivate (but don't unregister) a currently registered timer.
@ -71,5 +163,7 @@ bx_virt_timer_c::deactivate_timer( unsigned timer_index ) {
if(!use_virtual_timers) {
return bx_pc_system.deactivate_timer(timer_index);
}
//FIXME: Need error checking.
timer[timer_index].active = 0;
}

View File

@ -2,8 +2,9 @@
#define BX_USE_VIRTUAL_TIMERS 0
#define BX_MAX_VIRTUAL_TIMERS (15+BX_SMP_PROCESSORS)
#define BX_NULL_VIRTUAL_TIMER_HANDLE 100000
#define BX_NULL_VIRTUAL_TIMER_HANDLE 10000
#define BX_MAX_VIRTUAL_TIME (100000)
class bx_virt_timer_c {
private:
@ -16,14 +17,19 @@ class bx_virt_timer_c {
bx_bool continuous; // 0=one-shot timer, 1=continuous periodicity.
bx_timer_handler_t funct; // A callback function for when the
// timer fires.
// This function MUST return.
void *this_ptr; // The this-> pointer for C++ callbacks
// has to be stored as well.
#define BxMaxTimerIDLen 32
char id[BxMaxTimerIDLen]; // String ID of timer.
} timer[BX_MAX_VIRTUAL_TIMERS];
unsigned numTimers; // Number of currently allocated timers.
//Variables for the timer subsystem:
Bit64u current_virtual_time;
Bit64u next_event_time;
//Variables for the time sync subsystem:
Bit64u last_ips_time;
Bit64u last_virtual_time;
Bit64u last_host_time;
@ -47,6 +53,9 @@ class bx_virt_timer_c {
static void nullTimer(void* this_ptr);
Bit64u get_next_event_time(void);
void periodic(Bit64u time_passed);
public:
@ -56,6 +65,7 @@ class bx_virt_timer_c {
//Get the current virtual time.
// This will return a monotonically increasing value.
// MUST NOT be called from within a timer interrupt.
Bit64u time_usec_sequential(void);
//Register a timer handler to go off after a given interval.