Mercurial > mplayer.hg
comparison cpudetect.c @ 32335:fdf3f93c2828
Move some code around to avoid forward declarations in top-level .c files.
author | diego |
---|---|
date | Fri, 01 Oct 2010 18:29:35 +0000 |
parents | f3aed7bffcbb |
children | 5e3f013bf4c2 |
comparison
equal
deleted
inserted
replaced
32334:541a774ce8e4 | 32335:fdf3f93c2828 |
---|---|
52 * team for SSE support detection and more cpu detect code. | 52 * team for SSE support detection and more cpu detect code. |
53 */ | 53 */ |
54 | 54 |
55 /* I believe this code works. However, it has only been used on a PII and PIII */ | 55 /* I believe this code works. However, it has only been used on a PII and PIII */ |
56 | 56 |
57 static void check_os_katmai_support( void ); | |
58 | |
59 // return TRUE if cpuid supported | |
60 static int has_cpuid(void) | |
61 { | |
62 // code from libavcodec: | |
63 #if ARCH_X86_64 | |
64 return 1; | |
65 #else | |
66 long a, c; | |
67 __asm__ volatile ( | |
68 /* See if CPUID instruction is supported ... */ | |
69 /* ... Get copies of EFLAGS into eax and ecx */ | |
70 "pushfl\n\t" | |
71 "pop %0\n\t" | |
72 "mov %0, %1\n\t" | |
73 | |
74 /* ... Toggle the ID bit in one copy and store */ | |
75 /* to the EFLAGS reg */ | |
76 "xor $0x200000, %0\n\t" | |
77 "push %0\n\t" | |
78 "popfl\n\t" | |
79 | |
80 /* ... Get the (hopefully modified) EFLAGS */ | |
81 "pushfl\n\t" | |
82 "pop %0\n\t" | |
83 : "=a" (a), "=c" (c) | |
84 : | |
85 : "cc" | |
86 ); | |
87 | |
88 return a != c; | |
89 #endif | |
90 } | |
91 | |
92 void | |
93 do_cpuid(unsigned int ax, unsigned int *p) | |
94 { | |
95 // code from libavcodec: | |
96 __asm__ volatile | |
97 ("mov %%"REG_b", %%"REG_S"\n\t" | |
98 "cpuid\n\t" | |
99 "xchg %%"REG_b", %%"REG_S | |
100 : "=a" (p[0]), "=S" (p[1]), | |
101 "=c" (p[2]), "=d" (p[3]) | |
102 : "0" (ax)); | |
103 } | |
104 | |
105 void GetCpuCaps( CpuCaps *caps) | |
106 { | |
107 unsigned int regs[4]; | |
108 unsigned int regs2[4]; | |
109 | |
110 memset(caps, 0, sizeof(*caps)); | |
111 caps->isX86=1; | |
112 caps->cl_size=32; /* default */ | |
113 if (!has_cpuid()) { | |
114 mp_msg(MSGT_CPUDETECT,MSGL_WARN,"CPUID not supported!??? (maybe an old 486?)\n"); | |
115 return; | |
116 } | |
117 do_cpuid(0x00000000, regs); // get _max_ cpuid level and vendor name | |
118 mp_msg(MSGT_CPUDETECT,MSGL_V,"CPU vendor name: %.4s%.4s%.4s max cpuid level: %d\n", | |
119 (char*) (regs+1),(char*) (regs+3),(char*) (regs+2), regs[0]); | |
120 if (regs[0]>=0x00000001) | |
121 { | |
122 char *tmpstr, *ptmpstr; | |
123 unsigned cl_size; | |
124 | |
125 do_cpuid(0x00000001, regs2); | |
126 | |
127 caps->cpuType=(regs2[0] >> 8)&0xf; | |
128 caps->cpuModel=(regs2[0] >> 4)&0xf; | |
129 | |
130 // see AMD64 Architecture Programmer's Manual, Volume 3: General-purpose and | |
131 // System Instructions, Table 3-2: Effective family computation, page 120. | |
132 if(caps->cpuType==0xf){ | |
133 // use extended family (P4, IA64, K8) | |
134 caps->cpuType=0xf+((regs2[0]>>20)&255); | |
135 } | |
136 if(caps->cpuType==0xf || caps->cpuType==6) | |
137 caps->cpuModel |= ((regs2[0]>>16)&0xf) << 4; | |
138 | |
139 caps->cpuStepping=regs2[0] & 0xf; | |
140 | |
141 // general feature flags: | |
142 caps->hasTSC = (regs2[3] & (1 << 8 )) >> 8; // 0x0000010 | |
143 caps->hasMMX = (regs2[3] & (1 << 23 )) >> 23; // 0x0800000 | |
144 caps->hasSSE = (regs2[3] & (1 << 25 )) >> 25; // 0x2000000 | |
145 caps->hasSSE2 = (regs2[3] & (1 << 26 )) >> 26; // 0x4000000 | |
146 caps->hasSSE3 = (regs2[2] & 1); // 0x0000001 | |
147 caps->hasSSSE3 = (regs2[2] & (1 << 9 )) >> 9; // 0x0000200 | |
148 caps->hasMMX2 = caps->hasSSE; // SSE cpus supports mmxext too | |
149 cl_size = ((regs2[1] >> 8) & 0xFF)*8; | |
150 if(cl_size) caps->cl_size = cl_size; | |
151 | |
152 ptmpstr=tmpstr=GetCpuFriendlyName(regs, regs2); | |
153 while(*ptmpstr == ' ') // strip leading spaces | |
154 ptmpstr++; | |
155 mp_msg(MSGT_CPUDETECT,MSGL_V,"CPU: %s ", ptmpstr); | |
156 free(tmpstr); | |
157 mp_msg(MSGT_CPUDETECT,MSGL_V,"(Family: %d, Model: %d, Stepping: %d)\n", | |
158 caps->cpuType, caps->cpuModel, caps->cpuStepping); | |
159 | |
160 } | |
161 do_cpuid(0x80000000, regs); | |
162 if (regs[0]>=0x80000001) { | |
163 mp_msg(MSGT_CPUDETECT,MSGL_V,"extended cpuid-level: %d\n",regs[0]&0x7FFFFFFF); | |
164 do_cpuid(0x80000001, regs2); | |
165 caps->hasMMX |= (regs2[3] & (1 << 23 )) >> 23; // 0x0800000 | |
166 caps->hasMMX2 |= (regs2[3] & (1 << 22 )) >> 22; // 0x400000 | |
167 caps->has3DNow = (regs2[3] & (1 << 31 )) >> 31; //0x80000000 | |
168 caps->has3DNowExt = (regs2[3] & (1 << 30 )) >> 30; | |
169 caps->hasSSE4a = (regs2[2] & (1 << 6 )) >> 6; // 0x0000040 | |
170 } | |
171 if(regs[0]>=0x80000006) | |
172 { | |
173 do_cpuid(0x80000006, regs2); | |
174 mp_msg(MSGT_CPUDETECT,MSGL_V,"extended cache-info: %d\n",regs2[2]&0x7FFFFFFF); | |
175 caps->cl_size = regs2[2] & 0xFF; | |
176 } | |
177 mp_msg(MSGT_CPUDETECT,MSGL_V,"Detected cache-line size is %u bytes\n",caps->cl_size); | |
178 #if 0 | |
179 mp_msg(MSGT_CPUDETECT,MSGL_INFO,"cpudetect: MMX=%d MMX2=%d SSE=%d SSE2=%d 3DNow=%d 3DNowExt=%d\n", | |
180 gCpuCaps.hasMMX, | |
181 gCpuCaps.hasMMX2, | |
182 gCpuCaps.hasSSE, | |
183 gCpuCaps.hasSSE2, | |
184 gCpuCaps.has3DNow, | |
185 gCpuCaps.has3DNowExt); | |
186 #endif | |
187 | |
188 /* FIXME: Does SSE2 need more OS support, too? */ | |
189 if (caps->hasSSE) | |
190 check_os_katmai_support(); | |
191 if (!caps->hasSSE) | |
192 caps->hasSSE2 = 0; | |
193 // caps->has3DNow=1; | |
194 // caps->hasMMX2 = 0; | |
195 // caps->hasMMX = 0; | |
196 | |
197 #if !CONFIG_RUNTIME_CPUDETECT | |
198 #if !HAVE_MMX | |
199 if(caps->hasMMX) mp_msg(MSGT_CPUDETECT,MSGL_WARN,"MMX supported but disabled\n"); | |
200 caps->hasMMX=0; | |
201 #endif | |
202 #if !HAVE_MMX2 | |
203 if(caps->hasMMX2) mp_msg(MSGT_CPUDETECT,MSGL_WARN,"MMX2 supported but disabled\n"); | |
204 caps->hasMMX2=0; | |
205 #endif | |
206 #if !HAVE_SSE | |
207 if(caps->hasSSE) mp_msg(MSGT_CPUDETECT,MSGL_WARN,"SSE supported but disabled\n"); | |
208 caps->hasSSE=0; | |
209 #endif | |
210 #if !HAVE_SSE2 | |
211 if(caps->hasSSE2) mp_msg(MSGT_CPUDETECT,MSGL_WARN,"SSE2 supported but disabled\n"); | |
212 caps->hasSSE2=0; | |
213 #endif | |
214 #if !HAVE_AMD3DNOW | |
215 if(caps->has3DNow) mp_msg(MSGT_CPUDETECT,MSGL_WARN,"3DNow supported but disabled\n"); | |
216 caps->has3DNow=0; | |
217 #endif | |
218 #if !HAVE_AMD3DNOWEXT | |
219 if(caps->has3DNowExt) mp_msg(MSGT_CPUDETECT,MSGL_WARN,"3DNowExt supported but disabled\n"); | |
220 caps->has3DNowExt=0; | |
221 #endif | |
222 #endif // CONFIG_RUNTIME_CPUDETECT | |
223 } | |
224 | |
225 char *GetCpuFriendlyName(unsigned int regs[], unsigned int regs2[]){ | |
226 char vendor[13]; | |
227 char *retname; | |
228 int i; | |
229 | |
230 if (NULL==(retname=malloc(256))) { | |
231 mp_msg(MSGT_CPUDETECT,MSGL_FATAL,"Error: GetCpuFriendlyName() not enough memory\n"); | |
232 exit(1); | |
233 } | |
234 retname[0] = '\0'; | |
235 | |
236 sprintf(vendor,"%.4s%.4s%.4s",(char*)(regs+1),(char*)(regs+3),(char*)(regs+2)); | |
237 | |
238 do_cpuid(0x80000000,regs); | |
239 if (regs[0] >= 0x80000004) | |
240 { | |
241 // CPU has built-in namestring | |
242 for (i = 0x80000002; i <= 0x80000004; i++) | |
243 { | |
244 do_cpuid(i, regs); | |
245 strncat(retname, (char*)regs, 16); | |
246 } | |
247 } | |
248 return retname; | |
249 } | |
250 | |
251 #if defined(__linux__) && defined(_POSIX_SOURCE) && !ARCH_X86_64 | 57 #if defined(__linux__) && defined(_POSIX_SOURCE) && !ARCH_X86_64 |
252 static void sigill_handler_sse( int signal, struct sigcontext sc ) | 58 static void sigill_handler_sse( int signal, struct sigcontext sc ) |
253 { | 59 { |
254 mp_msg(MSGT_CPUDETECT,MSGL_V, "SIGILL, " ); | 60 mp_msg(MSGT_CPUDETECT,MSGL_V, "SIGILL, " ); |
255 | 61 |
413 */ | 219 */ |
414 mp_msg(MSGT_CPUDETECT,MSGL_WARN, "Cannot test OS support for SSE, leaving disabled.\n" ); | 220 mp_msg(MSGT_CPUDETECT,MSGL_WARN, "Cannot test OS support for SSE, leaving disabled.\n" ); |
415 gCpuCaps.hasSSE=0; | 221 gCpuCaps.hasSSE=0; |
416 #endif /* __linux__ */ | 222 #endif /* __linux__ */ |
417 } | 223 } |
224 | |
225 | |
226 // return TRUE if cpuid supported | |
227 static int has_cpuid(void) | |
228 { | |
229 // code from libavcodec: | |
230 #if ARCH_X86_64 | |
231 return 1; | |
232 #else | |
233 long a, c; | |
234 __asm__ volatile ( | |
235 /* See if CPUID instruction is supported ... */ | |
236 /* ... Get copies of EFLAGS into eax and ecx */ | |
237 "pushfl\n\t" | |
238 "pop %0\n\t" | |
239 "mov %0, %1\n\t" | |
240 | |
241 /* ... Toggle the ID bit in one copy and store */ | |
242 /* to the EFLAGS reg */ | |
243 "xor $0x200000, %0\n\t" | |
244 "push %0\n\t" | |
245 "popfl\n\t" | |
246 | |
247 /* ... Get the (hopefully modified) EFLAGS */ | |
248 "pushfl\n\t" | |
249 "pop %0\n\t" | |
250 : "=a" (a), "=c" (c) | |
251 : | |
252 : "cc" | |
253 ); | |
254 | |
255 return a != c; | |
256 #endif | |
257 } | |
258 | |
259 void | |
260 do_cpuid(unsigned int ax, unsigned int *p) | |
261 { | |
262 // code from libavcodec: | |
263 __asm__ volatile | |
264 ("mov %%"REG_b", %%"REG_S"\n\t" | |
265 "cpuid\n\t" | |
266 "xchg %%"REG_b", %%"REG_S | |
267 : "=a" (p[0]), "=S" (p[1]), | |
268 "=c" (p[2]), "=d" (p[3]) | |
269 : "0" (ax)); | |
270 } | |
271 | |
272 void GetCpuCaps( CpuCaps *caps) | |
273 { | |
274 unsigned int regs[4]; | |
275 unsigned int regs2[4]; | |
276 | |
277 memset(caps, 0, sizeof(*caps)); | |
278 caps->isX86=1; | |
279 caps->cl_size=32; /* default */ | |
280 if (!has_cpuid()) { | |
281 mp_msg(MSGT_CPUDETECT,MSGL_WARN,"CPUID not supported!??? (maybe an old 486?)\n"); | |
282 return; | |
283 } | |
284 do_cpuid(0x00000000, regs); // get _max_ cpuid level and vendor name | |
285 mp_msg(MSGT_CPUDETECT,MSGL_V,"CPU vendor name: %.4s%.4s%.4s max cpuid level: %d\n", | |
286 (char*) (regs+1),(char*) (regs+3),(char*) (regs+2), regs[0]); | |
287 if (regs[0]>=0x00000001) | |
288 { | |
289 char *tmpstr, *ptmpstr; | |
290 unsigned cl_size; | |
291 | |
292 do_cpuid(0x00000001, regs2); | |
293 | |
294 caps->cpuType=(regs2[0] >> 8)&0xf; | |
295 caps->cpuModel=(regs2[0] >> 4)&0xf; | |
296 | |
297 // see AMD64 Architecture Programmer's Manual, Volume 3: General-purpose and | |
298 // System Instructions, Table 3-2: Effective family computation, page 120. | |
299 if(caps->cpuType==0xf){ | |
300 // use extended family (P4, IA64, K8) | |
301 caps->cpuType=0xf+((regs2[0]>>20)&255); | |
302 } | |
303 if(caps->cpuType==0xf || caps->cpuType==6) | |
304 caps->cpuModel |= ((regs2[0]>>16)&0xf) << 4; | |
305 | |
306 caps->cpuStepping=regs2[0] & 0xf; | |
307 | |
308 // general feature flags: | |
309 caps->hasTSC = (regs2[3] & (1 << 8 )) >> 8; // 0x0000010 | |
310 caps->hasMMX = (regs2[3] & (1 << 23 )) >> 23; // 0x0800000 | |
311 caps->hasSSE = (regs2[3] & (1 << 25 )) >> 25; // 0x2000000 | |
312 caps->hasSSE2 = (regs2[3] & (1 << 26 )) >> 26; // 0x4000000 | |
313 caps->hasSSE3 = (regs2[2] & 1); // 0x0000001 | |
314 caps->hasSSSE3 = (regs2[2] & (1 << 9 )) >> 9; // 0x0000200 | |
315 caps->hasMMX2 = caps->hasSSE; // SSE cpus supports mmxext too | |
316 cl_size = ((regs2[1] >> 8) & 0xFF)*8; | |
317 if(cl_size) caps->cl_size = cl_size; | |
318 | |
319 ptmpstr=tmpstr=GetCpuFriendlyName(regs, regs2); | |
320 while(*ptmpstr == ' ') // strip leading spaces | |
321 ptmpstr++; | |
322 mp_msg(MSGT_CPUDETECT,MSGL_V,"CPU: %s ", ptmpstr); | |
323 free(tmpstr); | |
324 mp_msg(MSGT_CPUDETECT,MSGL_V,"(Family: %d, Model: %d, Stepping: %d)\n", | |
325 caps->cpuType, caps->cpuModel, caps->cpuStepping); | |
326 | |
327 } | |
328 do_cpuid(0x80000000, regs); | |
329 if (regs[0]>=0x80000001) { | |
330 mp_msg(MSGT_CPUDETECT,MSGL_V,"extended cpuid-level: %d\n",regs[0]&0x7FFFFFFF); | |
331 do_cpuid(0x80000001, regs2); | |
332 caps->hasMMX |= (regs2[3] & (1 << 23 )) >> 23; // 0x0800000 | |
333 caps->hasMMX2 |= (regs2[3] & (1 << 22 )) >> 22; // 0x400000 | |
334 caps->has3DNow = (regs2[3] & (1 << 31 )) >> 31; //0x80000000 | |
335 caps->has3DNowExt = (regs2[3] & (1 << 30 )) >> 30; | |
336 caps->hasSSE4a = (regs2[2] & (1 << 6 )) >> 6; // 0x0000040 | |
337 } | |
338 if(regs[0]>=0x80000006) | |
339 { | |
340 do_cpuid(0x80000006, regs2); | |
341 mp_msg(MSGT_CPUDETECT,MSGL_V,"extended cache-info: %d\n",regs2[2]&0x7FFFFFFF); | |
342 caps->cl_size = regs2[2] & 0xFF; | |
343 } | |
344 mp_msg(MSGT_CPUDETECT,MSGL_V,"Detected cache-line size is %u bytes\n",caps->cl_size); | |
345 #if 0 | |
346 mp_msg(MSGT_CPUDETECT,MSGL_INFO,"cpudetect: MMX=%d MMX2=%d SSE=%d SSE2=%d 3DNow=%d 3DNowExt=%d\n", | |
347 gCpuCaps.hasMMX, | |
348 gCpuCaps.hasMMX2, | |
349 gCpuCaps.hasSSE, | |
350 gCpuCaps.hasSSE2, | |
351 gCpuCaps.has3DNow, | |
352 gCpuCaps.has3DNowExt); | |
353 #endif | |
354 | |
355 /* FIXME: Does SSE2 need more OS support, too? */ | |
356 if (caps->hasSSE) | |
357 check_os_katmai_support(); | |
358 if (!caps->hasSSE) | |
359 caps->hasSSE2 = 0; | |
360 // caps->has3DNow=1; | |
361 // caps->hasMMX2 = 0; | |
362 // caps->hasMMX = 0; | |
363 | |
364 #if !CONFIG_RUNTIME_CPUDETECT | |
365 #if !HAVE_MMX | |
366 if(caps->hasMMX) mp_msg(MSGT_CPUDETECT,MSGL_WARN,"MMX supported but disabled\n"); | |
367 caps->hasMMX=0; | |
368 #endif | |
369 #if !HAVE_MMX2 | |
370 if(caps->hasMMX2) mp_msg(MSGT_CPUDETECT,MSGL_WARN,"MMX2 supported but disabled\n"); | |
371 caps->hasMMX2=0; | |
372 #endif | |
373 #if !HAVE_SSE | |
374 if(caps->hasSSE) mp_msg(MSGT_CPUDETECT,MSGL_WARN,"SSE supported but disabled\n"); | |
375 caps->hasSSE=0; | |
376 #endif | |
377 #if !HAVE_SSE2 | |
378 if(caps->hasSSE2) mp_msg(MSGT_CPUDETECT,MSGL_WARN,"SSE2 supported but disabled\n"); | |
379 caps->hasSSE2=0; | |
380 #endif | |
381 #if !HAVE_AMD3DNOW | |
382 if(caps->has3DNow) mp_msg(MSGT_CPUDETECT,MSGL_WARN,"3DNow supported but disabled\n"); | |
383 caps->has3DNow=0; | |
384 #endif | |
385 #if !HAVE_AMD3DNOWEXT | |
386 if(caps->has3DNowExt) mp_msg(MSGT_CPUDETECT,MSGL_WARN,"3DNowExt supported but disabled\n"); | |
387 caps->has3DNowExt=0; | |
388 #endif | |
389 #endif // CONFIG_RUNTIME_CPUDETECT | |
390 } | |
391 | |
392 char *GetCpuFriendlyName(unsigned int regs[], unsigned int regs2[]){ | |
393 char vendor[13]; | |
394 char *retname; | |
395 int i; | |
396 | |
397 if (NULL==(retname=malloc(256))) { | |
398 mp_msg(MSGT_CPUDETECT,MSGL_FATAL,"Error: GetCpuFriendlyName() not enough memory\n"); | |
399 exit(1); | |
400 } | |
401 retname[0] = '\0'; | |
402 | |
403 sprintf(vendor,"%.4s%.4s%.4s",(char*)(regs+1),(char*)(regs+3),(char*)(regs+2)); | |
404 | |
405 do_cpuid(0x80000000,regs); | |
406 if (regs[0] >= 0x80000004) | |
407 { | |
408 // CPU has built-in namestring | |
409 for (i = 0x80000002; i <= 0x80000004; i++) | |
410 { | |
411 do_cpuid(i, regs); | |
412 strncat(retname, (char*)regs, 16); | |
413 } | |
414 } | |
415 return retname; | |
416 } | |
417 | |
418 #else /* ARCH_X86 */ | 418 #else /* ARCH_X86 */ |
419 | 419 |
420 #ifdef __APPLE__ | 420 #ifdef __APPLE__ |
421 #include <sys/sysctl.h> | 421 #include <sys/sysctl.h> |
422 #elif defined(__AMIGAOS4__) | 422 #elif defined(__AMIGAOS4__) |