【问题标题】:How to probe a computer if it supports SSE2 in Delphi 32?如果计算机在 Delphi 32 中支持 SSE2,如何探测计算机?
【发布时间】:2012-03-09 14:41:55
【问题描述】:

c++ 的实现方式是here(在 Windows 下)。

same answer 但在 Linux 下使用 GCC。

我理解的相关asm代码的摘录:

mov     eax, 1
cpuid
mov     features, edx

我对 BASM 不太满意。

我的问题:

我需要如下包装测试

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

请帮帮我。

【问题讨论】:

  • 小心。 CPU 和操作系统都必须支持 SSE2。操作系统必须支持它,因为 SSE 寄存器在上下文切换时保存到内存中,并且操作系统必须提供内存区域。这就是为什么它有时不足以测试 SSE2 cpu 功能位。这也是您看到 XSTORE 和 FXSAVE 支持测试的原因。 IIRC,如果操作系统提供内存区域,则启用它们;否则操作系统会禁用它(有些人放弃)。除非您支持较旧的处理器和操作系统,否则它现在通常不是问题。另请参阅英特尔程序员手册中的第 11.6.2 节,检查 SSE/SSE2 支持
  • 另见 Determine processor support for SSE2?How to check if a CPU supports the SSE3 instruction set?。第二个问题提供了操作系统支持的详细信息。

标签: delphi sse basm


【解决方案1】:

我认为这样做:

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;

【讨论】:

  • 我可以安全地将函数签名更改为function SupportsSSE2: Boolean;吗?
【解决方案2】:

这是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) 了解您的需求。

【讨论】:

  • 谢谢大卫!我从来没有想过我可以很容易地在Graphic32 中拥有它。
  • 这是我的想法,因为我目前正在做一个 64 位端口,并且在 64 位下存在未对齐内存和 SSE2 指令的一些问题!
  • 这可能会给 Cyrix/NextGen 芯片带来问题,其中 ID 必须设置为使 CPUID 设施处于“启用”状态。
【解决方案3】:

您也可以在没有汇编程序的情况下做到这一点。但仅适用于 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;

【讨论】:

  • +1。这似乎是最好的答案(除非您需要支持 Win 2000)。
  • 我喜欢委派这些工作。更喜欢这种方法。
  • +1 显然是最好的解决方案,如果您可以忽略 windows 2000 和其他平台
  • +1 并且它也可能适用于针对 Win64 的 Delphi XE2 - 而 asm 版本将无法工作(绑定到 32 位 asm)。
猜你喜欢
  • 2019-01-23
  • 1970-01-01
  • 1970-01-01
  • 2018-09-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多