1 ////////////////////////////////////////////////////////////////////////
2 // $Id: virt_timer.cc,v 1.37 2008/02/15 22:05:43 sshwarts Exp $
3 /////////////////////////////////////////////////////////////////////////
5 // Copyright (C) 2002 MandrakeSoft S.A.
9 // 75002 Paris - France
10 // http://www.linux-mandrake.com/
11 // http://www.mandrakesoft.com/
13 // This library is free software; you can redistribute it and/or
14 // modify it under the terms of the GNU Lesser General Public
15 // License as published by the Free Software Foundation; either
16 // version 2 of the License, or (at your option) any later version.
18 // This library is distributed in the hope that it will be useful,
19 // but WITHOUT ANY WARRANTY; without even the implied warranty of
20 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 // Lesser General Public License for more details.
23 // You should have received a copy of the GNU Lesser General Public
24 // License along with this library; if not, write to the Free Software
25 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
26 ////////////////////////////////////////////////////////////////////////
28 /////////////////////////////////////////////////////////////////////////
30 //Realtime Algorithm (with gettimeofday)
32 // Real number of usec.
33 // Emulated number of usec.
35 // Number of ticks to use.
36 // Number of emulated usec to wait until next try.
38 // ticks=number of ticks needed to match total real usec.
39 // if(desired ticks > max ticks for elapsed real time)
40 // ticks = max ticks for elapsed real time.
41 // if(desired ticks > max ticks for elapsed emulated usec)
42 // ticks = max ticks for emulated usec.
43 // next wait ticks = number of ticks until next event.
44 // next wait real usec = (current ticks + next wait ticks) * usec per ticks
45 // next wait emulated usec = next wait real usec * emulated usec / real usec
46 // if(next wait emulated usec < minimum emulated usec for next wait ticks)
47 // next wait emulated usec = minimum emulated usec for next wait ticks.
48 // if(next wait emulated usec > max emulated usec wait)
49 // next wait emulated usec = max emulated usec wait.
51 // How to calculate elapsed real time:
52 // store an unused time value whenever no ticks are used in a given time.
53 // add this to the current elapsed time.
54 // How to calculate elapsed emulated time:
56 // Above can be done by not updating last_usec and last_sec.
58 // How to calculate emulated usec/real usec:
59 // Each time there are actual ticks:
60 // Alpha_product(old emulated usec, emulated usec);
61 // Alpha_product(old real usec, real usec);
62 // Divide resulting values.
64 /////////////////////////////////////////////////////////////////////////
67 #include "virt_timer.h"
69 #define BX_USE_VIRTUAL_TIMERS 1
70 #define BX_VIRTUAL_TIMERS_REALTIME 1
72 //Important constant #defines:
73 #define USEC_PER_SECOND (1000000)
76 // define a macro to convert floating point numbers into 64-bit integers.
77 // In MSVC++ you can convert a 64-bit float into a 64-bit signed integer,
78 // but it will not convert a 64-bit float into a 64-bit unsigned integer.
79 // This macro works around that.
80 #define F2I(x) ((Bit64u)(Bit64s) (x))
81 #define I2F(x) ((double)(Bit64s) (x))
83 //CONFIGURATION #defines:
86 //MAINLINE Configuration (For realtime PIT):
88 //How much faster than real time we can go:
89 #define MAX_MULT (1.25)
91 //Minimum number of emulated useconds per second.
92 // Now calculated using BX_MIN_IPS, the minimum number of
93 // instructions per second.
94 #define MIN_USEC_PER_SECOND (((((Bit64u)USEC_PER_SECOND)*((Bit64u)BX_MIN_IPS))/((Bit64u)(SIM->get_param_num(BXPN_IPS)->get())))+(Bit64u)1)
97 //DEBUG configuration:
99 //Debug with printf options.
100 #define DEBUG_REALTIME_WITH_PRINTF 0
102 //Use to test execution at multiples of real time.
103 #define TIME_DIVIDER (1)
104 #define TIME_MULTIPLIER (1)
105 #define TIME_HEADSTART (0)
108 #define GET_VIRT_REALTIME64_USEC() (((bx_get_realtime64_usec()*(Bit64u)TIME_MULTIPLIER/(Bit64u)TIME_DIVIDER)))
110 #define LOG_THIS bx_virt_timer.
113 bx_virt_timer_c bx_virt_timer
;
116 //Generic MAX and MIN Functions
117 #define BX_MAX(a,b) ( ((a)>(b))?(a):(b) )
118 #define BX_MIN(a,b) ( ((a)>(b))?(b):(a) )
121 //USEC_ALPHA is multiplier for the past.
122 //USEC_ALPHA_B is 1-USEC_ALPHA, or multiplier for the present.
123 #define USEC_ALPHA ((double)(.8))
124 #define USEC_ALPHA_B ((double)(((double)1)-USEC_ALPHA))
125 #define USEC_ALPHA2 ((double)(.5))
126 #define USEC_ALPHA2_B ((double)(((double)1)-USEC_ALPHA2))
127 #define ALPHA_LOWER(old,new) ((Bit64u)((old<new)?((USEC_ALPHA*(I2F(old)))+(USEC_ALPHA_B*(I2F(new)))):((USEC_ALPHA2*(I2F(old)))+(USEC_ALPHA2_B*(I2F(new))))))
130 //Conversion between emulated useconds and optionally realtime ticks.
131 #define TICKS_TO_USEC(a) (((a)*usec_per_second)/ticks_per_second)
132 #define USEC_TO_TICKS(a) (((a)*ticks_per_second)/usec_per_second)
134 bx_virt_timer_c::bx_virt_timer_c()
142 const Bit64u
bx_virt_timer_c::NullTimerInterval
= BX_MAX_VIRTUAL_TIME
;
144 void bx_virt_timer_c::nullTimer(void* this_ptr
)
149 void bx_virt_timer_c::periodic(Bit64u time_passed
)
151 //Assert that we haven't skipped any events.
152 BX_ASSERT (time_passed
<= timers_next_event_time
);
153 BX_ASSERT(!in_timer_handler
);
155 //Update time variables.
156 timers_next_event_time
-= time_passed
;
157 current_timers_time
+= time_passed
;
159 //If no events are occurring, just pass the time and we're done.
160 if(time_passed
< timers_next_event_time
) return;
162 //Starting timer handler calls.
163 in_timer_handler
= 1;
164 //Otherwise, cause any events to occur that should.
166 for(i
=0;i
<numTimers
;i
++) {
167 if(timer
[i
].inUse
&& timer
[i
].active
) {
168 //Assert that we haven't skipped any timers.
169 BX_ASSERT(current_timers_time
<= timer
[i
].timeToFire
);
170 if(timer
[i
].timeToFire
== current_timers_time
) {
171 if(timer
[i
].continuous
) {
172 timer
[i
].timeToFire
+=timer
[i
].period
;
176 //This function MUST return, or the timer mechanism
178 timer
[i
].funct(timer
[i
].this_ptr
);
182 //Finished timer handler calls.
183 in_timer_handler
= 0;
184 //Use a second FOR loop so that a timer function call can
185 // change the behavior of another timer.
186 //timers_next_event_time normally contains a cycle count, not a cycle time.
187 // here we use it as a temporary variable that IS a cycle time,
188 // but then convert it back to a cycle count afterwards.
189 timers_next_event_time
= current_timers_time
+ BX_MAX_VIRTUAL_TIME
;
190 for(i
=0;i
<numTimers
;i
++) {
191 if(timer
[i
].inUse
&& timer
[i
].active
&& ((timer
[i
].timeToFire
)<timers_next_event_time
)) {
192 timers_next_event_time
= timer
[i
].timeToFire
;
195 timers_next_event_time
-=current_timers_time
;
196 next_event_time_update();
201 //Get the current virtual time.
202 // This may return the same value on subsequent calls.
203 Bit64u
bx_virt_timer_c::time_usec(void)
205 if(!use_virtual_timers
) {
206 return bx_pc_system
.time_usec();
209 //Update the time here only if we're not in a timer handler.
210 //If we're in a timer handler we're up-to-date, and otherwise
211 // this prevents call stack loops.
212 if(!in_timer_handler
) {
216 return current_timers_time
;
219 //Get the current virtual time.
220 // This will return a monotonically increasing value.
221 // MUST NOT be called from within a timer interrupt.
222 Bit64u
bx_virt_timer_c::time_usec_sequential(void)
224 if(!use_virtual_timers
) {
225 return bx_pc_system
.time_usec_sequential();
228 //Can't prevent call stack loops here, so this
229 // MUST NOT be called from within a timer handler.
230 BX_ASSERT(timers_next_event_time
>0);
231 BX_ASSERT(!in_timer_handler
);
233 if(last_sequential_time
>= current_timers_time
) {
235 last_sequential_time
= current_timers_time
;
237 return current_timers_time
;
241 //Register a timer handler to go off after a given interval.
242 //Register a timer handler to go off with a periodic interval.
243 int bx_virt_timer_c::register_timer(void *this_ptr
, bx_timer_handler_t handler
,
245 bx_bool continuous
, bx_bool active
,
248 if(!use_virtual_timers
) {
249 return bx_pc_system
.register_timer(this_ptr
, handler
, useconds
,
250 continuous
, active
, id
);
253 //We don't like starting with a zero period timer.
254 BX_ASSERT((!active
) || (useconds
>0));
256 //Search for an unused timer.
258 for (i
=0; i
< numTimers
; i
++) {
259 if (timer
[i
].inUse
== 0 || i
==numTimers
)
262 // If we didn't find a free slot, increment the bound, numTimers.
264 numTimers
++; // One new timer installed.
265 BX_ASSERT(numTimers
<BX_MAX_VIRTUAL_TIMERS
);
268 timer
[i
].period
= useconds
;
269 timer
[i
].timeToFire
= current_timers_time
+ (Bit64u
)useconds
;
270 timer
[i
].active
= active
;
271 timer
[i
].continuous
= continuous
;
272 timer
[i
].funct
= handler
;
273 timer
[i
].this_ptr
= this_ptr
;
274 strncpy(timer
[i
].id
, id
, BxMaxTimerIDLen
);
275 timer
[i
].id
[BxMaxTimerIDLen
-1]=0; //I like null terminated strings.
277 if(useconds
< timers_next_event_time
) {
278 timers_next_event_time
= useconds
;
279 next_event_time_update();
285 //unregister a previously registered timer.
286 bx_bool
bx_virt_timer_c::unregisterTimer(unsigned timerID
)
288 if(!use_virtual_timers
)
289 return bx_pc_system
.unregisterTimer(timerID
);
291 BX_ASSERT(timerID
< BX_MAX_VIRTUAL_TIMERS
);
293 if (timer
[timerID
].active
) {
294 BX_PANIC(("unregisterTimer: timer '%s' is still active!", timer
[timerID
].id
));
298 //No need to prevent doing this to unused timers.
299 timer
[timerID
].inUse
= 0;
300 if (timerID
== (numTimers
-1)) numTimers
--;
304 void bx_virt_timer_c::start_timers(void)
306 if(!use_virtual_timers
) {
307 bx_pc_system
.start_timers();
313 //activate a deactivated but registered timer.
314 void bx_virt_timer_c::activate_timer(unsigned timer_index
, Bit32u useconds
,
317 if(!use_virtual_timers
) {
318 bx_pc_system
.activate_timer(timer_index
, useconds
, continuous
);
322 BX_ASSERT(timer_index
< BX_MAX_VIRTUAL_TIMERS
);
324 BX_ASSERT(timer
[timer_index
].inUse
);
325 BX_ASSERT(useconds
>0);
327 timer
[timer_index
].period
=useconds
;
328 timer
[timer_index
].timeToFire
= current_timers_time
+ (Bit64u
)useconds
;
329 timer
[timer_index
].active
=1;
330 timer
[timer_index
].continuous
=continuous
;
332 if(useconds
< timers_next_event_time
) {
333 timers_next_event_time
= useconds
;
334 next_event_time_update();
339 //deactivate (but don't unregister) a currently registered timer.
340 void bx_virt_timer_c::deactivate_timer(unsigned timer_index
)
342 if(!use_virtual_timers
) {
343 bx_pc_system
.deactivate_timer(timer_index
);
347 BX_ASSERT(timer_index
< BX_MAX_VIRTUAL_TIMERS
);
349 //No need to prevent doing this to unused/inactive timers.
350 timer
[timer_index
].active
= 0;
353 void bx_virt_timer_c::advance_virtual_time(Bit64u time_passed
)
355 BX_ASSERT(time_passed
<= virtual_next_event_time
);
357 current_virtual_time
+= time_passed
;
358 virtual_next_event_time
-= time_passed
;
360 if(current_virtual_time
> current_timers_time
) {
361 periodic(current_virtual_time
- current_timers_time
);
365 //Called when next_event_time changes.
366 void bx_virt_timer_c::next_event_time_update(void)
368 virtual_next_event_time
= timers_next_event_time
+ current_timers_time
- current_virtual_time
;
370 bx_pc_system
.deactivate_timer(system_timer_id
);
371 BX_ASSERT(virtual_next_event_time
);
372 bx_pc_system
.activate_timer(system_timer_id
,
373 (Bit32u
)BX_MIN(0x7FFFFFFF,BX_MAX(1,TICKS_TO_USEC(virtual_next_event_time
))),
378 void bx_virt_timer_c::setup(void)
381 current_timers_time
= 0;
382 timers_next_event_time
= BX_MAX_VIRTUAL_TIME
;
383 last_sequential_time
= 0;
384 in_timer_handler
= 0;
385 virtual_next_event_time
= BX_MAX_VIRTUAL_TIME
;
386 current_virtual_time
= 0;
388 use_virtual_timers
= BX_USE_VIRTUAL_TIMERS
;
392 void bx_virt_timer_c::init(void)
394 if ((SIM
->get_param_enum(BXPN_CLOCK_SYNC
)->get()!=BX_CLOCK_SYNC_REALTIME
) &&
395 (SIM
->get_param_enum(BXPN_CLOCK_SYNC
)->get()!=BX_CLOCK_SYNC_BOTH
))
396 virtual_timers_realtime
= 0;
398 virtual_timers_realtime
= 1;
400 if (virtual_timers_realtime
) {
401 BX_INFO(("using 'realtime pit' synchronization method"));
404 register_timer(this, nullTimer
, (Bit32u
)NullTimerInterval
, 1, 1, "Null Timer");
406 system_timer_id
= bx_pc_system
.register_timer(this, pc_system_timer_handler
,
407 (Bit32u
)virtual_next_event_time
, 0, 1, "Virtual Timer");
409 //Real time variables:
410 #if BX_HAVE_REALTIME_USEC
411 last_real_time
=GET_VIRT_REALTIME64_USEC()+(Bit64u
)TIME_HEADSTART
*(Bit64u
)USEC_PER_SECOND
;
414 last_realtime_delta
=0;
415 //System time variables:
417 usec_per_second
= USEC_PER_SECOND
;
421 //Virtual timer variables:
423 last_realtime_ticks
=0;
424 ticks_per_second
= USEC_PER_SECOND
;
429 void bx_virt_timer_c::register_state(void)
431 bx_list_c
*list
= new bx_list_c(SIM
->get_bochs_root(), "virt_timer", "Virtual Timer State", 17);
432 bx_list_c
*vtimers
= new bx_list_c(list
, "timer", numTimers
);
433 for (unsigned i
= 0; i
< numTimers
; i
++) {
435 sprintf(name
, "%d", i
);
436 bx_list_c
*bxtimer
= new bx_list_c(vtimers
, name
, 5);
437 BXRS_PARAM_BOOL(bxtimer
, inUse
, timer
[i
].inUse
);
438 BXRS_DEC_PARAM_FIELD(bxtimer
, period
, timer
[i
].period
);
439 BXRS_DEC_PARAM_FIELD(bxtimer
, timeToFire
, timer
[i
].timeToFire
);
440 BXRS_PARAM_BOOL(bxtimer
, active
, timer
[i
].active
);
441 BXRS_PARAM_BOOL(bxtimer
, continuous
, timer
[i
].continuous
);
443 BXRS_DEC_PARAM_SIMPLE(list
, current_timers_time
);
444 BXRS_DEC_PARAM_SIMPLE(list
, timers_next_event_time
);
445 BXRS_DEC_PARAM_SIMPLE(list
, last_sequential_time
);
446 BXRS_DEC_PARAM_SIMPLE(list
, virtual_next_event_time
);
447 BXRS_DEC_PARAM_SIMPLE(list
, current_virtual_time
);
448 BXRS_DEC_PARAM_SIMPLE(list
, last_real_time
);
449 BXRS_DEC_PARAM_SIMPLE(list
, total_real_usec
);
450 BXRS_DEC_PARAM_SIMPLE(list
, last_realtime_delta
);
451 BXRS_DEC_PARAM_SIMPLE(list
, last_usec
);
452 BXRS_DEC_PARAM_SIMPLE(list
, usec_per_second
);
453 BXRS_DEC_PARAM_SIMPLE(list
, stored_delta
);
454 BXRS_DEC_PARAM_SIMPLE(list
, last_system_usec
);
455 BXRS_DEC_PARAM_SIMPLE(list
, em_last_realtime
);
456 BXRS_DEC_PARAM_SIMPLE(list
, total_ticks
);
457 BXRS_DEC_PARAM_SIMPLE(list
, last_realtime_ticks
);
458 BXRS_DEC_PARAM_SIMPLE(list
, ticks_per_second
);
462 void bx_virt_timer_c::timer_handler(void)
464 if(!virtual_timers_realtime
) {
465 Bit64u temp_final_time
= bx_pc_system
.time_usec();
466 temp_final_time
-=current_virtual_time
;
467 while(temp_final_time
) {
468 if((temp_final_time
)>(virtual_next_event_time
)) {
469 temp_final_time
-=virtual_next_event_time
;
470 advance_virtual_time(virtual_next_event_time
);
472 advance_virtual_time(temp_final_time
);
473 temp_final_time
-=temp_final_time
;
476 bx_pc_system
.activate_timer(system_timer_id
,
477 (Bit32u
)BX_MIN(0x7FFFFFFF,(virtual_next_event_time
>2)?(virtual_next_event_time
-2):1),
482 Bit64u usec_delta
= bx_pc_system
.time_usec()-last_usec
;
485 #if BX_HAVE_REALTIME_USEC
486 Bit64u ticks_delta
= 0;
487 Bit64u real_time_delta
= GET_VIRT_REALTIME64_USEC() - last_real_time
;
488 Bit64u real_time_total
= real_time_delta
+ total_real_usec
;
489 Bit64u system_time_delta
= (Bit64u
)usec_delta
+ (Bit64u
)stored_delta
;
490 if(real_time_delta
) {
491 last_realtime_delta
= real_time_delta
;
492 last_realtime_ticks
= total_ticks
;
494 ticks_per_second
= USEC_PER_SECOND
;
496 //Start out with the number of ticks we would like
497 // to have to line up with real time.
498 ticks_delta
= real_time_total
- total_ticks
;
499 if(real_time_total
< total_ticks
) {
500 //This slows us down if we're already ahead.
501 // probably only an issue on startup, but it solves some problems.
504 if(ticks_delta
+ total_ticks
- last_realtime_ticks
> (F2I(MAX_MULT
* I2F(last_realtime_delta
)))) {
505 //This keeps us from going too fast in relation to real time.
507 ticks_delta
= (F2I(MAX_MULT
* I2F(last_realtime_delta
))) + last_realtime_ticks
- total_ticks
;
509 ticks_per_second
= F2I(MAX_MULT
* I2F(USEC_PER_SECOND
));
511 if(ticks_delta
> system_time_delta
* USEC_PER_SECOND
/ MIN_USEC_PER_SECOND
) {
512 //This keeps us from having too few instructions between ticks.
513 ticks_delta
= system_time_delta
* USEC_PER_SECOND
/ MIN_USEC_PER_SECOND
;
515 if(ticks_delta
> virtual_next_event_time
) {
516 //This keeps us from missing ticks.
517 ticks_delta
= virtual_next_event_time
;
522 # if DEBUG_REALTIME_WITH_PRINTF
523 //Every second print some info.
524 if(((last_real_time
+ real_time_delta
) / USEC_PER_SECOND
) > (last_real_time
/ USEC_PER_SECOND
)) {
525 Bit64u temp1
, temp2
, temp3
, temp4
;
526 temp1
= (Bit64u
) total_real_usec
;
527 temp2
= (total_real_usec
);
528 temp3
= (Bit64u
)total_ticks
;
529 temp4
= (Bit64u
)((total_real_usec
) - total_ticks
);
530 printf("useconds: " FMT_LL
"u, ", temp1
);
531 printf("expect ticks: " FMT_LL
"u, ", temp2
);
532 printf("ticks: " FMT_LL
"u, ", temp3
);
533 printf("diff: "FMT_LL
"u\n", temp4
);
537 last_real_time
+= real_time_delta
;
538 total_real_usec
+= real_time_delta
;
539 last_system_usec
+= system_time_delta
;
541 total_ticks
+= ticks_delta
;
543 stored_delta
= system_time_delta
;
546 Bit64u a
= usec_per_second
, b
;
547 if(real_time_delta
) {
549 Bit64u em_realtime_delta
= last_system_usec
+ stored_delta
- em_last_realtime
;
550 b
=((Bit64u
)USEC_PER_SECOND
* em_realtime_delta
/ real_time_delta
);
551 em_last_realtime
= last_system_usec
+ stored_delta
;
555 usec_per_second
= ALPHA_LOWER(a
,b
);
559 #if BX_HAVE_REALTIME_USEC
560 advance_virtual_time(ticks_delta
);
564 last_usec
=last_usec
+ usec_delta
;
565 bx_pc_system
.deactivate_timer(system_timer_id
);
566 BX_ASSERT(virtual_next_event_time
);
567 bx_pc_system
.activate_timer(system_timer_id
,
568 (Bit32u
)BX_MIN(0x7FFFFFFF,BX_MAX(1,TICKS_TO_USEC(virtual_next_event_time
))),
572 void bx_virt_timer_c::pc_system_timer_handler(void* this_ptr
)
574 ((bx_virt_timer_c
*)this_ptr
)->timer_handler();