cpu.pp 14 KB

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