[Back to DELPHI SWAG index] [Back to Main SWAG index] [Original]
{Here is a Delphi unit to detect the CPU type, modified from Intel's
code. Use should be fairly obvious. If not, send me email, and I can
send you an example program. Because Delphi's assembler is 16-bit,
the code looks a little wierd. Try using a 32-bit disassembler to see
the 32-bit instructions (or read the comments). }
unit CpuId;
{ 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.
[Back to DELPHI SWAG index] [Back to Main SWAG index] [Original]