277 lines
6.7 KiB
C
277 lines
6.7 KiB
C
#include "string.h"
|
|
#include "detect.h"
|
|
|
|
|
|
long CPUINFO;
|
|
char cIDENT[13];
|
|
|
|
|
|
/***********************************/
|
|
/* VISUAL 5 CPU detection function */
|
|
/***********************************/
|
|
#ifndef WATCOM
|
|
|
|
#define CPUID __asm _emit 0x0F __asm _emit 0x0a2
|
|
#define RDTSC __asm _emit 0x0F __asm _emit 0x31
|
|
|
|
long gIsCpuidSupported(void)
|
|
{
|
|
long retour;
|
|
|
|
_asm{
|
|
pushfd
|
|
pop eax
|
|
test eax,0x00200000
|
|
jz bit21
|
|
and eax,0xffdfffff
|
|
push eax
|
|
popfd
|
|
pushfd
|
|
pop eax
|
|
test eax,0x00200000
|
|
jz ok
|
|
jmp no_ok
|
|
bit21:
|
|
or eax,0x00200000
|
|
push eax
|
|
popfd
|
|
pushfd
|
|
pop eax
|
|
test eax,0x00200000
|
|
jnz ok
|
|
jmp no_ok
|
|
ok:
|
|
mov eax,1
|
|
jmp done
|
|
no_ok:
|
|
mov eax,0
|
|
done:
|
|
mov retour,eax
|
|
}
|
|
return retour;
|
|
}
|
|
|
|
|
|
long gCPUInfo()
|
|
{
|
|
long retour;
|
|
_asm{
|
|
mov eax,1
|
|
CPUID
|
|
mov retour, eax
|
|
}
|
|
return retour;
|
|
}
|
|
|
|
|
|
void gBuilderIdent(void)
|
|
{
|
|
_asm{
|
|
mov eax,0
|
|
CPUID
|
|
mov word ptr[cIDENT],bx
|
|
shr ebx,16
|
|
mov word ptr[cIDENT+2],bx
|
|
mov word ptr[cIDENT+4],dx
|
|
shr edx,16
|
|
mov word ptr[cIDENT+6],dx
|
|
mov word ptr[cIDENT+8],cx
|
|
shr ecx,16
|
|
mov word ptr[cIDENT+10],cx
|
|
}
|
|
}
|
|
|
|
|
|
#else
|
|
/***********************************/
|
|
/* WATCOM CPU detection function */
|
|
/***********************************/
|
|
|
|
long gIsCpuidSupported();
|
|
#pragma aux gIsCpuidSupported = \
|
|
"pushfd"\
|
|
"pop eax"\
|
|
"test eax,0x00200000"\
|
|
"jz bit21"\
|
|
"and eax,0xffdfffff"\
|
|
"push eax"\
|
|
"popfd"\
|
|
"pushfd"\
|
|
"pop eax"\
|
|
"test eax,0x00200000"\
|
|
"jz ok"\
|
|
"jmp no_ok"\
|
|
"bit21:"\
|
|
"or eax,0x00200000"\
|
|
"push eax"\
|
|
"popfd"\
|
|
"pushfd"\
|
|
"pop eax"\
|
|
"test eax,0x00200000"\
|
|
"jnz ok"\
|
|
"jmp no_ok"\
|
|
"ok:"\
|
|
"mov eax,1"\
|
|
"jmp done"\
|
|
"no_ok:"\
|
|
"mov eax,0"\
|
|
"done:"\
|
|
value [eax]\
|
|
modify [eax ebx ecx edx esi edi];
|
|
|
|
long gCPUInfo();
|
|
#pragma aux gCPUInfo = \
|
|
"mov eax,1"\
|
|
"db 0x0F, 0xa2"\
|
|
value [eax]\
|
|
modify [eax ebx ecx edx];
|
|
|
|
|
|
void gBuilderIdent();
|
|
#pragma aux gBuilderIdent=\
|
|
"mov eax,0"\
|
|
"db 0x0F, 0xa2"\
|
|
"mov word ptr[cIDENT],bx"\
|
|
"shr ebx,16"\
|
|
"mov word ptr[cIDENT+2],bx"\
|
|
"mov word ptr[cIDENT+4],dx"\
|
|
"shr edx,16"\
|
|
"mov word ptr[cIDENT+6],dx"\
|
|
"mov word ptr[cIDENT+8],cx"\
|
|
"shr ecx,16"\
|
|
"mov word ptr[cIDENT+10],cx"\
|
|
modify [eax ebx ecx edx];
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/**********************************/
|
|
/* Return 1 if RDTSC is available */
|
|
/**********************************/
|
|
long fn_lIsRdtscAvailable()
|
|
{
|
|
long Cpu_Type = UNKNOWN;
|
|
char cModel = (char)0xFF;
|
|
long lRdtscOk = 0;
|
|
|
|
if (gIsCpuidSupported())
|
|
{
|
|
CPUINFO = gCPUInfo();
|
|
gBuilderIdent();
|
|
if ( strcmp(cIDENT, "GenuineIntel") ==0 )
|
|
{
|
|
/* Family*/
|
|
switch ((CPUINFO&0xF00)>>8)
|
|
{
|
|
case 4:
|
|
if ( ((CPUINFO&0xF0)>>4) == 7)
|
|
Cpu_Type = iDX2;
|
|
else if ( ((CPUINFO&0xF0)>>4) == 8)
|
|
Cpu_Type = iDX4;
|
|
else
|
|
Cpu_Type = UNKNOWN;
|
|
break;
|
|
|
|
case 5:
|
|
Cpu_Type = PENTIUM;
|
|
if ( ((CPUINFO&0xF0)>>4) == 4) Cpu_Type = PENT_MMX;
|
|
lRdtscOk = 1;
|
|
break;
|
|
|
|
case 6:
|
|
case 15:
|
|
Cpu_Type = PENTIUM_PRO;
|
|
if ( ((CPUINFO&0xF0)>>4) == 3) Cpu_Type = PENTIUM2;
|
|
lRdtscOk = 1;
|
|
break;
|
|
|
|
default:
|
|
Cpu_Type = UNKNOWN;
|
|
break;
|
|
}
|
|
}
|
|
else if ( strcmp(cIDENT, "AuthenticAMD") ==0 )
|
|
{
|
|
switch (CPUINFO & 0x00000FF0)
|
|
{
|
|
case 0x0500 :
|
|
case 0x0510 :
|
|
Cpu_Type = AMD_K5;
|
|
cModel = (CPUINFO & 0x030) >> 4;
|
|
break;
|
|
|
|
case 0x0520 :
|
|
case 0x0530 :
|
|
Cpu_Type = AMD_K5;
|
|
cModel = (CPUINFO & 0x030) >> 4;
|
|
lRdtscOk = 1;
|
|
break;
|
|
|
|
case 0x0560 :
|
|
case 0x0570 :
|
|
case 0x0580 :
|
|
case 0x0590 :
|
|
Cpu_Type = AMD_K6;
|
|
cModel = (CPUINFO & 0x0F0) >> 4;
|
|
lRdtscOk = 1;
|
|
break;
|
|
|
|
case 0x06A0 :
|
|
// Athlon! But pretend it's a K6 so the timers work...
|
|
Cpu_Type = AMD_K6;
|
|
cModel = (CPUINFO & 0x0F0) >> 4;
|
|
lRdtscOk = 1;
|
|
break;
|
|
|
|
|
|
default:
|
|
if ( (CPUINFO&0xF00) == 0x400)
|
|
Cpu_Type = Am5x86;
|
|
else
|
|
Cpu_Type = UNKNOWN;
|
|
break;
|
|
}
|
|
}
|
|
else if (strcmp(cIDENT, "CyrixInstead") ==0 ) /* CYRIX */
|
|
{
|
|
switch ((CPUINFO&0xF00)>>8) /* Family */
|
|
{
|
|
case 4:
|
|
if ( ((CPUINFO&0xF0)>>4) == 4 )
|
|
Cpu_Type = MediaGX;
|
|
break;
|
|
|
|
case 5:
|
|
switch ((CPUINFO&0xF0)>>4) /* Model */
|
|
{
|
|
case 2:
|
|
Cpu_Type = CX_6X86;
|
|
break;
|
|
|
|
case 4:
|
|
Cpu_Type = GXm;
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case 6:
|
|
Cpu_Type = CX_6x86MX;
|
|
lRdtscOk = 1;
|
|
break;
|
|
|
|
default:
|
|
Cpu_Type = UNKNOWN;
|
|
break;
|
|
}
|
|
}
|
|
else if (strcmp(cIDENT, "CentaurHauls")==0) /* IDT */
|
|
{
|
|
Cpu_Type = IDT_C6;
|
|
}
|
|
}
|
|
|
|
return (lRdtscOk);
|
|
}
|
|
|