📄 fastcodecpuid.pas
字号:
unit FastcodeCPUID;
(***** BEGIN LICENSE BLOCK *****
Version: MPL 1.1
The contents of this file are subject to the Mozilla Public License Version 1.1
(the "License"); you may not use this file except in compliance with the
License. You may obtain a copy of the License at http://www.mozilla.org/MPL/
Software distributed under the License is distributed on an "AS IS" basis,
WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
the specific language governing rights and limitations under the License.
The Original Code is the FastCode CPUID code.
The Initial Developer of the Original Code is
Roelof Engelbrecht <roelof@cox-internet.com>. Portions created by
the Initial Developer are Copyright (C) 2004 by the Initial Developer.
All Rights Reserved.
Contributor(s): Dennis Passmore <Dennis_Passmore@ ultimatesoftware.com>,
Dennis Christensen <marianndkc@home3.gvdnet.dk>.
***** END LICENSE BLOCK *****)
interface
uses
SysUtils; {for exceptions}
type
TVendor = (cvUnknown, cvAMD, cvCentaur, cvCyrix, cvIntel,
cvTransmeta, cvNexGen, cvRise, cvUMC, cvNSC, cvSiS);
{Note: when changing TVendor, also change VendorStr array below}
TInstructions =
(isFPU, {80x87}
isTSC, {RDTSC}
isCX8, {CMPXCHG8B}
isSEP, {SYSENTER/SYSEXIT}
isCMOV, {CMOVcc, and if isFPU, FCMOVcc/FCOMI}
isMMX, {MMX}
isFXSR, {FXSAVE/FXRSTOR}
isSSE, {SSE}
isSSE2, {SSE2}
isSSE3, {SSE3*}
isMONITOR, {MONITOR/MWAIT*}
isCX16, {CMPXCHG16B*}
isX64, {AMD AMD64* or Intel EM64T*}
isExMMX, {MMX+ - AMD only}
isEx3DNow, {3DNow!+ - AMD only}
is3DNow); {3DNow! - AMD only}
{Note: when changing TInstruction, also change InstructionSupportStr below
* - instruction(s) not supported in Delphi 7 assembler}
TInstructionSupport = set of TInstructions;
TCPU = record
Vendor: TVendor;
Signature: Cardinal;
EffFamily: Byte; {ExtendedFamily + Family}
EffModel: Byte; {(ExtendedModel shl 4) + Model}
CodeL1CacheSize, {KB or micro-ops for Pentium 4}
DataL1CacheSize, {KB}
L2CacheSize, {KB}
L3CacheSize: Word; {KB}
InstructionSupport: TInstructionSupport;
end;
TFastCodeTarget =
(fctRTLReplacement, {not specific to any CPU}
fctBlended, {not specific to any CPU, requires FPU, MMX and CMOV}
fctP3, {Pentium/Celeron 3}
fctPM, {Pentium/Celeron M (Banias and Dothan)}
fctP4, {Pentium/Celeron/Xeon 4 without SSE3 (Willamette,
Foster, Foster MP, Northwood, Prestonia, Gallatin)}
fctP4_SSE3, {Pentium/Celeron 4 with SSE3 (Prescott)}
fctP4_64, {Pentium/Xeon 4 with EM64T (some Prescott, and Nocona)}
fctK7, {Athlon/Duron without SSE (Thunderbird and Spitfire)}
fctK7_SSE, {Athlon/Duron/Sempron with SSE (Palomino, Morgan,
Thoroughbred, Applebred, Barton)}
fctK8, {Opteron/Athlon FX/Athlon 64 (Clawhammer, Sledgehammer,
Newcastle)}
fctK8_SSE3); {Opteron/Athlon FX/Athlon 64 with SSE3 (future)}
{Note: when changing TFastCodeTarget, also change FastCodeTargetStr array
below}
const
VendorStr: array[Low(TVendor)..High(TVendor)] of ShortString =
('Unknown', 'AMD', 'Centaur (VIA)', 'Cyrix', 'Intel', 'Transmeta',
'NexGen', 'Rise', 'UMC', 'National Semiconductor', 'SiS');
InstructionSupportStr:
array[Low(TInstructions)..High(TInstructions)] of ShortString =
('FPU', 'TSC', 'CX8', 'SEP', 'CMOV', 'MMX', 'FXSR', 'SSE', 'SSE2', 'SSE3',
'MONITOR', 'CX16', 'X64', 'MMX+', '3DNow!+', '3DNow!');
FastCodeTargetStr:
array[Low(TFastCodeTarget)..High(TFastCodeTarget)] of ShortString =
('RTLReplacement', 'Blended', 'P3', 'PM', 'P4', 'P4_SSE3', 'P4_64',
'K7', 'K7_SSE', 'K8', 'K8_SSE3');
var
CPU: TCPU;
FastCodeTarget: TFastCodeTarget;
implementation
type
TRegisters = record
EAX,
EBX,
ECX,
EDX: Cardinal;
end;
TVendorStr = string[12];
TCpuFeatures =
({in EDX}
cfFPU, cfVME, cfDE, cfPSE, cfTSC, cfMSR, cfPAE, cfMCE,
cfCX8, cfAPIC, cf_d10, cfSEP, cfMTRR, cfPGE, cfMCA, cfCMOV,
cfPAT, cfPSE36, cfPSN, cfCLFSH, cf_d20, cfDS, cfACPI, cfMMX,
cfFXSR, cfSSE, cfSSE2, cfSS, cfHTT, cfTM, cfIA_64, cfPBE,
{in ECX}
cfSSE3, cf_c1, cf_c2, cfMON, cfDS_CPL, cf_c5, cf_c6, cfEIST,
cfTM2, cf_c9, cfCID, cf_c11, cf_c12, cfCX16, cfxTPR, cf_c15,
cf_c16, cf_c17, cf_c18, cf_c19, cf_c20, cf_c21, cf_c22, cf_c23,
cf_c24, cf_c25, cf_c26, cf_c27, cf_c28, cf_c29, cf_c30, cf_c31);
TCpuFeatureSet = set of TCpuFeatures;
TCpuExtendedFeatures =
(cefFPU, cefVME, cefDE, cefPSE, cefTSC, cefMSR, cefPAE, cefMCE,
cefCX8, cefAPIC, cef_10, cefSEP, cefMTRR, cefPGE, cefMCA, cefCMOV,
cefPAT, cefPSE36, cef_18, ceMPC, ceNX, cef_21, cefExMMX, cefMMX,
cefFXSR, cef_25, cef_26, cef_27, cef_28, cefLM, cefEx3DNow, cef3DNow);
TCpuExtendedFeatureSet = set of TCpuExtendedFeatures;
const
VendorIDString: array[Low(TVendor)..High(TVendor)] of TVendorStr =
('',
'AuthenticAMD', 'CentaurHauls', 'CyrixInstead', 'GenuineIntel',
'GenuineTMx86', 'NexGenDriven', 'RiseRiseRise', 'UMC UMC UMC ',
'Geode by NSC', 'SiS SiS SiS');
{CPU signatures}
IntelLowestSEPSupportSignature = $633;
K7DuronA0Signature = $630;
C3Samuel2EffModel = 7;
C3EzraEffModel = 8;
PMBaniasEffModel = 9;
PMDothanEffModel = $D;
P3LowestEffModel = 7;
function IsCPUID_Available: Boolean; register;
asm
PUSHFD {save EFLAGS to stack}
POP EAX {store EFLAGS in EAX}
MOV EDX, EAX {save in EDX for later testing}
XOR EAX, $200000; {flip ID bit in EFLAGS}
PUSH EAX {save new EFLAGS value on stack}
POPFD {replace current EFLAGS value}
PUSHFD {get new EFLAGS}
POP EAX {store new EFLAGS in EAX}
XOR EAX, EDX {check if ID bit changed}
JZ @exit {no, CPUID not available}
MOV EAX, True {yes, CPUID is available}
@exit:
end;
function IsFPU_Available: Boolean;
var
_FCW, _FSW: Word;
asm
MOV EAX, False {initialize return register}
MOV _FSW, $5A5A {store a non-zero value}
FNINIT {must use non-wait form}
FNSTSW _FSW {store the status}
CMP _FSW, 0 {was the correct status read?}
JNE @exit {no, FPU not available}
FNSTCW _FCW {yes, now save control word}
MOV DX, _FCW {get the control word}
AND DX, $103F {mask the proper status bits}
CMP DX, $3F {is a numeric processor installed?}
JNE @exit {no, FPU not installed}
MOV EAX, True {yes, FPU is installed}
@exit:
end;
procedure GetCPUID(Param: Cardinal; var Registers: TRegisters);
asm
PUSH EBX {save affected registers}
PUSH EDI
MOV EDI, Registers
XOR EBX, EBX {clear EBX register}
XOR ECX, ECX {clear ECX register}
XOR EDX, EDX {clear EDX register}
DB $0F, $A2 {CPUID opcode}
MOV TRegisters(EDI).&EAX, EAX {save EAX register}
MOV TRegisters(EDI).&EBX, EBX {save EBX register}
MOV TRegisters(EDI).&ECX, ECX {save ECX register}
MOV TRegisters(EDI).&EDX, EDX {save EDX register}
POP EDI {restore registers}
POP EBX
end;
procedure GetCPUVendor;
var
VendorStr: TVendorStr;
Registers: TRegisters;
begin
{call CPUID function 0}
GetCPUID(0, Registers);
{get vendor string}
SetLength(VendorStr, 12);
Move(Registers.EBX, VendorStr[1], 4);
Move(Registers.EDX, VendorStr[5], 4);
Move(Registers.ECX, VendorStr[9], 4);
{get CPU vendor from vendor string}
CPU.Vendor := High(TVendor);
while (VendorStr <> VendorIDString[CPU.Vendor]) and
(CPU.Vendor > Low(TVendor)) do
Dec(CPU.Vendor);
end;
procedure GetCPUFeatures;
{preconditions: 1. maximum CPUID must be at least $00000001
2. GetCPUVendor must have been called}
type
_Int64 = packed record
Lo: Longword;
Hi: Longword;
end;
var
Registers: TRegisters;
CpuFeatures: TCpuFeatureSet;
begin
{call CPUID function $00000001}
GetCPUID($00000001, Registers);
{get CPU signature}
CPU.Signature := Registers.EAX;
{extract effective processor family and model}
CPU.EffFamily := CPU.Signature and $00000F00 shr 8;
CPU.EffModel := CPU.Signature and $000000F0 shr 4;
if CPU.EffFamily = $F then
begin
CPU.EffFamily := CPU.EffFamily + (CPU.Signature and $0FF00000 shr 20);
CPU.EffModel := CPU.EffModel + (CPU.Signature and $000F0000 shr 12);
end;
{get CPU features}
Move(Registers.EDX, _Int64(CpuFeatures).Lo, 4);
Move(Registers.ECX, _Int64(CpuFeatures).Hi, 4);
{get instruction support}
if cfFPU in CpuFeatures then
Include(CPU.InstructionSupport, isFPU);
if cfTSC in CpuFeatures then
Include(CPU.InstructionSupport, isTSC);
if cfCX8 in CpuFeatures then
Include(CPU.InstructionSupport, isCX8);
if cfSEP in CpuFeatures then
begin
Include(CPU.InstructionSupport, isSEP);
{for Intel CPUs, qualify the processor family and model to ensure that the
SYSENTER/SYSEXIT instructions are actually present - see Intel Application
Note AP-485}
if (CPU.Vendor = cvIntel) and
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -