unit P32_CPUF;

interface

var
 MMXSupport, FPUSupport,S3DNOW:Boolean;
 CPUType:String;

Const
 YESNO:Array[FALSE..TRUE] of String[3] = ('No','Yes');

implementation

type
 CPUs = (i086,
         i186,
         i286,
         i386,
         i486,
         i586,
         i686,
         i786,
         i886,
         i986,
         pentium,
         pentiumpro,
         pentiummmx,
         pentium2,              { Hmm.. think I gotta look at the cache info }
         pentium2celeron,       { with these two ... Detection uncertain }
         am486,
         amdk5,
         amdk6,
         amdk63d,
         amdk63dplus,   { amd k6-3? }
         cyrix5x86,     { should be detected :) }
         cyrixmediagx,  { actually Cyrix Gx86 }
         cyrix6x86,     { actually Cyrix M1 }
         cyrix6x86mx,   { actually Cyrix M2 }
         cyrixmediagxmmx, { actually Cyrix EMMX????????? }
         cyrixemmx,       { why is Cyrix using different names all the time?? }
         umc,
         centaur,               {?????}
         centaur3dnow,
         nexgen);



Const
 CPUTypes:Array[CPUs] of String[32] =
            ('086 (?)',
             '186 (?)',
             '286 (?)',
             '386',
             '486',
             'Unknown 586',
             'Unknown 686',
             'Unknown 786',
             'Unknown 886',
             'Unknown 986',
             'Intel Pentium',
             'Intel Pentium Pro',
             'Intel Pentium MMX',
             'Intel Pentium 2',
             'Intel Pentium 2 Celeron',
             'am486 Enhanced or Am5x86',
             'AMD K5',
             'AMD K6',
             'AMD K6-2 3DNOW!',
             'AMD K6-3 3DNOW!+',
             'Cyrix 5x86',   { will be detected as a 486 }
             'Cyrix MediaGX',
             'Cyrix 6x86',
             'Cyrix 6x86MX',
             'Cyrix MediaGX MMX Enhanced',
             'Cyrix EMMX',  { not detected yet }
             'UMC 586',
             'Centaur WinChip MMX',
             'Centaur WinChip 3DNOW!',
             'NexGen 586');

var
 CPUt:CPUs;
 id:String[12];
 cpuinfo,compat,extcompat,moreinfo:LongInt;
 model,stepping,family,res:Byte;
 ExtName:Array[1..48] of Char;

label
 CPUFound;

begin
 asm
  mov dx,$22
  mov al,$e8
  out dx,al             {This enables the CPUID flag of Cyrixes}
  in al,dx              {Should have no effect on other CPUs}
  in al,dx
  in al,dx
  in al,dx
  in al,dx
  in al,dx              {wait for 5 or 6 clock cycles}
  inc dx
  in al,dx
  or al,128             {bit 7 on}
  out dx,al             {put bit 7 on, CPUID on Cyrixes enabled }

  db $66; pushf         {pushaf}
  db $66; pop ax        {pop eax}
  db $66; or ax,0; dw 32 {or eax,bit 21 = CPUID Support}
  db $66; push ax       {push eax}
  db $66; popf          {popaf}
  db $66; pushf         {pushaf}
  db $66; pop ax        {pop eax}
  db $66; test ax,0; dw 32 {test eax,bit 21}
  jnz @CPUIdSupport

  mov CPUt,i386         {It is atleast a 386}

  db $66; pushf         {pushaf}
  db $66; or ax,0; dw 4 {or eax,bit 18 (Align Flag), exists only on 486's+}
  db $66; push ax       {push eax}
  db $66; popf          {popaf}
  db $66; pushf         {pushaf}
  db $66; pop ax        {pop eax}
  db $66; popf          {popaf}
  db $66; test ax,0; dw 4 {test eax,bit 18}
  jz @is386
{ This code was actually NOT ripped! Think of my surprise
  when finding it on Cyrix's and AMD's Homepage :}

  mov CPUt,i486         {It is atleast a 486, checking stops here,
                         since rest support CPU id!}
@is386:
  xor ax,ax             { wooow .. .standard 16 bit code :) }
  sahf                  { clear flags }
  mov ax,5
  mov bx,2
  div bl                { do the 5 div 2 check  ??? = See Cyrix ... :)}
  lahf
  cmp ah,2
  jne @Not_Cyrix5x86    { Well. .. it wasn't a Cyrix5x86! }

  mov CPUt,cyrix5x86

@Not_Cyrix5x86:
  mov ax,-1
  fninit                {initialize FPU}
  fnstsw ax             {store status word, does nothing if FPU isn't present}
  cmp ax,-1             {Lack of FPU will result in ax being unchanged}
  je @NoFPU

  mov FPUSupport,TRUE   {got the FPU support...}

@NoFPU:
  jmp CPUFound          {It doesn't support CPUID }

@CPUIdSupport:
  db $66; xor ax,ax     {xor eax,eax}
  db $0f,$a2            {cpuid, get VendorInfo}
  lea si,id
  mov byte ptr[si],12
  inc si
  db $66; mov [si+0],bx {mov [si+0],ebx}
  db $66; mov [si+4],dx {mov [si+4],edx}
  db $66; mov [si+8],cx {mov [si+8],ecx}
  push ax

  db $66; mov ax,1; dw $0000 {mov eax,1}
  db $0f,$a2                 {cpuid}
  lea si,cpuinfo
  db $66; mov [si],ax        {mov [si],eax}
  lea si,compat
  db $66; mov [si],dx        {mov [si],edx}

  pop ax
  cmp ax,1
  jbe @No0000_0002Support

  db $66; mov ax,2; dw $0000;      { mov eax, $0000_0002 }
  db $0f,$a2
  lea si,moreinfo
  db $66; mov [si],bx              { mov [si],ebx }

@No0000_0002Support:
  db $66; mov ax,0; dw $8001;      { mov eax, $8000_0001 }
  db $0f,$a2                       { cpuid }
  lea si,extcompat
  db $66; mov [si],dx              { mov [si],edx }

  lea si,ExtName
  db $66; mov ax,2; dw $8000;      { mov eax, $8000_0002 }
  db $0f,$a2
  db $66; mov [si+00],ax           { mov [si+00],eax }
  db $66; mov [si+04],bx           { mov [si+04],ebx }
  db $66; mov [si+08],cx           { mov [si+08],ecx }
  db $66; mov [si+12],dx           { mov [si+12],edx }
  add si,16
  db $66; mov ax,3; dw $8000;      { mov eax, $8000_0003 }
  db $0f,$a2
  db $66; mov [si+00],ax           { mov [si+00],eax }
  db $66; mov [si+04],bx           { mov [si+04],ebx }
  db $66; mov [si+08],cx           { mov [si+08],ecx }
  db $66; mov [si+12],dx           { mov [si+12],edx }
  add si,16
  db $66; mov ax,4; dw $8000;      { mov eax, $8000_0004 }
  db $0f,$a2
  db $66; mov [si+00],ax           { mov [si+00],eax }
  db $66; mov [si+04],bx           { mov [si+04],ebx }
  db $66; mov [si+08],cx           { mov [si+08],ecx }
  db $66; mov [si+12],dx           { mov [si+12],edx }

 end;

 CPUt := CPUs((cpuinfo shr 8) AND $0f);

 Stepping := cpuinfo AND $0f;
 model    := (cpuinfo shr 4) AND $0f;
 family   := (cpuinfo shr 8) AND $0f;
 res      := (cpuinfo shr 12) AND $0f;

 If (compat AND 1 = 1) then FPUSupport := TRUE else FPUSupport := FALSE;
 If ((compat shr 23) AND 1 = 1) then MMXSupport := TRUE else MMXSupport := FALSE;
 If ((extcompat shr 31) AND 1 = 1) then S3DNOW := TRUE else S3DNOW := FALSE;

  If (id = 'GenuineIntel') then
   begin
    If (MMXSupport) then
     begin
      If (moreinfo AND $40 = $40) then
       If (moreinfo - $40 <> 0) then CPUt := pentium2 { has unified L2 cache }
       else CPUt := pentium2celeron  { no unified L2 cache }
      else CPUt := pentiummmx;
     end
    else
     If (family = 6) then CPUt := pentiumpro
     else CPUt := pentium;
   end
  else
  If (id = 'AuthenticAMD') then
   begin
    If (MMXSupport) then
     Case Model of
      6,7:CPUt := amdk6;
      8:CPUt := amdk63d;
      9:CPUt := amdk63dplus;
      else CPUt := amdk6;
     end
    else
     begin
      If (Family = 4) then CPUt := am486 else CPUt := amdk5;
      { hrrm... confusius }
     end;
   end
  else
  If (id = 'CyrixInstead') then
   begin
    If (MMXSupport) then
     If (family = 5) then CPUt := cyrixmediagxmmx
     else CPUt := cyrix6x86mx   { family = 6 }
    else If (family = 4) then CPUt := cyrixmediagx
         else CPUt := cyrix6x86;
   end
  else
  If (id = 'UMC UMC UMC ') then
   begin
    CPUt := umc;        { Are they alive? }
   end
  else
  If (id = 'NexGenDriven') then
   begin
    CPUt := nexgen;     { Couldn't find their Homepage!!!! }
   end
  else
  If (id = 'CentaurHauls') then
   begin
    If (S3DNOW) then CPUt := centaur3dnow
    else CPUt := centaur;
   end
  else
   begin
   end;

CPUFound: ;

 CPUType := CPUTypes[CPUt];
 If (CPUt in [i586..i986]) then CPUType := CPUType + '"' + id + '"';
 { the unknown CPUs }

 If (ExtName[1] <> #00) then
  begin
   CPUType := ExtName;
   For moreinfo := 1 to 48 do
    If (ExtName[moreinfo] = #00) then break;
   CPUType[0] := Chr(moreinfo);
  end;
 If (res = 1) then CPUType := CPUType+' Overdrive';
 If (res = 2) then CPUType := 'Dual '+CPUType;
end.