1 /*
2 * cpuinfo.cc --
3 *
4 * Provides information about the processor
5 *
6 * Copyright (c) 2001 The Regents of the University of California.
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions are met:
11 *
12 * A. Redistributions of source code must retain the above copyright notice,
13 * this list of conditions and the following disclaimer.
14 * B. Redistributions in binary form must reproduce the above copyright notice,
15 * this list of conditions and the following disclaimer in the documentation
16 * and/or other materials provided with the distribution.
17 * C. Neither the names of the copyright holders nor the names of its
18 * contributors may be used to endorse or promote products derived from this
19 * software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS
22 * IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
23 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
24 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
25 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 * POSSIBILITY OF SUCH DAMAGE.
32 *
33 * $Header: /usr/mash/src/repository/mash/mash-1/misc/cpuinfo.cc,v 1.5 2004/05/12 21:44:18 aswan Exp $
34 */
35
36 #include <iostream>
37 using namespace std;
38
39 #include "cpuinfo.h"
40 #ifdef WIN32
41 #include<excpt.h>
42 #endif
43
44 // #define ALLOW_UNIX_EXCEPTIONS
45
46 bool supportsMMX()// returns true if MMX supported, false otherwise
47 {
48 unsigned int a=CpuInfo::get();
49 return ((a&FLAG_MMX)?true:false);
50 }
51
52 bool supportsSIMD() // returns true if SIMD can be used (hardware&OS), false otherwise
53 {
54 unsigned int a=CpuInfo::get();
55 return (((a&FLAG_SIMD)&&(a&FLAG_SIMD_OS))?true:false);
56 }
57
58 #ifdef TEST_EXECUTE
59 int textexec();
60 #endif
61
62 CpuInfo cpuinfo();
63 bool CpuInfo::configured=false;
64 unsigned int CpuInfo::flags=0;
65
66 void getCpuInfo(unsigned int&);
67
68 CpuInfo::CpuInfo() { //: TclClass( (const char *)"CpuInfo") {
69 name("CpuInfo");
70 if(!configured) {
71 getCpuInfo(flags);
72 configured=true;
73 #ifdef TEST_EXECUTE
74 textexec();
75 #endif
76 }
77 }
78
79 unsigned int CpuInfo::get() {
80 if(configured) {
81 return flags;
82 }
83 else {
84 getCpuInfo(flags);
85 configured=true;
86 #ifdef TEST_EXECUTE
87 textexec();
88 #endif
89 return flags;
90 }
91 }
92
93 int CpuInfo::command(int argc, const char*const* argv)
94 {
95 if (argc == 2) {
96 Tcl& tcl = Tcl::instance();
97 char* cp = tcl.buffer();
98 if (strcmp(argv[1], "mmx") == 0 ) {
99 if( (flags&FLAG_MMX) ) {
100 strcpy(cp, "true");
101 }
102 else {
103 strcpy(cp, "false");
104 }
105 }
106 else if( strcmp(argv[1], "simd") == 0 ) {
107 if( ((flags&FLAG_SIMD)&&(flags&FLAG_SIMD_OS)) ) {
108 strcpy(cp, "true");
109 }
110 else {
111 strcpy(cp, "false");
112 }
113 }
114 else if( strcmp(argv[1], "processor") == 0 ) {
115 if( flags&FLAG_INTEL ) {
116 strcpy(cp, "intel");
117 }
118 else {
119 strcpy(cp, "non-intel");
120 }
121 }
122 else return (TclObject::command(argc, argv));
123 tcl.result(cp);
124 return (TCL_OK);
125 }
126 else return (TclObject::command(argc, argv));
127 }
128
129 #ifdef X86_ASSEMBLER
130 // this function can only really detect 486 and later processors
131 void getCpuInfo(unsigned int&flags)
132 {
133 flags=0;
134 int a=-1;
135 int line1=-1;
136 int line2=-1;
137 int line3=-1;
138 #ifdef WIN32
139 _try {
140 __asm {
141 mov eax, 0
142 cpuid
143 mov [a], eax
144 mov [line1], ebx
145 mov [line2], ecx
146 mov [line3], edx
147 }
148 }
149 _except( EXCEPTION_EXECUTE_HANDLER ) {
150 cout << "exception cpuid code is " << _exception_code() << endl;
151 return;
152 }
153 #else
154
155 #ifdef ALLOW_UNIX_EXCEPTIONS
156 try {
157 #endif
158 a=0;
159 __asm__ __volatile__(
160 "cpuid"
161 : "=a" (a), "=b" (line1), "=c" (line2), "=d" (line3)
162 : "a" (a) );
163 #ifdef ALLOW_UNIX_EXCEPTIONS
164 }
165 catch( ... ) { // exception e // cout << e.what() << endl;
166 cout << "caught cpuid exception" << endl;
167 return;
168 }
169 #endif
170
171 #endif
172
173 // "GenuineIntel" ==> 0x47656e75696e65496e74656c
174 if(line1!=0x756e6547 || line2!=0x6c65746e || line3!=0x49656e69) {
175 return;
176 }
177 flags|=FLAG_INTEL; // received intel chip
178
179 if(a<1) {
180 return; // can't check family or MMX bit
181 }
182
183 #ifdef WIN32
184 __asm {
185 mov eax, 1
186 cpuid
187 mov [a], eax // processor type, family, model, stepping [res,type,fam,mod,stepping]
188 mov [line1], edx // feature flags (intel table 5)
189 }
190 #else
191 a=1;
192 __asm__ __volatile__(
193 "cpuid"
194 : "=a" (a), "=d" (line1)
195 : "a" (a) );
196 #endif
197 // highest 18 bits undefined and reserved
198 // processor type is bits 12-13
199 // family is 8-11
200 // model 4-7
201 // stepping 0-3
202 if( /*family*/ ((a>>8)&0xf)==4 /*0100*/ ) {
203 int model=((a>>4)&0xf);
204 switch(model) {
205 case 0: case 1: // 486DX
206 case 2: // 486SX
207 case 3: // 487, 486DX2
208 case 4: // 486SL
209 case 5: // 486SX2
210 case 7: // 486DX2 write-back enhanced
211 case 8: // 486DX4
212 default: // unknown
213 flags|=FLAG_I486;
214 break;
215 }
216 }
217 else if( /*family*/ ((a>>8)&0xf)==5 /*0101*/ ) {
218 int model=((a>>4)&0xf);
219 switch(model) {
220 case 1: // Pentium 60,66Mhz (may be overdrive 60,66)
221 case 2: // Pentium 75-200Mhz (may be overdrive 75-133)
222 case 3: // Pentium Overdrive for 486-based systems
223 case 4: // Pentium with MMX (166,200Mhz) (may be overdrive 75-133)
224 default: // unknown
225 flags|=FLAG_I586;
226 break;
227 }
228 }
229 else if( /*family*/ ((a>>8)&0xf)==6 /*0110*/) {
230 int model=((a>>4)&0xf);
231 switch(model) {
232 case 1: // Pentium Pro
233 case 3: // Pentium II model 3 (or Pentium Pro overdrive)
234 case 5: // Pentium II model 5 or Celeron
235 default:
236 flags|=FLAG_I686;
237 break;
238 }
239 }
240 else {
241 // unknown intel family
242 if( ((a>>8)&0xf)>6 ) { // assuming newer families have 686 capabilities
243 flags|=FLAG_I686;
244 }
245 }
246 if( (line1>>23)&0x1 ) { // bit 23 is mmx
247 flags|=FLAG_MMX;
248 }
249 if( (line1>>25)&0x1 ) { // bit 25 is simd
250 flags|=FLAG_SIMD;
251 #ifndef OLD_ASM
252 // if assembler supports simd instructions, then try executing an operation
253 #ifdef WIN32
254 _try {
255 __asm xorps xmm0, xmm0; Streaming SIMD Extension
256 }
257 _except( EXCEPTION_EXECUTE_HANDLER ) {
258 cout << "simd exception code is " << _exception_code() << endl;
259 return;
260 }
261 #else
262 // using 'a' just to keep the compiler happy
263 #ifdef ALLOW_UNIX_EXCEPTIONS
264 try {
265 #endif
266 __asm__ __volatile__(
267 "xorps %%xmm0, %%xmm0"
268 : "=a" (a)
269 : "a" (a) );
270 #ifdef ALLOW_UNIX_EXCEPTIONS
271 }
272 catch(...) {
273 cout << "caught xorps exception" << endl;
274 return;
275 }
276 #endif
277 #endif
278 flags|=FLAG_SIMD_OS;
279 #endif
280 }
281 }
282 #else
283 void getCpuInfo(unsigned int&flags)
284 {
285 flags=0;
286 }
287 #endif
288
289 #if defined(TEST_MAIN) || defined(TEST_EXECUTE)
290
291 #ifdef TEST_MAIN
292 int main(int argc, char*argv[])
293 #else
294 int textexec()
295 #endif
296 {
297 unsigned int a=CpuInfo::get();
298 cout << ((a&FLAG_INTEL)?"intel chip":"non-intel chip") << endl;
299 cout << (((a&FLAG_FAMILY_MASK)==FLAG_I086)?"086 chip":"non-086 chip") << endl;
300 cout << (((a&FLAG_FAMILY_MASK)==FLAG_I286)?"286 chip":"non-286 chip") << endl;
301 cout << (((a&FLAG_FAMILY_MASK)==FLAG_I386)?"386 chip":"non-386 chip") << endl;
302 cout << (((a&FLAG_FAMILY_MASK)==FLAG_I486)?"486 chip":"non-486 chip") << endl;
303 cout << (((a&FLAG_FAMILY_MASK)==FLAG_I586)?"586 chip":"non-586 chip") << endl;
304 cout << (((a&FLAG_FAMILY_MASK)==FLAG_I686)?"686 chip":"non-686 chip") << endl;
305 cout << ((a&FLAG_MMX)?"MMX chip":"non-MMX chip") << endl;
306 cout << ((a&FLAG_SIMD)?"SIMD chip":"non-SIMD chip") << endl;
307 cout << ((a&FLAG_SIMD_OS)?"SIMD OS":"non-SIMD OS") << endl;
308
309 cout << "MMX supported=" << supportsMMX() << endl;
310 cout << "SIMD supported=" << supportsSIMD() << endl;
311 return 0;
312 }
313 #endif
314
315 CpuInfoClass cic;
316
This page was automatically generated by the
LXR engine.
Visit the LXR main site for more
information.