home *** CD-ROM | disk | FTP | other *** search
- unit Cputyp;
-
- { This code comes from Intel, and has been modified for Delphi's
- inline assembler. Since Intel made the original code freely
- available, I am making my changes freely available.
-
- Share and enjoy!
-
- Ray Lischner
- Tempest Software
- 6/18/95
- }
-
- interface
-
- type
- { All the types currently known. As new types are created,
- add suitable names, and extend the case statement in
- CpuTypeString. }
- TCpuType = (cpu8086, cpu80286, cpu386, cpu486, cpuPentium);
-
- { Return the type of the current CPU }
- function CpuType: TCpuType;
-
- { Return the type as a short string }
- function CpuTypeString: String;
-
- implementation
-
- uses SysUtils;
-
- function CpuType: TCpuType; assembler;
- asm
- push DS
-
- { First check for an 8086 CPU }
- { Bits 12-15 of the FLAGS register are always set on the }
- { 8086 processor. }
- pushf { save EFLAGS }
- pop bx { store EFLAGS in BX }
- mov ax,0fffh { clear bits 12-15 }
- and ax,bx { in EFLAGS }
- push ax { store new EFLAGS value on stack }
- popf { replace current EFLAGS value }
- pushf { set new EFLAGS }
- pop ax { store new EFLAGS in AX }
- and ax,0f000h { if bits 12-15 are set, then CPU }
- cmp ax,0f000h { is an 8086/8088 }
- mov ax, cpu8086 { turn on 8086/8088 flag }
- je @@End_CpuType
-
- { 80286 CPU check }
- { Bits 12-15 of the FLAGS register are always clear on the }
- { 80286 processor. }
- or bx,0f000h { try to set bits 12-15 }
- push bx
- popf
- pushf
- pop ax
- and ax,0f000h { if bits 12-15 are cleared, CPU=80286 }
- mov ax, cpu80286 { turn on 80286 flag }
- jz @@End_CpuType
-
- { To test for 386 or better, we need to use 32 bit instructions,
- but the 16-bit Delphi assembler does not recognize the 32 bit opcodes
- or operands. Instead, use the 66H operand size prefix to change
- each instruction to its 32-bit equivalent. For 32-bit immediate
- operands, we also need to store the high word of the operand immediately
- following the instruction. The 32-bit instruction is shown in a comment
- after the 66H instruction. }
-
- { i386 CPU check }
- { The AC bit, bit #18, is a new bit introduced in the EFLAGS }
- { register on the i486 DX CPU to generate alignment faults. }
- { This bit can not be set on the i386 CPU. }
-
- db 66h { pushfd }
- pushf
- db 66h { pop eax }
- pop ax { get original EFLAGS }
- db 66h { mov ecx, eax }
- mov cx,ax { save original EFLAGS }
- db 66h { xor eax,40000h }
- xor ax,0h { flip AC bit in EFLAGS }
- dw 0004h
- db 66h { push eax }
- push ax { save for EFLAGS }
- db 66h { popfd }
- popf { copy to EFLAGS }
- db 66h { pushfd }
- pushf { push EFLAGS }
- db 66h { pop eax }
- pop ax { get new EFLAGS value }
- db 66h { xor eax,ecx }
- xor ax,cx { can't toggle AC bit, CPU=Intel386 }
- mov ax,cpu386 { turn on 386 flag }
- je @@End_CpuType
-
- { i486 DX CPU / i487 SX MCP and i486 SX CPU checking }
- { Checking for ability to set/clear ID flag (Bit 21) in EFLAGS }
- { which indicates the presence of a processor }
- { with the ability to use the CPUID instruction. }
- db 66h { pushfd }
- pushf { push original EFLAGS }
- db 66h { pop eax }
- pop ax { get original EFLAGS in eax }
- db 66h { mov ecx, eax }
- mov cx,ax { save original EFLAGS in ecx }
- db 66h { xor eax,200000h }
- xor ax,0h { flip ID bit in EFLAGS }
- dw 0020h
- db 66h { push eax }
- push ax { save for EFLAGS }
- db 66h { popfd }
- popf { copy to EFLAGS }
- db 66h { pushfd }
- pushf { push EFLAGS }
- db 66h { pop eax }
- pop ax { get new EFLAGS value }
- db 66h { xor eax, ecx }
- xor ax, cx
- mov ax, cpu486 { turn on i486 flag }
- je @@End_CpuType { if ID bit cannot be changed, CPU=486
- }
- { without CPUID instruction functionality }
-
- { Execute CPUID instruction to determine vendor, family, }
- { model and stepping. The use of the CPUID instruction used }
- { in this program can be used for B0 and later steppings }
- { of the P5 processor. }
- db 66h { mov eax, 1 }
- mov ax, 1 { set up for CPUID instruction }
- dw 0
- db 66h { cpuid }
- db 0Fh { Hardcoded opcode for CPUID
- instruction }
- db 0a2h
- db 66h { and eax, 0F00H }
- and ax, 0F00H { mask everything but family }
- dw 0
- db 66h { shr eax, 8 }
- shr ax, 8 { shift the cpu type down to the low byte }
- sub ax, 1 { subtract 1 to map to TCpuType }
-
- @@End_CpuType:
- pop ds
- end;
-
- function CpuTypeString: String;
- var
- kind: TCpuType;
- begin
- kind := CpuType;
- case kind of
- cpu8086:
- Result := '8086';
- cpu80286:
- Result := '80286';
- cpu386:
- Result := '386';
- cpu486:
- Result := '486';
- cpuPentium:
- Result := 'Pentium';
- else
- { Try to be flexible for future cpu types, e.g., P6. }
- Result := Format('P%d', [Ord(kind)]);
- end;
- end;
-
- end.
-
-
-