|
1 /******************************************************************** |
|
2 * * |
|
3 * THIS FILE IS PART OF THE OggTheora SOFTWARE CODEC SOURCE CODE. * |
|
4 * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * |
|
5 * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * |
|
6 * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * |
|
7 * * |
|
8 * THE Theora SOURCE CODE IS COPYRIGHT (C) 2002-2009 * |
|
9 * by the Xiph.Org Foundation and contributors http://www.xiph.org/ * |
|
10 * * |
|
11 ******************************************************************** |
|
12 |
|
13 CPU capability detection for x86 processors. |
|
14 Originally written by Rudolf Marek. |
|
15 |
|
16 function: |
|
17 last mod: $Id: x86cpu.c 17410 2010-09-21 21:53:48Z tterribe $ |
|
18 |
|
19 ********************************************************************/ |
|
20 |
|
21 #include "x86cpu.h" |
|
22 |
|
23 #if !defined(OC_X86_ASM) |
|
24 ogg_uint32_t oc_cpu_flags_get(void){ |
|
25 return 0; |
|
26 } |
|
27 #else |
|
28 /*Why does MSVC need this complicated rigamarole? |
|
29 At this point I honestly do not care.*/ |
|
30 |
|
31 /*Visual C cpuid helper function. |
|
32 For VS2005 we could as well use the _cpuid builtin, but that wouldn't work |
|
33 for VS2003 users, so we do it in inline assembler.*/ |
|
34 static void oc_cpuid_helper(ogg_uint32_t _cpu_info[4],ogg_uint32_t _op){ |
|
35 _asm{ |
|
36 mov eax,[_op] |
|
37 mov esi,_cpu_info |
|
38 cpuid |
|
39 mov [esi+0],eax |
|
40 mov [esi+4],ebx |
|
41 mov [esi+8],ecx |
|
42 mov [esi+12],edx |
|
43 } |
|
44 } |
|
45 |
|
46 # define cpuid(_op,_eax,_ebx,_ecx,_edx) \ |
|
47 do{ \ |
|
48 ogg_uint32_t cpu_info[4]; \ |
|
49 oc_cpuid_helper(cpu_info,_op); \ |
|
50 (_eax)=cpu_info[0]; \ |
|
51 (_ebx)=cpu_info[1]; \ |
|
52 (_ecx)=cpu_info[2]; \ |
|
53 (_edx)=cpu_info[3]; \ |
|
54 }while(0) |
|
55 |
|
56 static void oc_detect_cpuid_helper(ogg_uint32_t *_eax,ogg_uint32_t *_ebx){ |
|
57 _asm{ |
|
58 pushfd |
|
59 pushfd |
|
60 pop eax |
|
61 mov ebx,eax |
|
62 xor eax,200000h |
|
63 push eax |
|
64 popfd |
|
65 pushfd |
|
66 pop eax |
|
67 popfd |
|
68 mov ecx,_eax |
|
69 mov [ecx],eax |
|
70 mov ecx,_ebx |
|
71 mov [ecx],ebx |
|
72 } |
|
73 } |
|
74 |
|
75 static ogg_uint32_t oc_parse_intel_flags(ogg_uint32_t _edx,ogg_uint32_t _ecx){ |
|
76 ogg_uint32_t flags; |
|
77 /*If there isn't even MMX, give up.*/ |
|
78 if(!(_edx&0x00800000))return 0; |
|
79 flags=OC_CPU_X86_MMX; |
|
80 if(_edx&0x02000000)flags|=OC_CPU_X86_MMXEXT|OC_CPU_X86_SSE; |
|
81 if(_edx&0x04000000)flags|=OC_CPU_X86_SSE2; |
|
82 if(_ecx&0x00000001)flags|=OC_CPU_X86_PNI; |
|
83 if(_ecx&0x00000100)flags|=OC_CPU_X86_SSSE3; |
|
84 if(_ecx&0x00080000)flags|=OC_CPU_X86_SSE4_1; |
|
85 if(_ecx&0x00100000)flags|=OC_CPU_X86_SSE4_2; |
|
86 return flags; |
|
87 } |
|
88 |
|
89 static ogg_uint32_t oc_parse_amd_flags(ogg_uint32_t _edx,ogg_uint32_t _ecx){ |
|
90 ogg_uint32_t flags; |
|
91 /*If there isn't even MMX, give up.*/ |
|
92 if(!(_edx&0x00800000))return 0; |
|
93 flags=OC_CPU_X86_MMX; |
|
94 if(_edx&0x00400000)flags|=OC_CPU_X86_MMXEXT; |
|
95 if(_edx&0x80000000)flags|=OC_CPU_X86_3DNOW; |
|
96 if(_edx&0x40000000)flags|=OC_CPU_X86_3DNOWEXT; |
|
97 if(_ecx&0x00000040)flags|=OC_CPU_X86_SSE4A; |
|
98 if(_ecx&0x00000800)flags|=OC_CPU_X86_SSE5; |
|
99 return flags; |
|
100 } |
|
101 |
|
102 ogg_uint32_t oc_cpu_flags_get(void){ |
|
103 ogg_uint32_t flags; |
|
104 ogg_uint32_t eax; |
|
105 ogg_uint32_t ebx; |
|
106 ogg_uint32_t ecx; |
|
107 ogg_uint32_t edx; |
|
108 # if !defined(__amd64__)&&!defined(__x86_64__) |
|
109 /*Not all x86-32 chips support cpuid, so we have to check.*/ |
|
110 oc_detect_cpuid_helper(&eax,&ebx); |
|
111 /*No cpuid.*/ |
|
112 if(eax==ebx)return 0; |
|
113 # endif |
|
114 cpuid(0,eax,ebx,ecx,edx); |
|
115 /* l e t n I e n i u n e G*/ |
|
116 if(ecx==0x6C65746E&&edx==0x49656E69&&ebx==0x756E6547|| |
|
117 /* 6 8 x M T e n i u n e G*/ |
|
118 ecx==0x3638784D&&edx==0x54656E69&&ebx==0x756E6547){ |
|
119 int family; |
|
120 int model; |
|
121 /*Intel, Transmeta (tested with Crusoe TM5800):*/ |
|
122 cpuid(1,eax,ebx,ecx,edx); |
|
123 flags=oc_parse_intel_flags(edx,ecx); |
|
124 family=(eax>>8)&0xF; |
|
125 model=(eax>>4)&0xF; |
|
126 /*The SSE unit on the Pentium M and Core Duo is much slower than the MMX |
|
127 unit, so don't use it.*/ |
|
128 if(family==6&&(model==9||model==13||model==14)){ |
|
129 flags&=~(OC_CPU_X86_SSE2|OC_CPU_X86_PNI); |
|
130 } |
|
131 } |
|
132 /* D M A c i t n e h t u A*/ |
|
133 else if(ecx==0x444D4163&&edx==0x69746E65&&ebx==0x68747541|| |
|
134 /* C S N y b e d o e G*/ |
|
135 ecx==0x43534e20&&edx==0x79622065&&ebx==0x646f6547){ |
|
136 /*AMD, Geode:*/ |
|
137 cpuid(0x80000000,eax,ebx,ecx,edx); |
|
138 if(eax<0x80000001)flags=0; |
|
139 else{ |
|
140 cpuid(0x80000001,eax,ebx,ecx,edx); |
|
141 flags=oc_parse_amd_flags(edx,ecx); |
|
142 } |
|
143 /*Also check for SSE.*/ |
|
144 cpuid(1,eax,ebx,ecx,edx); |
|
145 flags|=oc_parse_intel_flags(edx,ecx); |
|
146 } |
|
147 /*Technically some VIA chips can be configured in the BIOS to return any |
|
148 string here the user wants. |
|
149 There is a special detection method that can be used to identify such |
|
150 processors, but in my opinion, if the user really wants to change it, they |
|
151 deserve what they get.*/ |
|
152 /* s l u a H r u a t n e C*/ |
|
153 else if(ecx==0x736C7561&&edx==0x48727561&&ebx==0x746E6543){ |
|
154 /*VIA:*/ |
|
155 /*I only have documentation for the C7 (Esther) and Isaiah (forthcoming) |
|
156 chips (thanks to the engineers from Centaur Technology who provided it). |
|
157 These chips support Intel-like cpuid info. |
|
158 The C3-2 (Nehemiah) cores appear to, as well.*/ |
|
159 cpuid(1,eax,ebx,ecx,edx); |
|
160 flags=oc_parse_intel_flags(edx,ecx); |
|
161 if(eax>=0x80000001){ |
|
162 /*The (non-Nehemiah) C3 processors support AMD-like cpuid info. |
|
163 We need to check this even if the Intel test succeeds to pick up 3DNow! |
|
164 support on these processors. |
|
165 Unlike actual AMD processors, we cannot _rely_ on this info, since |
|
166 some cores (e.g., the 693 stepping of the Nehemiah) claim to support |
|
167 this function, yet return edx=0, despite the Intel test indicating |
|
168 MMX support. |
|
169 Therefore the features detected here are strictly added to those |
|
170 detected by the Intel test.*/ |
|
171 /*TODO: How about earlier chips?*/ |
|
172 cpuid(0x80000001,eax,ebx,ecx,edx); |
|
173 /*Note: As of the C7, this function returns Intel-style extended feature |
|
174 flags, not AMD-style. |
|
175 Currently, this only defines bits 11, 20, and 29 (0x20100800), which |
|
176 do not conflict with any of the AMD flags we inspect. |
|
177 For the remaining bits, Intel tells us, "Do not count on their value", |
|
178 but VIA assures us that they will all be zero (at least on the C7 and |
|
179 Isaiah chips). |
|
180 In the (unlikely) event a future processor uses bits 18, 19, 30, or 31 |
|
181 (0xC0C00000) for something else, we will have to add code to detect |
|
182 the model to decide when it is appropriate to inspect them.*/ |
|
183 flags|=oc_parse_amd_flags(edx,ecx); |
|
184 } |
|
185 } |
|
186 else{ |
|
187 /*Implement me.*/ |
|
188 flags=0; |
|
189 } |
|
190 return flags; |
|
191 } |
|
192 #endif |