Main Page | Alphabetical List | Data Structures | File List | Data Fields | Globals | Related Pages

SRC/timer.c

Go to the documentation of this file.
00001 00018 #include <stdio.h> 00019 #include <stdlib.h> 00020 #include <limits.h> 00021 #include <signal.h> 00022 #include <time.h> 00023 #include <math.h> 00024 #include <errno.h> 00025 #include <sys/wtime.h> 00026 00027 #include "wattcp.h" 00028 #include "ioport.h" 00029 #include "strings.h" 00030 #include "gettod.h" 00031 #include "pcconfig.h" 00032 #include "pcqueue.h" 00033 #include "language.h" 00034 #include "cpumodel.h" 00035 #include "powerpak.h" 00036 #include "wdpmi.h" 00037 #include "x32vm.h" 00038 #include "rs232.h" 00039 #include "misc.h" 00040 #include "timer.h" 00041 00042 #if (DOSX & PHARLAP) 00043 #include <mw/exc.h> /* _dx_alloc_rmode_wrapper_iret() */ 00044 #endif 00045 00046 DWORD start_time = 0; 00047 DWORD start_day = 0; 00049 BOOL has_8254 = FALSE; 00050 BOOL has_rdtsc = FALSE; 00051 BOOL use_rdtsc = FALSE; 00052 BOOL using_int8 = FALSE; 00053 DWORD clocks_per_usec; 00055 time_t user_tick_base = 0UL; /* time() when user-tick started */ 00056 DWORD user_tick_msec = 0UL; /* milli-sec user-tick counter */ 00057 BOOL user_tick_active = FALSE; 00058 00059 static DWORD date = 0; 00060 static DWORD date_ms = 0; 00061 00062 /* 00063 * Things for the user installable timer ISR. 00064 */ 00065 #if !(DOSX & DJGPP) 00066 #define TIMER_ISR_PERIOD 10UL /* 10 msec between interrupts */ 00067 #define TIMER_INTR 8 00068 #endif 00069 00070 #if (DOSX == 0) || (DOSX & DOS4GW) 00071 #define HAVE_TIMER_ISR 00072 00073 static W32_IntrHandler old_int_8 = NULL; 00074 00075 #elif (DOSX & (PHARLAP|X32VM)) 00076 #define HAVE_TIMER_ISR 00077 00078 static REALPTR old_int_8, int8_cback; 00079 /*static FARPTR old_int_8_pm; */ 00080 static RMC_BLK rmBlock_int8; 00081 00082 #elif (DOSX & DJGPP) 00083 #define HAVE_TIMER_ISR 00084 00085 static DWORD itimer_resolution = 0UL; /* in usec */ 00086 static void (*old_sigalrm)(int); 00087 static struct itimerval old_itimer; 00088 #endif 00089 00090 #if defined(HAVE_TIMER_ISR) && !(DOSX & DJGPP) 00091 static DWORD tick_timer_8254 = 0UL; 00092 00093 /* 1193181 = 4.77MHz/4 pulses per sec. 00094 */ 00095 #define TIMER_8254_COUNT ((1193181UL * TIMER_ISR_PERIOD) / 1000UL) 00096 #endif 00097 00098 00103 void init_timers (void) 00104 { 00105 #if (DOSX) /* problems using 64-bit types in small/large models */ 00106 hires_timer (TRUE); 00108 #if defined(HAVE_UINT64) 00109 if (use_rdtsc && has_rdtsc) 00110 { 00111 clocks_per_usec = (DWORD) (get_cpu_speed() / S64_SUFFIX(1000000)); 00112 if (clocks_per_usec == 0UL) 00113 { 00114 outsnl ("CPU speed is 0?"); 00115 use_rdtsc = FALSE; 00116 has_rdtsc = FALSE; 00117 } 00118 } 00119 set_utc_offset(); /* don't pull in gettod.c unneccesary */ 00120 #endif 00121 #endif 00122 00123 chk_timeout (0UL); /* init 'date' variables */ 00124 } 00125 00135 void init_userSuppliedTimerTick (void) 00136 { 00137 SIO_TRACE (("init_userSuppliedTimerTick")); 00138 user_tick_active = TRUE; 00139 user_tick_base = time (NULL); 00140 has_8254 = FALSE; 00141 } 00142 00143 /* 00144 * Disable stack-checking here 00145 */ 00146 #if defined(__HIGHC__) 00147 #pragma off(Call_trace) 00148 #pragma off(Prolog_trace) 00149 #pragma off(Epilog_trace) 00150 #endif 00151 00152 #include "nochkstk.h" 00153 00162 void userTimerTick (DWORD elapsed_time_msec) 00163 { 00164 user_tick_msec += elapsed_time_msec; 00165 } 00166 00167 #if defined(HAVE_TIMER_ISR) 00168 00171 #if (DOSX & (DJGPP|PHARLAP|X32VM)) 00172 static void new_int_8 (void) /* not really an intr-handler */ 00173 #else 00174 static INTR_PROTOTYPE new_int_8 (void) 00175 #endif 00176 { 00177 #if !(DOSX & DJGPP) 00178 tick_timer_8254 += TIMER_8254_COUNT; 00179 00180 if (tick_timer_8254 >= 0x10000) 00181 { 00182 tick_timer_8254 -= 0x10000; 00183 00184 #if defined(__WATCOMC__) 00185 _chain_intr (old_int_8); /* chain now */ 00186 #elif (DOSX & (PHARLAP|X32VM)) 00187 _dx_call_real (old_int_8, &rmBlock_int8, 1); 00188 #else 00189 (*old_int_8)(); 00190 #endif 00191 } 00192 else 00193 _outportb (0x20, 0x60); /* specific EOI for IRQ 0 */ 00194 00195 userTimerTick (TIMER_ISR_PERIOD); 00196 00197 #else 00198 userTimerTick (itimer_resolution / 1000UL); 00199 #endif /* !(DOSX & DJGPP) */ 00200 00201 00202 #if (DOSX & DJGPP) 00203 /* BEEP(); */ /* !! test */ 00204 #endif 00205 } 00206 00207 void exit_timer_isr (void) 00208 { 00209 if (!using_int8) 00210 return; 00211 00212 #if (DOSX & DJGPP) 00213 signal (SIGALRM, old_sigalrm); 00214 setitimer (ITIMER_REAL, &old_itimer, NULL); 00215 #else 00216 if (old_int_8) 00217 { 00218 _outportb (0x43, 0x34); /* restore default timer rate */ 00219 _outportb (0x40, 0); 00220 _outportb (0x40, 0); 00221 00222 PUSHF_CLI(); 00223 00224 #if (DOSX & (PHARLAP|X32VM)) 00225 _dx_rmiv_set (TIMER_INTR, old_int_8); 00226 if (int8_cback) 00227 _dx_free_rmode_wrapper (int8_cback); 00228 old_int_8 = 0; 00229 int8_cback = 0; 00230 #else 00231 _dos_setvect (TIMER_INTR, old_int_8); 00232 old_int_8 = NULL; 00233 #endif 00234 00235 POPF(); 00236 } 00237 #endif /* DJGPP */ 00238 00239 /* This causes timeout calculations for timers started earlier 00240 * to go wrong. 00241 */ 00242 user_tick_active = FALSE; 00243 using_int8 = FALSE; 00244 } 00245 00246 /* 00247 * Hook INT 8 and modify rate of timer channel 0 for 55msec (djgpp) 00248 * or 10 msec (others) period. 00249 */ 00250 void init_timer_isr (void) 00251 { 00252 /* Caller must do exit_timer_isr() before doing this again 00253 */ 00254 if (using_int8) 00255 return; 00256 00257 #if (DOSX & DJGPP) 00258 { 00259 struct itimerval tim; 00260 00261 memset (&tim, 0, sizeof(tim)); 00262 tim.it_interval.tv_usec = 1; 00263 setitimer (ITIMER_REAL, &tim, NULL); 00264 setitimer (ITIMER_REAL, NULL, &tim); 00265 itimer_resolution = 1000000UL * tim.it_interval.tv_sec + /* should become 55000 */ 00266 tim.it_interval.tv_usec; 00267 tim.it_value.tv_sec = tim.it_interval.tv_sec; 00268 tim.it_value.tv_usec = tim.it_interval.tv_usec; 00269 00270 memset (&old_itimer, 0, sizeof(old_itimer)); 00271 old_sigalrm = signal (SIGALRM, (W32_IntrHandler)new_int_8); 00272 setitimer (ITIMER_REAL, &tim, &old_itimer); 00273 } 00274 00275 #elif (DOSX & (PHARLAP|X32VM)) 00276 #if 1 00277 int8_cback = _dx_alloc_rmode_wrapper_iret ((pmodeHook)new_int_8, 256); 00278 if (!int8_cback) 00279 { 00280 outsnl (_LANG("Cannot allocate real-mode timer callback")); 00281 return; 00282 } 00283 _dx_rmiv_get (8, &old_int_8); 00284 _dx_rmiv_set (8, int8_cback); 00285 #else 00286 { 00287 FARPTR fp; 00288 FP_SET (fp, new_int_8, MY_CS()); 00289 _dx_pmiv_get (8, &old_int_8_pm); 00290 _dx_apmiv_set (8, fp); 00291 } 00292 #endif 00293 #else 00294 old_int_8 = _dos_getvect (8); 00295 _dos_setvect (8, new_int_8); 00296 #endif 00297 00298 #if !(DOSX & DJGPP) 00299 _outportb (0x43, 0x34); 00300 _outportb (0x40, loBYTE(TIMER_8254_COUNT)); 00301 _outportb (0x40, hiBYTE(TIMER_8254_COUNT)); 00302 #endif 00303 00304 init_userSuppliedTimerTick(); 00305 using_int8 = TRUE; 00306 00307 /* release it very early */ 00308 RUNDOWN_ADD (exit_timer_isr, -2); 00309 } 00310 00311 #else 00312 00313 void init_timer_isr (void) 00314 { 00315 #if defined(USE_DEBUG) 00316 if (debug_on) 00317 outsnl ("No timer-ISR in this environment"); 00318 #endif 00319 } 00320 00321 void exit_timer_isr (void) 00322 { 00323 } 00324 #endif 00325 00335 int cmp_timers (DWORD t1, DWORD t2) 00336 { 00337 if (t1 == t2) 00338 return (0); 00339 return (t1 < t2 ? -1 : +1); 00340 } 00341 00351 int hires_timer (int on) 00352 { 00353 int old = has_8254; 00354 00355 SIO_TRACE (("hires_timer %s", on ? "on" : "off")); 00356 has_8254 = on; 00357 chk_timeout (0UL); 00358 return (old); 00359 } 00360 00361 00362 #if !defined(WIN32) 00363 /* 00364 * The following 2 routines are modified versions from KA9Q NOS 00365 * by Phil Karn. 00366 * 00367 * clockbits() - Read low order bits of timer 0 (the TOD clock) 00368 * This works only for the 8254 chips used in ATs and 386+. 00369 * 00370 * Old version: 00371 * The timer 0 runs in mode 3 (square wave mode), counting down 00372 * by 2s, twice for each cycle. So it is necessary to read back the 00373 * OUTPUT pin to see which half of the cycle we're in. I.e., the OUTPUT 00374 * pin forms the most significant bit of the count. Unfortunately, 00375 * the 8253 in the PC/XT lacks a command to read the OUTPUT pin... 00376 * 00377 * Now simply: 00378 * The timer 0 runs in mode 2 (rate generator), counting down. 00379 * We don't compare the OUTPUT pin to see what cycle we're in. 00380 * A bit lower precision, but a bit faster. 00381 * 00382 * WARNING!: This can cause serious trouble if anything else is also using 00383 * timer interrupts. In that case use the above "userSuppliedTimerTick()". 00384 * The reading of I/O registers gives bad precision under Windows. 00385 */ 00386 DWORD clockbits (void) 00387 { 00388 static VOLATILE DWORD count; /* static because of PUSHF_CLI() */ 00389 00390 #if 1 00391 /* 00392 * The following version was suggested by Andrew Paulsen 00393 * <andrew.paulsen@ndsu.nodak.edu>. Seem to work fine. 00394 */ 00395 static BOOL started = FALSE; 00396 00397 PUSHF_CLI(); 00398 00399 if (!started) /* Initialize once, it is periodic */ 00400 { 00401 _outportb (0x43, 0x34); /* Set timer 0, mode 2 */ 00402 _outportb (0x40, 0x00); /* Count is decremented, then compared to 0 */ 00403 _outportb (0x40, 0x00); /* so set count to 0 to get 65536 */ 00404 started = TRUE; 00405 } 00406 00407 _outportb (0x43, 0x04); /* Latch present counter value command */ 00408 count = _inportb (0x40); /* LSB of count */ 00409 count |= _inportb (0x40) << 8; /* MSB of count */ 00410 00411 POPF(); 00412 00413 return (count); 00414 00415 #else 00416 static VOLATILE DWORD stat, count; /* static because of PUSHF_CLI() */ 00417 00418 do 00419 { 00420 PUSHF_CLI(); 00421 _outportb (0x43, 0xC2); /* Read Back Command (timer 0, 8254 only) */ 00422 stat = _inportb (0x40); /* get status of timer 0 */ 00423 count = _inportb (0x40); /* LSB of count */ 00424 count |= _inportb (0x40) << 8; /* MSB of count */ 00425 POPF(); 00426 } 00427 while (stat & 0x40); /* reread if NULL COUNT bit set */ 00428 00429 stat = (stat & 0x80) << 8; /* Shift OUTPUT to MSB of 16-bit word */ 00430 count >>= 1; /* count = count/2 */ 00431 if (count == 0) 00432 return (stat ^ 0x8000UL); /* return complement of OUTPUT bit */ 00433 return (count | stat); /* Combine OUTPUT with counter */ 00434 #endif 00435 } 00436 00437 #if !defined(W32_NO_8087) 00438 /* 00439 * Return hardware time-of-day in milliseconds. Resolution is improved 00440 * beyond 55 ms (the clock tick interval) by reading back the instantaneous 00441 * 8254 counter value and combining it with the clock tick counter. 00442 * 00443 * Reading the 8254 is a bit tricky since a tick could occur asynchronously 00444 * between the two reads in clockbits(). The tick counter is examined before 00445 * and after the hardware counter is read. If the tick counter changes, try 00446 * again. 00447 * 00448 * \note The hardware counter (lo) counts down from 65536 at a rate of 00449 * 1.193181 MHz (4.77/4). System tick count (hi) counts up. 00450 */ 00451 DWORD millisec_clock (void) 00452 { 00453 DWORD hi; 00454 WORD lo; 00455 double x; 00456 00457 do 00458 { 00459 hi = PEEKL (0, BIOS_CLK); 00460 lo = clockbits(); 00461 } 00462 while (hi != PEEKL(0, BIOS_CLK)); /* tick count changed, try again */ 00463 lo = 0 - lo; 00464 00465 /* Emulating this would be slow. We'd better have a math-processor 00466 */ 00467 x = ldexp ((double)hi, 16) + (double)lo; /* x = hi*2^16 + lo */ 00468 return (DWORD) (x * 4.0 / 4770.0); 00469 } 00470 #endif /* !W32_NO_8087 */ 00471 #endif /* !WIN32 */ 00472 00473 00478 DWORD set_timeout (DWORD msec) 00479 { 00480 DWORD ret; 00481 00482 if (user_tick_active) /* using timer ISR or user-timer */ 00483 { 00484 ret = user_tick_msec + msec; 00485 } 00486 #if defined(HAVE_UINT64) /* CPU-clock, 8254 PIT or 55msec ticks */ || \ 00487 defined(WIN32) /* GetSystemTimeAsFileTime() */ 00488 else 00489 { 00490 struct timeval now; 00491 00492 gettimeofday2 (&now, NULL); 00493 ret = msec + 1000 * (DWORD)now.tv_sec + (DWORD)(now.tv_usec / 1000); 00494 } 00495 #else 00496 00497 #if !defined(W32_NO_8087) 00498 else if (has_8254) /* high-resolution PIT */ 00499 { 00500 ret = msec + date_ms + millisec_clock(); 00501 } 00502 #endif 00503 else /* fallback to 55msec ticks */ 00504 { 00505 DWORD ticks = 1; 00506 00507 if (msec > 55) 00508 ticks = msec / 55UL; 00509 /* ret = ticks + ms_clock(); !!!! try this */ 00510 ret = ticks + date + PEEKL (0,BIOS_CLK); 00511 } 00512 #endif 00513 00514 return (ret == 0 ? 1 : ret); 00515 } 00516 00522 BOOL chk_timeout (DWORD value) 00523 { 00524 if (user_tick_active) /* using timer ISR or user-timer */ 00525 { 00526 if (value == 0) 00527 return (0); 00528 return (user_tick_msec >= value); 00529 } 00530 00531 #if defined(HAVE_UINT64) || defined(WIN32) 00532 if (value == 0UL) 00533 return (0); 00534 return (set_timeout(0) >= value); 00535 00536 #else 00537 { 00538 static char oldHour = -1; 00539 #if !defined(W32_NO_8087) 00540 static DWORD now_ms; 00541 #endif 00542 static DWORD now; 00543 char hour; 00544 00545 now = (DWORD) PEEKL (0, BIOS_CLK); 00546 #if 1 00547 hour = (char)(now >> 16U); 00548 #else 00549 hour = (char)(now/65543.33496093); /* Jan De Geeter 17.12.01 */ 00550 #endif 00551 00552 if (hour != oldHour) 00553 { 00554 if (hour < oldHour) /* midnight passed */ 00555 { 00556 #define CORR 290UL /* experimental correction */ 00557 date += 1572750UL + CORR; /* Update date (0x1800B0UL) */ 00558 date_ms += 3600UL*24UL*1000UL; /* ~2^26 */ 00559 } 00560 oldHour = hour; 00561 } 00562 00563 if (value == 0L) /* timer not initialised */ 00564 return (0); /* (or stopped) */ 00565 00566 #if !defined(W32_NO_8087) 00567 if (has_8254) 00568 { 00569 now_ms = millisec_clock(); 00570 return (now_ms + date_ms >= value); 00571 } 00572 #endif 00573 now += date; /* date extend current time */ 00574 return (now >= value); /* return true if expired */ 00575 } 00576 #endif /* HAVE_UINT64 || WIN32 */ 00577 } 00578 00583 int set_timediff (long msec) 00584 { 00585 date_ms -= msec; 00586 date -= msec/55; 00587 return (0); 00588 } 00589 00596 long get_timediff (DWORD now, DWORD tim) 00597 { 00598 #if defined(HAVE_UINT64) || defined(WIN32) 00599 return (long)(now - tim); 00600 #else 00601 long dt = (long)(now - tim); 00602 00603 if (has_8254) 00604 dt = dt % (3600L*24L*1000L); 00605 else dt = dt % (1572750L + CORR); 00606 return (dt); 00607 #endif 00608 } 00609 00610 #if !defined(W32_NO_8087) 00611 /* 00612 * Return difference (in micro-sec) between timevals `*newer' and `*older' 00613 */ 00614 double timeval_diff (const struct timeval *newer, const struct timeval *older) 00615 { 00616 long d_sec = (long)newer->tv_sec - (long)older->tv_sec; 00617 long d_usec = newer->tv_usec - older->tv_usec; 00618 return ((1E6 * (double)d_sec) + (double)d_usec); 00619 } 00620 #endif 00621 00622 #if defined(WIN32) 00623 /* 00624 * Return FILETIME in seconds. 00625 */ 00626 double filetime_sec (const void *filetime) 00627 { 00628 const LARGE_INTEGER ft = *(const LARGE_INTEGER*) filetime; 00629 long double rc = (long double)ft.QuadPart; 00630 00631 return (double) (rc/1E7); /* from 100 nano-sec periods to sec */ 00632 } 00633 #endif 00634 00635 #if defined(USE_DEBUG) 00636 /* 00637 * Return string "x.xx" for timeout value. 00638 * 'val' is always in milli-sec units if we're using the 8254 PIT, 00639 * RDTSC timestamps, timer ISR or user-supplied timer. 00640 */ 00641 const char *time_str (DWORD val) 00642 { 00643 static char buf[30]; 00644 char fmt[6]; 00645 double flt_val; 00646 00647 if (has_8254 || has_rdtsc || user_tick_active) 00648 { 00649 flt_val = (double)val / 1000.0F; 00650 strcpy (fmt, "%.3f"); 00651 } 00652 else 00653 { 00654 flt_val = (double)val / 18.2F; 00655 strcpy (fmt, "%.2f"); 00656 } 00657 00658 #if (!DOSX) && defined(__BORLANDC__) && 0 /* Bug? Try "%.xlf" */ 00659 fmt[3] = 'l'; 00660 fmt[4] = 'f'; 00661 fmt[5] = '\0'; 00662 #endif 00663 00664 sprintf (buf, fmt, flt_val); 00665 return (buf); 00666 } 00667 00668 /* 00669 * Return string "HH:MM:SS" for a time in seconds. 00670 */ 00671 const char *hms_str (DWORD sec) 00672 { 00673 static char buf[30]; 00674 WORD hour = (WORD) (sec / 3600UL); 00675 WORD min = (WORD) (sec / 60) - (60 * hour); 00676 00677 sprintf (buf, "%02u:%02u:%02u", hour, min, (UINT)(sec % 60UL)); 00678 return (buf); 00679 } 00680 00681 /* 00682 * Return string "xx:xx" for time elapsed since started. 00683 * Handles max 24 days. Or max 49 days with user_tick_active. 00684 */ 00685 const char *elapsed_str (DWORD val) 00686 { 00687 static char buf[30]; 00688 WORD hour, min, msec; 00689 DWORD sec; 00690 BOOL is_win = (DOSX & WINWATT); 00691 00692 if (val == 0UL) 00693 return ("00:00:00.000"); 00694 00695 if (!user_tick_active && val < start_time) /* wrapped? */ 00696 val = ULONG_MAX - val + start_time; 00697 00698 /* If user-ticks is used, 'val' should be correct msec count 00699 * since init_userSuppliedTimerTick() was called. 00700 */ 00701 if (user_tick_active) 00702 { 00703 sec = val / 1000UL; 00704 msec = (WORD) (val % 1000UL); 00705 } 00706 else if (has_8254 || has_rdtsc || is_win) 00707 { 00708 val -= start_time; 00709 sec = val / 1000UL; 00710 msec = (WORD) (val % 1000UL); 00711 } 00712 else 00713 { 00714 val -= start_time; 00715 sec = val / 18; 00716 msec = 55 * (WORD)(val % 18UL); 00717 } 00718 00719 hour = (WORD) (sec / 3600UL); 00720 min = (WORD) (sec / 60UL) - 60 * hour; 00721 sec = sec % 60UL; 00722 sprintf (buf, "%02u:%02u:%02lu.%03u", hour, min, sec, msec); 00723 return (buf); 00724 } 00725 #endif /* USE_DEBUG */ 00726 00727 00728 #if !defined(WIN32) 00729 /* 00730 * The following was contributed by 00731 * "Alain" <alainm@pobox.com> 00732 */ 00733 #define TICKS_DAY 1573067UL /* Number of ticks in one day */ 00734 00735 DWORD ms_clock (void) 00736 { 00737 static DWORD lastTick, tickOffset; 00738 static char firstTime = 1; 00739 DWORD tick = PEEKL (0, 0x46C); 00740 00741 if (firstTime) 00742 { 00743 firstTime = 0; 00744 lastTick = tickOffset = tick; 00745 return (0); 00746 } 00747 if (lastTick > tick) /* day changed */ 00748 tickOffset -= TICKS_DAY; 00749 lastTick = tick; 00750 return (tick - tickOffset); 00751 } 00752 #endif /* !WIN32 */ 00753 00754 00755 00756 #if (DOSX) && defined(HAVE_UINT64) 00757 /* 00758 * Wait for BIOS timer-tick to change 'num' times. 00759 */ 00760 static void Wait_N_ticks (int num) 00761 { 00762 DWORD tim; 00763 00764 while (num--) 00765 { 00766 #if defined(WIN32) 00767 tim = GetTickCount() + 55; 00768 while (GetTickCount() < tim) 00769 Sleep (0); 00770 #else 00771 tim = PEEKL (0, BIOS_CLK); 00772 while (PEEKL(0,BIOS_CLK) == tim) 00773 { 00774 #ifdef __DJGPP__ 00775 ENABLE(); /* CWSDPMI requires this! */ 00776 #else 00777 ((void)0); 00778 #endif 00779 } 00780 #endif 00781 } 00782 } 00783 00787 uint64 get_cpu_speed (void) 00788 { 00789 #define NUM_SAMPLES 3 00790 #define WAIT_TICKS 2 00791 00792 uint64 speed; 00793 uint64 sample [NUM_SAMPLES]; 00794 int i; 00795 00796 Wait_N_ticks (1); 00797 00798 for (i = 0; i < NUM_SAMPLES; i++) 00799 { 00800 uint64 start = GET_RDTSC(); 00801 00802 Wait_N_ticks (WAIT_TICKS); 00803 sample[i] = 1000 * (GET_RDTSC() - start) / (WAIT_TICKS*55); 00804 } 00805 00806 speed = 0; 00807 for (i = 0; i < NUM_SAMPLES; i++) 00808 speed += sample[i]; 00809 return (speed / NUM_SAMPLES); 00810 } 00811 #endif /* DOSX && HAVE_UINT64 */ 00812

Generated on Wed Aug 4 08:55:54 2010 for Watt-32 tcp/ip by doxygen 1.3.8