2012-02-18 8 views
6

Il modo C++ per farlo è here (sotto Windows).Come sondare un computer se supporta SSE2 in Delphi 32?

same answer ma con Linux che utilizza GCC.

Estratto del codice asm rilevante se ho capito bene:

mov  eax, 1 
cpuid 
mov  features, edx 

io non sono molto comodo a BASM.

La mia domanda:

ho bisogno di avvolgere il test come segue

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

Ti prego, aiutami.

+0

Fare attenzione. Sia la CPU che il sistema operativo devono supportare SSE2. Il sistema operativo deve supportarlo perché i registri SSE vengono salvati in memoria su un interruttore di contesto e il sistema operativo deve fornire l'area della memoria. Ecco perché a volte non è sufficiente testare il bit della cpu della SSE2. Questo è anche il motivo per cui vedi i test per il supporto XSTORE e FXSAVE. IIRC, sono abilitati se il sistema operativo fornisce l'area di memoria; altrimenti il ​​sistema operativo lo disabilita (rinuncia a qualche mano). Di solito non è un problema al giorno d'oggi, a meno che non supporti processori e sistemi operativi meno recenti. Vedi anche Sezione 11.6.2, Verifica del supporto SSE/SSE2 * nel Manuale dei programmatori Intel. – jww

+0

Vedere anche [Determinare il supporto del processore per SSE2?] (Https://stackoverflow.com/q/2403660/608639) e [Come verificare se una CPU supporta il set di istruzioni SSE3?] (Https://stackoverflow.com/ q/6121792/608 mila seicentotrentanove). La seconda domanda fornisce dettagli sul supporto del sistema operativo. – jww

risposta

21

Si può fare anche senza assemblatore. Funziona con Windows XP e versioni successive solo però.

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. Questa sembra la migliore risposta (a meno che non sia necessario supportare Win 2000). –

+0

Amo delegare questi lavori. Preferisci questo approccio. –

+1

+1 è chiaramente la soluzione migliore se puoi ignorare Windows 2000 e altre piattaforme –

8

Penso che questo lo fa:

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

Posso tranquillamente cambiare la firma della funzione in 'function SupportsSSE2: Boolean;'? – menjaraz

+0

@menjaraz: Sì, penso di sì. –

+0

Grazie. Anche la tua risposta è accettabile. – menjaraz

7

Ecco il codice usato dalla libreria graphics32 di rilevare le caratteristiche del processore:

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

È possibile chiamare HasInstructionSet(ciSSE2) per scoprire che cosa avete bisogno.

+0

Grazie, David! Non mi passa mai per la testa di poterlo avere facilmente in 'Graphic32'. – menjaraz

+0

Era in testa perché stavo facendo una porta a 64 bit al momento e avevo alcuni problemi con la memoria non allineata e le istruzioni SSE2 sotto 64 bit! –

+0

Questo potrebbe rappresentare un problema sui chip Cyrix/NextGen in cui l'ID deve essere lasciato impostato per lasciare la funzione CPUID nello stato "abilitato". – OnTheFly

Problemi correlati