Category : Assembly Language Source Code
Archive   : CPUUID.ZIP
Filename : CPUID.PAS

 
Output of file : CPUID.PAS contained in archive : CPUUID.ZIP
{
Here is some code that identifies the CPU and FPU of your computer. It
demonstrates coordination of INLINE, ASM and standard Pascal code. This
routine uses INTEL recommended CPU identification techniques. It also
demontrates two techniques that may be used to address the extended
registers of the 386 and 486.

Donated to the public domain. John D. Leonard II
}

unit cpuid;

interface


Procedure CPUFPUID(var CPU,FPU:integer);

{- This routine determine the type of CPU and FPU (Floating Point Unit)
using INTEL recommended techniques as posted in CPUID.ASM on the
PCEO Intel Forum. It has been supplemented with a check for the
386SX }

{-Returns 1: 8088/8086
2: 80286
3: 80386 -3: 80386SX
4: 80486 -}

{-This routine does not require external OBJ files, all assembler
calls are implemented using ASM directive or INLINE code. -}

{-Use of INLINE was required, as the TP6 ASM processor does not
recognize 386/486 specific register addressing -}

{-The procedure first determines the CPU type by filtering through
a series of tests. Then, the FPU check is performed. -}

{-This procedure demonstrates the use of ASM directives and INLINE
code, in conjunction with regular TP assignments and labels. -}

{-This code as been tested with 8088, 80286, 80386, 80386sx and 80486,
(Yes, Virginia, we have them all sitting around the place.) }

{ ==================================================================== }

implementation


Procedure CPUFPUID(var CPU,FPU:integer);
label check_fpu,stop,restore_eflags;
var fp_status:word;
begin

{- Begin a series of tests to determine CPU type ... -}

{- On an 8086/8088 Flag Bits 12-15 are always set -}
cpu := 1;
asm
PUSHF
POP BX
MOV AX,0FFFH
AND AX,BX
PUSH AX
POPF
PUSHF
POP AX
AND AX,0F000H
CMP AX,0F000H
JE CHECK_FPU
end;

{- On a 80286 Flag Bits 12-15 are always clear -}

cpu := 2;
asm
OR BX,0F000H
PUSH BX
POPF
PUSHF
POP AX
AND AX,0F000H
JZ CHECK_FPU
end;

{- On a 80486, bit 18 of EFLAGS can be set. It can't be set on 386.
(This bit relates to generation of alignment faults. )
Note the use of DB 66H in this code for reference to the
386 extended registers. It acts like a SHIFT key, allowing direct
translation of some addressing commands between the standard
registers and the 386/486 extended registers. }

cpu := 4;
asm

{- Align Stack to prevent a fault -}

MOV DX,SP { MOV DX, SP }
AND SP, NOT 3 { AND SP, NOT 3 }

{- Get EFLAGS and store in ECX for later comparison and restoration }

DB 66H
PUSHF { PUSHFD }
DB 66H
POP AX { POP EAX }
DB 66H
MOV CX,AX { MOV ECX,EAX }


{- Set Bit #18. Note use of DW to get large integer -}

DB 66H
XOR AX,0
DW 4H { XOR EAX,40000H }

{- Stick the result into EFLAGS, and get it back. Keep in EAX -}

DB 66H
PUSH AX { PUSH EAX }
DB 66H
POPF { POPFD }
DB 66H
PUSHF { PUSHFD }
DB 66H
POP AX { POP EAX }

{- Restore Flags and Stack before making comparison -}

DB 66H
PUSH CX { PUSH ECX }
DB 66H
POPF { POPFD }
MOV SP,DX { MOV SP,DX }

DB 66H
XOR AX,CX { XOR EAX,ECX }
JNZ CHECK_FPU

end;


{- On a 386, the coprocessor type bit in CR0 can be set. On a 386Sx,
it can not be set. NOTE: this test is not a part of the recommended
INTEL CPU check code. ALSO NOTE: this code can not determine early
versions of the 386sx, as they allow this bit to be set. INLINE was
required, as there is no way to "shift" ala "DB 66H" to access CR0. }


cpu := -3;
inline( $0f/$20/$c0 ); { MOV EAX,CR0 }
inline( $66/$8b/$c8 ); { MOV ECX,EAX }
inline( $66/$83/$F0/$10); { MOV EAX,10H }
inline( $0f/$22/$c0 ); { MOV CR0,EAX }
inline( $0f/$20/$c0 ); { MOV EAX,CR0 }
inline( $0f/$22/$c1 ); { MOV CR0,ECX }
inline( $66/$33/$c1 ); { XOR EAX,ECX }
asm
JZ CHECK_FPU
end;

{- The default CPU type, if all else fails. -}

cpu := 3;


{- Begin CoProcessor Check. We first check if the FPU can be initialized.
If not, there is no FPU. If we have got one, it will, in general
match the CPU type, i.e. 8087 goes with 8086/88, 287 goes with 286, etc.
The only exception is the 386, which may use either the 387 or 287. }


CHECK_FPU:

{- Can we initialize the CoProcessor? -}

FPU := 0;
asm
FNINIT
MOV FP_STATUS,5A5AH
FNSTSW FP_STATUS
MOV AX,FP_STATUS
JNE STOP
FNSTCW FP_STATUS
MOV AX,FP_STATUS
AND AX,103FH
CMP AX,3FH
JNE STOP
end;

{- Yes! Assign the corresponding FPU based on CPU -}

FPU := abs(CPU);

{- However, if we have a 386/386SX, we must determine 387 or 287. A 387
differentiates between positive and negative infinity, a 287 does not. }

if FPU=3 then begin

FPU := 2;
asm
FLD1
FLDZ
FDIV
FLD ST
FCHS
FCOMPP
FSTSW FP_STATUS
MOV AX,FP_STATUS
SAHF
JZ STOP
end;

fpu := 3;

end;


stop:


end;




end.


  3 Responses to “Category : Assembly Language Source Code
Archive   : CPUUID.ZIP
Filename : CPUID.PAS

  1. Very nice! Thank you for this wonderful archive. I wonder why I found it only now. Long live the BBS file archives!

  2. This is so awesome! 😀 I’d be cool if you could download an entire archive of this at once, though.

  3. But one thing that puzzles me is the “mtswslnkmcjklsdlsbdmMICROSOFT” string. There is an article about it here. It is definitely worth a read: http://www.os2museum.com/wp/mtswslnk/