Commit | Line | Data |
---|---|---|
de6d9b64 FB |
1 | /* Cpu detection code, extracted from mmx.h ((c)1997-99 by H. Dietz |
2 | and R. Fisher). Converted to C and improved by Gerard Lantau */ | |
3 | ||
4 | #include <stdlib.h> | |
5 | #include "../dsputil.h" | |
6 | ||
a9e3707d FB |
7 | /* ebx saving is necessary for PIC. gcc seems unable to see it alone */ |
8 | static inline void cpuid(int index, int *eax, int *ebx, int *ecx, int *edx) | |
9 | { | |
10 | asm ("pushl %%ebx\n\t" | |
11 | "cpuid\n\t" | |
12 | "movl %%ebx, %1\n\t" | |
13 | "popl %%ebx\n\t" | |
14 | : "=a" (*eax), "=m" (*ebx), | |
15 | "=c" (*ecx), "=d" (*edx) | |
16 | : "a" (index) | |
17 | : "cc"); | |
18 | } | |
de6d9b64 FB |
19 | |
20 | /* Function to test if multimedia instructions are supported... */ | |
21 | int mm_support(void) | |
22 | { | |
23 | int rval; | |
24 | int eax, ebx, ecx, edx; | |
25 | ||
de6d9b64 FB |
26 | __asm__ __volatile__ ( |
27 | /* See if CPUID instruction is supported ... */ | |
28 | /* ... Get copies of EFLAGS into eax and ecx */ | |
29 | "pushf\n\t" | |
30 | "popl %0\n\t" | |
31 | "movl %0, %1\n\t" | |
32 | ||
33 | /* ... Toggle the ID bit in one copy and store */ | |
34 | /* to the EFLAGS reg */ | |
35 | "xorl $0x200000, %0\n\t" | |
36 | "push %0\n\t" | |
37 | "popf\n\t" | |
38 | ||
39 | /* ... Get the (hopefully modified) EFLAGS */ | |
40 | "pushf\n\t" | |
41 | "popl %0\n\t" | |
42 | : "=a" (eax), "=c" (ecx) | |
43 | : | |
44 | : "cc" | |
45 | ); | |
46 | ||
47 | if (eax == ecx) | |
48 | return 0; /* CPUID not supported */ | |
49 | ||
a9e3707d | 50 | cpuid(0, &eax, &ebx, &ecx, &edx); |
de6d9b64 FB |
51 | |
52 | if (ebx == 0x756e6547 && | |
53 | edx == 0x49656e69 && | |
54 | ecx == 0x6c65746e) { | |
55 | ||
56 | /* intel */ | |
57 | inteltest: | |
a9e3707d | 58 | cpuid(1, &eax, &ebx, &ecx, &edx); |
de6d9b64 FB |
59 | if ((edx & 0x00800000) == 0) |
60 | return 0; | |
61 | rval = MM_MMX; | |
62 | if (edx & 0x02000000) | |
63 | rval |= MM_MMXEXT | MM_SSE; | |
64 | if (edx & 0x04000000) | |
65 | rval |= MM_SSE2; | |
66 | return rval; | |
67 | } else if (ebx == 0x68747541 && | |
68 | edx == 0x69746e65 && | |
69 | ecx == 0x444d4163) { | |
70 | /* AMD */ | |
a9e3707d | 71 | cpuid(0x80000000, &eax, &ebx, &ecx, &edx); |
de6d9b64 FB |
72 | if ((unsigned)eax < 0x80000001) |
73 | goto inteltest; | |
a9e3707d | 74 | cpuid(0x80000001, &eax, &ebx, &ecx, &edx); |
de6d9b64 FB |
75 | if ((edx & 0x00800000) == 0) |
76 | return 0; | |
77 | rval = MM_MMX; | |
78 | if (edx & 0x80000000) | |
79 | rval |= MM_3DNOW; | |
80 | if (edx & 0x00400000) | |
81 | rval |= MM_MMXEXT; | |
82 | return rval; | |
83 | } else if (ebx == 0x69727943 && | |
84 | edx == 0x736e4978 && | |
85 | ecx == 0x64616574) { | |
86 | /* Cyrix Section */ | |
87 | /* See if extended CPUID level 80000001 is supported */ | |
88 | /* The value of CPUID/80000001 for the 6x86MX is undefined | |
89 | according to the Cyrix CPU Detection Guide (Preliminary | |
90 | Rev. 1.01 table 1), so we'll check the value of eax for | |
91 | CPUID/0 to see if standard CPUID level 2 is supported. | |
92 | According to the table, the only CPU which supports level | |
93 | 2 is also the only one which supports extended CPUID levels. | |
94 | */ | |
95 | if (eax != 2) | |
96 | goto inteltest; | |
a9e3707d | 97 | cpuid(0x80000001, &eax, &ebx, &ecx, &edx); |
de6d9b64 FB |
98 | if ((eax & 0x00800000) == 0) |
99 | return 0; | |
100 | rval = MM_MMX; | |
101 | if (eax & 0x01000000) | |
102 | rval |= MM_MMXEXT; | |
103 | return rval; | |
104 | } else { | |
105 | return 0; | |
106 | } | |
107 | } |