/** * Identify the characteristics of the host CPU. * * Implemented according to: - AP-485 Intel(C) Processor Identification and the CPUID Instruction $(LINK http://www.intel.com/design/xeon/applnots/241618.htm) - Intel(R) 64 and IA-32 Architectures Software Developer's Manual, Volume 2A: Instruction Set Reference, A-M $(LINK http://developer.intel.com/design/pentium4/manuals/index_new.htm) - AMD CPUID Specification Publication # 25481 $(LINK http://www.amd.com/us-en/assets/content_type/white_papers_and_tech_docs/25481.pdf) Example: --- import std.cpuid; import std.stdio; void main() { writefln(std.cpuid.toString()); } --- AUTHORS: Tomas Lindquist Olsen <tomas@famolsen.dk> (slightly altered by Walter Bright) COPYRIGHT: Public Domain * BUGS: Only works on x86 CPUs * * Macros: * WIKI = Phobos/StdCpuid * COPYRIGHT = Public Domain */ module std.cpuid; import std.string; version(D_InlineAsm_X86) { /// Returns everything as a printable string string toString() { string feats; if (mmx) feats ~= "MMX "; if (fxsr) feats ~= "FXSR "; if (sse) feats ~= "SSE "; if (sse2) feats ~= "SSE2 "; if (sse3) feats ~= "SSE3 "; if (ssse3) feats ~= "SSSE3 "; if (amd3dnow) feats ~= "3DNow! "; if (amd3dnowExt) feats ~= "3DNow!+ "; if (amdMmx) feats ~= "MMX+ "; if (ia64) feats ~= "IA-64 "; if (amd64) feats ~= "AMD64 "; if (hyperThreading) feats ~= "HTT"; return format( "Vendor string: %s\n", vendor, "Processor string: %s\n", processor, "Signature: Family=%d Model=%d Stepping=%d\n", family, model, stepping, "Features: %s\n", feats, "Multithreading: %d threads / %d cores\n", threadsPerCPU, coresPerCPU); } /// Returns vendor string string vendor() {return vendorStr;} /// Returns processor string string processor() {return processorStr;} /// Is MMX supported? bool mmx() {return (flags&MMX_BIT)!=0;} /// Is FXSR supported? bool fxsr() {return (flags&FXSR_BIT)!=0;} /// Is SSE supported? bool sse() {return (flags&SSE_BIT)!=0;} /// Is SSE2 supported? bool sse2() {return (flags&SSE2_BIT)!=0;} /// Is SSE3 supported? bool sse3() {return (misc&SSE3_BIT)!=0;} /// Is SSSE3 supported? bool ssse3() {return (misc&SSSE3_BIT)!=0;} /// Is AMD 3DNOW supported? bool amd3dnow() {return (exflags&AMD_3DNOW_BIT)!=0;} /// Is AMD 3DNOW Ext supported? bool amd3dnowExt() {return (exflags&AMD_3DNOW_EXT_BIT)!=0;} /// Is AMD MMX supported? bool amdMmx() {return (exflags&AMD_MMX_BIT)!=0;} /// Is this an Intel Architecture IA64? bool ia64() {return (flags&IA64_BIT)!=0;} /// Is this an AMD 64? bool amd64() {return (exflags&AMD64_BIT)!=0;} /// Is hyperthreading supported? bool hyperThreading() {return (flags&HTT_BIT)!=0;} /// Returns number of threads per CPU uint threadsPerCPU() {return maxThreads;} /// Returns number of cores in CPU uint coresPerCPU() {return maxCores;} /// Is this an Intel processor? bool intel() {return manufac==INTEL;} /// Is this an AMD processor? bool amd() {return manufac==AMD;} /// Returns stepping uint stepping() {return _stepping;} /// Returns model uint model() {return _model;} /// Returns family uint family() {return _family;} //uint processorType() {return (signature>>>12)&0x3;} static this() { getVendorString(); getProcessorString(); getFeatureFlags(); // stepping / family / model _stepping = signature&0xF; uint fbase = (signature>>>8)&0xF; uint fex = (signature>>>20)&0xFF; uint mbase = (signature>>>4)&0xF; uint mex = (signature>>>16)&0xF; // vendor specific void function() threadFn; switch(vendorStr) { case "GenuineIntel": manufac = INTEL; threadFn = &getThreadingIntel; if (fbase == 0xF) _family = fbase+fex; else _family = fbase; if (_family == 0x6 || _family == 0xF) _model = mbase+(mex<<4); else _model = mbase; break; case "AuthenticAMD": manufac = AMD; threadFn = &getThreadingAMD; if (fbase < 0xF) { _family = fbase; _model = mbase; } else { _family = fbase+fex; _model = mbase+(mex<<4); } break; default: manufac = OTHER; } // threading details if (hyperThreading && threadFn !is null) { threadFn(); } } private: // feature flags enum : uint { MMX_BIT = 1<<23, FXSR_BIT = 1<<24, SSE_BIT = 1<<25, SSE2_BIT = 1<<26, HTT_BIT = 1<<28, IA64_BIT = 1<<30 } // feature flags misc enum : uint { SSE3_BIT = 1, SSSE3_BIT = 1<<9 } // extended feature flags enum : uint { AMD_MMX_BIT = 1<<22, AMD64_BIT = 1<<29, AMD_3DNOW_EXT_BIT = 1<<30, AMD_3DNOW_BIT = 1<<31 } // manufacturer enum { OTHER, INTEL, AMD } uint flags, misc, exflags, apic, signature; uint _stepping, _model, _family; char[12] vendorStr = 0; string processorStr = ""; uint maxThreads=1; uint maxCores=1; uint manufac=OTHER; /* ** * fetches the cpu vendor string */ private void getVendorString() { char* dst = vendorStr.ptr; // puts the vendor string into dst asm { mov EAX, 0 ; cpuid ; mov EAX, dst ; mov [EAX], EBX ; mov [EAX+4], EDX ; mov [EAX+8], ECX ; } } private void getProcessorString() { char[48] buffer; char* dst = buffer.ptr; // puts the processor string into dst asm { mov EAX, 0x8000_0000 ; cpuid ; cmp EAX, 0x8000_0004 ; jb PSLabel ; // no support push EDI ; mov EDI, dst ; mov EAX, 0x8000_0002 ; cpuid ; mov [EDI], EAX ; mov [EDI+4], EBX ; mov [EDI+8], ECX ; mov [EDI+12], EDX ; mov EAX, 0x8000_0003 ; cpuid ; mov [EDI+16], EAX ; mov [EDI+20], EBX ; mov [EDI+24], ECX ; mov [EDI+28], EDX ; mov EAX, 0x8000_0004 ; cpuid ; mov [EDI+32], EAX ; mov [EDI+36], EBX ; mov [EDI+40], ECX ; mov [EDI+44], EDX ; pop EDI ; PSLabel: ; } if (buffer[0] == char.init) // no support return; // seems many intel processors prepend whitespace processorStr = std.string.strip(std.string.toString(dst)).dup; } private void getFeatureFlags() { uint f,m,e,a,s; asm { mov EAX, 0 ; cpuid ; cmp EAX, 1 ; jb FeatLabel ; // no support mov EAX, 1 ; cpuid ; mov f, EDX ; mov m, ECX ; mov a, EBX ; mov s, EAX ; FeatLabel: ; mov EAX, 0x8000_0000 ; cpuid ; cmp EAX, 0x8000_0001 ; jb FeatLabel2 ; // no support mov EAX, 0x8000_0001 ; cpuid ; mov e, EDX ; FeatLabel2: ; } flags = f; misc = m; exflags = e; apic = a; signature = s; } private void getThreadingIntel() { uint n; ubyte b = 0; asm { mov EAX, 0 ; cpuid ; cmp EAX, 4 ; jb IntelSingle ; mov EAX, 4 ; mov ECX, 0 ; cpuid ; mov n, EAX ; mov b, 1 ; IntelSingle: ; } if (b != 0) { maxCores = ((n>>>26)&0x3F)+1; maxThreads = (apic>>>16)&0xFF; } else { maxCores = maxThreads = 1; } } private void getThreadingAMD() { ubyte n; ubyte b = 0; asm { mov EAX, 0x8000_0000 ; cpuid ; cmp EAX, 0x8000_0008 ; jb AMDSingle ; mov EAX, 0x8000_0008 ; cpuid ; mov n, CL ; mov b, 1 ; AMDSingle: ; } if (b != 0) { maxCores = n+1; maxThreads = (apic>>>16)&0xFF; } else { maxCores = maxThreads = 1; } } } else { char[] toString() { return "unknown CPU\n"; } char[] vendor() {return "unknown vendor"; } char[] processor() {return "unknown processor"; } bool mmx() {return false; } bool fxsr() {return false; } bool sse() {return false; } bool sse2() {return false; } bool sse3() {return false; } bool ssse3() {return false; } bool amd3dnow() {return false; } bool amd3dnowExt() {return false; } bool amdMmx() {return false; } bool ia64() {return false; } bool amd64() {return false; } bool hyperThreading() {return false; } uint threadsPerCPU() {return 0; } uint coresPerCPU() {return 0; } bool intel() {return false; } bool amd() {return false; } uint stepping() {return 0; } uint model() {return 0; } uint family() {return 0; } }