2
0

cpu.pp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548
  1. {
  2. This file is part of the Free Pascal run time library.
  3. Copyright (c) 1999-2000 by Florian Klaempfl
  4. This unit contains some routines to get informations about the
  5. processor
  6. See the file COPYING.FPC, included in this distribution,
  7. for details about the copyright.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  11. **********************************************************************}
  12. {$mode objfpc}
  13. {$goto on}
  14. {$IFNDEF FPC_DOTTEDUNITS}
  15. unit cpu;
  16. {$ENDIF FPC_DOTTEDUNITS}
  17. interface
  18. { returns true, if the processor supports the cpuid instruction }
  19. function cpuid_support : boolean;
  20. type
  21. TCpuidResult = record
  22. eax, ebx, ecx, edx: uint32;
  23. end;
  24. function CPUID(in_eax: uint32; in_ecx: uint32 = 0): TCpuidResult; inline;
  25. function CPUBrandString: shortstring;
  26. { returns true, if floating point is done by an emulator }
  27. function floating_point_emulation : boolean;
  28. { returns the contents of the cr0 register }
  29. function cr0 : longint;
  30. function TSCSupport: boolean;inline;
  31. function MMXSupport: boolean;inline;
  32. function CMOVSupport: boolean;inline;
  33. function InterlockedCompareExchange128Support: boolean;
  34. function AESSupport: boolean;inline;
  35. function AVXSupport: boolean;inline;
  36. function AVX2Support: boolean;inline;
  37. function AVX512FSupport: boolean;inline;
  38. function AVX512DQSupport: boolean;inline;
  39. function AVX512IFMASupport: boolean;inline;
  40. function AVX512PFSupport: boolean;inline;
  41. function AVX512ERSupport: boolean;inline;
  42. function AVX512CDSupport: boolean;inline;
  43. function AVX512BWSupport: boolean;inline;
  44. function AVX512VLSupport: boolean;inline;
  45. function AVX512VBMISupport: boolean;inline;
  46. function AVX512VBMI2Support: boolean;inline;
  47. function AVX512VNNISupport: boolean;inline;
  48. function VAESSupport: boolean;inline;
  49. function VCLMULSupport: boolean;inline;
  50. function AVX512BITALGSupport: boolean;inline;
  51. function RDSEEDSupport: boolean;inline;
  52. function ADXSupport: boolean;inline;
  53. function SHASupport: boolean;inline;
  54. function FMASupport: boolean;inline;
  55. function POPCNTSupport: boolean;inline;
  56. function LZCNTSupport: boolean;inline;
  57. function SSE3Support: boolean;inline;
  58. function SSSE3Support: boolean;inline;
  59. function SSE41Support: boolean;inline;
  60. function SSE42Support: boolean;inline;
  61. function MOVBESupport: boolean;inline;
  62. function F16CSupport: boolean;inline;
  63. function RDRANDSupport: boolean;inline;
  64. function RTMSupport: boolean;inline;
  65. function BMI1Support: boolean;inline;
  66. function BMI2Support: boolean;inline;
  67. var
  68. is_sse3_cpu : boolean = false;
  69. function InterlockedCompareExchange128(var Target: Int128Rec; NewValue: Int128Rec; Comperand: Int128Rec): Int128Rec;
  70. implementation
  71. {$ASMMODE INTEL}
  72. var
  73. _TSCSupport,
  74. _MMXSupport,
  75. _CMOVSupport,
  76. _AESSupport,
  77. _AVXSupport,
  78. _AVX2Support,
  79. _AVX512FSupport,
  80. _AVX512DQSupport,
  81. _AVX512IFMASupport,
  82. _AVX512PFSupport,
  83. _AVX512ERSupport,
  84. _AVX512CDSupport,
  85. _AVX512BWSupport,
  86. _AVX512VLSupport,
  87. _AVX512VBMISupport,
  88. _AVX512VBMI2Support,
  89. _VAESSupport,
  90. _VCLMULSupport,
  91. _AVX512VNNISupport,
  92. _AVX512BITALGSupport,
  93. _RDSEEDSupport,
  94. _ADXSupport,
  95. _SHASupport,
  96. _FMASupport,
  97. _POPCNTSupport,
  98. _LZCNTSupport,
  99. _SSE3Support,
  100. _SSSE3Support,
  101. _SSE41Support,
  102. _SSE42Support,
  103. _MOVBESupport,
  104. _F16CSupport,
  105. _RDRANDSupport,
  106. _RTMSupport,
  107. _BMI1Support,
  108. _BMI2Support: boolean;
  109. {$ASMMODE ATT}
  110. function InterlockedCompareExchange128(var Target: Int128Rec; NewValue: Int128Rec; Comperand: Int128Rec): Int128Rec;
  111. begin
  112. {$if FPC_FULLVERSION >= 30101}
  113. {$ifndef FPC_PIC}
  114. if _RTMSupport then
  115. begin
  116. asm
  117. {$ifdef USE_REAL_INSTRUCTIONS}
  118. .Lretry:
  119. xbegin .Lretry
  120. {$else}
  121. { 3d: c7 f8 fa ff ff ff xbegin }
  122. .byte 0xc7,0xf8, 0xfa, 0xff, 0xff, 0xff
  123. {$endif}
  124. end;
  125. Result:=Target;
  126. if (Result.Lo=Comperand.Lo) and (Result.Hi=Comperand.Hi) then
  127. Target:=NewValue;
  128. asm
  129. {$ifdef USE_REAL_INSTRUCTIONS}
  130. xend
  131. {$else}
  132. { 8a: 0f 01 d5 xend }
  133. .byte 0x0f, 0x01, 0xd5
  134. {$endif}
  135. end;
  136. end
  137. else
  138. {$endif FPC_PIC}
  139. {$endif FPC_FULLVERSION >= 30101}
  140. RunError(217);
  141. end;
  142. {$ASMMODE INTEL}
  143. function cpuid_support : boolean;assembler;
  144. {
  145. Check if the ID-flag can be changed, if changed then CpuID is supported.
  146. Tested under go32v1 and Linux on c6x86 with CpuID enabled and disabled (PFV)
  147. }
  148. asm
  149. push ebx
  150. pushfd
  151. pushfd
  152. pop eax
  153. mov ebx,eax
  154. xor eax,200000h
  155. push eax
  156. popfd
  157. pushfd
  158. pop eax
  159. popfd
  160. and eax,200000h
  161. and ebx,200000h
  162. cmp eax,ebx
  163. setnz al
  164. pop ebx
  165. end;
  166. procedure CPUID(in_eax: uint32; in_ecx: uint32; out res: TCpuidResult); assembler; nostackframe;
  167. // eax = in_eax, edx = in_ecx, ecx = res
  168. asm
  169. push ebx
  170. push esi
  171. mov esi, ecx // esi = res
  172. mov ecx, edx // ecx = in_ecx
  173. cpuid
  174. mov TCpuidResult.eax[esi], eax
  175. mov TCpuidResult.ebx[esi], ebx
  176. mov TCpuidResult.ecx[esi], ecx
  177. mov TCpuidResult.edx[esi], edx
  178. pop esi
  179. pop ebx
  180. end;
  181. function CPUID(in_eax: uint32; in_ecx: uint32 = 0): TCpuidResult;
  182. begin
  183. CPUID(in_eax, in_ecx, result);
  184. end;
  185. function CPUBrandString: shortstring;
  186. begin
  187. if not cpuid_support or (CPUID($80000000).eax<$80000004) then
  188. exit('');
  189. TCpuidResult(pointer(@result[1])^):=CPUID($80000002);
  190. TCpuidResult(pointer(@result[17])^):=CPUID($80000003);
  191. TCpuidResult(pointer(@result[33])^):=CPUID($80000004);
  192. result[49]:=#0;
  193. result[0]:=chr(length(PAnsiChar(@result[1])));
  194. end;
  195. function cr0 : longint;assembler;
  196. asm
  197. {$ifdef USE_REAL_INSTRUCTIONS}
  198. mov eax,cr0
  199. {$else}
  200. DB 0Fh,20h,0C0h
  201. {$endif}
  202. { mov eax,cr0
  203. special registers are not allowed in the assembler
  204. parsers }
  205. end;
  206. function floating_point_emulation : boolean;
  207. begin
  208. {!!!! I don't know currently the position of the EM flag }
  209. { $4 after Ralf Brown's list }
  210. floating_point_emulation:=(cr0 and $4)<>0;
  211. end;
  212. {$ASMMODE ATT}
  213. function XGETBV(i : dword) : int64;assembler;
  214. asm
  215. movl %eax,%ecx
  216. {$ifdef USE_REAL_INSTRUCTIONS}
  217. xgetbv
  218. {$else}
  219. // older FPCs don't know the xgetbv opcode
  220. .byte 0x0f,0x01,0xd0
  221. {$endif}
  222. end;
  223. procedure SetupSupport;
  224. var
  225. maxcpuidvalue : longint;
  226. cpuid1,cpuid7 : TCpuidResult;
  227. begin
  228. is_sse3_cpu:=false;
  229. if cpuid_support then
  230. begin
  231. maxcpuidvalue:=CPUID(0).eax;
  232. cpuid1:=CPUID(1);
  233. _TSCSupport:=(cpuid1.edx and $10)<>0;
  234. _MMXSupport:=(cpuid1.edx and $800000)<>0;
  235. _CMOVSupport:=(cpuid1.edx and $8000)<>0;
  236. _AESSupport:=(cpuid1.ecx and $2000000)<>0;
  237. _POPCNTSupport:=(cpuid1.ecx and $800000)<>0;
  238. _SSE3Support:=(cpuid1.ecx and $1)<>0;
  239. _SSSE3Support:=(cpuid1.ecx and $200)<>0;
  240. _SSE41Support:=(cpuid1.ecx and $80000)<>0;
  241. _SSE42Support:=(cpuid1.ecx and $100000)<>0;
  242. _MOVBESupport:=(cpuid1.ecx and $400000)<>0;
  243. _F16CSupport:=(cpuid1.ecx and $20000000)<>0;
  244. _RDRANDSupport:=(cpuid1.ecx and $40000000)<>0;
  245. _AVXSupport:=
  246. { XGETBV suspport? }
  247. ((cpuid1.ecx and $08000000)<>0) and
  248. { xmm and ymm state enabled? }
  249. ((XGETBV(0) and %110)=%110) and
  250. { avx supported? }
  251. ((cpuid1.ecx and $10000000)<>0);
  252. is_sse3_cpu:=(cpuid1.ecx and $1)<>0;
  253. _FMASupport:=_AVXSupport and ((cpuid1.ecx and $1000)<>0);
  254. _LZCNTSupport:=(CPUID($80000001).ecx and $20)<>0;
  255. if maxcpuidvalue>=7 then
  256. begin
  257. cpuid7:=CPUID(7);
  258. _AVX2Support:=_AVXSupport and ((cpuid7.ebx and $20)<>0);
  259. _AVX512FSupport:=(cpuid7.ebx and $10000)<>0;
  260. _AVX512DQSupport:=(cpuid7.ebx and $20000)<>0;
  261. _RDSEEDSupport:=(cpuid7.ebx and $40000)<>0;
  262. _ADXSupport:=(cpuid7.ebx and $80000)<>0;
  263. _AVX512IFMASupport:=(cpuid7.ebx and $200000)<>0;
  264. _AVX512PFSupport:=(cpuid7.ebx and $4000000)<>0;
  265. _AVX512ERSupport:=(cpuid7.ebx and $8000000)<>0;
  266. _AVX512CDSupport:=(cpuid7.ebx and $10000000)<>0;
  267. _AVX512BWSupport:=(cpuid7.ebx and $40000000)<>0;
  268. _AVX512VBMISupport:=(cpuid7.ecx and $00000002)<>0;
  269. _AVX512VBMI2Support:=(cpuid7.ecx and $00000040)<>0;
  270. _VAESSupport:=(cpuid7.ecx and $00000200)<>0;
  271. _VCLMULSupport:=(cpuid7.ecx and $00000400)<>0;
  272. _AVX512VNNISupport:=(cpuid7.ecx and $00000800)<>0;
  273. _AVX512BITALGSupport:=(cpuid7.ecx and $00001000)<>0;
  274. _SHASupport:=(cpuid7.ebx and $20000000)<>0;
  275. _AVX512VLSupport:=(cpuid7.ebx and $80000000)<>0;
  276. _BMI1Support:=(cpuid7.ebx and $8)<>0;
  277. _BMI2Support:=(cpuid7.ebx and $100)<>0;
  278. _RTMSupport:=((cpuid7.ebx and $800)<>0) and (cpuid7.edx and (1 shl 11)=0 {RTM_ALWAYS_ABORT});
  279. end;
  280. end;
  281. end;
  282. function InterlockedCompareExchange128Support : boolean;
  283. begin
  284. { 32 Bit CPUs have no 128 Bit interlocked exchange support,
  285. but it can simulated using RTM }
  286. result:=_RTMSupport;
  287. end;
  288. function TSCSupport: boolean;
  289. begin
  290. result:=_TSCSupport;
  291. end;
  292. function MMXSupport: boolean;
  293. begin
  294. result:=_MMXSupport;
  295. end;
  296. function CMOVSupport : boolean;
  297. begin
  298. result:=_CMOVSupport;
  299. end;
  300. function AESSupport : boolean;
  301. begin
  302. result:=_AESSupport;
  303. end;
  304. function AVXSupport: boolean;inline;
  305. begin
  306. result:=_AVXSupport;
  307. end;
  308. function AVX2Support: boolean;inline;
  309. begin
  310. result:=_AVX2Support;
  311. end;
  312. function AVX512FSupport: boolean;inline;
  313. begin
  314. result:=_AVX512FSupport;
  315. end;
  316. function AVX512DQSupport: boolean;inline;
  317. begin
  318. result:=_AVX512DQSupport;
  319. end;
  320. function AVX512IFMASupport: boolean;inline;
  321. begin
  322. result:=_AVX512IFMASupport;
  323. end;
  324. function AVX512PFSupport: boolean;inline;
  325. begin
  326. result:=_AVX512PFSupport;
  327. end;
  328. function AVX512ERSupport: boolean;inline;
  329. begin
  330. result:=_AVX512ERSupport;
  331. end;
  332. function AVX512CDSupport: boolean;inline;
  333. begin
  334. result:=_AVX512CDSupport;
  335. end;
  336. function AVX512BWSupport: boolean;inline;
  337. begin
  338. result:=_AVX512BWSupport;
  339. end;
  340. function AVX512VLSupport: boolean;inline;
  341. begin
  342. result:=_AVX512VLSupport;
  343. end;
  344. function AVX512VBMISupport: boolean;inline;
  345. begin
  346. result:=_AVX512VBMISupport;
  347. end;
  348. function AVX512VBMI2Support: boolean;inline;
  349. begin
  350. result:=_AVX512VBMI2Support;
  351. end;
  352. function VAESSupport: boolean;inline;
  353. begin
  354. result:=_VAESSupport;
  355. end;
  356. function VCLMULSupport: boolean;inline;
  357. begin
  358. result:=_VCLMULSupport;
  359. end;
  360. function AVX512VNNISupport: boolean;inline;
  361. begin
  362. result:=_AVX512VNNISupport;
  363. end;
  364. function AVX512BITALGSupport: boolean;inline;
  365. begin
  366. result:=_AVX512BITALGSupport;
  367. end;
  368. function RDSEEDSupport: boolean;inline;
  369. begin
  370. result:=_RDSEEDSupport;
  371. end;
  372. function ADXSupport: boolean;inline;
  373. begin
  374. result:=_ADXSupport;
  375. end;
  376. function SHASupport: boolean;inline;
  377. begin
  378. result:=_SHASupport;
  379. end;
  380. function FMASupport: boolean;inline;
  381. begin
  382. result:=_FMASupport;
  383. end;
  384. function POPCNTSupport: boolean;inline;
  385. begin
  386. result:=_POPCNTSupport;
  387. end;
  388. function LZCNTSupport: boolean;inline;
  389. begin
  390. result:=_LZCNTSupport;
  391. end;
  392. function SSE3Support: boolean;inline;
  393. begin
  394. result:=_SSE3Support;
  395. end;
  396. function SSSE3Support: boolean;inline;
  397. begin
  398. result:=_SSSE3Support;
  399. end;
  400. function SSE41Support: boolean;inline;
  401. begin
  402. result:=_SSE41Support;
  403. end;
  404. function SSE42Support: boolean;inline;
  405. begin
  406. result:=_SSE42Support;
  407. end;
  408. function MOVBESupport: boolean;inline;
  409. begin
  410. result:=_MOVBESupport;
  411. end;
  412. function F16CSupport: boolean;inline;
  413. begin
  414. result:=_F16CSupport;
  415. end;
  416. function RDRANDSupport: boolean;inline;
  417. begin
  418. result:=_RDRANDSupport;
  419. end;
  420. function RTMSupport: boolean;inline;
  421. begin
  422. result:=_RTMSupport;
  423. end;
  424. function BMI1Support: boolean;inline;
  425. begin
  426. result:=_BMI1Support;
  427. end;
  428. function BMI2Support: boolean;inline;
  429. begin
  430. result:=_BMI2Support;
  431. end;
  432. begin
  433. SetupSupport;
  434. end.