cpu.pp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547
  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. {$IFDEF FPC_DOTTEDUNITS}
  19. uses
  20. System.SysUtils;
  21. {$ELSE FPC_DOTTEDUNITS}
  22. uses
  23. sysutils;
  24. {$ENDIF FPC_DOTTEDUNITS}
  25. { returns true, if the processor supports the cpuid instruction }
  26. function cpuid_support : boolean;
  27. type
  28. TCpuidResult = record
  29. eax, ebx, ecx, edx: uint32;
  30. end;
  31. function CPUID(in_eax: uint32; in_ecx: uint32 = 0): TCpuidResult; inline;
  32. function CPUBrandString: shortstring;
  33. { returns true, if floating point is done by an emulator }
  34. function floating_point_emulation : boolean;
  35. { returns the contents of the cr0 register }
  36. function cr0 : longint;
  37. function MMXSupport: boolean;inline;
  38. function CMOVSupport: boolean;inline;
  39. function InterlockedCompareExchange128Support: boolean;
  40. function AESSupport: boolean;inline;
  41. function AVXSupport: boolean;inline;
  42. function AVX2Support: boolean;inline;
  43. function AVX512FSupport: boolean;inline;
  44. function AVX512DQSupport: boolean;inline;
  45. function AVX512IFMASupport: boolean;inline;
  46. function AVX512PFSupport: boolean;inline;
  47. function AVX512ERSupport: boolean;inline;
  48. function AVX512CDSupport: boolean;inline;
  49. function AVX512BWSupport: boolean;inline;
  50. function AVX512VLSupport: boolean;inline;
  51. function AVX512VBMISupport: boolean;inline;
  52. function AVX512VBMI2Support: boolean;inline;
  53. function AVX512VNNISupport: boolean;inline;
  54. function VAESSupport: boolean;inline;
  55. function VCLMULSupport: boolean;inline;
  56. function AVX512BITALGSupport: boolean;inline;
  57. function RDSEEDSupport: boolean;inline;
  58. function ADXSupport: boolean;inline;
  59. function SHASupport: boolean;inline;
  60. function FMASupport: boolean;inline;
  61. function POPCNTSupport: boolean;inline;
  62. function LZCNTSupport: boolean;inline;
  63. function SSE3Support: boolean;inline;
  64. function SSSE3Support: boolean;inline;
  65. function SSE41Support: boolean;inline;
  66. function SSE42Support: boolean;inline;
  67. function MOVBESupport: boolean;inline;
  68. function F16CSupport: boolean;inline;
  69. function RDRANDSupport: boolean;inline;
  70. function RTMSupport: boolean;inline;
  71. function BMI1Support: boolean;inline;
  72. function BMI2Support: boolean;inline;
  73. var
  74. is_sse3_cpu : boolean = false;
  75. function InterlockedCompareExchange128(var Target: Int128Rec; NewValue: Int128Rec; Comperand: Int128Rec): Int128Rec;
  76. implementation
  77. {$ASMMODE INTEL}
  78. var
  79. _MMXSupport,
  80. _CMOVSupport,
  81. _AESSupport,
  82. _AVXSupport,
  83. _AVX2Support,
  84. _AVX512FSupport,
  85. _AVX512DQSupport,
  86. _AVX512IFMASupport,
  87. _AVX512PFSupport,
  88. _AVX512ERSupport,
  89. _AVX512CDSupport,
  90. _AVX512BWSupport,
  91. _AVX512VLSupport,
  92. _AVX512VBMISupport,
  93. _AVX512VBMI2Support,
  94. _VAESSupport,
  95. _VCLMULSupport,
  96. _AVX512VNNISupport,
  97. _AVX512BITALGSupport,
  98. _RDSEEDSupport,
  99. _ADXSupport,
  100. _SHASupport,
  101. _FMASupport,
  102. _POPCNTSupport,
  103. _LZCNTSupport,
  104. _SSE3Support,
  105. _SSSE3Support,
  106. _SSE41Support,
  107. _SSE42Support,
  108. _MOVBESupport,
  109. _F16CSupport,
  110. _RDRANDSupport,
  111. _RTMSupport,
  112. _BMI1Support,
  113. _BMI2Support: boolean;
  114. {$ASMMODE ATT}
  115. function InterlockedCompareExchange128(var Target: Int128Rec; NewValue: Int128Rec; Comperand: Int128Rec): Int128Rec;
  116. begin
  117. {$if FPC_FULLVERSION >= 30101}
  118. {$ifndef FPC_PIC}
  119. if _RTMSupport then
  120. begin
  121. asm
  122. {$ifdef USE_REAL_INSTRUCTIONS}
  123. .Lretry:
  124. xbegin .Lretry
  125. {$else}
  126. { 3d: c7 f8 fa ff ff ff xbegin }
  127. .byte 0xc7,0xf8, 0xfa, 0xff, 0xff, 0xff
  128. {$endif}
  129. end;
  130. Result:=Target;
  131. if (Result.Lo=Comperand.Lo) and (Result.Hi=Comperand.Hi) then
  132. Target:=NewValue;
  133. asm
  134. {$ifdef USE_REAL_INSTRUCTIONS}
  135. xend
  136. {$else}
  137. { 8a: 0f 01 d5 xend }
  138. .byte 0x0f, 0x01, 0xd5
  139. {$endif}
  140. end;
  141. end
  142. else
  143. {$endif FPC_PIC}
  144. {$endif FPC_FULLVERSION >= 30101}
  145. RunError(217);
  146. end;
  147. {$ASMMODE INTEL}
  148. function cpuid_support : boolean;assembler;
  149. {
  150. Check if the ID-flag can be changed, if changed then CpuID is supported.
  151. Tested under go32v1 and Linux on c6x86 with CpuID enabled and disabled (PFV)
  152. }
  153. asm
  154. push ebx
  155. pushfd
  156. pushfd
  157. pop eax
  158. mov ebx,eax
  159. xor eax,200000h
  160. push eax
  161. popfd
  162. pushfd
  163. pop eax
  164. popfd
  165. and eax,200000h
  166. and ebx,200000h
  167. cmp eax,ebx
  168. setnz al
  169. pop ebx
  170. end;
  171. procedure CPUID(in_eax: uint32; in_ecx: uint32; out res: TCpuidResult); assembler; nostackframe;
  172. // eax = in_eax, edx = in_ecx, ecx = res
  173. asm
  174. push ebx
  175. push esi
  176. mov esi, ecx // esi = res
  177. mov ecx, edx // ecx = in_ecx
  178. cpuid
  179. mov TCpuidResult.eax[esi], eax
  180. mov TCpuidResult.ebx[esi], ebx
  181. mov TCpuidResult.ecx[esi], ecx
  182. mov TCpuidResult.edx[esi], edx
  183. pop esi
  184. pop ebx
  185. end;
  186. function CPUID(in_eax: uint32; in_ecx: uint32 = 0): TCpuidResult;
  187. begin
  188. CPUID(in_eax, in_ecx, result);
  189. end;
  190. function CPUBrandString: shortstring;
  191. begin
  192. if not cpuid_support or (CPUID($80000000).eax<$80000004) then
  193. exit('');
  194. TCpuidResult(pointer(@result[1])^):=CPUID($80000002);
  195. TCpuidResult(pointer(@result[17])^):=CPUID($80000003);
  196. TCpuidResult(pointer(@result[33])^):=CPUID($80000004);
  197. result[49]:=#0;
  198. result[0]:=chr(length(PAnsiChar(@result[1])));
  199. end;
  200. function cr0 : longint;assembler;
  201. asm
  202. {$ifdef USE_REAL_INSTRUCTIONS}
  203. mov eax,cr0
  204. {$else}
  205. DB 0Fh,20h,0C0h
  206. {$endif}
  207. { mov eax,cr0
  208. special registers are not allowed in the assembler
  209. parsers }
  210. end;
  211. function floating_point_emulation : boolean;
  212. begin
  213. {!!!! I don't know currently the position of the EM flag }
  214. { $4 after Ralf Brown's list }
  215. floating_point_emulation:=(cr0 and $4)<>0;
  216. end;
  217. {$ASMMODE ATT}
  218. function XGETBV(i : dword) : int64;assembler;
  219. asm
  220. movl %eax,%ecx
  221. {$ifdef USE_REAL_INSTRUCTIONS}
  222. xgetbv
  223. {$else}
  224. // older FPCs don't know the xgetbv opcode
  225. .byte 0x0f,0x01,0xd0
  226. {$endif}
  227. end;
  228. procedure SetupSupport;
  229. var
  230. maxcpuidvalue : longint;
  231. cpuid1,cpuid7 : TCpuidResult;
  232. begin
  233. is_sse3_cpu:=false;
  234. if cpuid_support then
  235. begin
  236. maxcpuidvalue:=CPUID(0).eax;
  237. cpuid1:=CPUID(1);
  238. _MMXSupport:=(cpuid1.edx and $800000)<>0;
  239. _CMOVSupport:=(cpuid1.edx and $8000)<>0;
  240. _AESSupport:=(cpuid1.ecx and $2000000)<>0;
  241. _POPCNTSupport:=(cpuid1.ecx and $800000)<>0;
  242. _SSE3Support:=(cpuid1.ecx and $1)<>0;
  243. _SSSE3Support:=(cpuid1.ecx and $200)<>0;
  244. _SSE41Support:=(cpuid1.ecx and $80000)<>0;
  245. _SSE42Support:=(cpuid1.ecx and $100000)<>0;
  246. _MOVBESupport:=(cpuid1.ecx and $400000)<>0;
  247. _F16CSupport:=(cpuid1.ecx and $20000000)<>0;
  248. _RDRANDSupport:=(cpuid1.ecx and $40000000)<>0;
  249. _AVXSupport:=
  250. { XGETBV suspport? }
  251. ((cpuid1.ecx and $08000000)<>0) and
  252. { xmm and ymm state enabled? }
  253. ((XGETBV(0) and %110)=%110) and
  254. { avx supported? }
  255. ((cpuid1.ecx and $10000000)<>0);
  256. is_sse3_cpu:=(cpuid1.ecx and $1)<>0;
  257. _FMASupport:=_AVXSupport and ((cpuid1.ecx and $1000)<>0);
  258. _LZCNTSupport:=(CPUID($80000001).ecx and $20)<>0;
  259. if maxcpuidvalue>=7 then
  260. begin
  261. cpuid7:=CPUID(7);
  262. _AVX2Support:=_AVXSupport and ((cpuid7.ebx and $20)<>0);
  263. _AVX512FSupport:=(cpuid7.ebx and $10000)<>0;
  264. _AVX512DQSupport:=(cpuid7.ebx and $20000)<>0;
  265. _RDSEEDSupport:=(cpuid7.ebx and $40000)<>0;
  266. _ADXSupport:=(cpuid7.ebx and $80000)<>0;
  267. _AVX512IFMASupport:=(cpuid7.ebx and $200000)<>0;
  268. _AVX512PFSupport:=(cpuid7.ebx and $4000000)<>0;
  269. _AVX512ERSupport:=(cpuid7.ebx and $8000000)<>0;
  270. _AVX512CDSupport:=(cpuid7.ebx and $10000000)<>0;
  271. _AVX512BWSupport:=(cpuid7.ebx and $40000000)<>0;
  272. _AVX512VBMISupport:=(cpuid7.ecx and $00000002)<>0;
  273. _AVX512VBMI2Support:=(cpuid7.ecx and $00000040)<>0;
  274. _VAESSupport:=(cpuid7.ecx and $00000200)<>0;
  275. _VCLMULSupport:=(cpuid7.ecx and $00000400)<>0;
  276. _AVX512VNNISupport:=(cpuid7.ecx and $00000800)<>0;
  277. _AVX512BITALGSupport:=(cpuid7.ecx and $00001000)<>0;
  278. _SHASupport:=(cpuid7.ebx and $20000000)<>0;
  279. _AVX512VLSupport:=(cpuid7.ebx and $80000000)<>0;
  280. _BMI1Support:=(cpuid7.ebx and $8)<>0;
  281. _BMI2Support:=(cpuid7.ebx and $100)<>0;
  282. _RTMSupport:=((cpuid7.ebx and $800)<>0) and (cpuid7.edx and (1 shl 11)=0 {RTM_ALWAYS_ABORT});
  283. end;
  284. end;
  285. end;
  286. function InterlockedCompareExchange128Support : boolean;
  287. begin
  288. { 32 Bit CPUs have no 128 Bit interlocked exchange support,
  289. but it can simulated using RTM }
  290. result:=_RTMSupport;
  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.