Fpc-3.2.0 искаропки умеет определять поддержку AVX/AVX2(модуль Cpu).
Код: Выделить всё
unit uCpu;
{$mode objfpc}{$H+}
{$COPERATORS ON}
{$WRITEABLECONST OFF}
{$BOOLEVAL OFF}
{$POINTERMATH ON}
{$MODESWITCH ADVANCEDRECORDS}
{$IFDEF CPUI386)}
{$DEFINE UC_CPU_I386}
{$ENDIF}
{$IF DEFINED(CPUAMD64) or DEFINED(CPUX86_64)}
{$DEFINE UC_CPU_AMD64}
{$ENDIF}
{$IF DEFINED(UC_CPU_AMD64) or DEFINED(UC_CPU_I386)}
{$DEFINE UC_CPU_INTEL}
{$ASMMODE INTEL}
{$ENDIF}
interface
uses
SysUtils;
{$IFDEF UC_CPU_INTEL}
type
TCpu = record
public
type
TCpuVendor = (cvUnknown, cvIntel, cvAMD, cvVIA, cvZhaoxin, cvHygon, cvMcst);
private
type //todo: split by features ???
TCpuFeature = (
cfCPUID, cfCMOV, cfTSC, cfInvTSC, cfMMX, cfSSE, cfSSE2, cfSSE3, cfSSSE3,
cfFMA, cfSSE41, cfSSE42, cfAESNI, cfCLMULQDQ, cfAVX, cfAVX2, cfTsxHle,
cfTsxRtm, cfBMI1, cfBMI2, cfAVX512f, cfAVX512dq, cfAVX512er, cfAVX512ifma,
cfAVX512pf, cfAVX512cd, cfAVX512bw, cfAVX512vbmi, cfADX, cfPOPCNT, cfRDRAND,
cfRDSeed, cfSHAX, cfVIARNG, cfVIAACE, cfVIAACE2, cfVIAPHE, cfVIAPMM);
TCpuFeatures = set of TCpuFeature;
const
CpuVendors: array [TCpuVendor] of string = (
'Unknown vendor', 'Intel Corporation', 'Advanced Micro Devices',
'VIA Technologies', 'Shanghai Zhaoxin Semiconductor',
'Chengdu Haiguang Integrated Circuit Design', 'MCST Elbrus');
class var
CvFeatures: TCpuFeatures;
CvFamily,
CvModel,
CvStepping: DWord;
CvVendor: TCpuVendor;
CvBrand: string;
class procedure TestFeatures; static;
class constructor Setup;
public
class property Vendor: TCpuVendor read CvVendor;
class property Family: DWord read CvFamily;
class property Model: DWord read CvModel;
class property Stepping: DWord read CvStepping;
class function VendorString: string; static; inline;
class function BrandString: string; static; inline;
class function HasCPUID: Boolean; static; inline;
class function HasCMOV: Boolean; static; inline;
class function HasTSC: Boolean; static; inline;
class function HasInvariantTSC: Boolean; static; inline;
class function HasMMX: Boolean; static; inline;
class function HasSSE: Boolean; static; inline;
class function HasSSE2: Boolean; static; inline;
class function HasSSE3: Boolean; static; inline;
class function HasSSSE3: Boolean; static; inline;
class function HasFMA3: Boolean; static; inline;
class function HasSSE41: Boolean; static; inline;
class function HasSSE42: Boolean; static; inline;
class function HasAESNI: Boolean; static; inline;
class function HasCLMULQDQ: Boolean; static; inline;
class function HasAVX: Boolean; static; inline;
class function HasAVX2: Boolean; static; inline;
class function HasHLE: Boolean; static; inline;
class function HasRTM: Boolean; static; inline;
class function HasXTEST: Boolean; static; inline;
class function HasAVX512f: Boolean; static; inline;
class function HasAVX512cd: Boolean; static; inline;
class function HasAVX512er: Boolean; static; inline;
class function HasAVX512pf: Boolean; static; inline;
class function HasAVX512dq: Boolean; static; inline;
class function HasAVX512bw: Boolean; static; inline;
class function HasAVX512ifma: Boolean; static; inline;
class function HasAVX512vbmi: Boolean; static; inline;
class function HasBMI1: Boolean; static; inline;
class function HasBMI2: Boolean; static; inline;
class function HasRDRAND: Boolean; static; inline;
class function HasRDSEED: Boolean; static; inline;
class function HasADX: Boolean; static; inline;
class function HasPOPCNT: Boolean; static; inline;
class function HasVAESNI: Boolean; static; inline;
class function HasVCLMULQDQ: Boolean; static; inline;
class function HasSHAX: Boolean; static; inline;
class function HasVIARng: Boolean; static; inline;
class function HasVIAAce: Boolean; static; inline;
class function HasVIAAce2: Boolean; static; inline;
class function HasVIAPHE: Boolean; static; inline;
class function HasVIAPMM: Boolean; static; inline;
end;
{$ENDIF UC_CPU_INTEL}
implementation
{$IFDEF UC_CPU_INTEL}
type
TCpuIdQuery = packed record
EAX, EBX, ECX, EDX: DWord;
end;
const
CPUVendorQuery: TCpuIdQuery = (EAX: 0; EBX: 0; ECX: 0; EDX: 0);
CPUFeaturesQuery: TCpuIdQuery = (EAX: 1; EBX: 0; ECX: 0; EDX: 0);
CPUExtFeaturesQuery1: TCpuIdQuery = (EAX: 7; EBX: 0; ECX: 0; EDX: 0);
CPUExtFeaturesQuery2: TCpuIdQuery = (EAX: $80000000; EBX: 0; ECX: 0; EDX: 0); //////////////////
CPUPowManFeatureQuery: TCpuIdQuery = (EAX: $80000007; EBX: 0; ECX: 0; EDX: 0); ////////////////////
VIAPadlockExists: TCpuIdQuery = (EAX: $C0000000; EBX: 0; ECX: 0; EDX: 0);
VIAPadlockFeatures: TCpuIdQuery = (EAX: $C0000001; EBX: 0; ECX: 0; EDX: 0);
BrandQuery1: TCpuIdQuery = (EAX: $80000002; EBX: 0; ECX: 0; EDX: 0);
BrandQuery2: TCpuIdQuery = (EAX: $80000003; EBX: 0; ECX: 0; EDX: 0);
BrandQuery3: TCpuIdQuery = (EAX: $80000004; EBX: 0; ECX: 0; EDX: 0);
BrandFeatureSupport = DWord($80000004);
LowestVIAPadlockFunc = DWord($C0000001);
TscEdxFlag = DWord(1) shl 4; //edx
InvTscEdxFlag = DWord(1) shl 8; //edx
CmovEdxFlag = DWord(1) shl 15; //edx
MmxEdxFlag = DWord(1) shl 23; //edx
SseEdxFlag = DWord(1) shl 25; //edx
Sse2EdxFlag = DWord(1) shl 26; //edx
ViaRngEdxFlags = DWord(3) shl 2; //edx
ViaAceEdxFlags = DWord(3) shl 6; //edx
ViaAce2EdxFlags = DWord(3) shl 8; //edx
ViaPheEdxFlags = DWord(3) shl 10; //edx
ViaPmmEdxFlags = DWord(3) shl 12; //edx
Sse3EcxFlag = DWord(1) shl 0; //ecx
ClmulqdqEcxFlag = DWord(1) shl 1; //ecx
Avx512vbmiEcxFlag = DWord(1) shl 1; //ecx
Ssse3EcxFlag = DWord(1) shl 9; //ecx
FmaEcxFlag = DWord(1) shl 12; //ecx
Sse41EcxFlag = DWord(1) shl 19; //ecx
Sse42EcxFlag = DWord(1) shl 20; //ecx
PopcntEcxFlag = DWord(1) shl 23; //ecx
AesniEcxFlag = DWord(1) shl 25; //ecx
XSaveEcxFlag = DWord(1) shl 26; //ecx
OSXSaveEcxFlag = DWord(1) shl 27; //ecx
AvxEcxFlag = DWord(1) shl 28; //ecx
RDRandEcxFlag = DWord(1) shl 30; //ecx
Bmi1EbxFlag = DWord(1) shl 3; //ebx
TsxHleEbxFlag = DWord(1) shl 4; //ebx
TsxRtmEbxFlag = DWord(1) shl 11; //ebx
Avx2EbxFlag = DWord(1) shl 5; //ebx
Bmi2EbxFlag = DWord(1) shl 8; //ebx
Avx512fEbxFlag = DWord(1) shl 16; //ebx
Avx512dqEbxFlag = DWord(1) shl 17; //ebx
RDSeedEbxFlag = DWord(1) shl 18; //ebx
AdxEbxFlag = DWord(1) shl 19; //ebx
Avx512ifmaEbxFlag = DWord(1) shl 21; //ebx
Avx512pfEbxFlag = DWord(1) shl 26; //ebx
Avx512erEbxFlag = DWord(1) shl 27; //ebx
Avx512cdEbxFlag = DWord(1) shl 28; //ebx
ShaxEbxFlag = DWord(1) shl 29; //ebx
Avx512bwEbxFlag = DWord(1) shl 30; //ebx
function CpuIdAvailable: Boolean; register; assembler;
asm
{$IFDEF UC_CPU_I386}
pushfd
pushfd
pop eax
mov edx, eax
xor eax, 200000h
push eax
popfd
pushfd
pop eax
popfd
and eax, 200000h
and edx, 200000h
cmp eax, edx
mov eax, 0
setnz al
{$ELSE UC_CPU_I386}
mov rax, True
{$ENDIF UC_CPU_I386}
end;
procedure CallCpuId(var aQuery: TCpuIdQuery); register; assembler;
asm
{$IFDEF UC_CPU_I386}
push ebx
push esi
mov esi, eax
mov ecx, [eax + offset TCpuIdQuery.ECX]
mov eax, [eax + offset TCpuIdQuery.EAX]
cpuid
mov [esi + offset TCpuIdQuery.EAX], eax
mov [esi + offset TCpuIdQuery.EBX], ebx
mov [esi + offset TCpuIdQuery.ECX], ecx
mov [esi + offset TCpuIdQuery.EDX], edx
pop esi
pop ebx
{$ELSE UC_CPU_I386}
push rbx
{$IFDEF MSWINDOWS}
push rdi
mov rdi, rcx
{$ENDIF MSWINDOWS}
mov eax, dword ptr[rdi + offset TCpuIdQuery.EAX]
mov ecx, dword ptr[rdi + offset TCpuIdQuery.ECX]
cpuid
mov dword ptr[rdi + offset TCpuIdQuery.EAX], eax
mov dword ptr[rdi + offset TCpuIdQuery.EBX], ebx
mov dword ptr[rdi + offset TCpuIdQuery.ECX], ecx
mov dword ptr[rdi + offset TCpuIdQuery.EDX], edx
{$IFDEF MSWINDOWS}
pop rdi
{$ENDIF MSWINDOWS}
pop rbx
{$ENDIF UC_CPU_I386}
end;
function GetXCRValue(aXCrIndex: DWord): QWord; register; assembler; nostackframe;
asm
{$IFDEF UC_CPU_AMD64}
{$IFNDEF MSWINDOWS}
mov rcx, rdi
{$ENDIF MSWINDOWS}
{$ELSE UC_CPU_AMD64}
mov ecx, eax
{$ENDIF UC_CPU_AMD64}
//db $0f, $01, $d0 //XGETBV
xgetbv
{$IFDEF UC_CPU_AMD64}
shl rdx, 32
or rax, rdx
{$ENDIF UC_CPU_AMD64}
end;
function OSSupportsAVX: Boolean;
begin
Result := GetXCRValue(0) and 6 = 6;
end;
function OSSupportsAVX512: Boolean;
begin
Result := GetXCRValue(0) and $e6 = $e6;
end;
function ReadTSC: QWord; assembler; nostackframe;
asm
rdtsc
{$IFDEF UC_CPU_AMD64}
shl rdx, 32
or rax, rdx
{$ENDIF}
end;
function ReadInvTSC: QWord; assembler; nostackframe;
asm
rdtscp
//db $0F,$01,$F9 //rdtscp
{$IFDEF UC_CPU_AMD64}
shl rdx, 32
or rax, rdx
{$ENDIF}
end;
function OsSupportsTSC: Boolean;
begin
Result := True;
try
ReadTSC;
except
Result := False;
end;
end;
function OsSupportsInvTSC: Boolean;
begin
Result := True;
try
ReadInvTSC;
except
Result := False;
end;
end;
{ TCpu }
class procedure TCpu.TestFeatures;
type
TVendorId = packed record
case Integer of
0: (DWords: array[0..2] of DWord);
1: (Alpha: array[0..11] of AnsiChar);
end;
var
Query: TCpuIdQuery;
MaxLeaf: DWord;
OsXSave, XSave: Boolean;
procedure TestCpuVendor;
var
VendorId: TVendorId;
begin
with Query do
begin
VendorId.DWords[0] := EBX;
VendorId.DWords[1] := EDX;
VendorId.DWords[2] := ECX;
end;
case shortstring(VendorId.Alpha) of
'GenuineIntel': CvVendor := cvIntel;
'AuthenticAMD': CvVendor := cvAMD;
'VIA VIA VIA ',
'CentaurHauls': CvVendor := cvVIA;
' Shanghai ': CvVendor := cvZhaoxin;
'HygonGenuine': CvVendor := cvHygon;
'E2K MACHINE': CvVendor := cvMcst; //todo: ???
else
CvVendor := cvUnknown;
end;
end;
procedure TestCpuModel;
const
ModelShift = 4;
FamilyShift = 8;
ExtModelShift = 16;
ExtFamilyShift = 20;
Stepping_Mask = DWord($0f);
ModelMask = DWord($0f) shl ModelShift;
FamilyMask = DWord($0f) shl FamilyShift;
ExtModelMask = DWord($0f) shl ExtModelShift;
ExtFamilyMask = DWord($ff) shl ExtFamilyShift;
begin
with Query do
begin
CvStepping := EAX and Stepping_Mask;
CvFamily := (EAX and FamilyMask) shr FamilyShift;
CvModel := (EAX and ModelMask) shr ModelShift;
if CvFamily = $06 then
CvModel += (EAX and ExtModelMask) shr (ExtModelShift - ModelShift)
else
if CvFamily = $0f then
begin
CvFamily += (EAX and ExtFamilyMask) shr ExtFamilyShift;
CvModel += (EAX and ExtModelMask) shr (ExtModelShift - ModelShift);
end;
end;
end;
var
BrandPart: array[0..15] of AnsiChar absolute Query;
begin
if not CpuIdAvailable then
exit;
Include(CvFeatures, cfCPUID);
Query := CPUVendorQuery;
CallCpuId(Query);
MaxLeaf := Query.EAX;
TestCpuVendor;
if CPUFeaturesQuery.EAX > MaxLeaf then
exit;
Query := CPUFeaturesQuery;
CallCpuId(Query);
TestCpuModel;
if (Query.EDX and CmovEdxFlag) <> 0 then
Include(CvFeatures, cfCMOV);
if LongBool(Query.EDX and TscEdxFlag) and OsSupportsTSC then
Include(CvFeatures, cfTSC);
if (Query.EDX and MmxEdxFlag) <> 0 then
Include(CvFeatures, cfMMX);
if (Query.EDX and SseEdxFlag) <> 0 then
Include(CvFeatures, cfSSE);
if (Query.EDX and Sse2EdxFlag) <> 0 then
Include(CvFeatures, cfSSE2);
if (Query.ECX and Sse3EcxFlag) <> 0 then
Include(CvFeatures, cfSSE3);
if (Query.ECX and Ssse3EcxFlag) <> 0 then
Include(CvFeatures, cfSSSE3);
if (Query.ECX and FmaEcxFlag) <> 0 then
Include(CvFeatures, cfFMA);
if (Query.ECX and Sse41EcxFlag) <> 0 then
Include(CvFeatures, cfSSE41);
if (Query.ECX and Sse42EcxFlag) <> 0 then
Include(CvFeatures, cfSSE42);
if (Query.ECX and PopcntEcxFlag) <> 0 then
Include(CvFeatures, cfPOPCNT);
if (Query.ECX and AesniEcxFlag) <> 0 then
Include(CvFeatures, cfAESNI);
if (Query.ECX and ClmulqdqEcxFlag) <> 0 then
Include(CvFeatures, cfCLMULQDQ);
if (Query.ECX and RDRandEcxFlag) <> 0 then
Include(CvFeatures, cfRDRand);
OsXSave := (Query.ECX and OSXSaveEcxFlag) <> 0;
XSave := (Query.ECX and XSaveEcxFlag) <> 0;
if XSave and OsXSave then
begin
if LongBool(Query.ECX and AvxEcxFlag) and OSSupportsAVX then
Include(CvFeatures, cfAVX);
end;
if CPUExtFeaturesQuery1.EAX > MaxLeaf then
exit;
Query := CPUExtFeaturesQuery1;
CallCpuId(Query);
if (cfAVX in CvFeatures) and LongBool(Query.EBX and Avx2EbxFlag) then
Include(CvFeatures, cfAVX2);
if (Query.EBX and Bmi1EbxFlag) <> 0 then
Include(CvFeatures, cfBMI1);
if (Query.EBX and Bmi2EbxFlag) <> 0 then
Include(CvFeatures, cfBMI2);
if (Query.EBX and RDSeedEbxFlag) <> 0 then
Include(CvFeatures, cfRDSeed);
if (Query.EBX and AdxEbxFlag) <> 0 then
Include(CvFeatures, cfADX);
if (Query.EBX and ShaxEbxFlag) <> 0 then
Include(CvFeatures, cfSHAX);
if (Query.EBX and TsxHleEbxFlag) <> 0 then
Include(CvFeatures, cfTsxHle);
if (Query.EBX and TsxRtmEbxFlag) <> 0 then
Include(CvFeatures, cfTsxRtm);
if XSave and OsXSave and OSSupportsAVX512 then
begin
if (Query.EBX and Avx512fEbxFlag) <> 0 then
Include(CvFeatures, cfAVX512f);
if (Query.EBX and Avx512dqEbxFlag) <> 0 then
Include(CvFeatures, cfAVX512dq);
if (Query.EBX and Avx512ifmaEbxFlag) <> 0 then
Include(CvFeatures, cfAVX512ifma);
if (Query.EBX and Avx512pfEbxFlag) <> 0 then
Include(CvFeatures, cfAVX512pf);
if (Query.EBX and Avx512erEbxFlag) <> 0 then
Include(CvFeatures, cfAVX512er);
if (Query.EBX and Avx512cdEbxFlag) <> 0 then
Include(CvFeatures, cfAVX512cd);
if (Query.EBX and Avx512bwEbxFlag) <> 0 then
Include(CvFeatures, cfAVX512bw);
if (Query.ECX and Avx512vbmiEcxFlag) <> 0 then
Include(CvFeatures, cfAVX512vbmi);
end;
Query := CPUExtFeaturesQuery2;
CallCpuId(Query);
MaxLeaf := Query.EAX;
if MaxLeaf >= BrandFeatureSupport then
begin
Query := BrandQuery1;
CallCpuId(Query);
CvBrand := shortstring(BrandPart);
Query := BrandQuery2;
CallCpuId(Query);
CvBrand += shortstring(BrandPart);
Query := BrandQuery3;
CallCpuId(Query);
CvBrand += shortstring(BrandPart);
end;
if CPUPowManFeatureQuery.EAX > MaxLeaf then
exit;
Query := CPUPowManFeatureQuery;
CallCpuId(Query);
if LongBool(Query.EDX and InvTscEdxFlag) and OsSupportsInvTSC then
Include(CvFeatures, cfInvTSC);
//VIA Padlock ACE detection
if (CvVendor = cvVIA) and (cfSSE in CvFeatures) then///??????
begin
//Centaur Extended Feature Flags
Query := VIAPadlockExists;
CallCpuId(Query);
if Query.EAX < LowestVIAPadlockFunc then
exit;
Query := VIAPadlockFeatures;
CallCpuId(Query);
if (Query.EDX and ViaRngEdxFlags) = ViaRngEdxFlags then
Include(CvFeatures, cfVIARNG);
if (Query.EDX and ViaAceEdxFlags) = ViaAceEdxFlags then
Include(CvFeatures, cfVIAACE);
if (Query.EDX and ViaAce2EdxFlags) = ViaAce2EdxFlags then
Include(CvFeatures, cfVIAACE2);
if (Query.EDX and ViaPheEdxFlags) = ViaPheEdxFlags then
Include(CvFeatures, cfVIAPHE);
if (Query.EDX and ViaPmmEdxFlags) = ViaPmmEdxFlags then
Include(CvFeatures, cfVIAPMM);
end;
end;
class constructor TCpu.Setup;
begin
CvFeatures := [];
CvFamily := 0;
CvModel := 0;
CvStepping := 0;
CvVendor := cvUnknown;
CvBrand := 'Not supported';
try
TestFeatures;
except
end;
end;
class function TCpu.VendorString: string;
begin
Result := CpuVendors[CvVendor];
end;
class function TCpu.BrandString: string;
begin
Result := CvBrand;
end;
class function TCpu.HasCPUID: Boolean;
begin
Result := cfCPUID in CvFeatures;
end;
class function TCpu.HasCMOV: Boolean;
begin
Result := cfCMOV in CvFeatures;
end;
class function TCpu.HasTSC: Boolean;
begin
Result := cfTSC in CvFeatures;
end;
class function TCpu.HasInvariantTSC: Boolean;
begin
Result := cfInvTSC in CvFeatures;
end;
class function TCpu.HasMMX: Boolean;
begin
Result := cfMMX in CvFeatures;
end;
class function TCpu.HasSSE: Boolean;
begin
Result := cfSSE in CvFeatures;
end;
class function TCpu.HasSSE2: Boolean;
begin
Result := cfSSE2 in CvFeatures;
end;
class function TCpu.HasSSE3: Boolean;
begin
Result := cfSSE3 in CvFeatures;
end;
class function TCpu.HasSSSE3: Boolean;
begin
Result := cfSSSE3 in CvFeatures;
end;
class function TCpu.HasFMA3: Boolean;
begin
Result := cfFMA in CvFeatures;
end;
class function TCpu.HasSSE41: Boolean;
begin
Result := cfSSE41 in CvFeatures;
end;
class function TCpu.HasSSE42: Boolean;
begin
Result := cfSSE42 in CvFeatures;
end;
class function TCpu.HasAESNI: Boolean;
begin
Result := cfAESNI in CvFeatures;
end;
class function TCpu.HasCLMULQDQ: Boolean;
begin
Result := cfCLMULQDQ in CvFeatures;
end;
class function TCpu.HasAVX: Boolean;
begin
Result := cfAVX in CvFeatures;
end;
class function TCpu.HasAVX2: Boolean;
begin
Result := cfAVX2 in CvFeatures;
end;
class function TCpu.HasHLE: Boolean;
begin
Result := cfTsxHle in CvFeatures;
end;
class function TCpu.HasRTM: Boolean;
begin
Result := cfTsxRtm in CvFeatures;
end;
class function TCpu.HasXTEST: Boolean;
begin
Result := HasHLE or HasRTM;
end;
class function TCpu.HasAVX512f: Boolean;
begin
Result := cfAVX512f in CvFeatures;
end;
class function TCpu.HasAVX512cd: Boolean;
begin
Result := cfAVX512cd in CvFeatures;
end;
class function TCpu.HasAVX512er: Boolean;
begin
Result := cfAVX512er in CvFeatures;
end;
class function TCpu.HasAVX512pf: Boolean;
begin
Result := cfAVX512pf in CvFeatures;
end;
class function TCpu.HasAVX512dq: Boolean;
begin
Result := cfAVX512dq in CvFeatures;
end;
class function TCpu.HasAVX512bw: Boolean;
begin
Result := cfAVX512bw in CvFeatures;
end;
class function TCpu.HasAVX512ifma: Boolean;
begin
Result := cfAVX512ifma in CvFeatures;
end;
class function TCpu.HasAVX512vbmi: Boolean;
begin
Result := cfAVX512vbmi in CvFeatures;
end;
class function TCpu.HasBMI1: Boolean;
begin
Result := cfBMI1 in CvFeatures;
end;
class function TCpu.HasBMI2: Boolean;
begin
Result := cfBMI2 in CvFeatures;
end;
class function TCpu.HasRDRAND: Boolean;
begin
Result := cfRDRAND in CvFeatures;
end;
class function TCpu.HasRDSEED: Boolean;
begin
Result := cfRDSeed in CvFeatures;
end;
class function TCpu.HasADX: Boolean;
begin
Result := cfADX in CvFeatures;
end;
class function TCpu.HasPOPCNT: Boolean;
begin
Result := cfPOPCNT in CvFeatures;
end;
class function TCpu.HasVAESNI: Boolean;
begin
Result := HasAESNI and HasAVX;
end;
class function TCpu.HasVCLMULQDQ: Boolean;
begin
Result := HasCLMULQDQ and HasAVX;
end;
class function TCpu.HasSHAX: Boolean;
begin
Result := cfSHAX in CvFeatures;
end;
class function TCpu.HasVIARng: Boolean;
begin
Result := cfVIARNG in CvFeatures;
end;
class function TCpu.HasVIAAce: Boolean;
begin
Result := cfVIAACE in CvFeatures;
end;
class function TCpu.HasVIAAce2: Boolean;
begin
Result := cfVIAACE2 in CvFeatures;
end;
class function TCpu.HasVIAPHE: Boolean;
begin
Result := cfVIAPHE in CvFeatures;
end;
class function TCpu.HasVIAPMM: Boolean;
begin
Result := cfVIAPMM in CvFeatures;
end;
{$ENDIF UC_CPU_INTEL}
end.
Вроде даже работал.