2012-02-18 7 views
6

La manera C++ de hacerlo es here (en Windows).¿Cómo sondear una computadora si es compatible con SSE2 en Delphi 32?

El same answer pero bajo Linux usando GCC.

Extracto del código asm relevante como lo entiendo:

mov  eax, 1 
cpuid 
mov  features, edx 

no estoy muy cómodo en BASM.

Mi Pregunta:

necesito para envolver la prueba de la siguiente manera

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

por favor me ayude.

+0

Tenga cuidado. Tanto la CPU como el sistema operativo deben ser compatibles con SSE2. El sistema operativo debe admitirlo porque los registros SSE se guardan en la memoria en un cambio de contexto, y el sistema operativo tiene que suministrar el área de memoria. Es por eso que a veces no es suficiente para probar el bit de función de la CPU SSE2. Es también por eso que ve pruebas para XSTORE y soporte FXSAVE. IIRC, están habilitados si el sistema operativo proporciona el área de memoria; de lo contrario, el sistema operativo lo desactiva (algunos renuncian a mano). Por lo general, hoy no es un problema, a menos que admita procesadores y sistemas operativos más antiguos. Consulte también * Sección 11.6.2, Comprobación del soporte de SSE/SSE2 * en el Manual de programadores de Intel. – jww

+0

Consulte también [¿Determinación del soporte del procesador para SSE2?] (Https://stackoverflow.com/q/2403660/608639) y [Cómo verificar si una CPU admite el conjunto de instrucciones SSE3?] (Https://stackoverflow.com/ q/6121792/608639). La segunda pregunta proporciona detalles del soporte del sistema operativo. – jww

Respuesta

21

Puede hacerlo sin ensamblador también. Sin embargo, funciona con Windows XP y versiones posteriores.

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. Esta parece ser la mejor respuesta (a menos que necesite soportar Win 2000). –

+0

Me encanta delegar estos trabajos. Prefiere este enfoque. –

+1

+1 claramente la mejor solución si puede ignorar Windows 2000 y otras plataformas –

8

creo que esto lo hace:

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

¿Puedo cambiar con seguridad la firma de la función a 'function SupportsSSE2: Boolean;'? – menjaraz

+0

@menjaraz: Sí, eso creo. –

+0

Gracias. Tu respuesta también es aceptable. – menjaraz

7

Este es el código utilizado por la biblioteca graphics32 para detectar las características del procesador:

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

Puede llamar HasInstructionSet(ciSSE2) para descubrir lo que necesita.

+0

¡Gracias, David! Nunca me pasa por la mente que puedo tenerlo fácilmente en 'Graphic32'. – menjaraz

+0

¡Estaba en el fondo de mi mente porque estoy haciendo un puerto de 64 bits en este momento y tuve algunos problemas con la memoria no alineada y las instrucciones SSE2 por debajo de 64 bits! –

+0

Esto podría suponer un problema en los chips Cyrix/NextGen donde ID debe dejarse configurado para dejar la instalación de CPUID en el estado "habilitado". – OnTheFly

Cuestiones relacionadas