232 lines
6.1 KiB
C
232 lines
6.1 KiB
C
|
/*+ pentime.h
|
||
|
*
|
||
|
* pentium specific high precision timer functions for 16 or 32 bit apps
|
||
|
* (16 bit also needs pentime.asm)
|
||
|
*
|
||
|
*-======================================================================*/
|
||
|
|
||
|
#ifndef PENTIME_H
|
||
|
#define PENTIME_H
|
||
|
|
||
|
typedef struct {
|
||
|
DWORD dwlo;
|
||
|
DWORD dwhi;
|
||
|
} PENTIMER, NEAR * PPENTIMER;
|
||
|
|
||
|
void FAR PASCAL pentimeInitTimer (
|
||
|
PPENTIMER pptimer);
|
||
|
|
||
|
DWORD FAR PASCAL pentimeGetMicrosecs (
|
||
|
PPENTIMER pptimer);
|
||
|
|
||
|
DWORD FAR PASCAL pentimeGetMicrosecDelta (
|
||
|
PPENTIMER pptimer);
|
||
|
|
||
|
DWORD FAR PASCAL pentimeGetMillisecs (
|
||
|
PPENTIMER pptimer);
|
||
|
|
||
|
struct _pentime_global {
|
||
|
DWORD dwTimerKhz;
|
||
|
BOOL bActive;
|
||
|
PENTIMER base;
|
||
|
DWORD dwCpuMhz;
|
||
|
DWORD dwCpuKhz;
|
||
|
};
|
||
|
extern struct _pentime_global pentime;
|
||
|
|
||
|
//
|
||
|
// macros to make whether to use pentium timers or not a runtime option
|
||
|
//
|
||
|
#ifdef _X86_
|
||
|
|
||
|
#define pentimeGetTime() pentime.bActive ? pentimeGetMillisecs(&pentime.base) : timeGetTime()
|
||
|
#define pentimeGetTicks() pentime.bActive ? pentimeGetMicrosecs(&pentime.base) : timeGetTime()
|
||
|
#define pentimeBegin() pentime.bActive ? (pentimeInitTimer(&pentime.base), 0l) : (void)(pentime.base.dwlo = timeGetTime())
|
||
|
#define pentimeGetTickRate() (pentime.bActive ? (pentime.dwTimerKhz * 1000) : 1000l)
|
||
|
#define pentimeGetDeltaTicks(ppt) pentime.bActive ? pentimeGetMicrosecDelta(ppt) : \
|
||
|
((ppt)->dwhi = (ppt)->dwlo, (ppt)->dwlo = timeGetTime(), (ppt)->dwlo - (ppt)->dwhi)
|
||
|
|
||
|
#else
|
||
|
|
||
|
#define pentimeGetTime() timeGetTime()
|
||
|
#define pentimeGetTicks() timeGetTime()
|
||
|
#define pentimeBegin() (pentime.base.dwlo = timeGetTime())
|
||
|
#define pentimeGetTickRate() (1000l)
|
||
|
#define pentimeGetDeltaTicks(ppt) \
|
||
|
((ppt)->dwhi = (ppt)->dwlo, (ppt)->dwlo = timeGetTime(), (ppt)->dwlo - (ppt)->dwhi)
|
||
|
|
||
|
#endif
|
||
|
|
||
|
#if (defined _INC_PENTIME_CODE_) && (_INC_PENTIME_CODE_ != FALSE)
|
||
|
#undef _INC_PENTIME_CODE_
|
||
|
#define _INC_PENTIME_CODE_ FALSE
|
||
|
|
||
|
struct _pentime_global pentime = {1, 0};
|
||
|
|
||
|
#ifdef _WIN32
|
||
|
#ifdef _X86_
|
||
|
static BYTE opGetP5Ticks[] = {
|
||
|
0x0f, 0x31, // rtdsc
|
||
|
0xc3 // ret
|
||
|
};
|
||
|
|
||
|
static void (WINAPI * GetP5Ticks)() = (LPVOID)opGetP5Ticks;
|
||
|
|
||
|
#pragma warning(disable:4704)
|
||
|
#pragma warning(disable:4035)
|
||
|
|
||
|
void FAR PASCAL pentimeInitTimer (
|
||
|
PPENTIMER pptimer)
|
||
|
{
|
||
|
GetP5Ticks();
|
||
|
_asm {
|
||
|
mov ebx, pptimer
|
||
|
mov [ebx], eax
|
||
|
mov [ebx+4], edx
|
||
|
};
|
||
|
}
|
||
|
|
||
|
DWORD FAR PASCAL pentimeGetCpuTicks (
|
||
|
PPENTIMER pptimer)
|
||
|
{
|
||
|
GetP5Ticks();
|
||
|
_asm {
|
||
|
mov ebx, pptimer
|
||
|
sub eax, [ebx]
|
||
|
sbb edx, [ebx+4]
|
||
|
};
|
||
|
}
|
||
|
|
||
|
DWORD FAR PASCAL pentimeGetMicrosecs (
|
||
|
PPENTIMER pptimer)
|
||
|
{
|
||
|
GetP5Ticks();
|
||
|
_asm {
|
||
|
mov ebx, pptimer
|
||
|
sub eax, [ebx]
|
||
|
sbb edx, [ebx+4]
|
||
|
and edx, 31 // to prevent overflow
|
||
|
mov ecx, pentime.dwCpuMhz
|
||
|
div ecx
|
||
|
};
|
||
|
}
|
||
|
|
||
|
DWORD WINAPI pentimeGetMicrosecDelta (
|
||
|
PPENTIMER pptimer)
|
||
|
{
|
||
|
GetP5Ticks();
|
||
|
_asm {
|
||
|
mov ebx, pptimer
|
||
|
mov ecx, eax
|
||
|
sub eax, [ebx]
|
||
|
mov [ebx], ecx
|
||
|
mov ecx, edx
|
||
|
sbb edx, [ebx+4]
|
||
|
mov [ebx+4], ecx
|
||
|
and edx, 31
|
||
|
mov ecx, pentime.dwCpuMhz
|
||
|
div ecx
|
||
|
};
|
||
|
}
|
||
|
|
||
|
DWORD FAR PASCAL pentimeGetMillisecs (
|
||
|
PPENTIMER pptimer)
|
||
|
{
|
||
|
GetP5Ticks();
|
||
|
_asm {
|
||
|
mov ebx, pptimer
|
||
|
sub eax, [ebx]
|
||
|
sbb edx, [ebx+4]
|
||
|
and edx, 0x7fff // to prevent overflow
|
||
|
mov ecx, pentime.dwCpuKhz
|
||
|
div ecx
|
||
|
};
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
void FAR PASCAL pentimeSetMhz (
|
||
|
DWORD dwCpuMhz)
|
||
|
{
|
||
|
pentime.dwCpuMhz = dwCpuMhz;
|
||
|
pentime.dwCpuKhz = dwCpuMhz * 1000;
|
||
|
}
|
||
|
#else // 16 bit - set mhz is in ASM file
|
||
|
|
||
|
void FAR PASCAL pentimeSetMhz (
|
||
|
DWORD dwCpuMhz);
|
||
|
|
||
|
#endif
|
||
|
|
||
|
void FAR PASCAL pentimeInit (
|
||
|
BOOL bIsPentium,
|
||
|
DWORD dwCpuMhz)
|
||
|
{
|
||
|
if (pentime.bActive = bIsPentium)
|
||
|
{
|
||
|
pentimeSetMhz (dwCpuMhz);
|
||
|
pentime.dwTimerKhz = 1000;
|
||
|
}
|
||
|
else
|
||
|
pentime.dwTimerKhz = 1;
|
||
|
|
||
|
pentimeBegin();
|
||
|
}
|
||
|
|
||
|
#ifdef _WIN32
|
||
|
VOID WINAPI pentimeDetectCPU ()
|
||
|
{
|
||
|
SYSTEM_INFO si;
|
||
|
static DWORD MS_INTERVAL = 500; // measure pentium cpu clock for this
|
||
|
// many millisec. the larger this number
|
||
|
// the more accurate our Mhz measurement.
|
||
|
// numbers less than 100 are unlikely
|
||
|
// to be reliable because of the slop
|
||
|
// in GetTickCount
|
||
|
|
||
|
#ifdef _X86_
|
||
|
GetSystemInfo(&si);
|
||
|
if (si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_INTEL &&
|
||
|
si.wProcessorLevel == 5
|
||
|
)
|
||
|
{
|
||
|
DWORD dw;
|
||
|
PENTIMER qwTicks;
|
||
|
DWORD dwTicks;
|
||
|
|
||
|
pentime.bActive = TRUE;
|
||
|
pentime.dwTimerKhz = 1000;
|
||
|
|
||
|
timeBeginPeriod(1);
|
||
|
dw = timeGetTime ();
|
||
|
pentimeInitTimer (&qwTicks);
|
||
|
|
||
|
Sleep(MS_INTERVAL);
|
||
|
|
||
|
dw = timeGetTime() - dw;
|
||
|
dwTicks = pentimeGetCpuTicks (&qwTicks);
|
||
|
timeEndPeriod(1);
|
||
|
|
||
|
// calculate the CPU Mhz value and Khz value
|
||
|
// to use as millisec and microsec divisors
|
||
|
//
|
||
|
pentime.dwCpuMhz = (dwTicks + dw*500)/dw/1000;
|
||
|
pentime.dwCpuKhz = pentime.dwCpuMhz * 1000;
|
||
|
}
|
||
|
else
|
||
|
#endif
|
||
|
{
|
||
|
pentime.bActive = FALSE;
|
||
|
pentime.dwTimerKhz = 1;
|
||
|
}
|
||
|
}
|
||
|
#else // win16
|
||
|
VOID WINAPI pentimeDetectCPU ()
|
||
|
{
|
||
|
pentimeInit (FALSE, 33);
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
|
||
|
#endif // _INC_PENTIME_CODE_
|
||
|
#endif // PENTIME_H
|