Как на Ассемблере получить строку названия процессора
Для получения различной информации о процессоре используется ассемблерная команда CPUID. С ее помощью можно, например, узнать марку процессора и набор поддерживаемых им функций. На старых процессорах инструкция CPUID отсутствовала, поэтому во всех руководствах рекомендуют сперва проверить, что процессор ее поддерживает. Конечно, сейчас придется немало напрячься, чтобы найти такие древние компьютеры для ваших приложений, но порядок есть порядок. Итак, чтобы удостоверится, что команда CPUID доступна, достаточно попытаться изменить 21-й бит расширенного регистра EFLAGS. Если бит успешно поменяется, то инструкция CPUID процессором поддерживается, если регистр флагов остался без изменений, то процессор команду CPUID не поддерживает.Code (Assembler) : Убрать нумерацию
- ; Проверить, поддерживается ли команда CPUID
- pushfd
- pop eax
- ; Получить регистр флагов
- mov ebx,eax
- ; Изменить 21-й бит в регистре флагов
- xor eax, 200000h
- ; Сохранить и снова получить регистр флагов
- push eax
- popfd
- pushfd
- pop eax
- ; Регистр флагов изменился?
- cmp eax,ebx
- ; Нет, значит команда CPUID не поддерживается
- je cpuid_not_supported
ASCII-строка | HEX-значения EBX:EDX:ECX | Производитель |
---|---|---|
GenuineIntel | 756E6547:49656E69:6C65746E | Intel |
AuthenticAMD | 68747541:69746E65:444D4163 | AMD |
CyrixInstead | 69727943:736E4978:64616574 | Cyrix |
CentaurHauls | 746E6543:48727561:736C7561 | Centaur |
SiS SiS SiS | 20536953:20536953:20536953 | SiS |
NexGenDriven | 4778654E:72446E65:6E657669 | NexGen |
GenuineTMx86 | 756E6547:54656E69:3638784D | Transmeta |
RiseRiseRise | 65736952:65736952:65736952 | Rise |
UMC UMC UMC | 20434D55:20434D55:20434D55 | UMC |
Geode by NSC | 646F6547:79622065:43534E20 | National Semiconductor |
Но это лишь общее название производителя, а нам надо получить полное наименование. Для этого надо последовательно вызвать команду CPUID с параметрами в EAX = 80000002h, 80000003h и 80000004h. На каждый запрос в регистрах EAX:EBX:ECX:EDX будет возвращаться фрагмент 48-символьной строки полного наименования процессора, например, что-то типа Intel(R) Core(TM) i7-3770K CPU @ 3.50GHz. Если строка короче 48 символов, то она будет дополняться пробелами, причем в разных местах. Для удобного получения строки названия процессора я написал вот такую функцию.
Code (Assembler) : Убрать нумерацию
- ;-------------------------------------------------------------------
- ; Функция получения строки названия процессора
- ;-------------------------------------------------------------------
- ; Параметры:
- ; lpBuff - указатель на строку-приемник
- ; dFixString - надо ли чистить результат от лишних пробелов и
- ; заменять строки (TM) и (R) на отдельные символы
- ;-------------------------------------------------------------------
- proc GetCPUString lpBuff:DWORD, dFixString:DWORD
- pusha
- ; Указатель на строку-приемник
- mov esi,[lpBuff]
- mov edi,esi
- cld
- ; Прочитать информацию о процессоре
- mov eax,80000002h
- @@:
- push eax
- cpuid
- stosd
- xchg eax,ebx
- stosd
- xchg eax,ecx
- stosd
- xchg eax,edx
- stosd
- pop eax
- inc eax
- cmp eax,80000004h
- jbe @b
- ; Привести строку к формату ASCIIZ
- xor eax,eax
- stosb
- ; Нужно ли чистить строку?
- cmp [dFixString],0
- je .loc_ret
- ; Почистить строку от лишних и неправильных символов
- mov edi,esi
- @@:
- ; Убрать лидирующие пробелы, если они есть
- cmp byte [esi],' '
- jne @f
- inc esi
- jmp @b
- @@:
- xor ebx,ebx
- .loc_clean_string:
- lodsb
- cmp al,' '
- jnz @f
- ; Убрать повторяющиеся пробелы
- cmp bl,1
- je .loc_clean_string
- ; Установить флажок, что начались пробелы
- mov bl,1
- jmp .loc_store_char
- @@:
- ; Сбросить флажок пробелов
- mov bl,0
- ; Преобразовать символы "(R)" в один
- cmp al,'('
- jne @f
- cmp word [esi],'R)'
- jne @f
- ; ESI + 2
- lodsw
- ; Символ (R)
- mov al,0AEh
- jmp .loc_store_char
- @@:
- ; Преобразовать символы "(TM)" в один
- cmp dword [esi-1],'(TM)'
- je @f
- ; Написание может быть различным
- cmp dword [esi-1],'(tm)'
- jne .loc_store_char
- @@:
- ; ESI + 3
- lodsw
- lodsb
- ; Символ (TM)
- mov al,099h
- .loc_store_char:
- ; Записать символ в строку
- stosb
- ; Конец строки достигнут?
- or al,al
- jnz .loc_clean_string
- ; Удалить финальный пробел если есть
- cmp byte [edi-1],' '
- jne .loc_ret
- mov byte [edi-1],0
- .loc_ret:
- popa
- ret
- endp
В приложении пример программы с исходным текстом, показывающей Vendor ID и полное название вашего процессора. Файл "x86 Architecture CPUID Manual" - подробное описание всех параметров команды CPUID и расшифровкой возвращаемых ей значений (на английском).
Просмотров: 13287 | Комментариев: 5
Внимание! Статья опубликована больше года назад, информация могла устареть!
Комментарии
Отзывы посетителей сайта о статье
Андрей
(16.05.2014 в 16:36):
ManHunter, сабж вполне наглядно отображает вехи развития x86.
ManHunter
(16.05.2014 в 16:14):
DW 310Fh - это запись команды RDTSC, подробнее http://ru.wikipedia.org/wiki/Rdtsc
Код ставит процессу приоритет реального времени, замеряет количество тактов, делает паузу в 500 мс, снова замеряет количество тактов, считает разницу между начальным и конечным значением. Дальше простая математика,
(скорость процессора) = (разница в тактах) / (время паузы).
Код ставит процессу приоритет реального времени, замеряет количество тактов, делает паузу в 500 мс, снова замеряет количество тактов, считает разницу между начальным и конечным значением. Дальше простая математика,
(скорость процессора) = (разница в тактах) / (время паузы).
Doxtup
(16.05.2014 в 16:05):
Мой кирпич i5 определил точно, годная утилита.
Вот нашел кодес, когда-то скомуниздил с какого-то форума, писал под windows 98, но работает и сейчас:
Сорри за много кодеса, если можете вкратце объяснить его суть ?
function GetCPUSpeed: Double;
const
DelayTime = 500;
var
TimerHi : DWORD;
TimerLo : DWORD;
PriorityClass : Integer;
Priority : Integer;
begin
PriorityClass := GetPriorityClass(GetCurrentProcess);
Priority := GetThreadPriority(GetCurrentThread);
SetPriorityClass(GetCurrentProcess, REALTIME_PRIORITY_CLASS);
SetThreadPriority(GetCurrentThread, THREAD_PRIORITY_TIME_CRITICAL);
Sleep(10);
asm
DW 310Fh
MOV TimerLo, EAX
MOV TimerHi, EDX
end;
Sleep(DelayTime);
asm
DW 310Fh
SUB EAX, TimerLo
SBB EDX, TimerHi
MOV TimerLo, EAX
MOV TimerHi, EDX
end;
SetThreadPriority(GetCurrentThread, Priority);
SetPriorityClass(GetCurrentProcess, PriorityClass);
Result := TimerLo / (1000.0 * DelayTime);
end;
Вот нашел кодес, когда-то скомуниздил с какого-то форума, писал под windows 98, но работает и сейчас:
Сорри за много кодеса, если можете вкратце объяснить его суть ?
function GetCPUSpeed: Double;
const
DelayTime = 500;
var
TimerHi : DWORD;
TimerLo : DWORD;
PriorityClass : Integer;
Priority : Integer;
begin
PriorityClass := GetPriorityClass(GetCurrentProcess);
Priority := GetThreadPriority(GetCurrentThread);
SetPriorityClass(GetCurrentProcess, REALTIME_PRIORITY_CLASS);
SetThreadPriority(GetCurrentThread, THREAD_PRIORITY_TIME_CRITICAL);
Sleep(10);
asm
DW 310Fh
MOV TimerLo, EAX
MOV TimerHi, EDX
end;
Sleep(DelayTime);
asm
DW 310Fh
SUB EAX, TimerLo
SBB EDX, TimerHi
MOV TimerLo, EAX
MOV TimerHi, EDX
end;
SetThreadPriority(GetCurrentThread, Priority);
SetPriorityClass(GetCurrentProcess, PriorityClass);
Result := TimerLo / (1000.0 * DelayTime);
end;
ManHunter
(16.05.2014 в 10:37):
Которое тут костыли?
Андрей
(16.05.2014 в 09:26):
"Порядок есть порядок", костыли есть костыли.
Добавить комментарий
Заполните форму для добавления комментария