Советы по Delphi

         

А какой у меня процессор?


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



Содержание раздела