А какой у меня процессор?
{ Ниже приведен код модуля 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]