#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); }