64656c65a5e087ca7299450ddd779c31dc6f2556
[ffmpeg.git] / libavcodec / i386 / cputest.c
1 /* Cpu detection code, extracted from mmx.h ((c)1997-99 by H. Dietz
2    and R. Fisher). Converted to C and improved by Fabrice Bellard */
3
4 #include <stdlib.h>
5 #include "../dsputil.h"
6
7 #ifdef ARCH_X86_64
8 #  define REG_b "rbx"
9 #  define REG_S "rsi"
10 #else
11 #  define REG_b "ebx"
12 #  define REG_S "esi"
13 #endif
14
15 /* ebx saving is necessary for PIC. gcc seems unable to see it alone */
16 #define cpuid(index,eax,ebx,ecx,edx)\
17     __asm __volatile\
18         ("mov %%"REG_b", %%"REG_S"\n\t"\
19          "cpuid\n\t"\
20          "xchg %%"REG_b", %%"REG_S\
21          : "=a" (eax), "=S" (ebx),\
22            "=c" (ecx), "=d" (edx)\
23          : "0" (index));
24
25 /* Function to test if multimedia instructions are supported...  */
26 int mm_support(void)
27 {
28     int rval = 0;
29     int eax, ebx, ecx, edx;
30     int max_std_level, max_ext_level, std_caps=0, ext_caps=0;
31     long a, c;
32
33     __asm__ __volatile__ (
34                           /* See if CPUID instruction is supported ... */
35                           /* ... Get copies of EFLAGS into eax and ecx */
36                           "pushf\n\t"
37                           "pop %0\n\t"
38                           "mov %0, %1\n\t"
39
40                           /* ... Toggle the ID bit in one copy and store */
41                           /*     to the EFLAGS reg */
42                           "xor $0x200000, %0\n\t"
43                           "push %0\n\t"
44                           "popf\n\t"
45
46                           /* ... Get the (hopefully modified) EFLAGS */
47                           "pushf\n\t"
48                           "pop %0\n\t"
49                           : "=a" (a), "=c" (c)
50                           :
51                           : "cc"
52                           );
53
54     if (a == c)
55         return 0; /* CPUID not supported */
56
57     cpuid(0, max_std_level, ebx, ecx, edx);
58
59     if(max_std_level >= 1){
60         cpuid(1, eax, ebx, ecx, std_caps);
61         if (std_caps & (1<<23))
62             rval |= MM_MMX;
63         if (std_caps & (1<<25))
64             rval |= MM_MMXEXT | MM_SSE;
65         if (std_caps & (1<<26))
66             rval |= MM_SSE2;
67     }
68
69     cpuid(0x80000000, max_ext_level, ebx, ecx, edx);
70
71     if(max_ext_level >= 0x80000001){
72         cpuid(0x80000001, eax, ebx, ecx, ext_caps);
73         if (ext_caps & (1<<31))
74             rval |= MM_3DNOW;
75         if (ext_caps & (1<<30))
76             rval |= MM_3DNOWEXT;
77         if (ext_caps & (1<<23))
78             rval |= MM_MMX;
79     }
80
81     cpuid(0, eax, ebx, ecx, edx);
82     if (       ebx == 0x68747541 &&
83                edx == 0x69746e65 &&
84                ecx == 0x444d4163) {
85         /* AMD */
86         if(ext_caps & (1<<22))
87             rval |= MM_MMXEXT;
88     } else if (ebx == 0x746e6543 &&
89                edx == 0x48727561 &&
90                ecx == 0x736c7561) {  /*  "CentaurHauls" */
91         /* VIA C3 */
92         if(ext_caps & (1<<24))
93           rval |= MM_MMXEXT;
94     } else if (ebx == 0x69727943 &&
95                edx == 0x736e4978 &&
96                ecx == 0x64616574) {
97         /* Cyrix Section */
98         /* See if extended CPUID level 80000001 is supported */
99         /* The value of CPUID/80000001 for the 6x86MX is undefined
100            according to the Cyrix CPU Detection Guide (Preliminary
101            Rev. 1.01 table 1), so we'll check the value of eax for
102            CPUID/0 to see if standard CPUID level 2 is supported.
103            According to the table, the only CPU which supports level
104            2 is also the only one which supports extended CPUID levels.
105         */
106         if (eax < 2)
107             return rval;
108         if (ext_caps & (1<<24))
109             rval |= MM_MMXEXT;
110     }
111 #if 0
112     av_log(NULL, AV_LOG_DEBUG, "%s%s%s%s%s%s\n",
113         (rval&MM_MMX) ? "MMX ":"",
114         (rval&MM_MMXEXT) ? "MMX2 ":"",
115         (rval&MM_SSE) ? "SSE ":"",
116         (rval&MM_SSE2) ? "SSE2 ":"",
117         (rval&MM_3DNOW) ? "3DNow ":"",
118         (rval&MM_3DNOWEXT) ? "3DNowExt ":"");
119 #endif
120     return rval;
121 }
122
123 #ifdef __TEST__
124 int main ( void )
125 {
126   int mm_flags;
127   mm_flags = mm_support();
128   printf("mm_support = 0x%08X\n",mm_flags);
129   return 0;
130 }
131 #endif