2012-02-18 3 views
6

C++ способ сделать это here (под Windows).Как проверить компьютер, если он поддерживает SSE2 в Delphi 32?

same answer но под Linux с использованием GCC.

Отрывок соответствующего кода ассемблерный как я понимаю:

mov  eax, 1 
cpuid 
mov  features, edx 

Я не очень комфортно в BASM.

Мой вопрос:

мне нужно обернуть тест следующим

function IsSSE2: Boolean; 
begin 
    try 
    Result := False; 
    // 
    // Some BASM code here 
    // 
    except 
    Result := False; 
    end; 
end; 

Пожалуйста, помогите мне.

+0

Будьте осторожны. И CPU, и ОС должны поддерживать SSE2. ОС должна поддерживать его, потому что регистры SSE сохраняются в памяти на коммутаторе контекста, а ОС должна обеспечивать область памяти. Вот почему его иногда недостаточно, чтобы проверить бит функции SSE2 cpu. Вот почему вы видите тесты для поддержки XSTORE и FXSAVE. IIRC, они включены, если ОС поставляет область памяти; в противном случае ОС отключает его (некоторые отказываются от руки). Обычно это не проблема в настоящее время, если вы не поддерживаете старые процессоры и ОС. Также см. Раздел 11.6.2 «Проверка поддержки SSE/SSE2» в Руководстве Intel для программистов. – jww

+0

Также см. [Определение поддержки процессора для SSE2?] (Https://stackoverflow.com/q/2403660/608639) и [Как проверить, поддерживает ли процессор набор инструкций SSE3?] (Https://stackoverflow.com/ д/6121792/608639). Второй вопрос содержит подробную информацию о поддержке ОС. – jww

ответ

21

Вы можете сделать это без ассемблера. Однако работает только с Windows XP и новее.

function IsProcessorFeaturePresent(ProcessorFeature: DWORD): BOOL; stdcall; 
    external kernel32 name 'IsProcessorFeaturePresent'; 

const 
    PF_XMMI64_INSTRUCTIONS_AVAILABLE = 10; 

function HasSSE2: boolean; 
begin 
    result := IsProcessorFeaturePresent(PF_XMMI64_INSTRUCTIONS_AVAILABLE); 
end; 
+2

+1. Это похоже на лучший ответ (если вам не нужна поддержка Win 2000). –

+0

Мне нравится делегировать эти задания. Предпочитайте этот подход. –

+1

+1 ясно лучшее решение, если вы можете игнорировать Windows 2000 и другие платформы –

8

Я думаю, что это делает:

function SupportsSSE2: LongBool; 
const 
    CPUID_INTEL_SSE2 = $04000000; 
asm 
    push ebx 
    mov eax, 1 
    cpuid 
    mov eax, FALSE 
    test edx, CPUID_INTEL_SSE2 
    jz @END 
    mov eax, TRUE 
@END: 
    pop ebx 
end; 
+0

Могу ли я безопасно изменить подпись функции на 'function SupportsSSE2: Boolean;'? – menjaraz

+0

@menjaraz: Да, я так думаю. –

+0

Спасибо. Ваш ответ также является приемлемым. – menjaraz

7

Вот код, используемый graphics32 библиотеки для обнаружения функции процессора:

{$IFDEF WIN64} 
  {$DEFINE TARGET_x64} 
{$ENDIF} 

type 
    TCPUInstructionSet = (ciMMX, ciEMMX, ciSSE, ciSSE2, ci3DNow, ci3DNowExt); 

const 
    CPUISChecks: Array[TCPUInstructionSet] of Cardinal = 
    ($800000, $400000, $2000000, $4000000, $80000000, $40000000); 
    {ciMMX , ciEMMX, ciSSE , ciSSE2 , ci3DNow , ci3DNowExt} 

function CPUID_Available: Boolean; 
asm 
{$IFDEF TARGET_x64} 
     MOV  EDX,False 
     PUSHFQ 
     POP  RAX 
     MOV  ECX,EAX 
     XOR  EAX,$00200000 
     PUSH  RAX 
     POPFQ 
     PUSHFQ 
     POP  RAX 
     XOR  ECX,EAX 
     JZ  @1 
     MOV  EDX,True 
@1:  PUSH  RAX 
     POPFQ 
     MOV  EAX,EDX 
{$ELSE} 
     MOV  EDX,False 
     PUSHFD 
     POP  EAX 
     MOV  ECX,EAX 
     XOR  EAX,$00200000 
     PUSH  EAX 
     POPFD 
     PUSHFD 
     POP  EAX 
     XOR  ECX,EAX 
     JZ  @1 
     MOV  EDX,True 
@1:  PUSH  EAX 
     POPFD 
     MOV  EAX,EDX 
{$ENDIF} 
end; 

function CPU_Signature: Integer; 
asm 
{$IFDEF TARGET_x64} 
     PUSH  RBX 
     MOV  EAX,1 
     CPUID 
     POP  RBX 
{$ELSE} 
     PUSH  EBX 
     MOV  EAX,1 
     {$IFDEF FPC} 
     CPUID 
     {$ELSE} 
     DW  $A20F // CPUID 
     {$ENDIF} 
     POP  EBX 
{$ENDIF} 
end; 

function CPU_Features: Integer; 
asm 
{$IFDEF TARGET_x64} 
     PUSH  RBX 
     MOV  EAX,1 
     CPUID 
     POP  RBX 
     MOV  EAX,EDX 
{$ELSE} 
     PUSH  EBX 
     MOV  EAX,1 
     {$IFDEF FPC} 
     CPUID 
     {$ELSE} 
     DW  $A20F // CPUID 
     {$ENDIF} 
     POP  EBX 
     MOV  EAX,EDX 
{$ENDIF} 
end; 

function CPU_ExtensionsAvailable: Boolean; 
asm 
{$IFDEF TARGET_x64} 
     PUSH  RBX 
     MOV  @Result, True 
     MOV  EAX, $80000000 
     CPUID 
     CMP  EAX, $80000000 
     JBE  @NOEXTENSION 
     JMP  @EXIT 
     @NOEXTENSION: 
     MOV  @Result, False 
     @EXIT: 
     POP  RBX 
{$ELSE} 
     PUSH  EBX 
     MOV  @Result, True 
     MOV  EAX, $80000000 
     {$IFDEF FPC} 
     CPUID 
     {$ELSE} 
     DW  $A20F // CPUID 
     {$ENDIF} 
     CMP  EAX, $80000000 
     JBE  @NOEXTENSION 
     JMP  @EXIT 
     @NOEXTENSION: 
     MOV  @Result, False 
     @EXIT: 
     POP  EBX 
{$ENDIF} 
end; 

function CPU_ExtFeatures: Integer; 
asm 
{$IFDEF TARGET_x64} 
     PUSH  RBX 
     MOV  EAX, $80000001 
     CPUID 
     POP  RBX 
     MOV  EAX,EDX 
{$ELSE} 
     PUSH  EBX 
     MOV  EAX, $80000001 
     {$IFDEF FPC} 
     CPUID 
     {$ELSE} 
     DW  $A20F // CPUID 
     {$ENDIF} 
     POP  EBX 
     MOV  EAX,EDX 
{$ENDIF} 
end; 

function HasInstructionSet(const InstructionSet: TCPUInstructionSet): Boolean; 
// Must be implemented for each target CPU on which specific functions rely 
begin 
    Result := False; 
    if not CPUID_Available then Exit;     // no CPUID available 
    if CPU_Signature shr 8 and $0F < 5 then Exit;  // not a Pentium class 

    case InstructionSet of 
    ci3DNow, ci3DNowExt: 
     {$IFNDEF FPC} 
     if not CPU_ExtensionsAvailable or (CPU_ExtFeatures and CPUISChecks[InstructionSet] = 0) then 
     {$ENDIF} 
     Exit; 
    ciEMMX: 
     begin 
     // check for SSE, necessary for Intel CPUs because they don't implement the 
     // extended info 
     if (CPU_Features and CPUISChecks[ciSSE] = 0) and 
      (not CPU_ExtensionsAvailable or (CPU_ExtFeatures and CPUISChecks[ciEMMX] = 0)) then 
      Exit; 
     end; 
    else 
    if CPU_Features and CPUISChecks[InstructionSet] = 0 then 
     Exit; // return -> instruction set not supported 
    end; 

    Result := True; 
end; 

Вы можете позвонить HasInstructionSet(ciSSE2), чтобы узнать, что вам нужно.

+0

Спасибо, Дэвид! Мне никогда не приходит в голову, что я могу с легкостью получить его в «Graphic32». – menjaraz

+0

Это было на первый взгляд, потому что я делаю 64-битный порт на данный момент и имел некоторые проблемы с неизмененной памятью и инструкциями SSE2 под 64 бит! –

+0

Это может создать проблему с чипами Cyrix/NextGen, где идентификатор должен оставаться установленным, чтобы оставить объект CPUID в состоянии «включено». – OnTheFly