home *** CD-ROM | disk | FTP | other *** search
- {
- 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.
-