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