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 }