This repository has been archived by the owner on Feb 11, 2021. It is now read-only.
/
SDL_cpuinfo.c
525 lines (490 loc) · 16.3 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
#if defined(__MACOSX__) && (defined(__ppc__) || defined(__ppc64__))
29
#include <sys/sysctl.h> /* For AltiVec check */
30
31
32
#elif SDL_ALTIVEC_BLITTERS && HAVE_SETJMP
#include <signal.h>
#include <setjmp.h>
33
34
#endif
35
36
#define CPU_HAS_RDTSC 0x00000001
#define CPU_HAS_MMX 0x00000002
37
38
39
40
41
42
#define CPU_HAS_MMXEXT 0x00000004
#define CPU_HAS_3DNOW 0x00000010
#define CPU_HAS_3DNOWEXT 0x00000020
#define CPU_HAS_SSE 0x00000040
#define CPU_HAS_SSE2 0x00000080
#define CPU_HAS_ALTIVEC 0x00000100
43
44
#if SDL_ALTIVEC_BLITTERS && HAVE_SETJMP && !__MACOSX__
45
46
47
48
/* This is the brute force way of detecting instruction sets...
the idea is borrowed from the libmpeg2 library - thanks!
*/
static jmp_buf jmpbuf;
49
50
static void
illegal_instruction(int sig)
51
{
52
longjmp(jmpbuf, 1);
53
}
54
#endif /* HAVE_SETJMP */
55
56
57
static __inline__ int
CPU_haveCPUID(void)
58
{
59
60
int has_CPUID = 0;
/* *INDENT-OFF* */
61
62
63
64
65
66
67
68
69
70
71
72
73
74
#if defined(__GNUC__) && defined(i386)
__asm__ (
" 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"
75
: "=m" (has_CPUID)
76
77
78
:
: "%eax", "%ecx"
);
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
#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. :) */
__asm__ (
" 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"
: "=m" (has_CPUID)
:
: "%rax", "%rcx"
);
99
#elif (defined(_MSC_VER) && defined(_M_IX86)) || defined(__WATCOMC__)
100
__asm {
101
102
103
104
105
106
107
108
109
110
111
112
113
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:
}
114
#elif defined(__sun) && defined(__i386)
115
__asm (
116
" pushfl \n"
117
118
119
120
121
122
123
124
125
126
" 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"
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
"1: \n"
);
#elif defined(__sun) && defined(__amd64)
__asm (
" 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"
);
144
#endif
145
146
/* *INDENT-ON* */
return has_CPUID;
147
148
}
149
150
static __inline__ int
CPU_getCPUIDFeatures(void)
151
{
152
153
int features = 0;
/* *INDENT-OFF* */
154
#if defined(__GNUC__) && defined(i386)
155
156
__asm__ (
" xorl %%eax,%%eax # Set up for CPUID instruction \n"
157
" pushl %%ebx \n"
158
" cpuid # Get and save vendor ID \n"
159
" popl %%ebx \n"
160
161
162
163
" cmpl $1,%%eax # Make sure 1 is valid input for CPUID\n"
" jl 1f # We dont have the CPUID instruction\n"
" xorl %%eax,%%eax \n"
" incl %%eax \n"
164
" pushl %%ebx \n"
165
" cpuid # Get family/model/stepping/features\n"
166
" popl %%ebx \n"
167
168
" movl %%edx,%0 \n"
"1: \n"
169
: "=m" (features)
170
:
171
: "%eax", "%ecx", "%edx"
172
);
173
174
175
#elif defined(__GNUC__) && defined(__x86_64__)
__asm__ (
" xorl %%eax,%%eax # Set up for CPUID instruction \n"
176
" pushq %%rbx \n"
177
" cpuid # Get and save vendor ID \n"
178
" popq %%rbx \n"
179
180
181
182
" cmpl $1,%%eax # Make sure 1 is valid input for CPUID\n"
" jl 1f # We dont have the CPUID instruction\n"
" xorl %%eax,%%eax \n"
" incl %%eax \n"
183
" pushq %%rbx \n"
184
" cpuid # Get family/model/stepping/features\n"
185
" popq %%rbx \n"
186
187
188
189
" movl %%edx,%0 \n"
"1: \n"
: "=m" (features)
:
190
: "%rax", "%rcx", "%rdx"
191
);
192
#elif (defined(_MSC_VER) && defined(_M_IX86)) || defined(__WATCOMC__)
193
__asm {
194
xor eax, eax ; Set up for CPUID instruction
195
push ebx
196
cpuid ; Get and save vendor ID
197
pop ebx
198
199
200
201
cmp eax, 1 ; Make sure 1 is valid input for CPUID
jl done ; We dont have the CPUID instruction
xor eax, eax
inc eax
202
push ebx
203
cpuid ; Get family/model/stepping/features
204
pop ebx
205
206
207
mov features, edx
done:
}
208
#elif defined(__sun) && (defined(__i386) || defined(__amd64))
209
210
__asm(
" xorl %eax,%eax \n"
211
" pushl %ebx \n"
212
" cpuid \n"
213
" popl %ebx \n"
214
215
216
217
" cmpl $1,%eax \n"
" jl 1f \n"
" xorl %eax,%eax \n"
" incl %eax \n"
218
" pushl %ebx \n"
219
" cpuid \n"
220
" popl %ebx \n"
221
222
223
224
225
226
#ifdef __i386
" movl %edx,-8(%ebp) \n"
#else
" movl %edx,-8(%rbp) \n"
#endif
"1: \n"
227
#endif
228
229
/* *INDENT-ON* */
return features;
230
231
}
232
233
static __inline__ int
CPU_getCPUIDFeaturesExt(void)
234
{
235
236
int features = 0;
/* *INDENT-OFF* */
237
#if defined(__GNUC__) && defined(i386)
238
239
__asm__ (
" movl $0x80000000,%%eax # Query for extended functions \n"
240
" pushl %%ebx \n"
241
" cpuid # Get extended function limit \n"
242
" popl %%ebx \n"
243
" cmpl $0x80000001,%%eax \n"
244
" jl 1f # Nope, we dont have function 800000001h\n"
245
" movl $0x80000001,%%eax # Setup extended function 800000001h\n"
246
" pushl %%ebx \n"
247
" cpuid # and get the information \n"
248
" popl %%ebx \n"
249
" movl %%edx,%0 \n"
250
"1: \n"
251
: "=m" (features)
252
:
253
: "%eax", "%ecx", "%edx"
254
);
255
256
257
#elif defined(__GNUC__) && defined (__x86_64__)
__asm__ (
" movl $0x80000000,%%eax # Query for extended functions \n"
258
" pushq %%rbx \n"
259
" cpuid # Get extended function limit \n"
260
" popq %%rbx \n"
261
262
263
" cmpl $0x80000001,%%eax \n"
" jl 1f # Nope, we dont have function 800000001h\n"
" movl $0x80000001,%%eax # Setup extended function 800000001h\n"
264
" pushq %%rbx \n"
265
" cpuid # and get the information \n"
266
" popq %%rbx \n"
267
268
269
270
" movl %%edx,%0 \n"
"1: \n"
: "=m" (features)
:
271
: "%rax", "%rcx", "%rdx"
272
);
273
#elif (defined(_MSC_VER) && defined(_M_IX86)) || defined(__WATCOMC__)
274
__asm {
275
mov eax,80000000h ; Query for extended functions
276
push ebx
277
cpuid ; Get extended function limit
278
pop ebx
279
cmp eax,80000001h
280
jl done ; Nope, we dont have function 800000001h
281
mov eax,80000001h ; Setup extended function 800000001h
282
push ebx
283
cpuid ; and get the information
284
pop ebx
285
mov features,edx
286
287
done:
}
288
289
290
#elif defined(__sun) && ( defined(__i386) || defined(__amd64) )
__asm (
" movl $0x80000000,%eax \n"
291
" pushl %ebx \n"
292
" cpuid \n"
293
" popl %ebx \n"
294
295
296
" cmpl $0x80000001,%eax \n"
" jl 1f \n"
" movl $0x80000001,%eax \n"
297
" pushl %ebx \n"
298
" cpuid \n"
299
" popl %ebx \n"
300
#ifdef __i386
301
" movl %edx,-8(%ebp) \n"
302
#else
303
" movl %edx,-8(%rbp) \n"
304
305
306
#endif
"1: \n"
);
307
#endif
308
309
/* *INDENT-ON* */
return features;
310
311
}
312
313
static __inline__ int
CPU_haveRDTSC(void)
314
{
315
316
317
318
if (CPU_haveCPUID()) {
return (CPU_getCPUIDFeatures() & 0x00000010);
}
return 0;
319
320
}
321
322
static __inline__ int
CPU_haveMMX(void)
323
{
324
325
326
327
if (CPU_haveCPUID()) {
return (CPU_getCPUIDFeatures() & 0x00800000);
}
return 0;
328
329
}
330
331
static __inline__ int
CPU_haveMMXExt(void)
332
{
333
334
335
336
if (CPU_haveCPUID()) {
return (CPU_getCPUIDFeaturesExt() & 0x00400000);
}
return 0;
337
338
}
339
340
static __inline__ int
CPU_have3DNow(void)
341
{
342
343
344
345
if (CPU_haveCPUID()) {
return (CPU_getCPUIDFeaturesExt() & 0x80000000);
}
return 0;
346
347
}
348
349
static __inline__ int
CPU_have3DNowExt(void)
350
{
351
352
353
354
if (CPU_haveCPUID()) {
return (CPU_getCPUIDFeaturesExt() & 0x40000000);
}
return 0;
355
356
}
357
358
static __inline__ int
CPU_haveSSE(void)
359
{
360
361
362
363
if (CPU_haveCPUID()) {
return (CPU_getCPUIDFeatures() & 0x02000000);
}
return 0;
364
}
365
366
367
static __inline__ int
CPU_haveSSE2(void)
368
{
369
370
371
372
if (CPU_haveCPUID()) {
return (CPU_getCPUIDFeatures() & 0x04000000);
}
return 0;
373
374
}
375
376
static __inline__ int
CPU_haveAltiVec(void)
377
{
378
volatile int altivec = 0;
379
#if defined(__MACOSX__) && (defined(__ppc__) || defined(__ppc64__))
380
381
382
383
384
385
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);
386
#elif SDL_ALTIVEC_BLITTERS && HAVE_SETJMP
387
388
389
390
391
392
393
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);
394
#endif
395
return altivec;
396
397
}
398
399
static Uint32 SDL_CPUFeatures = 0xFFFFFFFF;
400
401
static Uint32
SDL_GetCPUFeatures(void)
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
427
428
429
430
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;
431
432
}
433
434
SDL_bool
SDL_HasRDTSC(void)
435
{
436
437
438
439
if (SDL_GetCPUFeatures() & CPU_HAS_RDTSC) {
return SDL_TRUE;
}
return SDL_FALSE;
440
441
}
442
443
SDL_bool
SDL_HasMMX(void)
444
{
445
446
447
448
if (SDL_GetCPUFeatures() & CPU_HAS_MMX) {
return SDL_TRUE;
}
return SDL_FALSE;
449
450
}
451
452
SDL_bool
SDL_HasMMXExt(void)
453
{
454
455
456
457
if (SDL_GetCPUFeatures() & CPU_HAS_MMXEXT) {
return SDL_TRUE;
}
return SDL_FALSE;
458
459
}
460
461
SDL_bool
SDL_Has3DNow(void)
462
{
463
464
465
466
if (SDL_GetCPUFeatures() & CPU_HAS_3DNOW) {
return SDL_TRUE;
}
return SDL_FALSE;
467
468
}
469
470
SDL_bool
SDL_Has3DNowExt(void)
471
{
472
473
474
475
if (SDL_GetCPUFeatures() & CPU_HAS_3DNOWEXT) {
return SDL_TRUE;
}
return SDL_FALSE;
476
477
}
478
479
SDL_bool
SDL_HasSSE(void)
480
{
481
482
483
484
if (SDL_GetCPUFeatures() & CPU_HAS_SSE) {
return SDL_TRUE;
}
return SDL_FALSE;
485
486
}
487
488
SDL_bool
SDL_HasSSE2(void)
489
{
490
491
492
493
if (SDL_GetCPUFeatures() & CPU_HAS_SSE2) {
return SDL_TRUE;
}
return SDL_FALSE;
494
495
}
496
497
SDL_bool
SDL_HasAltiVec(void)
498
{
499
500
501
502
if (SDL_GetCPUFeatures() & CPU_HAS_ALTIVEC) {
return SDL_TRUE;
}
return SDL_FALSE;
503
504
}
505
506
507
508
#ifdef TEST_MAIN
#include <stdio.h>
509
510
int
main()
511
{
512
513
514
515
516
517
518
519
520
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;
521
522
523
}
#endif /* TEST_MAIN */
524
525
/* vi: set ts=4 sw=4 expandtab: */