Mail Archives: djgpp-workers/2003/04/29/00:40:34
For Windows 2000 and XP; I'll try a test on NT4 and on a 486 running NT 3.1
if I get a chance. Autocalibrates as needed to always keep the tic
counter aligned. This might cause some jitter due to the inaccuracy of
the NT tic counter, but since it's not a real time OS and multitasking
who knows what really happened. Installs signal handler, should never
been seen in real life (no one is running Windows NT 3.5 or earlier
which were the last versions to support 486s which didn't have rdtsc).
If they are, it falls back to tic accuracy.
Comments?
--- uclock.c_ Tue Dec 11 21:28:06 2001
+++ uclock.c Mon Apr 28 23:25:18 2003
@@ -11,4 +11,21 @@
#include <dpmi.h>
#include <libc/bss.h>
+#include <dos.h>
+#include <signal.h>
+#include <setjmp.h>
+#include <sys/exceptn.h>
+
+/* Catch rdtsc exception and always return 0LL */
+static void catch_rdtsc(int val)
+{
+ short *eip = (short *)__djgpp_exception_state->__eip;
+ if(*eip == 0x310f) {
+ __djgpp_exception_state->__eip += 2;
+ __djgpp_exception_state->__edx = 0;
+ longjmp(__djgpp_exception_state, 0);
+ }
+ return;
+}
+
static int uclock_bss = -1;
@@ -30,4 +47,32 @@
uclock_t rv;
+ _farsetsel(_dos_ds);
+
+ if(_os_trueversion == 0x532) { /* Windows NT, 2000, XP */
+ static double multiplier;
+ static unsigned long btics;
+ uclock_t rval;
+
+ if (uclock_bss != __bss_count) {
+ signal(SIGILL, catch_rdtsc);
+ tics = _farnspeekl(0x46c);
+ while ( (btics = _farnspeekl(0x46c)) == tics);
+ base = _rdtsc();
+ if (base == 0) base = -1LL;
+ while ( (tics = _farnspeekl(0x46c)) == btics);
+ if (tics < btics) tics = btics + 1; /* Midnight */
+ multiplier = ((tics - btics)*65536) / (double)(_rdtsc() - base);
+ uclock_bss = __bss_count;
+ }
+ rval = (_rdtsc() - base) * multiplier;
+ tics = _farnspeekl(0x46c) - btics;
+ while (tics <= 0) tics += 0x1800b0; /* Midnight */
+ if( (unsigned long)(rval >> 16) != tics) { /* Recalibrate */
+ rval = ((uclock_t)tics) << 16;
+ multiplier = (tics*65536) / (double)(_rdtsc() - base);
+ }
+ return rval;
+ }
+
if (uclock_bss != __bss_count)
{
@@ -52,5 +97,4 @@
if the timer worked in mode 3. So we simply wait for one clock
tick when we run on Windows. */
- _farsetsel(_dos_ds);
otics = _farnspeekl(0x46c);
do {
@@ -63,9 +107,9 @@
/* Make sure the numbers we get are consistent */
do {
- otics = _farpeekl(_dos_ds, 0x46c);
+ otics = _farnspeekl(0x46c);
outportb(0x43, 0x00);
lsb = inportb(0x40);
msb = inportb(0x40);
- tics = _farpeekl(_dos_ds, 0x46c);
+ tics = _farnspeekl(0x46c);
} while (otics != tics);
- Raw text -