2012-02-18 7 views
6

Sposób C++ to zrobić: here (w systemie Windows).Jak sondować komputer, czy obsługuje on SSE2 w Delphi 32?

The same answer ale pod Linuksem za pomocą GCC.

Wyciąg z odpowiednim kodem asm jak rozumiem:

mov  eax, 1 
cpuid 
mov  features, edx 

nie jestem bardzo wygodne w Basm.

Moje pytanie:

muszę zawinąć test następująco

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

Proszę mi pomóc.

+0

Uważaj. Zarówno procesor jak i system operacyjny muszą obsługiwać SSE2. System operacyjny musi go obsługiwać, ponieważ rejestry SSE są zapisywane w pamięci na przełączniku kontekstu, a system operacyjny musi dostarczać obszar pamięci. To dlatego czasami nie wystarczy, aby przetestować dla bitu funkcji SSE2 cpu. Właśnie dlatego widzisz testy dla obsługi XSTORE i FXSAVE. IIRC, są one włączone, jeśli system operacyjny dostarcza obszar pamięci; w przeciwnym razie system operacyjny go wyłącza (niektóre strony znoszą). Zwykle nie stanowi to problemu, chyba że obsługujesz starsze procesory i systemy operacyjne. Zobacz także * Rozdział 11.6.2, Sprawdzanie obsługi SSE/SSE2 * w Podręczniku dla programistów Intela. – jww

+0

Zobacz również [Określ obsługę procesora dla SSE2?] (Https://stackoverflow.com/q/2403660/608639) i [Jak sprawdzić, czy procesor obsługuje zestaw instrukcji SSE3?] (Https://stackoverflow.com/ q/6121792/608639). Drugie pytanie zawiera szczegółowe informacje na temat obsługi systemu operacyjnego. – jww

Odpowiedz

21

Możesz to zrobić bez asemblera. Działa tylko z Windows XP i nowszymi.

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. To wydaje się najlepszą odpowiedzią (chyba że potrzebujesz wsparcia dla Win 2000). –

+0

Uwielbiam delegować te prace. Preferuj to podejście. –

+1

+1 jednoznacznie najlepsze rozwiązanie, jeśli można zignorować Windows 2000 i inne platformy –

8

myślę, że to prawda:

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

Czy mogę bezpiecznie zmienić podpis funkcji na 'function SupportsSSE2: Boolean;'? – menjaraz

+0

@menjaraz: Tak, tak myślę. –

+0

Dziękuję. Twoja odpowiedź jest również do przyjęcia. – menjaraz

7

Oto kod używany przez bibliotekę graphics32 wykryć cechy Procesor:

{$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; 

Można zadzwonić HasInstructionSet(ciSSE2) aby dowiedzieć się, co trzeba.

+0

Dziękuję David! Nigdy nie przyszło mi do głowy, że mogę go łatwo znaleźć w 'Graphic32'. – menjaraz

+0

To było na mojej głowie, ponieważ robię 64-bitowy port i miałem problemy z niezalecanymi pamięcią i instrukcjami SSE2 pod 64-bitowymi! –

+0

Może to powodować problemy w układach Cyrix/NextGen, w których identyfikator musi pozostać ustawiony tak, aby obiekt CPUID pozostawał w stanie "włączony". – OnTheFly

Powiązane problemy