This repository has been archived by the owner on Feb 11, 2021. It is now read-only.
/
SDL_cpuinfo.c
523 lines (480 loc) · 15.1 KB
1
2
/*
SDL - Simple DirectMedia Layer
3
Copyright (C) 1997-2009 Sam Lantinga
4
5
This library is free software; you can redistribute it and/or
6
modify it under the terms of the GNU Lesser General Public
7
License as published by the Free Software Foundation; either
8
version 2.1 of the License, or (at your option) any later version.
9
10
11
12
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13
Lesser General Public License for more details.
14
15
16
17
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18
19
20
21
Sam Lantinga
slouken@libsdl.org
*/
22
#include "SDL_config.h"
23
24
25
/* CPU feature detection for SDL */
26
27
#include "SDL_cpuinfo.h"
28
29
30
31
#ifdef HAVE_SYSCTLBYNAME
#include <sys/types.h>
#include <sys/sysctl.h>
#endif
32
#if defined(__MACOSX__) && (defined(__ppc__) || defined(__ppc64__))
33
#include <sys/sysctl.h> /* For AltiVec check */
34
35
36
#elif SDL_ALTIVEC_BLITTERS && HAVE_SETJMP
#include <signal.h>
#include <setjmp.h>
37
#endif
38
39
40
41
#ifdef __WIN32__
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#endif
42
43
44
45
46
#define CPU_HAS_RDTSC 0x00000001
#define CPU_HAS_MMX 0x00000002
#define CPU_HAS_MMXEXT 0x00000004
#define CPU_HAS_3DNOW 0x00000010
47
#define CPU_HAS_3DNOWEXT 0x00000020
48
49
50
#define CPU_HAS_SSE 0x00000040
#define CPU_HAS_SSE2 0x00000080
#define CPU_HAS_ALTIVEC 0x00000100
51
52
#if SDL_ALTIVEC_BLITTERS && HAVE_SETJMP && !__MACOSX__
53
54
55
56
/* This is the brute force way of detecting instruction sets...
the idea is borrowed from the libmpeg2 library - thanks!
*/
static jmp_buf jmpbuf;
57
58
static void
illegal_instruction(int sig)
59
{
60
longjmp(jmpbuf, 1);
61
}
62
#endif /* HAVE_SETJMP */
63
64
65
static __inline__ int
CPU_haveCPUID(void)
66
{
67
68
int has_CPUID = 0;
/* *INDENT-OFF* */
69
#if defined(__GNUC__) && defined(i386)
70
__asm__ (
71
72
73
74
75
76
77
78
79
80
81
82
" pushfl # Get original EFLAGS \n"
" popl %%eax \n"
" movl %%eax,%%ecx \n"
" xorl $0x200000,%%eax # Flip ID bit in EFLAGS \n"
" pushl %%eax # Save new EFLAGS value on stack \n"
" popfl # Replace current EFLAGS value \n"
" pushfl # Get new EFLAGS \n"
" popl %%eax # Store new EFLAGS in EAX \n"
" xorl %%ecx,%%eax # Can not toggle ID bit, \n"
" jz 1f # Processor=80486 \n"
" movl $1,%0 # We have CPUID support \n"
"1: \n"
83
84
85
86
: "=m" (has_CPUID)
:
: "%eax", "%ecx"
);
87
88
89
#elif defined(__GNUC__) && defined(__x86_64__)
/* Technically, if this is being compiled under __x86_64__ then it has
CPUid by definition. But it's nice to be able to prove it. :) */
90
__asm__ (
91
92
93
94
95
96
97
98
99
100
101
102
" pushfq # Get original EFLAGS \n"
" popq %%rax \n"
" movq %%rax,%%rcx \n"
" xorl $0x200000,%%eax # Flip ID bit in EFLAGS \n"
" pushq %%rax # Save new EFLAGS value on stack \n"
" popfq # Replace current EFLAGS value \n"
" pushfq # Get new EFLAGS \n"
" popq %%rax # Store new EFLAGS in EAX \n"
" xorl %%ecx,%%eax # Can not toggle ID bit, \n"
" jz 1f # Processor=80486 \n"
" movl $1,%0 # We have CPUID support \n"
"1: \n"
103
104
105
106
: "=m" (has_CPUID)
:
: "%rax", "%rcx"
);
107
#elif (defined(_MSC_VER) && defined(_M_IX86)) || defined(__WATCOMC__)
108
__asm {
109
110
111
112
113
114
115
116
117
118
119
120
pushfd ; Get original EFLAGS
pop eax
mov ecx, eax
xor eax, 200000h ; Flip ID bit in EFLAGS
push eax ; Save new EFLAGS value on stack
popfd ; Replace current EFLAGS value
pushfd ; Get new EFLAGS
pop eax ; Store new EFLAGS in EAX
xor eax, ecx ; Can not toggle ID bit,
jz done ; Processor=80486
mov has_CPUID,1 ; We have CPUID support
done:
121
}
122
#elif defined(__sun) && defined(__i386)
123
__asm (
124
" pushfl \n"
125
126
127
128
129
130
131
132
133
134
" popl %eax \n"
" movl %eax,%ecx \n"
" xorl $0x200000,%eax \n"
" pushl %eax \n"
" popfl \n"
" pushfl \n"
" popl %eax \n"
" xorl %ecx,%eax \n"
" jz 1f \n"
" movl $1,-8(%ebp) \n"
135
"1: \n"
136
);
137
#elif defined(__sun) && defined(__amd64)
138
__asm (
139
140
141
142
143
144
145
146
147
148
149
150
" pushfq \n"
" popq %rax \n"
" movq %rax,%rcx \n"
" xorl $0x200000,%eax \n"
" pushq %rax \n"
" popfq \n"
" pushfq \n"
" popq %rax \n"
" xorl %ecx,%eax \n"
" jz 1f \n"
" movl $1,-8(%rbp) \n"
"1: \n"
151
);
152
#endif
153
154
/* *INDENT-ON* */
return has_CPUID;
155
156
}
157
#if defined(__GNUC__) && (defined(i386) || defined(__x86_64__))
158
#define cpuid(func, a, b, c, d) \
159
160
161
162
163
164
__asm__ __volatile__ ( \
" pushl %%ebx \n" \
" cpuid \n" \
" movl %%ebx, %%esi \n" \
" popl %%ebx \n" : \
"=a" (a), "=S" (b), "=c" (c), "=d" (d) : "a" (func))
165
#elif (defined(_MSC_VER) && defined(_M_IX86)) || defined(__WATCOMC__)
166
167
168
169
170
171
172
173
#define cpuid(func, a, b, c, d) \
__asm { \
__asm mov eax, func \
__asm cpuid \
__asm mov a, eax \
__asm mov b, ebx \
__asm mov c, ecx \
__asm mov d, edx \
174
175
}
#else
176
177
#define cpuid(func, a, b, c, d) \
a = b = c = d = 0
178
179
#endif
180
181
static __inline__ int
CPU_getCPUIDFeatures(void)
182
{
183
int features = 0;
184
int a, b, c, d;
185
186
187
188
189
cpuid(0, a, b, c, d);
if (a >= 1) {
cpuid(1, a, b, c, d);
features = d;
190
}
191
return features;
192
193
}
194
195
static __inline__ int
CPU_getCPUIDFeaturesExt(void)
196
{
197
int features = 0;
198
int a, b, c, d;
199
200
201
202
203
cpuid(0x80000000, a, b, c, d);
if (a >= 0x80000001) {
cpuid(0x80000001, a, b, c, d);
features = d;
204
}
205
return features;
206
207
}
208
209
static __inline__ int
CPU_haveRDTSC(void)
210
{
211
212
213
214
if (CPU_haveCPUID()) {
return (CPU_getCPUIDFeatures() & 0x00000010);
}
return 0;
215
216
}
217
218
static __inline__ int
CPU_haveMMX(void)
219
{
220
221
222
223
if (CPU_haveCPUID()) {
return (CPU_getCPUIDFeatures() & 0x00800000);
}
return 0;
224
225
}
226
227
static __inline__ int
CPU_haveMMXExt(void)
228
{
229
230
231
232
if (CPU_haveCPUID()) {
return (CPU_getCPUIDFeaturesExt() & 0x00400000);
}
return 0;
233
234
}
235
236
static __inline__ int
CPU_have3DNow(void)
237
{
238
239
240
241
if (CPU_haveCPUID()) {
return (CPU_getCPUIDFeaturesExt() & 0x80000000);
}
return 0;
242
243
}
244
245
static __inline__ int
CPU_have3DNowExt(void)
246
{
247
248
249
250
if (CPU_haveCPUID()) {
return (CPU_getCPUIDFeaturesExt() & 0x40000000);
}
return 0;
251
252
}
253
254
static __inline__ int
CPU_haveSSE(void)
255
{
256
257
258
259
if (CPU_haveCPUID()) {
return (CPU_getCPUIDFeatures() & 0x02000000);
}
return 0;
260
}
261
262
263
static __inline__ int
CPU_haveSSE2(void)
264
{
265
266
267
268
if (CPU_haveCPUID()) {
return (CPU_getCPUIDFeatures() & 0x04000000);
}
return 0;
269
270
}
271
272
static __inline__ int
CPU_haveAltiVec(void)
273
{
274
volatile int altivec = 0;
275
#if defined(__MACOSX__) && (defined(__ppc__) || defined(__ppc64__))
276
277
278
279
280
281
int selectors[2] = { CTL_HW, HW_VECTORUNIT };
int hasVectorUnit = 0;
size_t length = sizeof(hasVectorUnit);
int error = sysctl(selectors, 2, &hasVectorUnit, &length, NULL, 0);
if (0 == error)
altivec = (hasVectorUnit != 0);
282
#elif SDL_ALTIVEC_BLITTERS && HAVE_SETJMP
283
284
285
286
287
288
289
void (*handler) (int sig);
handler = signal(SIGILL, illegal_instruction);
if (setjmp(jmpbuf) == 0) {
asm volatile ("mtspr 256, %0\n\t" "vand %%v0, %%v0, %%v0"::"r" (-1));
altivec = 1;
}
signal(SIGILL, handler);
290
#endif
291
return altivec;
292
293
}
294
295
296
297
298
299
300
static int SDL_CPUCount = 0;
int
SDL_GetCPUCount()
{
if (!SDL_CPUCount) {
#ifdef HAVE_SYSCTLBYNAME
301
302
303
304
305
306
307
308
309
310
311
{
size_t size = sizeof(SDL_CPUCount);
sysctlbyname("hw.ncpu", &SDL_CPUCount, &size, NULL, 0);
}
#endif
#ifdef __WIN32__
{
SYSTEM_INFO info;
GetSystemInfo(&info);
SDL_CPUCount = info.dwNumberOfProcessors;
}
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
#endif
/* There has to be at least 1, right? :) */
if (!SDL_CPUCount) {
SDL_CPUCount = 1;
}
}
return SDL_CPUCount;
}
/* Oh, such a sweet sweet trick, just not very useful. :) */
const char *
SDL_GetCPUType()
{
static char SDL_CPUType[48];
if (!SDL_CPUType[0]) {
int i = 0;
329
int a, b, c, d;
330
331
if (CPU_haveCPUID()) {
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
cpuid(0x80000000, a, b, c, d);
if (a >= 0x80000004) {
cpuid(0x80000002, a, b, c, d);
SDL_CPUType[i++] = (char)(a & 0xff); a >>= 8;
SDL_CPUType[i++] = (char)(a & 0xff); a >>= 8;
SDL_CPUType[i++] = (char)(a & 0xff); a >>= 8;
SDL_CPUType[i++] = (char)(a & 0xff); a >>= 8;
SDL_CPUType[i++] = (char)(b & 0xff); b >>= 8;
SDL_CPUType[i++] = (char)(b & 0xff); b >>= 8;
SDL_CPUType[i++] = (char)(b & 0xff); b >>= 8;
SDL_CPUType[i++] = (char)(b & 0xff); b >>= 8;
SDL_CPUType[i++] = (char)(c & 0xff); c >>= 8;
SDL_CPUType[i++] = (char)(c & 0xff); c >>= 8;
SDL_CPUType[i++] = (char)(c & 0xff); c >>= 8;
SDL_CPUType[i++] = (char)(c & 0xff); c >>= 8;
SDL_CPUType[i++] = (char)(d & 0xff); d >>= 8;
SDL_CPUType[i++] = (char)(d & 0xff); d >>= 8;
SDL_CPUType[i++] = (char)(d & 0xff); d >>= 8;
SDL_CPUType[i++] = (char)(d & 0xff); d >>= 8;
cpuid(0x80000003, a, b, c, d);
SDL_CPUType[i++] = (char)(a & 0xff); a >>= 8;
SDL_CPUType[i++] = (char)(a & 0xff); a >>= 8;
SDL_CPUType[i++] = (char)(a & 0xff); a >>= 8;
SDL_CPUType[i++] = (char)(a & 0xff); a >>= 8;
SDL_CPUType[i++] = (char)(b & 0xff); b >>= 8;
SDL_CPUType[i++] = (char)(b & 0xff); b >>= 8;
SDL_CPUType[i++] = (char)(b & 0xff); b >>= 8;
SDL_CPUType[i++] = (char)(b & 0xff); b >>= 8;
SDL_CPUType[i++] = (char)(c & 0xff); c >>= 8;
SDL_CPUType[i++] = (char)(c & 0xff); c >>= 8;
SDL_CPUType[i++] = (char)(c & 0xff); c >>= 8;
SDL_CPUType[i++] = (char)(c & 0xff); c >>= 8;
SDL_CPUType[i++] = (char)(d & 0xff); d >>= 8;
SDL_CPUType[i++] = (char)(d & 0xff); d >>= 8;
SDL_CPUType[i++] = (char)(d & 0xff); d >>= 8;
SDL_CPUType[i++] = (char)(d & 0xff); d >>= 8;
cpuid(0x80000004, a, b, c, d);
SDL_CPUType[i++] = (char)(a & 0xff); a >>= 8;
SDL_CPUType[i++] = (char)(a & 0xff); a >>= 8;
SDL_CPUType[i++] = (char)(a & 0xff); a >>= 8;
SDL_CPUType[i++] = (char)(a & 0xff); a >>= 8;
SDL_CPUType[i++] = (char)(b & 0xff); b >>= 8;
SDL_CPUType[i++] = (char)(b & 0xff); b >>= 8;
SDL_CPUType[i++] = (char)(b & 0xff); b >>= 8;
SDL_CPUType[i++] = (char)(b & 0xff); b >>= 8;
SDL_CPUType[i++] = (char)(c & 0xff); c >>= 8;
SDL_CPUType[i++] = (char)(c & 0xff); c >>= 8;
SDL_CPUType[i++] = (char)(c & 0xff); c >>= 8;
SDL_CPUType[i++] = (char)(c & 0xff); c >>= 8;
SDL_CPUType[i++] = (char)(d & 0xff); d >>= 8;
SDL_CPUType[i++] = (char)(d & 0xff); d >>= 8;
SDL_CPUType[i++] = (char)(d & 0xff); d >>= 8;
SDL_CPUType[i++] = (char)(d & 0xff); d >>= 8;
385
386
387
388
389
390
391
392
393
}
}
if (!SDL_CPUType[0]) {
SDL_strlcpy(SDL_CPUType, "Unknown", sizeof(SDL_CPUType));
}
}
return SDL_CPUType;
}
394
395
static Uint32 SDL_CPUFeatures = 0xFFFFFFFF;
396
397
static Uint32
SDL_GetCPUFeatures(void)
398
{
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
if (SDL_CPUFeatures == 0xFFFFFFFF) {
SDL_CPUFeatures = 0;
if (CPU_haveRDTSC()) {
SDL_CPUFeatures |= CPU_HAS_RDTSC;
}
if (CPU_haveMMX()) {
SDL_CPUFeatures |= CPU_HAS_MMX;
}
if (CPU_haveMMXExt()) {
SDL_CPUFeatures |= CPU_HAS_MMXEXT;
}
if (CPU_have3DNow()) {
SDL_CPUFeatures |= CPU_HAS_3DNOW;
}
if (CPU_have3DNowExt()) {
SDL_CPUFeatures |= CPU_HAS_3DNOWEXT;
}
if (CPU_haveSSE()) {
SDL_CPUFeatures |= CPU_HAS_SSE;
}
if (CPU_haveSSE2()) {
SDL_CPUFeatures |= CPU_HAS_SSE2;
}
if (CPU_haveAltiVec()) {
SDL_CPUFeatures |= CPU_HAS_ALTIVEC;
}
}
return SDL_CPUFeatures;
427
428
}
429
430
SDL_bool
SDL_HasRDTSC(void)
431
{
432
433
434
435
if (SDL_GetCPUFeatures() & CPU_HAS_RDTSC) {
return SDL_TRUE;
}
return SDL_FALSE;
436
437
}
438
439
SDL_bool
SDL_HasMMX(void)
440
{
441
442
443
444
if (SDL_GetCPUFeatures() & CPU_HAS_MMX) {
return SDL_TRUE;
}
return SDL_FALSE;
445
446
}
447
448
SDL_bool
SDL_HasMMXExt(void)
449
{
450
451
452
453
if (SDL_GetCPUFeatures() & CPU_HAS_MMXEXT) {
return SDL_TRUE;
}
return SDL_FALSE;
454
455
}
456
457
SDL_bool
SDL_Has3DNow(void)
458
{
459
460
461
462
if (SDL_GetCPUFeatures() & CPU_HAS_3DNOW) {
return SDL_TRUE;
}
return SDL_FALSE;
463
464
}
465
466
SDL_bool
SDL_Has3DNowExt(void)
467
{
468
469
470
471
if (SDL_GetCPUFeatures() & CPU_HAS_3DNOWEXT) {
return SDL_TRUE;
}
return SDL_FALSE;
472
473
}
474
475
SDL_bool
SDL_HasSSE(void)
476
{
477
478
479
480
if (SDL_GetCPUFeatures() & CPU_HAS_SSE) {
return SDL_TRUE;
}
return SDL_FALSE;
481
482
}
483
484
SDL_bool
SDL_HasSSE2(void)
485
{
486
487
488
489
if (SDL_GetCPUFeatures() & CPU_HAS_SSE2) {
return SDL_TRUE;
}
return SDL_FALSE;
490
491
}
492
493
SDL_bool
SDL_HasAltiVec(void)
494
{
495
496
497
498
if (SDL_GetCPUFeatures() & CPU_HAS_ALTIVEC) {
return SDL_TRUE;
}
return SDL_FALSE;
499
500
}
501
502
503
504
#ifdef TEST_MAIN
#include <stdio.h>
505
506
int
main()
507
{
508
509
printf("CPU count: %d\n", SDL_GetCPUCount());
printf("CPU name: %s\n", SDL_GetCPUType());
510
511
512
513
514
515
516
517
518
printf("RDTSC: %d\n", SDL_HasRDTSC());
printf("MMX: %d\n", SDL_HasMMX());
printf("MMXExt: %d\n", SDL_HasMMXExt());
printf("3DNow: %d\n", SDL_Has3DNow());
printf("3DNowExt: %d\n", SDL_Has3DNowExt());
printf("SSE: %d\n", SDL_HasSSE());
printf("SSE2: %d\n", SDL_HasSSE2());
printf("AltiVec: %d\n", SDL_HasAltiVec());
return 0;
519
520
521
}
#endif /* TEST_MAIN */
522
523
/* vi: set ts=4 sw=4 expandtab: */