cpu.pp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484
  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 SHA512Support: boolean;inline;
  55. function FMASupport: boolean;inline;
  56. function POPCNTSupport: boolean;inline;
  57. function LZCNTSupport: boolean;inline;
  58. function SSE3Support: boolean;inline;
  59. function SSSE3Support: boolean;inline;
  60. function SSE41Support: boolean;inline;
  61. function SSE42Support: boolean;inline;
  62. function MOVBESupport: boolean;inline;
  63. function F16CSupport: boolean;inline;
  64. function RDRANDSupport: boolean;inline;
  65. function RTMSupport: boolean;inline;
  66. function BMI1Support: boolean;inline;
  67. function BMI2Support: boolean;inline;
  68. var
  69. is_sse3_cpu : boolean = false;
  70. function InterlockedCompareExchange128(var Target: Int128Rec; NewValue: Int128Rec; Comperand: Int128Rec): Int128Rec;
  71. implementation
  72. {$ASMMODE INTEL}
  73. var
  74. data: record
  75. cpuid1, cpuid7_0, cpuid7_1: TCpuidResult;
  76. AVXSupport,
  77. LZCNTSupport: boolean;
  78. end;
  79. {$ASMMODE ATT}
  80. function InterlockedCompareExchange128(var Target: Int128Rec; NewValue: Int128Rec; Comperand: Int128Rec): Int128Rec;
  81. begin
  82. {$if FPC_FULLVERSION >= 30101}
  83. {$ifndef FPC_PIC}
  84. if RTMSupport then
  85. begin
  86. asm
  87. {$ifdef USE_REAL_INSTRUCTIONS}
  88. .Lretry:
  89. xbegin .Lretry
  90. {$else}
  91. { 3d: c7 f8 fa ff ff ff xbegin }
  92. .byte 0xc7,0xf8, 0xfa, 0xff, 0xff, 0xff
  93. {$endif}
  94. end;
  95. Result:=Target;
  96. if (Result.Lo=Comperand.Lo) and (Result.Hi=Comperand.Hi) then
  97. Target:=NewValue;
  98. asm
  99. {$ifdef USE_REAL_INSTRUCTIONS}
  100. xend
  101. {$else}
  102. { 8a: 0f 01 d5 xend }
  103. .byte 0x0f, 0x01, 0xd5
  104. {$endif}
  105. end;
  106. end
  107. else
  108. {$endif FPC_PIC}
  109. {$endif FPC_FULLVERSION >= 30101}
  110. RunError(217);
  111. end;
  112. {$ASMMODE INTEL}
  113. function cpuid_support : boolean;assembler;
  114. {
  115. Check if the ID-flag can be changed, if changed then CpuID is supported.
  116. Tested under go32v1 and Linux on c6x86 with CpuID enabled and disabled (PFV)
  117. }
  118. asm
  119. push ebx
  120. pushfd
  121. pushfd
  122. pop eax
  123. mov ebx,eax
  124. xor eax,200000h
  125. push eax
  126. popfd
  127. pushfd
  128. pop eax
  129. popfd
  130. and eax,200000h
  131. and ebx,200000h
  132. cmp eax,ebx
  133. setnz al
  134. pop ebx
  135. end;
  136. procedure CPUID(in_eax: uint32; in_ecx: uint32; out res: TCpuidResult); assembler; nostackframe;
  137. // eax = in_eax, edx = in_ecx, ecx = res
  138. asm
  139. push ebx
  140. push esi
  141. mov esi, ecx // esi = res
  142. mov ecx, edx // ecx = in_ecx
  143. cpuid
  144. mov TCpuidResult.eax[esi], eax
  145. mov TCpuidResult.ebx[esi], ebx
  146. mov TCpuidResult.ecx[esi], ecx
  147. mov TCpuidResult.edx[esi], edx
  148. pop esi
  149. pop ebx
  150. end;
  151. function CPUID(in_eax: uint32; in_ecx: uint32 = 0): TCpuidResult;
  152. begin
  153. CPUID(in_eax, in_ecx, result);
  154. end;
  155. function CPUBrandString: shortstring;
  156. begin
  157. if not cpuid_support or (CPUID($80000000).eax<$80000004) then
  158. exit('');
  159. TCpuidResult(pointer(@result[1])^):=CPUID($80000002);
  160. TCpuidResult(pointer(@result[17])^):=CPUID($80000003);
  161. TCpuidResult(pointer(@result[33])^):=CPUID($80000004);
  162. result[49]:=#0;
  163. result[0]:=chr(length(PAnsiChar(@result[1])));
  164. end;
  165. function cr0 : longint;assembler;
  166. asm
  167. {$ifdef USE_REAL_INSTRUCTIONS}
  168. mov eax,cr0
  169. {$else}
  170. DB 0Fh,20h,0C0h
  171. {$endif}
  172. { mov eax,cr0
  173. special registers are not allowed in the assembler
  174. parsers }
  175. end;
  176. function floating_point_emulation : boolean;
  177. begin
  178. {!!!! I don't know currently the position of the EM flag }
  179. { $4 after Ralf Brown's list }
  180. floating_point_emulation:=(cr0 and $4)<>0;
  181. end;
  182. {$ASMMODE ATT}
  183. function XGETBV(i : dword) : int64;assembler;
  184. asm
  185. movl %eax,%ecx
  186. {$ifdef USE_REAL_INSTRUCTIONS}
  187. xgetbv
  188. {$else}
  189. // older FPCs don't know the xgetbv opcode
  190. .byte 0x0f,0x01,0xd0
  191. {$endif}
  192. end;
  193. procedure SetupSupport;
  194. var
  195. maxcpuidvalue : longint;
  196. begin
  197. if cpuid_support then
  198. begin
  199. maxcpuidvalue:=CPUID(0).eax;
  200. CPUID(1, 0, data.cpuid1);
  201. if maxcpuidvalue>=7 then
  202. begin
  203. CPUID(7, 0, data.cpuid7_0);
  204. CPUID(7, 1, data.cpuid7_1);
  205. end;
  206. is_sse3_cpu:=(data.cpuid1.ecx and (1 shl 0))<>0;
  207. data.AVXSupport:=
  208. { cpuid(1).ecx[27]: XGETBV support, cpuid(1).ecx[28]: AVX support }
  209. (data.cpuid1.ecx shr 27 and %11=%11) and
  210. { xmm and ymm state enabled? }
  211. ((XGETBV(0) and %110)=%110);
  212. data.LZCNTSupport:=(CPUID($80000001).ecx and (1 shl 5))<>0;
  213. end;
  214. end;
  215. function InterlockedCompareExchange128Support : boolean;
  216. begin
  217. { 32 Bit CPUs have no 128 Bit interlocked exchange support,
  218. but it can simulated using RTM }
  219. result:=RTMSupport;
  220. end;
  221. function TSCSupport: boolean;
  222. begin
  223. result:=(data.cpuid1.edx and (1 shl 4))<>0;
  224. end;
  225. function MMXSupport: boolean;
  226. begin
  227. result:=(data.cpuid1.edx and (1 shl 23))<>0;
  228. end;
  229. function CMOVSupport : boolean;
  230. begin
  231. result:=(data.cpuid1.edx and (1 shl 15))<>0;
  232. end;
  233. function AESSupport : boolean;
  234. begin
  235. result:=(data.cpuid1.ecx and (1 shl 25))<>0;
  236. end;
  237. function AVXSupport: boolean;inline;
  238. begin
  239. result:=data.AVXSupport;
  240. end;
  241. function AVX2Support: boolean;inline;
  242. begin
  243. result:=data.AVXSupport and ((data.cpuid7_0.ebx and (1 shl 5))<>0);
  244. end;
  245. function AVX512FSupport: boolean;inline;
  246. begin
  247. result:=(data.cpuid7_0.ebx and (1 shl 16))<>0;
  248. end;
  249. function AVX512DQSupport: boolean;inline;
  250. begin
  251. result:=(data.cpuid7_0.ebx and (1 shl 17))<>0;
  252. end;
  253. function AVX512IFMASupport: boolean;inline;
  254. begin
  255. result:=(data.cpuid7_0.ebx and (1 shl 21))<>0;
  256. end;
  257. function AVX512PFSupport: boolean;inline;
  258. begin
  259. result:=(data.cpuid7_0.ebx and (1 shl 26))<>0;
  260. end;
  261. function AVX512ERSupport: boolean;inline;
  262. begin
  263. result:=(data.cpuid7_0.ebx and (1 shl 27))<>0;
  264. end;
  265. function AVX512CDSupport: boolean;inline;
  266. begin
  267. result:=(data.cpuid7_0.ebx and (1 shl 28))<>0;
  268. end;
  269. function AVX512BWSupport: boolean;inline;
  270. begin
  271. result:=(data.cpuid7_0.ebx and (1 shl 30))<>0;
  272. end;
  273. function AVX512VLSupport: boolean;inline;
  274. begin
  275. result:=(data.cpuid7_0.ebx and (1 shl 31))<>0;
  276. end;
  277. function AVX512VBMISupport: boolean;inline;
  278. begin
  279. result:=(data.cpuid7_0.ecx and (1 shl 1))<>0;
  280. end;
  281. function AVX512VBMI2Support: boolean;inline;
  282. begin
  283. result:=(data.cpuid7_0.ecx and (1 shl 6))<>0;
  284. end;
  285. function VAESSupport: boolean;inline;
  286. begin
  287. result:=(data.cpuid7_0.ecx and (1 shl 9))<>0;
  288. end;
  289. function VCLMULSupport: boolean;inline;
  290. begin
  291. result:=(data.cpuid7_0.ecx and (1 shl 10))<>0;
  292. end;
  293. function AVX512VNNISupport: boolean;inline;
  294. begin
  295. result:=(data.cpuid7_0.ecx and (1 shl 11))<>0;
  296. end;
  297. function AVX512BITALGSupport: boolean;inline;
  298. begin
  299. result:=(data.cpuid7_0.ecx and (1 shl 12))<>0;
  300. end;
  301. function RDSEEDSupport: boolean;inline;
  302. begin
  303. result:=(data.cpuid7_0.ebx and (1 shl 18))<>0;
  304. end;
  305. function ADXSupport: boolean;inline;
  306. begin
  307. result:=(data.cpuid7_0.ebx and (1 shl 19))<>0;
  308. end;
  309. function SHASupport: boolean;inline;
  310. begin
  311. result:=(data.cpuid7_0.ebx and (1 shl 29))<>0;
  312. end;
  313. function SHA512Support: boolean;inline;
  314. begin
  315. result:=(data.cpuid7_1.eax and 1)<>0;
  316. end;
  317. function FMASupport: boolean;inline;
  318. begin
  319. result:=data.AVXSupport and ((data.cpuid1.ecx and (1 shl 12))<>0);
  320. end;
  321. function POPCNTSupport: boolean;inline;
  322. begin
  323. result:=(data.cpuid1.ecx and (1 shl 23))<>0;
  324. end;
  325. function LZCNTSupport: boolean;inline;
  326. begin
  327. result:=data.LZCNTSupport;
  328. end;
  329. function SSE3Support: boolean;inline;
  330. begin
  331. result:=(data.cpuid1.ecx and (1 shl 0))<>0;
  332. end;
  333. function SSSE3Support: boolean;inline;
  334. begin
  335. result:=(data.cpuid1.ecx and (1 shl 9))<>0;
  336. end;
  337. function SSE41Support: boolean;inline;
  338. begin
  339. result:=(data.cpuid1.ecx and (1 shl 19))<>0;
  340. end;
  341. function SSE42Support: boolean;inline;
  342. begin
  343. result:=(data.cpuid1.ecx and (1 shl 20))<>0;
  344. end;
  345. function MOVBESupport: boolean;inline;
  346. begin
  347. result:=(data.cpuid1.ecx and (1 shl 22))<>0;
  348. end;
  349. function F16CSupport: boolean;inline;
  350. begin
  351. result:=(data.cpuid1.ecx and (1 shl 29))<>0;
  352. end;
  353. function RDRANDSupport: boolean;inline;
  354. begin
  355. result:=(data.cpuid1.ecx and (1 shl 30))<>0;
  356. end;
  357. function RTMSupport: boolean;inline;
  358. begin
  359. result:=((data.cpuid7_0.ebx and (1 shl 11))<>0) and (data.cpuid7_0.edx and (1 shl 11)=0 {RTM_ALWAYS_ABORT});
  360. end;
  361. function BMI1Support: boolean;inline;
  362. begin
  363. result:=(data.cpuid7_0.ebx and (1 shl 3))<>0;
  364. end;
  365. function BMI2Support: boolean;inline;
  366. begin
  367. result:=(data.cpuid7_0.ebx and (1 shl 8))<>0;
  368. end;
  369. begin
  370. SetupSupport;
  371. end.