-
1 можно ли push ebx выносить за пределы текущей функции/процедуры например здесь function CPUFeature(EAX_Leaf: integer; Register_Name: TRegisterName; Bit: ShortInt): boolean;
var _Result: Longword;
procedure push_registr;
begin
case Register_Name of
EDX:
asm
push ebx
mov r10, rbx
end;
ECX:
asm
push ecx
mov r10, rcx
end;
ECX:
asm
push ecx
mov r10, rcx
end;
end;
end;
procedure pop_register;
begin
case Register_Name of
EDX:
asm
pop edx
mov rdx, r10
end;
ECX:
asm
pop ecx
mov rcx, r10
end;
EBX:
asm
pop ebx
mov rbx, r10
end;
end;
end;
begin
Case Register_Name of
EDX:
asm
call push_registr;
mov eax, EAX_Leaf
cpuid
mov _Result, edx
call pop_registr
end;
ECX:
asm
call push_registr;
mov eax, EAX_Leaf
cpuid
mov _Result, ecx
call pop_registr
end;
EBX:
asm
call push_registr;
mov eax, EAX_Leaf
cpuid
mov _Result, ebx
call pop_registr
end;
End;
if (_Result and (1 shl bit)) = (1 shl bit) then Result := true
else Result := false;
end;
-
2. вопрос "push" она в делфи обязательна, я где то читал, что компилятор сам автоматически делает сохранение регистров перед вызовом директив "ASM ... END" . И кажется в одной из статей Анатолия Подгорецкого, но вот проблема уже не могу найти его статью, а может и не у него читал
-
Не надо желать странного. Гораздо проще запоминать значения всех регистров перед вызовом cpuid, сохранять полученные значения в памяти и восстанавливать регистры
-
Стало быть все-таки вот так function CPUFeature(EAX_Leaf: integer; Register_Name: TRegisterName; Bit: ShortInt): boolean;
var _Result: Longword;
begin
Case Register_Name of
EDX:
asm
push edx
mov r10, rdx
mov eax, EAX_Leaf cpuid
mov _Result, edx
pop edx
mov rdx, r10
end;
ECX:
asm
push ecx
mov r10, rcx
mov eax, EAX_Leaf
cpuid
mov _Result, ecx
pop ecx
mov rcx, r10
end;
EBX:
asm
push ebx
mov r10, rbx
mov eax, EAX_Leaf
cpuid
mov _Result, ebx
pop ebx
mov rbx, r10
end;
End;
if (_Result and (1 shl bit)) = (1 shl bit) then Result := true
else Result := false;
end;
-
О...!!! теперь у меня универсальная функция есть, для проверки процессоров
-
-
-
Готовый мод unit cpu_info_xe;
interface
USES Winapi.Windows, System.SysUtils, System.Win.Registry;
Type
TCPUInstruction = (cpu_MMX, cpu_SSE, cpu_SSE2, cpu_SSE3, cpu_SSSE3, cpu_SSE_4_1, cpu_SSE_4_2, cpu_AVX, cpu_AVX2, cpu_AES);
Type TRegisterName = (EBX, ECX, EDX);
const
strCPUFeature : array [TCPUInstruction] of string =
('MMX', 'SSE', 'SSE2', 'SSE3', 'SSSE3', 'SSE4.1', 'SSE4.2', 'AVX', 'AVX2', 'AES');
function DetectCPUFeature(CPUInstruction: TCPUInstruction): Boolean;
function CPUFeature(EAX_Leaf: integer; Register_Name: TRegisterName; Bit: ShortInt): boolean;
implementation
function CPUFeature(EAX_Leaf: integer; Register_Name: TRegisterName; Bit: ShortInt): boolean;
var _Result: Longword;
begin
Case Register_Name of
EDX:
asm
push edx
mov r10, rdx
mov eax, EAX_Leaf cpuid
mov _Result, edx
pop edx
mov rdx, r10
end;
ECX:
asm
push ecx
mov r10, rcx
mov eax, EAX_Leaf
cpuid
mov _Result, ecx
pop ecx
mov rcx, r10
end;
EBX:
asm
push ebx
mov r10, rbx
mov eax, EAX_Leaf
cpuid
mov _Result, ebx
pop ebx
mov rbx, r10
end;
End;
if (_Result and (1 shl bit)) = (1 shl bit) then Result := true
else Result := false;
end;
function DetectCPUFeature(CPUInstruction: TCPUInstruction): Boolean;
var
_Result: Longword;
begin
Case CPUInstruction of
cpu_MMX: Result := CPUFeature(1, EDX, 23); cpu_SSE: Result := CPUFeature(1, EDX, 25); cpu_SSE2: Result := CPUFeature(1, EDX, 26); cpu_SSE3: Result := CPUFeature(1, ECX, 0); cpu_SSSE3: Result := CPUFeature(1, ECX, 9); cpu_SSE_4_1: Result := CPUFeature(1, ECX, 19); cpu_SSE_4_2: Result := CPUFeature(1, ECX, 20); cpu_AVX: Result := CPUFeature(1, ECX, 28); cpu_AVX2: Result := CPUFeature(7, EDX, 5); cpu_AES: Result := CPUFeature(1, ECX, 25); End;
end;
end. Можно применять разовым вызовом или в цикле if DetectCPUFeature(cpu_AVX) then ShowMessage(strCPUFeature[TCPUInstruction(cpu_AVX)] + ' инструкции поддерживаются')
else ShowMessage(strCPUFeature[TCPUInstruction(cpu_AVX)] + ' инструкции не поддерживаются');
for i := 0 to Ord(High(TCPUInstruction)) do
if DetectCPUFeature(TCPUInstruction(i)) then mm.Lines.Add(strCPUFeature[TCPUInstruction(i)] + ' инструкции поддерживаются')
else mm.Lines.Add(strCPUFeature[TCPUInstruction(i)] + ' инструкции не поддерживаются');
-
Если кому нужно протестируйте потом напишите что и как, у меня нет такого количества разных процессоров, что бы на всех опробовать
-
В модуле исправить нужно
// .................. EBX: asm {$IFDEF CPUX86} push ebx {$ENDIF} {$IFDEF CPUX64} mov r10, rbx {$ENDIF} mov eax, EAX_Leaf mov ecx, 0 <- дописать комманду cpuid mov _Result, ebx {$IFDEF CPUX86} pop ebx {$ENDIF} {$IFDEF CPUX64} mov rbx, r10 {$ENDIF} end; // ..................
изменить строчку cpu_AVX2: Result := CPUFeature(7, EDX, 5); // SSE instructions EAX=7 EDX=5 на новую cpu_AVX2: Result := CPUFeature(7, EBX, 5); // SSE instructions EAX=7 EBX=5
-
На 64 битах не заработает
-
-
> Rouse_ © (12.02.17 10:45) [10] > > На 64 битах не заработает
Имеется ввиду: 1. на 64 битных процессорах ? 2. не откомпилируется в 64 битный код
если не откомпилируется 64 битный код, то это пока мне и не нужно тогда это можно убрать {$IFDEF CPUX64} ...... {$ENDIF} или это все-таки нужно?
> megavoid © (12.02.17 15:57) [11]
большое спасибо код очень полезен для изучения
-
> cryptologic © (14.02.17 12:26) [12] > 2. не откомпилируется в 64 битный код
инлайны в 64 битах - нонсенс
-
> Rouse_ © (14.02.17 14:46) [13] > > > > cryptologic © (14.02.17 12:26) [12] > > 2. не откомпилируется в 64 битный код > > инлайны в 64 битах - нонсенс
Инлайны это вот это "asm end"? как же быть? как вставить в 64 битной версии ассемблерную вставку?
Просто как то раньше не заморачивался по 64 битному коду, может вдруг понадобится.
Еще интересует вопрос:
Еще одну функию сделал
function GetCPUVendor: AnsiString; var _bx, _dx, _cx: LongWord; begin SetLength(Result, 12); FillChar(result, length(Result), #0); asm {$IFDEF CPUX86} PUSHAD xor eax, eax CPUID mov _bx, ebx mov _dx, edx mov _cx, ecx POPAD {$ENDIF} {$IFDEF CPUX64} push rad push rbx push rdx push rcx xor rax, rax CPUID mov _bx, rax mov _dx, rdx mov _cx, rcx pop rcx pop rdx pop rbx pop rad {$ENDIF} end; move(_bx, Result[1], 4); move(_dx, Result[5], 4); move(_cx, Result[9], 4); end;
А как то можно move(_bx, Result[1], 4); это сделать на ассемблере так, что бы сразу в Result записывать Пробовал вот так
mov eax, @Result[1] mov [eax], edx mov [eax + 4], ebx mov [eax + 8], ecx
делал и так
mov @Result[1], ebx mov @Result[5], edx ......
Возникает ошибка записи в память
-
Еще одну функцию сделал для проверки доступности CPUID function IsCPUIDSuported: boolean;
var di_before, di_after : LongWord;
begin
asm
push edi;
mov di_before, edi
btc edi, 21 mov di_after, edi
pop edi
end;
if di_before <> di_after then Result := true
else Result := false;
end; if di_before <> di_after then Result := true
else Result := false; И вот без этого обойтись не смог. Можно ли как то на ASM установить результат функции?
-
> if di_before <> di_after then Result := true > else Result := false;
> Можно ли как то на ASM установить результат функции?
Вместо > mov di_after, edi > pop edi
cmp edi,di_before
pop edi
setne al
-
> Игорь Шевченко © (16.02.17 18:37) [16]
проанализировал свой код и ваше предложение и пришел к выводу ваше предложение не подходит и сделал такой код т.к. команда btc инвертирует бит с 0 на 1 с 1 на 0 и состояние измененного бита по результату может быть любым и не только 1 но и 0, стало быть анализировать командой cmp edi,di_before не всегда будет правильно анализировать изменение бита через XOR надежнее мой вариант:
asm
push edi;
push eax
mov eax, edi
btc edi, 21 xor eax, edi
shr eax, 21
mov Result, al
pop eax
pop edi
end;
-
Интересно как будут работать инструкции asm 386+ на разных такм на Win10 + rasbpery pi 2/3 и других платформах?
-
> Интересно как будут работать инструкции asm 386+ на разных > такм на Win10 + rasbpery pi 2/3 и других платформах?
Никак
-
Удалено модератором
|