1 /** 2 * Identify the characteristics of the host CPU. 3 * 4 * Implemented according to: 5 6 - AP-485 Intel(C) Processor Identification and the CPUID Instruction 7 $(LINK http://www.intel.com/design/xeon/applnots/241618.htm) 8 9 - Intel(R) 64 and IA-32 Architectures Software Developer's Manual, Volume 2A: Instruction Set Reference, A-M 10 $(LINK http://developer.intel.com/design/pentium4/manuals/index_new.htm) 11 12 - AMD CPUID Specification Publication # 25481 13 $(LINK http://www.amd.com/us-en/assets/content_type/white_papers_and_tech_docs/25481.pdf) 14 15 Example: 16 --- 17 import std.cpuid; 18 import std.stdio; 19 20 void main() 21 { 22 writefln(std.cpuid.toString()); 23 } 24 --- 25 26 AUTHORS: Tomas Lindquist Olsen <tomas@famolsen.dk> 27 (slightly altered by Walter Bright) 28 COPYRIGHT: Public Domain 29 30 * BUGS: Only works on x86 CPUs 31 * 32 * Macros: 33 * WIKI = Phobos/StdCpuid 34 * COPYRIGHT = Public Domain 35 */ 36 37 /* 38 * Modified by Sean Kelly <sean@f4.ca> for use with Tango. 39 */ 40 41 module rt.compiler.util.cpuid; 42 43 private import tango.stdc.string : strlen; 44 45 version(D_InlineAsm_X86) 46 { 47 /// Returns vendor string 48 char[] vendor() {return vendorStr;} 49 /// Returns processor string 50 char[] processor() {return processorStr;} 51 52 /// Is MMX supported? 53 bool mmx() {return (flags&MMX_BIT)!=0;} 54 /// Is FXSR supported? 55 bool fxsr() {return (flags&FXSR_BIT)!=0;} 56 /// Is SSE supported? 57 bool sse() {return (flags&SSE_BIT)!=0;} 58 /// Is SSE2 supported? 59 bool sse2() {return (flags&SSE2_BIT)!=0;} 60 /// Is SSE3 supported? 61 bool sse3() {return (misc&SSE3_BIT)!=0;} 62 /// Is SSSE3 supported? 63 bool ssse3() {return (misc&SSSE3_BIT)!=0;} 64 65 /// Is AMD 3DNOW supported? 66 bool amd3dnow() {return (exflags&AMD_3DNOW_BIT)!=0;} 67 /// Is AMD 3DNOW Ext supported? 68 bool amd3dnowExt() {return (exflags&AMD_3DNOW_EXT_BIT)!=0;} 69 /// Is AMD MMX supported? 70 bool amdMmx() {return (exflags&AMD_MMX_BIT)!=0;} 71 72 /// Is this an Intel Architecture IA64? 73 bool ia64() {return (flags&IA64_BIT)!=0;} 74 /// Is this an AMD 64? 75 bool amd64() {return (exflags&AMD64_BIT)!=0;} 76 77 /// Is hyperthreading supported? 78 bool hyperThreading() {return (flags&HTT_BIT)!=0;} 79 /// Returns number of threads per CPU 80 uint threadsPerCPU() {return maxThreads;} 81 /// Returns number of cores in CPU 82 uint coresPerCPU() {return maxCores;} 83 84 /// Is this an Intel processor? 85 bool intel() {return manufac==INTEL;} 86 /// Is this an AMD processor? 87 bool amd() {return manufac==AMD;} 88 89 /// Returns stepping 90 uint stepping() {return _stepping;} 91 /// Returns model 92 uint model() {return _model;} 93 /// Returns family 94 uint family() {return _family;} 95 //uint processorType() {return (signature>>>12)&0x3;} 96 97 static this() 98 { 99 getVendorString(); 100 getProcessorString(); 101 getFeatureFlags(); 102 103 // stepping / family / model 104 _stepping = signature&0xF; 105 uint fbase = (signature>>>8)&0xF; 106 uint fex = (signature>>>20)&0xFF; 107 uint mbase = (signature>>>4)&0xF; 108 uint mex = (signature>>>16)&0xF; 109 110 // vendor specific 111 void function() threadFn; 112 switch(vendorStr) 113 { 114 case "GenuineIntel": 115 manufac = INTEL; 116 threadFn = &getThreadingIntel; 117 if (fbase == 0xF) 118 _family = fbase+fex; 119 else 120 _family = fbase; 121 if (_family == 0x6 || _family == 0xF) 122 _model = mbase+(mex<<4); 123 else 124 _model = mbase; 125 break; 126 127 case "AuthenticAMD": 128 manufac = AMD; 129 threadFn = &getThreadingAMD; 130 if (fbase < 0xF) 131 { 132 _family = fbase; 133 _model = mbase; 134 } 135 else 136 { 137 _family = fbase+fex; 138 _model = mbase+(mex<<4); 139 } 140 break; 141 142 default: 143 manufac = OTHER; 144 } 145 146 // threading details 147 if (hyperThreading && threadFn !is null) 148 { 149 threadFn(); 150 } 151 } 152 153 private: 154 // feature flags 155 enum : uint 156 { 157 MMX_BIT = 1<<23, 158 FXSR_BIT = 1<<24, 159 SSE_BIT = 1<<25, 160 SSE2_BIT = 1<<26, 161 HTT_BIT = 1<<28, 162 IA64_BIT = 1<<30 163 } 164 // feature flags misc 165 enum : uint 166 { 167 SSE3_BIT = 1, 168 SSSE3_BIT = 1<<9 169 } 170 // extended feature flags 171 enum : uint 172 { 173 AMD_MMX_BIT = 1<<22, 174 AMD64_BIT = 1<<29, 175 AMD_3DNOW_EXT_BIT = 1<<30, 176 AMD_3DNOW_BIT = 1<<31 177 } 178 // manufacturer 179 enum 180 { 181 OTHER, 182 INTEL, 183 AMD 184 } 185 186 uint flags, misc, exflags, apic, signature; 187 uint _stepping, _model, _family; 188 189 char[12] vendorStr = ""; 190 char[] processorStr = ""; 191 192 uint maxThreads=1; 193 uint maxCores=1; 194 uint manufac=OTHER; 195 196 /* ** 197 * fetches the cpu vendor string 198 */ 199 private void getVendorString() 200 { 201 char* dst = vendorStr.ptr; 202 // puts the vendor string into dst 203 asm 204 { 205 mov EAX, 0 ; 206 cpuid ; 207 mov EAX, dst ; 208 mov [EAX], EBX ; 209 mov [EAX+4], EDX ; 210 mov [EAX+8], ECX ; 211 } 212 } 213 214 private void getProcessorString() 215 { 216 char[48] buffer; 217 char* dst = buffer.ptr; 218 // puts the processor string into dst 219 asm 220 { 221 mov EAX, 0x8000_0000 ; 222 cpuid ; 223 cmp EAX, 0x8000_0004 ; 224 jb PSLabel ; // no support 225 push EDI ; 226 mov EDI, dst ; 227 mov EAX, 0x8000_0002 ; 228 cpuid ; 229 mov [EDI], EAX ; 230 mov [EDI+4], EBX ; 231 mov [EDI+8], ECX ; 232 mov [EDI+12], EDX ; 233 mov EAX, 0x8000_0003 ; 234 cpuid ; 235 mov [EDI+16], EAX ; 236 mov [EDI+20], EBX ; 237 mov [EDI+24], ECX ; 238 mov [EDI+28], EDX ; 239 mov EAX, 0x8000_0004 ; 240 cpuid ; 241 mov [EDI+32], EAX ; 242 mov [EDI+36], EBX ; 243 mov [EDI+40], ECX ; 244 mov [EDI+44], EDX ; 245 pop EDI ; 246 PSLabel: ; 247 } 248 249 if (buffer[0] == char.init) // no support 250 return; 251 252 // seems many intel processors prepend whitespace 253 processorStr = strip(toString(dst)).dup; 254 } 255 256 private void getFeatureFlags() 257 { 258 uint f,m,e,a,s; 259 asm 260 { 261 mov EAX, 0 ; 262 cpuid ; 263 cmp EAX, 1 ; 264 jb FeatLabel ; // no support 265 mov EAX, 1 ; 266 cpuid ; 267 mov f, EDX ; 268 mov m, ECX ; 269 mov a, EBX ; 270 mov s, EAX ; 271 272 FeatLabel: ; 273 mov EAX, 0x8000_0000 ; 274 cpuid ; 275 cmp EAX, 0x8000_0001 ; 276 jb FeatLabel2 ; // no support 277 mov EAX, 0x8000_0001 ; 278 cpuid ; 279 mov e, EDX ; 280 281 FeatLabel2: 282 ; 283 } 284 flags = f; 285 misc = m; 286 exflags = e; 287 apic = a; 288 signature = s; 289 } 290 291 private void getThreadingIntel() 292 { 293 uint n; 294 ubyte b = 0; 295 asm 296 { 297 mov EAX, 0 ; 298 cpuid ; 299 cmp EAX, 4 ; 300 jb IntelSingle ; 301 mov EAX, 4 ; 302 mov ECX, 0 ; 303 cpuid ; 304 mov n, EAX ; 305 mov b, 1 ; 306 IntelSingle: ; 307 } 308 if (b != 0) 309 { 310 maxCores = ((n>>>26)&0x3F)+1; 311 maxThreads = (apic>>>16)&0xFF; 312 } 313 else 314 { 315 maxCores = maxThreads = 1; 316 } 317 } 318 319 private void getThreadingAMD() 320 { 321 ubyte n; 322 ubyte b = 0; 323 asm 324 { 325 mov EAX, 0x8000_0000 ; 326 cpuid ; 327 cmp EAX, 0x8000_0008 ; 328 jb AMDSingle ; 329 mov EAX, 0x8000_0008 ; 330 cpuid ; 331 mov n, CL ; 332 mov b, 1 ; 333 AMDSingle: ; 334 } 335 if (b != 0) 336 { 337 maxCores = n+1; 338 maxThreads = (apic>>>16)&0xFF; 339 } 340 else 341 { 342 maxCores = maxThreads = 1; 343 } 344 } 345 346 /*************************************************************************** 347 * Support code for above, from std.string and std.ctype 348 ***************************************************************************/ 349 350 private 351 { 352 enum 353 { 354 _SPC = 8, 355 _CTL = 0x20, 356 _BLK = 0x40, 357 _HEX = 0x80, 358 _UC = 1, 359 _LC = 2, 360 _PNC = 0x10, 361 _DIG = 4, 362 _ALP = _UC|_LC, 363 } 364 365 ubyte _ctype[128] = 366 [ 367 _CTL,_CTL,_CTL,_CTL,_CTL,_CTL,_CTL,_CTL, 368 _CTL,_CTL|_SPC,_CTL|_SPC,_CTL|_SPC,_CTL|_SPC,_CTL|_SPC,_CTL,_CTL, 369 _CTL,_CTL,_CTL,_CTL,_CTL,_CTL,_CTL,_CTL, 370 _CTL,_CTL,_CTL,_CTL,_CTL,_CTL,_CTL,_CTL, 371 _SPC|_BLK,_PNC,_PNC,_PNC,_PNC,_PNC,_PNC,_PNC, 372 _PNC,_PNC,_PNC,_PNC,_PNC,_PNC,_PNC,_PNC, 373 _DIG|_HEX,_DIG|_HEX,_DIG|_HEX,_DIG|_HEX,_DIG|_HEX, 374 _DIG|_HEX,_DIG|_HEX,_DIG|_HEX,_DIG|_HEX,_DIG|_HEX, 375 _PNC,_PNC,_PNC,_PNC,_PNC,_PNC, 376 _PNC,_UC|_HEX,_UC|_HEX,_UC|_HEX,_UC|_HEX,_UC|_HEX,_UC|_HEX,_UC, 377 _UC,_UC,_UC,_UC,_UC,_UC,_UC,_UC, 378 _UC,_UC,_UC,_UC,_UC,_UC,_UC,_UC, 379 _UC,_UC,_UC,_PNC,_PNC,_PNC,_PNC,_PNC, 380 _PNC,_LC|_HEX,_LC|_HEX,_LC|_HEX,_LC|_HEX,_LC|_HEX,_LC|_HEX,_LC, 381 _LC,_LC,_LC,_LC,_LC,_LC,_LC,_LC, 382 _LC,_LC,_LC,_LC,_LC,_LC,_LC,_LC, 383 _LC,_LC,_LC,_PNC,_PNC,_PNC,_PNC,_CTL 384 ]; 385 386 /** 387 * Returns !=0 if c is a space, tab, vertical tab, form feed, 388 * carriage return, or linefeed. 389 */ 390 int isspace(dchar c) { return (c <= 0x7F) ? _ctype[c] & (_SPC) : 0; } 391 392 /***************************************** 393 * Strips leading or trailing whitespace, or both. 394 */ 395 char[] stripl(char[] s) 396 { 397 uint i; 398 399 for (i = 0; i < s.length; i++) 400 { 401 if (!isspace(s[i])) 402 break; 403 } 404 return s[i .. s.length]; 405 } 406 407 char[] stripr(char[] s) /// ditto 408 { 409 uint i; 410 411 for (i = s.length; i > 0; i--) 412 { 413 if (!isspace(s[i - 1])) 414 break; 415 } 416 return s[0 .. i]; 417 } 418 419 char[] strip(char[] s) /// ditto 420 { 421 return stripr(stripl(s)); 422 } 423 424 char[] toString(char *s) 425 { 426 return s ? s[0 .. strlen(s)] : cast(char[])null; 427 } 428 } 429 } 430 else 431 { 432 char[] vendor() {return "unknown vendor"; } 433 char[] processor() {return "unknown processor"; } 434 435 bool mmx() {return false; } 436 bool fxsr() {return false; } 437 bool sse() {return false; } 438 bool sse2() {return false; } 439 bool sse3() {return false; } 440 bool ssse3() {return false; } 441 442 bool amd3dnow() {return false; } 443 bool amd3dnowExt() {return false; } 444 bool amdMmx() {return false; } 445 446 bool ia64() {return false; } 447 bool amd64() {return false; } 448 449 bool hyperThreading() {return false; } 450 uint threadsPerCPU() {return 0; } 451 uint coresPerCPU() {return 0; } 452 453 bool intel() {return false; } 454 bool amd() {return false; } 455 456 uint stepping() {return 0; } 457 uint model() {return 0; } 458 uint family() {return 0; } 459 }