А какой у меня процессор?
{ Ниже приведен код модуля Delphi, позволяющий определить тип CPU. Код является модифицированным кодом Intel. Использование его очевидно. Если для вас это утверждение спорно, пошлите мне ваш электронный адрес, и я вышлю вам демонстрационный пример. Поскольку Delphi ассемблер 16-битный, код смотрится несколько странным. Чтобы видеть 32-битные инструкции, попробуйте воспользоваться 32-битным дизассемблером (или прочтите комментарии). } unit CpuId; { Источником данного кода послужил код Intel, который был модифицирован для Delphi inline-ассемблера. Посколько Intel сделал свой код доступным, я также придаю ему статус свободнораспространяемого. |
Успехов!
Ray Lischner
Tempest Software
6/18/95
}
interface
type
{ Все типы известны. В случае создания новых, задайте им пригодные имена, и соответственно расширьте функцию CpuTypeString.
}
TCpuType = (cpu8086, cpu80286, cpu386, cpu486, cpuPentium);
{ Возвращает тип текущего CPU }
function CpuType: TCpuType;
{ Возвращаем тип как короткую строку }
function CpuTypeString: String;
implementation
uses SysUtils;
function CpuType: TCpuType; assembler;
asm
push DS
{ Во-первых, проверяем наличие 8086 CPU }
{ Биты 12-15 в регистре FLAGS всегда выставлены в }
{ 8086 процессоре. }
pushf { сохраняем EFLAGS }
pop bx { сохраняем EFLAGS в BX }
mov ax,0fffh { сбрасываем биты 12-15 }
and ax,bx { в EFLAGS }
push ax { сохраняем в стеке значение EFLAGS }
popf { замещаем текущее значение EFLAGS }
pushf { устанавливаем новый EFLAGS }
pop ax { сохраняем новый EFLAGS в AX }
and ax,0f000h { если биты 12-15 выставлены, то CPU }
cmp ax,0f000h { 8086/8088 }
mov ax, cpu8086 { вывешиваем флаг 8086/8088 }
je @@End_CpuType
{ Проверка 80286 CPU }
{ Биты 12-15 регистра FLAGS всегда очищены в случае }
{ 80286 процессора. }
or bx,0f000h { пробуем установить биты 12-15 }
push bx
popf
pushf
pop ax
and ax,0f000h { если биты 12-15 сброшены, CPU=80286 }
mov ax, cpu80286 { включаем флаг 80286 }
jz @@End_CpuType
{ Для определения процессоров марки 386 и выше, необходимо использовать 32-битные инструкции, но 16-битный ассемблер Delphi не признает 32-битные коды операций и операнды. Взамен этого используется префикс размера операнда 66H, который позволяет преобразовать каждую инструкцию в ее 32-битный эквивалент. Для непосредственных 32-битных операндов вам нужно будет также хранить первое слово операнда сразу после следующей за ним инструкции. 32-битная инструкция показана в комментариях после инструкции 66H. }
{ Проверяем на i386 CPU }
{ Бит AC и бит #18 - новые биты, введенные в регистр EFLAGS }
{ в i486 DX CPU для компенсационного выравнивания. }
{ Этот бит не может быть выставлен в i386 CPU. }
db 66h { pushfd }
pushf
db 66h { pop eax }
pop ax { получаем оригинальный EFLAGS }
db 66h { mov ecx, eax }
mov cx,ax { сохраняем оригинальный EFLAGS }
db 66h { xor eax,40000h }
xor ax,0h { перебрасываем бит AC в EFLAGS }
dw 0004h
db 66h { push eax }
push ax { сохраняем для EFLAGS }
db 66h { popfd }
popf { копируем в EFLAGS }
db 66h { pushfd }
pushf { выталкиваем EFLAGS }
db 66h { pop eax }
pop ax { получаем новое значение EFLAGS }
db 66h { xor eax,ecx }
xor ax,cx { невозможно переключить бит AC, CPU=Intel386 }
mov ax, cpu386 { включаем 386 флаг }
je @@End_CpuType
{ Производим проверку i486 DX CPU / i487 SX MCP и i486 SX CPU }
{ Проверяем способность устанавливать/сбрасывать флаг ID (бит 21) в EFLAGS, }
{ который указывает присутствие процессора }
{ с помощью использования инструкции CPUID. }
db 66h { pushfd }
pushf { выталкиваем оригинальный EFLAGS }
db 66h { pop eax }
pop ax { получаем оригинальный EFLAGS в eax }
db 66h { mov ecx, eax }
mov cx,ax { сохраняем оригинальный EFLAGS в ecx }
db 66h { xor eax,200000h }
xor ax,0h { перебрасываем бит ID в EFLAGS }
dw 0020h
db 66h { push eax }
push ax { сохраняем для EFLAGS }
db 66h { popfd }
popf { копируем в EFLAGS }
db 66h { pushfd }
pushf { выталкиваем EFLAGS }
db 66h { pop eax }
pop ax { получаем новое значение EFLAGS }
db 66h { xor eax, ecx }
xor ax, cx
mov ax, cpu486 { вывешиваем i486 флаг }
je @@End_CpuType { если бит ID не может быть изменен, CPU=486
}
{ инструкция CPUID без функционального назначения }
{ Выполняем инструкцию CPUID для определения поставщика, }
{ семейства, модели и версии. Инструкция CPUID для этих }
{ целей может быть использована, начиная с версии B0 }
{ процессора P5. }
db 66h { mov eax, 1 }
mov ax, 1 { устанавливаем для инструкции CPUID }
dw 0
db 66h { cpuid }
db 0Fh { код операции Hardcoded для инструкции CPUID }
db 0a2h
db 66h { and eax, 0F00H }
and ax, 0F00H { все маскируем }
dw 0
db 66h { shr eax, 8 }
shr ax, 8 { сдвигаем тип cpu вплоть до нижнего байта }
sub ax, 1 { вычитаем 1 для отображения на 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
{ Пытаемся добавить "гибкости" для будущих версий процессоров, например, для P6. }
Result := Format('P%d', [Ord(kind)]);
end;
end;
end.
[001953]