GR32.CPUID.pas 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915
  1. unit GR32.CPUID;
  2. {***** BEGIN LICENSE BLOCK *****
  3. Version: MPL 1.1
  4. The contents of this file are subject to the Mozilla Public License Version 1.1
  5. (the "License"); you may not use this file except in compliance with the
  6. License. You may obtain a copy of the License at http://www.mozilla.org/MPL/
  7. Software distributed under the License is distributed on an "AS IS" basis,
  8. WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
  9. the specific language governing rights and limitations under the License.
  10. The Original Code is the FastCode CPUID code.
  11. The Initial Developer of the Original Code is
  12. Roelof Engelbrecht <[email protected]>. Portions created by
  13. the Initial Developer are Copyright (C) 2004 by the Initial Developer.
  14. All Rights Reserved.
  15. Contributor(s): Dennis Passmore <Dennis_Passmore@ ultimatesoftware.com>,
  16. Dennis Kjaer Christensen <[email protected]>,
  17. Jouni Turunen <[email protected]>.
  18. ***** END LICENSE BLOCK *****
  19. This is a merge of several different forks of the FastcodeCPUID unit.
  20. Common to them, compared to version 3.0.2 of the original unit, is added support
  21. for 64-bit and various CPU features.
  22. Code and changes related to "Fastcode targets" has been removed.
  23. }
  24. interface
  25. {$include GR32.inc}
  26. {$if (defined(CompilerVersion)) and (CompilerVersion >= 17.0)} // Delphi 2005
  27. {$WARN UNSAFE_CAST OFF}
  28. {$WARN UNSAFE_CODE OFF}
  29. {$ifend}
  30. type
  31. TCPUVendor = (
  32. cvUnknown,
  33. cvAMD,
  34. cvCentaur,
  35. cvCyrix,
  36. cvIntel,
  37. cvTransmeta,
  38. cvNexGen,
  39. cvRise,
  40. cvUMC,
  41. cvNSC,
  42. cvSiS,
  43. cvAMDEarly,
  44. cvVIA,
  45. cvVortex,
  46. cvVM_KVM,
  47. cvVM_Microsoft,
  48. cvVM_Parallels,
  49. cvVM_VMWare,
  50. cvVM_XEN,
  51. cvVM_XTA,
  52. cvVM_Rosetta2,
  53. cvZhaoxin,
  54. cvHygon,
  55. cvRDC,
  56. cvElbrus
  57. );
  58. TCPUInstructionSet = (
  59. // Synthetic features. Used by the binding system.
  60. isReference,{ Reference implementation }
  61. isPascal, { PUREPASCAL implementation }
  62. isAssembler,{ Assembler implementation, using no features beyond base x86/x64 assembler }
  63. // CPU hardware features
  64. isFPU, {80x87}
  65. isTSC, {RDTSC}
  66. isCX8, {CMPXCHG8B}
  67. isSEP, {SYSENTER/SYSEXIT}
  68. isCMOV, {CMOVcc, and if isFPU, FCMOVcc/FCOMI}
  69. isMMX, {MMX}
  70. isFXSR, {FXSAVE/FXRSTOR}
  71. isSSE, {SSE}
  72. isSSE2, {SSE2}
  73. isSSE3, {SSE3*}
  74. isMONITOR, {MONITOR/MWAIT*}
  75. isCX16, {CMPXCHG16B*}
  76. isX64, {AMD AMD64* or Intel EM64T*}
  77. isExMMX, {MMX+ - AMD only}
  78. isEx3DNow, {3DNow!+ - AMD only}
  79. is3DNow, {3DNow! - AMD only}
  80. isSSSE3, {Supplemental SSE3}
  81. isSSE41, {SSE 4.1}
  82. isSSE42, {SSE 4.2}
  83. isAES, {AES support}
  84. isAVX, {AVX}
  85. isPopCnt, {Popcnt, lzcnt, tzcnt}
  86. isXSAVE, {XSAVE}
  87. isRDTSCP, {Read synchronized RDTSCP}
  88. isTBM, {Trailing bit manipulations}
  89. isFMA4, {4 operand FMA instructions support}
  90. isXOP, {XOP support}
  91. isSSE4A, {SSE 4a support, note that popcount has its own flag}
  92. isABM, {Advanced bit manipulation}
  93. isLAHF, {Lahf, Sahf support in 64-bit}
  94. isPCLMULQDQ,{PCLMULQDQ support}
  95. isFMA, {Fused multiply and add}
  96. isMOVBE, {move Big Endian}
  97. isF16C, {half precision FP support}
  98. isRDRAND, {Onchip random generator}
  99. isBMI1, {Bit manipulation instruction set 1}
  100. isAVX2, {Advanced vector instructions 2}
  101. isBMI2, {Bit manipulation instruction set 2}
  102. isERMS, {Enhanced REP MOVSB/STOSB}
  103. isINVPCID, {INVPCID instructions}
  104. isRTM, {Transactional Synchronization Extensions}
  105. isMPX, {Memory Protection Extensions}
  106. isAVX512f, {AVX-512 Foundation}
  107. isAVX512dq, {AVX-512 Doubleword and Quadword Instructions}
  108. isRDSEED, {RDSEED instruction}
  109. isADX, {Multi-Precision Add-Carry Instruction Extensions}
  110. isPCOMMIT, {PCOMMIT instruction}
  111. isCLFLUSHOPT,{CLFLUSHOPT instruction}
  112. isCLWB, {CLWB instruction}
  113. isAVX512pf, {AVX-512 Prefetch Instructions}
  114. isAVX512er, {AVX-512 Exponential and Reciprocal Instructions}
  115. isAVX512cd, {AVX-512 Conflict Detection Instructions}
  116. isSHA, {SHA extensions}
  117. isAVX512bw, {AVX-512 Byte and Word Instructions}
  118. isAVX512vl, {AVX-512 Vector Length Extensions}
  119. isPREFETCHWT1,{PREFETCHWT1 instruction}
  120. isAVX512vbmi {AVX-512 Vector Bit Manipulation Instructions}
  121. );
  122. TInstructionSupport = set of TCPUInstructionSet;
  123. TCPU = record
  124. private
  125. procedure GetCPUVendor;
  126. procedure GetCPUFeatures;
  127. procedure GetCPUExtendedFeatures;
  128. procedure GetCPUExtendedFeatures7;
  129. procedure GetProcessorCacheInfo;
  130. procedure GetExtendedProcessorCacheInfo;
  131. procedure VerifyOSSupportForXMMRegisters;
  132. function IsXmmYmmOSEnabled: boolean;
  133. procedure VerifyOSSupportForYMMRegisters;
  134. function GetVendorName: string; overload;
  135. public
  136. Vendor: TCPUVendor;
  137. Signature: Cardinal;
  138. // Signature unpacked
  139. Stepping: Byte;
  140. Model: Byte;
  141. ProcessorType: Byte;
  142. Family: Byte;
  143. ExtendedModel: Byte;
  144. ExtendedFamily: Byte;
  145. // Calculated fields
  146. ActualFamily: Byte;
  147. ActualModel: Byte;
  148. CodeL1CacheSize, // Kilobytes, or micro-ops for Pentium 4
  149. DataL1CacheSize, // Kilobytes
  150. L2CacheSize, // Kilobytes
  151. L3CacheSize: Word; // Kilobytes
  152. PrefetchSize: Word; // Bytes
  153. InstructionSupport: TInstructionSupport;
  154. property VendorName: string read GetVendorName;
  155. class function GetCPUInfo: TCPU; static;
  156. class function GetVendorName(Vendor: TCPUVendor): string; overload; static;
  157. class function GetInstructionSetName(InstructionSet: TCPUInstructionSet): string; static;
  158. end;
  159. implementation
  160. const
  161. sVendorNames: array[TCPUVendor] of string = (
  162. 'Unknown',
  163. 'AMD',
  164. 'Centaur (VIA)',
  165. 'Cyrix',
  166. 'Intel',
  167. 'Transmeta',
  168. 'NexGen',
  169. 'Rise',
  170. 'UMC',
  171. 'National Semiconductor',
  172. 'SiS',
  173. 'AMD K5 engineering sample',
  174. 'VIA',
  175. 'Vortex',
  176. 'KVM VM',
  177. 'Microsoft VM',
  178. 'Parallels VM',
  179. 'VMWare VM',
  180. 'XEN VM',
  181. 'Microsoft X86-to-ARM VM',
  182. 'Apple Rosetta 2',
  183. 'Zhaoxin',
  184. 'Hygon',
  185. 'RDC Semiconductor Co. Ltd.',
  186. 'Elbrus'
  187. );
  188. type
  189. TVendorStr = string[12];
  190. const
  191. VendorIDs: array[0..26] of record
  192. ID: TCPUVendor;
  193. Signature: TVendorStr;
  194. end = (
  195. (ID: cvUnknown; Signature: ''),
  196. (ID: cvAMD; Signature: 'AuthenticAMD'),
  197. (ID: cvCentaur; Signature: 'CentaurHauls'),
  198. (ID: cvCyrix; Signature: 'CyrixInstead'),
  199. (ID: cvIntel; Signature: 'GenuineIntel'),
  200. (ID: cvIntel; Signature: 'GenuineIotel'),
  201. (ID: cvTransmeta; Signature: 'GenuineTMx86'),
  202. (ID: cvTransMeta; Signature: 'TransmetaCPU'),
  203. (ID: cvNexGen; Signature: 'NexGenDriven'),
  204. (ID: cvRise; Signature: 'RiseRiseRise'),
  205. (ID: cvUMC; Signature: 'UMC UMC UMC '),
  206. (ID: cvNSC; Signature: 'Geode by NSC'),
  207. (ID: cvSiS; Signature: 'SiS SiS SiS '),
  208. (ID: cvAMDEarly; Signature: 'AMDisbetter!'),
  209. (ID: cvVIA; Signature: 'VIA VIA VIA '),
  210. (ID: cvVortex; Signature: 'Vortex86 SoC'),
  211. (ID: cvVM_KVM; Signature: 'KVMKVMKVM '),
  212. (ID: cvVM_Microsoft; Signature: 'Microsoft Hv'),
  213. (ID: cvVM_Parallels; Signature: ' lrpepyh vr'),
  214. (ID: cvVM_VMWare; Signature: 'VMwareVMware'),
  215. (ID: cvVM_XEN; Signature: 'XenVMMXenVMM'),
  216. (ID: cvVM_XTA; Signature: 'MicrosoftXTA'),
  217. (ID: cvVM_Rosetta2; Signature: 'VirtualApple'),
  218. (ID: cvZhaoxin; Signature: ' Shanghai '),
  219. (ID: cvHygon; Signature: 'HygonGenuine'),
  220. (ID: cvRDC; Signature: 'Genuine RDC'),
  221. (ID: cvElbrus; Signature: 'E2K MACHINE')
  222. );
  223. sInstructionSetNames: array[TCPUInstructionSet] of string = (
  224. 'PUREPASCAL', 'Assembler', 'Reference',
  225. 'FPU', 'TSC', 'CX8', 'SEP', 'CMOV', 'MMX', 'FXSR', 'SSE', 'SSE2', 'SSE3',
  226. 'MONITOR', 'CX16', 'X64', 'MMX+', '3DNow!+', '3DNow!','SSSE3','SSE4.1',
  227. 'SSE4.2','AES','AVX','PopCnt','XSAVE','RDTSCP','TBM','FMA4','XOP','SSE4A',
  228. 'ABM','LAHF','PCLMULQDQ','FMA','MOVBE','F16C','RDRAND','BMI1','AVX2','BMI2',
  229. 'ERMS','INVPCID','RTM','MPX', 'AVX512f','AVX512dq','RDSEED','ADX','PCOMMIT',
  230. 'CLFLUSHOPT','CLWB','AVX512pf','AVX512er','AVX512cd','SHA','AVX512bw','AVX512vl',
  231. 'PREFETCHWT1','AVX512vbmi'
  232. );
  233. type
  234. TRegisters = record
  235. EAX,
  236. EBX,
  237. ECX,
  238. EDX: Cardinal;
  239. end;
  240. TCpuFeatures = (
  241. {in EDX}
  242. cfFPU, cfVME, cfDE, cfPSE, cfTSC, cfMSR, cfPAE, cfMCE,
  243. cfCX8, cfAPIC, cf_d10, cfSEP, cfMTRR, cfPGE, cfMCA, cfCMOV,
  244. cfPAT, cfPSE36, cfPSN, cfCLFSH, cf_d20, cfDS, cfACPI, cfMMX,
  245. cfFXSR, cfSSE, cfSSE2, cfSS, cfHyperThreading, cfTM, cfIA_64, cfPBE,
  246. {in ECX}
  247. cfSSE3, cfPCLMULQDQ, cf_c2, cfMON, cfDS_CPL, cf_c5, cf_c6, cfEIST,
  248. cfTM2, cfSSSE3, cfCID, cf_c11, cfFMA, cfCX16, cfxTPR, cf_c15,
  249. cf_c16, cf_c17, cf_c18, cfSSE41, cfSSE42, cf_c21, cfMovBE, cfPOPCNT,
  250. cf_c24, cfAES, cfXSAVE, cfOSXSAVE, cfAVX, cfF16C, cfRDRAND, cfRAZ
  251. );
  252. TCpuFeatureSet = set of TCpuFeatures;
  253. TCpuExtendedFeatures = (
  254. {in EDX}
  255. cefFPU, cefVME, cefDE, cefPSE, cefTSC, cefMSR, cefPAE, cefMCE,
  256. cefCX8, cefAPIC, cef_10, cefSEP, cefMTRR, cefPGE, cefMCA, cefCMOV,
  257. cefPAT, cefPSE36, cef_18, ceMPC, ceNX, cef_21, cefExMMX, cefMMX,
  258. cefFXSR, cefFFXSR, cefPage1GB, cefRDTSCP, cef_28, cefLM, cefEx3DNow, cef3DNow,
  259. {in ECX}
  260. cefLahfSahf, cefCmpLegacy, cefSVM, cefExtApicSpace, cefAltMovCR8, cefABM, cefSSE4A, cefMisAlignSSE,
  261. cef3DNOWPrefetch, cefOSVW, cefIBS, cefXOP, cefSKINIT, cefWDT, cef_c14, cefLWP,
  262. cefFMA4, cefTCE, cef_c18, cefNodeId, cef_c20, cefTBM, cefTopologyExtensions, cefPERFCTR_core,
  263. cefPERFCTR_nb, cef_c25, cefDBX, cefPERFTSC, cefPCX_l2i, cef_c29, cef_c30, cef_c31
  264. );
  265. TCpuExtendedFeatureSet = set of TCpuExtendedFeatures;
  266. TCPUExtendedFeatures7 = ( {EAX = 7, ECX = 0}
  267. {in EBX}
  268. ce7FSGSbase, ce7TSC_Adjust, ce7SGX, ce7BMI1, ce7HLE, ce7AVX2, ce7_06, ce7SMEP,
  269. ce7BMI2, ce7ERMS, ce7INVPCID, ce7RTM, ce7PQM, ce7NoFPUcsds, ce7MPX, ce7PQE,
  270. ce7AVX512f, ce7AVX512dq, ce7RDSEED, ce7ADX, ce7SMAP, ce7AVX512ifma, ce7PCOMMIT, ce7CLFLUSHOPT,
  271. ce7CLWB, ce7ProcessorTrace, ce7AVX512pf, ce7AVX512er, ce7AVX512cd, ce7SHA, ce7AVX512bw, ce7AVX512vl,
  272. {in ECX}
  273. ce7cPREFETCHWT1, ce7cAVX512vbmi, ce7c_02, ce7c_03, ce7c_04, ce7c_05, ce7c_06, ce7c_07,
  274. ce7c_08, ce7c_09, ce7c_10, ce7c_11, ce7c_12, ce7c_13, ce7c_14, ce7c_15,
  275. ce7c_16, ce7c_17, ce7c_18, ce7c_19, ce7c_20, ce7c_21, ce7c_22, ce7c_23,
  276. ce7c_24, ce7c_25, ce7c_26, ce7c_27, ce7c_28, ce7c_29, ce7c_30, ce7c_31
  277. );
  278. TCpuExtendedFeature7Set = set of TCpuExtendedFeatures7;
  279. const
  280. {CPU signatures}
  281. IntelLowestSEPSupportSignature = $633;
  282. K7DuronA0Signature = $630;
  283. C3Samuel2EffModel = 7;
  284. C3EzraEffModel = 8;
  285. // For a list of Intel CPU models by family, microarchitecture and core, see: https://en.wikichip.org/wiki/intel/cpuid
  286. {$IFNDEF PUREPASCAL}
  287. function IsCPUID_Available: Boolean; register;
  288. asm
  289. {$IFDEF CPUx86}
  290. PUSHFD {save EFLAGS to stack}
  291. POP EAX {store EFLAGS in EAX}
  292. MOV EDX, EAX {save in EDX for later testing}
  293. XOR EAX, $200000; {flip ID bit in EFLAGS}
  294. PUSH EAX {save new EFLAGS value on stack}
  295. POPFD {replace current EFLAGS value}
  296. PUSHFD {get new EFLAGS}
  297. POP EAX {store new EFLAGS in EAX}
  298. XOR EAX, EDX {check if ID bit changed}
  299. JZ @exit {no, CPUID not available}
  300. MOV EAX, True {yes, CPUID is available}
  301. @exit:
  302. {$ELSE}
  303. MOV EAX, True {x64 always has CPUID}
  304. {$ENDIF}
  305. end;
  306. function IsFPU_Available: Boolean;
  307. {$IFDEF CPUx86}
  308. var
  309. _FCW, _FSW: Word;
  310. asm
  311. MOV EAX, False {initialize return register}
  312. MOV _FSW, $5A5A {store a non-zero value}
  313. FNINIT {must use non-wait form}
  314. FNSTSW _FSW {store the status}
  315. CMP _FSW, 0 {was the correct status read?}
  316. JNE @exit {no, FPU not available}
  317. FNSTCW _FCW {yes, now save control word}
  318. MOV DX, _FCW {get the control word}
  319. AND DX, $103F {mask the proper status bits}
  320. CMP DX, $3F {is a numeric processor installed?}
  321. JNE @exit {no, FPU not installed}
  322. MOV EAX, True {yes, FPU is installed}
  323. @exit:
  324. {$ELSE}
  325. asm
  326. MOV EAX, True {Every X64 has an FPU}
  327. {$ENDIF}
  328. end;
  329. procedure GetCPUID(Param: Cardinal; var Registers: TRegisters);
  330. asm
  331. {$ifdef CPUx86}
  332. PUSH EBX {save affected registers}
  333. PUSH EDI
  334. MOV EDI, Registers
  335. XOR EBX, EBX {clear EBX register}
  336. XOR ECX, ECX {clear ECX register}
  337. XOR EDX, EDX {clear EDX register}
  338. DB $0F, $A2 {CPUID opcode}
  339. MOV TRegisters(EDI).&EAX, EAX {save EAX register}
  340. MOV TRegisters(EDI).&EBX, EBX {save EBX register}
  341. MOV TRegisters(EDI).&ECX, ECX {save ECX register}
  342. MOV TRegisters(EDI).&EDX, EDX {save EDX register}
  343. POP EDI {restore registers}
  344. POP EBX
  345. {$else X64}
  346. PUSH RBX
  347. PUSH RDI
  348. MOV RDI, Registers
  349. MOV EAX, ECX
  350. XOR EBX, EBX
  351. XOR ECX, ECX
  352. XOR EDX, EDX
  353. CPUID
  354. MOV TRegisters(RDI).&EAX, EAX
  355. MOV TRegisters(RDI).&EBX, EBX
  356. MOV TRegisters(RDI).&ECX, ECX
  357. MOV TRegisters(RDI).&EDX, EDX
  358. POP RDI
  359. POP RBX
  360. {$endif}
  361. end;
  362. {$ELSE}
  363. function IsCPUID_Available: Boolean;
  364. begin
  365. Result := False;
  366. end;
  367. function IsFPU_Available: Boolean;
  368. begin
  369. Result := False;
  370. end;
  371. procedure GetCPUID(Param: Cardinal; var Registers: TRegisters);
  372. begin
  373. Registers := Default(TRegisters);
  374. end;
  375. {$ENDIF}
  376. procedure TCPU.GetCPUVendor;
  377. var
  378. VendorStr: TVendorStr;
  379. Registers: TRegisters;
  380. i: integer;
  381. begin
  382. {call CPUID function 0}
  383. GetCPUID(0, Registers);
  384. {get vendor string}
  385. SetLength(VendorStr, 12);
  386. Move(Registers.EBX, VendorStr[1], 4);
  387. Move(Registers.EDX, VendorStr[5], 4);
  388. Move(Registers.ECX, VendorStr[9], 4);
  389. {get CPU vendor from vendor string}
  390. Vendor:= cvUnknown;
  391. for i := 0 to High(VendorIDs) do
  392. if (VendorStr = VendorIDs[i].Signature) then
  393. begin
  394. Vendor := VendorIDs[i].ID;
  395. break;
  396. end;
  397. end;
  398. procedure TCPU.GetCPUFeatures;
  399. { preconditions:
  400. 1. maximum CPUID must be at least $00000001
  401. 2. GetCPUVendor must have been called }
  402. type
  403. _Int64 = packed record
  404. Lo: Longword;
  405. Hi: Longword;
  406. end;
  407. var
  408. Registers: TRegisters;
  409. CpuFeatures: TCpuFeatureSet;
  410. begin
  411. {call CPUID function $00000001}
  412. GetCPUID($00000001, Registers);
  413. {get CPU signature}
  414. Signature:= Registers.EAX;
  415. Stepping := Signature and $0F;
  416. Model := (Signature shr 4) and $0F;
  417. ProcessorType := (Signature shr 12) and $03;
  418. Family := (Signature shr 8) and $0F;
  419. ExtendedModel := (Signature shr 16) and $0F;
  420. ExtendedFamily := (Signature shr 20) and $FF;
  421. if Family in [6, 15] then
  422. ActualModel:= (ExtendedModel shl 4) or (Model)
  423. else
  424. ActualModel:= Model;
  425. if Family = 15 then
  426. ActualFamily:= ExtendedFamily + Family
  427. else
  428. ActualFamily:= Family;
  429. (* Old logic. Doesn't appear to be correct.
  430. {extract effective processor family and model}
  431. EffFamily:= Signature and $00000F00 shr 8;
  432. EffModel:= Signature and $000000F0 shr 4;
  433. EffModelBasic:= EffModel;
  434. if EffFamily = $F then
  435. begin
  436. EffFamily:= EffFamily + (Signature and $0FF00000 shr 20);
  437. EffModel:= EffModel + (Signature and $000F0000 shr 12);
  438. end;
  439. *)
  440. {get CPU features}
  441. Move(Registers.EDX, _Int64(CpuFeatures).Lo, 4);
  442. Move(Registers.ECX, _Int64(CpuFeatures).Hi, 4);
  443. {get instruction support}
  444. if cfFPU in CpuFeatures then Include(InstructionSupport, isFPU);
  445. if cfTSC in CpuFeatures then Include(InstructionSupport, isTSC);
  446. if cfCX8 in CpuFeatures then Include(InstructionSupport, isCX8);
  447. if cfSEP in CpuFeatures then
  448. begin
  449. Include(InstructionSupport, isSEP);
  450. {for Intel CPUs, qualify the processor family and model to ensure that the
  451. SYSENTER/SYSEXIT instructions are actually present - see Intel Application
  452. Note AP-485}
  453. if (Vendor = cvIntel) and (Signature and $0FFF3FFF < IntelLowestSEPSupportSignature) then
  454. Exclude(InstructionSupport, isSEP);
  455. end;
  456. if cfCMOV in CpuFeatures then Include(InstructionSupport, isCMOV);
  457. if cfFXSR in CpuFeatures then Include(InstructionSupport, isFXSR);
  458. if cfMMX in CpuFeatures then Include(InstructionSupport, isMMX);
  459. if cfSSE in CpuFeatures then Include(InstructionSupport, isSSE);
  460. if cfSSE2 in CpuFeatures then Include(InstructionSupport, isSSE2);
  461. if cfSSE3 in CpuFeatures then Include(InstructionSupport, isSSE3);
  462. if cfSSSE3 in CpuFeatures then Include(InstructionSupport, isSSSE3);
  463. if cfSSE41 in CpuFeatures then Include(InstructionSupport, isSSE41);
  464. if cfSSE42 in CpuFeatures then Include(InstructionSupport, isSSE42);
  465. if cfAES in CpuFeatures then Include(InstructionSupport, isAES);
  466. if cfAVX in CpuFeatures then Include(InstructionSupport, isAVX);
  467. if cfPOPCNT in CpuFeatures then Include(InstructionSupport, isPopCnt);
  468. if cfCX16 in CpuFeatures then Include(InstructionSupport, isCX16);
  469. if cfXSAVE in CpuFeatures then Include(InstructionSupport, isXSAVE);
  470. if cfPCLMULQDQ in CpuFeatures then Include(InstructionSupport, isPCLMULQDQ);
  471. if cfFMA in CpuFeatures then Include(InstructionSupport, isFMA);
  472. if cfMovBE in CpuFeatures then Include(InstructionSupport, isMovBE);
  473. if cfF16C in CpuFeatures then Include(InstructionSupport, isF16C);
  474. if cfRDRAND in CpuFeatures then Include(InstructionSupport, isRDRAND);
  475. if {(Vendor = cvIntel) and }(cfMON in CpuFeatures) then Include(InstructionSupport, isMONITOR);
  476. end;
  477. procedure TCPU.GetCPUExtendedFeatures;
  478. {preconditions: maximum extended CPUID >= $80000001}
  479. type
  480. _Int64 = packed record
  481. Lo: Longword;
  482. Hi: Longword;
  483. end;
  484. var
  485. Registers: TRegisters;
  486. CpuExFeatures: TCpuExtendedFeatureSet;
  487. begin
  488. {call CPUID function $80000001}
  489. GetCPUID($80000001, Registers);
  490. {get CPU extended features}
  491. // Note: The various versions of FastcodeCPUID disagreed on the EDX/ECX order here
  492. Move(Registers.EDX, _Int64(CpuExFeatures).Lo, 4);
  493. Move(Registers.ECX, _Int64(CpuExFeatures).Hi, 4);
  494. {get instruction support}
  495. if cefLM in CpuExFeatures then Include(InstructionSupport, isX64);
  496. if cefExMMX in CpuExFeatures then Include(InstructionSupport, isExMMX);
  497. if cefEx3DNow in CpuExFeatures then Include(InstructionSupport, isEx3DNow);
  498. if cef3DNow in CpuExFeatures then Include(InstructionSupport, is3DNow);
  499. if cefRDTSCP in CpuExFeatures then Include(InstructionSupport, isRDTSCP);
  500. if cefTBM in CpuExFeatures then Include(InstructionSupport, isTBM);
  501. if cefFMA4 in CpuExFeatures then Include(InstructionSupport, isFMA4);
  502. if cefXOP in CpuExFeatures then Include(InstructionSupport, isXOP);
  503. if cefSSE4A in CpuExFeatures then Include(InstructionSupport, isSSE4A);
  504. if cefABM in CpuExFeatures then Include(InstructionSupport, isABM);
  505. if cefLahfSahf in CpuExFeatures then Include(InstructionSupport, isLAHF);
  506. end;
  507. procedure TCPU.GetCPUExtendedFeatures7;
  508. type
  509. _Int64 = packed record
  510. Lo: Longword;
  511. Hi: Longword;
  512. end;
  513. var
  514. Registers: TRegisters;
  515. Cpu7ExFeatures: TCpuExtendedFeature7Set;
  516. begin
  517. {call CPUID function $80000001}
  518. GetCPUID($7, Registers);
  519. {get CPU extended features}
  520. Move(Registers.EBX, _Int64(Cpu7ExFeatures).Lo, 4);
  521. Move(Registers.ECX, _Int64(Cpu7ExFeatures).Hi, 4);
  522. {get instruction support}
  523. if ce7BMI1 in Cpu7ExFeatures then Include(InstructionSupport, isBMI1);
  524. if ce7AVX2 in Cpu7ExFeatures then Include(InstructionSupport, isAVX2);
  525. if ce7BMI2 in Cpu7ExFeatures then Include(InstructionSupport, isBMI2);
  526. if ce7ERMS in Cpu7ExFeatures then Include(InstructionSupport, isERMS);
  527. if ce7INVPCID in Cpu7ExFeatures then Include(InstructionSupport, isINVPCID);
  528. if ce7RTM in Cpu7ExFeatures then Include(InstructionSupport, isRTM);
  529. if ce7MPX in Cpu7ExFeatures then Include(InstructionSupport, isMPX);
  530. if ce7AVX512f in Cpu7ExFeatures then Include(InstructionSupport, isAVX512f);
  531. if ce7AVX512dq in Cpu7ExFeatures then Include(InstructionSupport, isAVX512dq);
  532. if ce7RDSEED in Cpu7ExFeatures then Include(InstructionSupport, isRDSEED);
  533. if ce7ADX in Cpu7ExFeatures then Include(InstructionSupport, isADX);
  534. if ce7PCOMMIT in Cpu7ExFeatures then Include(InstructionSupport, isPCOMMIT);
  535. if ce7CLFLUSHOPT in Cpu7ExFeatures then Include(InstructionSupport, isCLFLUSHOPT);
  536. if ce7CLWB in Cpu7ExFeatures then Include(InstructionSupport, isCLWB);
  537. if ce7AVX512pf in Cpu7ExFeatures then Include(InstructionSupport, isAVX512pf);
  538. if ce7AVX512er in Cpu7ExFeatures then Include(InstructionSupport, isAVX512er);
  539. if ce7AVX512cd in Cpu7ExFeatures then Include(InstructionSupport, isAVX512cd);
  540. if ce7SHA in Cpu7ExFeatures then Include(InstructionSupport, isSHA);
  541. if ce7AVX512bw in Cpu7ExFeatures then Include(InstructionSupport, isAVX512bw);
  542. if ce7AVX512vl in Cpu7ExFeatures then Include(InstructionSupport, isAVX512vl);
  543. if ce7cPREFETCHWT1 in Cpu7ExFeatures then Include(InstructionSupport, isPREFETCHWT1);
  544. if ce7cAVX512vbmi in Cpu7ExFeatures then Include(InstructionSupport, isAVX512vbmi);
  545. end;
  546. procedure TCPU.GetProcessorCacheInfo;
  547. {preconditions: 1. maximum CPUID must be at least $00000002
  548. 2. GetCPUVendor must have been called}
  549. type
  550. TCacheDescriptor = record
  551. case integer of
  552. 0: (Descriptor: packed array[0..3, 0..3] of Byte);
  553. 1: (Registers: TRegisters);
  554. end;
  555. var
  556. CacheDescriptor: TCacheDescriptor;
  557. i, j: Integer;
  558. QueryCount: Byte;
  559. begin
  560. {call CPUID function 2}
  561. GetCPUID($00000002, CacheDescriptor.Registers);
  562. QueryCount := CacheDescriptor.Descriptor[0, 0]; // Apparently always 1, according to wikipedia
  563. CacheDescriptor.Descriptor[0, 0] := 0; // Clear count field so we don't interpret it as a descriptor
  564. while (QueryCount > 0) do
  565. begin
  566. for i := 0 to 3 do
  567. begin
  568. if (CacheDescriptor.Descriptor[i, 3] and $80 = $80) then
  569. // Block isn't valid; Skip it
  570. continue;
  571. for j := 0 to 3 do
  572. {decode configuration descriptor byte}
  573. case CacheDescriptor.Descriptor[i, j] of
  574. $06: CodeL1CacheSize := 8;
  575. $08: CodeL1CacheSize := 16;
  576. $09: CodeL1CacheSize := 32;
  577. $0A: DataL1CacheSize := 8;
  578. $0C: DataL1CacheSize := 16;
  579. $0D: DataL1CacheSize := 16;
  580. $21: L2CacheSize := 256;
  581. $22: L3CacheSize := 512;
  582. $23: L3CacheSize := 1024;
  583. $25: L3CacheSize := 2048;
  584. $29: L3CacheSize := 4096;
  585. $2C: DataL1CacheSize := 32;
  586. $30: CodeL1CacheSize := 32;
  587. $39: L2CacheSize := 128;
  588. $3B: L2CacheSize := 128;
  589. $3C: L2CacheSize := 256;
  590. $3D: L2CacheSize := 384;
  591. $3E: L2CacheSize := 512;
  592. $40: {no 2nd-level cache or, if processor contains a valid 2nd-level
  593. cache, no 3rd-level cache}
  594. if L2CacheSize <> 0 then
  595. L3CacheSize := 0;
  596. $41: L2CacheSize := 128;
  597. $42: L2CacheSize := 256;
  598. $43: L2CacheSize := 512;
  599. $44: L2CacheSize := 1024;
  600. $45: L2CacheSize := 2048;
  601. $46: L3CacheSize := 4096;
  602. $47: L3CacheSize := 8192;
  603. $48: L2CacheSize := 3072;
  604. $49: if (Vendor = cvIntel) and (ActualFamily = $F) and (ActualModel = 6) then
  605. L3CacheSize := 4096
  606. else
  607. L2CacheSize := 4096;
  608. $4A: L3CacheSize := 6144;
  609. $4B: L3CacheSize := 8192;
  610. $4C: L3CacheSize := 12288;
  611. $4D: L3CacheSize := 16384;
  612. $4E: L2CacheSize := 6144;
  613. $60: DataL1CacheSize := 16;
  614. $66: DataL1CacheSize := 8;
  615. $67: DataL1CacheSize := 16;
  616. $68: DataL1CacheSize := 32;
  617. $70: if not (Vendor in [cvCyrix, cvNSC]) then
  618. CodeL1CacheSize := 12; {i micro-ops}
  619. $71: CodeL1CacheSize := 16; {i micro-ops}
  620. $72: CodeL1CacheSize := 32; {i micro-ops}
  621. $78: L2CacheSize := 1024;
  622. $79: L2CacheSize := 128;
  623. $7A: L2CacheSize := 256;
  624. $7B: L2CacheSize := 512;
  625. $7C: L2CacheSize := 1024;
  626. $7D: L2CacheSize := 2048;
  627. $7F: L2CacheSize := 512;
  628. $80: if Vendor in [cvCyrix, cvNSC] then
  629. begin {Cyrix and NSC only - 16 KB unified L1 cache}
  630. CodeL1CacheSize := 8;
  631. DataL1CacheSize := 8;
  632. end;
  633. $82: L2CacheSize := 256;
  634. $83: L2CacheSize := 512;
  635. $84: L2CacheSize := 1024;
  636. $85: L2CacheSize := 2048;
  637. $86: L2CacheSize := 512;
  638. $87: L2CacheSize := 1024;
  639. $D0: L3CacheSize := 512;
  640. $D1: L3CacheSize := 1024;
  641. $D2: L3CacheSize := 2048;
  642. $D6: L3CacheSize := 1024;
  643. $D7: L3CacheSize := 2048;
  644. $D8: L3CacheSize := 4096;
  645. $DC: L3CacheSize := 1536;
  646. $DD: L3CacheSize := 3072;
  647. $DE: L3CacheSize := 6144;
  648. $E2: L3CacheSize := 2048;
  649. $E3: L3CacheSize := 4096;
  650. $E4: L3CacheSize := 8192;
  651. $EA: L3CacheSize := 12288;
  652. $EB: L3CacheSize := 18432;
  653. $EC: L3CacheSize := 24576;
  654. $F0: PrefetchSize := 64;
  655. $F1: PrefetchSize := 128;
  656. end;
  657. end;
  658. Dec(QueryCount);
  659. if (QueryCount > 0) then
  660. GetCPUID(2, CacheDescriptor.Registers);
  661. end;
  662. end;
  663. procedure TCPU.GetExtendedProcessorCacheInfo;
  664. {preconditions: 1. maximum extended CPUID must be at least $80000006
  665. 2. GetCPUVendor and GetCPUFeatures must have been called}
  666. var
  667. Registers: TRegisters;
  668. begin
  669. {call CPUID function $80000005}
  670. GetCPUID($80000005, Registers);
  671. {get L1 cache size}
  672. {Note: Intel does not support function $80000005 for L1 cache size, so ignore.
  673. Cyrix returns CPUID function 2 descriptors (already done), so ignore.}
  674. if not (Vendor in [cvIntel, cvCyrix]) then
  675. begin
  676. CodeL1CacheSize := Registers.EDX shr 24;
  677. DataL1CacheSize := Registers.ECX shr 24;
  678. end;
  679. {call CPUID function $80000006}
  680. GetCPUID($80000006, Registers);
  681. {get L2 cache size}
  682. if (Vendor = cvAMD) and (Signature and $FFF = K7DuronA0Signature) then
  683. {workaround for AMD Duron Rev A0 L2 cache size erratum - see AMD Technical
  684. Note TN-13}
  685. L2CacheSize := 64
  686. else
  687. if (Vendor = cvCentaur) and (ActualFamily = 6) and (ActualModel in [C3Samuel2EffModel, C3EzraEffModel]) then
  688. {handle VIA (Centaur) C3 Samuel 2 and Ezra non-standard encoding}
  689. L2CacheSize := Registers.ECX shr 24
  690. else {standard encoding}
  691. L2CacheSize := Registers.ECX shr 16;
  692. end;
  693. procedure TCPU.VerifyOSSupportForXMMRegisters;
  694. begin
  695. {$if defined(CPUx86) and not defined(PUREPASCAL)}
  696. {try a SSE instruction that operates on XMM registers}
  697. try
  698. asm
  699. DB $0F, $54, $C0 // ANDPS XMM0, XMM0
  700. end
  701. except
  702. {if it fails, assume that none of the SSE instruction sets are available}
  703. Exclude(InstructionSupport, isSSE);
  704. Exclude(InstructionSupport, isSSE2);
  705. Exclude(InstructionSupport, isSSE3);
  706. Exclude(InstructionSupport, isSSSE3);
  707. Exclude(InstructionSupport, isSSE41);
  708. Exclude(InstructionSupport, isSSE42);
  709. Exclude(InstructionSupport, isSSE4A);
  710. end;
  711. {$else}
  712. {do nothing}
  713. {$ifend}
  714. end;
  715. function TCPU.IsXmmYmmOSEnabled: boolean;
  716. {$if not defined(PUREPASCAL)}
  717. asm
  718. {$IFDEF CPUx86}
  719. push ebx
  720. {$ELSE CPUx64}
  721. mov r10, rbx
  722. {$ENDIF}
  723. mov eax, 1
  724. cpuid
  725. bt ecx, 27 // CPUID.1:ECX.OSXSAVE[bit 27] = 1 means that XGETBV is enabled for application use; this also implies XGETBV is an available instruction
  726. jnc @not_supported
  727. xor ecx, ecx //Specify control register XCR0 = XFEATURE_ENABLED_MASK register
  728. db 0Fh, 01h, 0D0h // XGETBV //Reads XCR (extended control register) -> EDX:EAX
  729. // NB: LGDT eax = db 0Fh, 01h = privileged instruction, so don't go here unless XGETBV is allowed/enabled
  730. // CHECK XFEATURE_ENABLED_MASK[2:1] = 11b
  731. and eax, 06h // 06h= 00000000000000000000000000000110b
  732. cmp eax, 06h // check OS has enabled both XMM (bit 1) and YMM (bit 2) state management support
  733. jne @not_supported
  734. mov eax, 1 // Result := True
  735. jmp @out
  736. @not_supported:
  737. xor eax, eax // Result := False
  738. @out:
  739. {$IFDEF CPUx86}
  740. pop ebx
  741. {$ELSE CPUx64}
  742. mov rbx, r10
  743. {$ENDIF}
  744. {$else}
  745. begin
  746. Result := False;
  747. {$ifend}
  748. end;
  749. // http://software.intel.com/en-us/articles/introduction-to-intel-advanced-vector-extensions/
  750. // Necessary to check that IsXmmYmmOSEnabled = true before using AVX, AVX2, FMA, etc. instructions!
  751. procedure TCPU.VerifyOSSupportForYMMRegisters;
  752. begin
  753. if not IsXmmYmmOSEnabled then
  754. Exclude(InstructionSupport, isAVX);
  755. end;
  756. function TCPU.GetVendorName: string;
  757. begin
  758. Result := sVendorNames[Vendor];
  759. end;
  760. class function TCPU.GetVendorName(Vendor: TCPUVendor): string;
  761. begin
  762. Result := sVendorNames[Vendor];
  763. end;
  764. class function TCPU.GetInstructionSetName(InstructionSet: TCPUInstructionSet): string;
  765. begin
  766. Result := sInstructionSetNames[InstructionSet];
  767. end;
  768. class function TCPU.GetCPUInfo: TCPU;
  769. var
  770. Registers: TRegisters;
  771. MaxCPUID: Cardinal;
  772. MaxExCPUID: Cardinal;
  773. begin
  774. {initialize - just to be sure}
  775. Result := Default(TCPU);
  776. // Default synthetic support properties
  777. Result.InstructionSupport := [isPascal, isAssembler];
  778. try
  779. if not IsCPUID_Available then
  780. begin
  781. if IsFPU_Available then
  782. Include(Result.InstructionSupport, isFPU);
  783. end else
  784. begin
  785. {get maximum CPUID input value}
  786. GetCPUID($00000000, Registers);
  787. MaxCPUID:= Registers.EAX;
  788. {get CPU vendor - Max CPUID will always be >= 0}
  789. Result.GetCPUVendor;
  790. {get CPU features if available}
  791. if MaxCPUID >= $00000001 then
  792. Result.GetCPUFeatures;
  793. {get cache info if available}
  794. if MaxCPUID >= $00000002 then
  795. Result.GetProcessorCacheInfo;
  796. if MaxCPUID >= $00000007 then
  797. Result.GetCPUExtendedFeatures7;
  798. {get maximum extended CPUID input value}
  799. GetCPUID($80000000, Registers);
  800. MaxExCPUID:= Registers.EAX;
  801. {get CPU extended features if available}
  802. if MaxExCPUID >= $80000001 then
  803. Result.GetCPUExtendedFeatures;
  804. {verify operating system support for XMM registers}
  805. if isSSE in Result.InstructionSupport then
  806. Result.VerifyOSSupportForXMMRegisters;
  807. { verify operating system support for YMM registers }
  808. if isAVX in Result.InstructionSupport then
  809. Result.VerifyOSSupportForYMMRegisters;
  810. {get extended cache features if available}
  811. {Note: ignore processors that only report L1 cache info,
  812. i.e. have a MaxExCPUID = $80000005}
  813. if MaxExCPUID >= $80000006 then
  814. Result.GetExtendedProcessorCacheInfo;
  815. end;
  816. except
  817. {silent exception - should not occur, just ignore}
  818. end;
  819. end;
  820. end.