MythTV  0.27pre
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Groups Pages
cpu_detect_x86_gcc.cpp
Go to the documentation of this file.
1 
2 
3 
4 
5 
6 
7 
8 
9 
10 
11 
12 
13 
14 //
15 // Last changed : $Date$
16 // File revision : $Revision$
17 //
18 // $Id$
19 //
21 //
22 // License :
23 //
24 // SoundTouch audio processing library
25 // Copyright (c) Olli Parviainen
26 //
27 // This library is free software; you can redistribute it and/or
28 // modify it under the terms of the GNU Lesser General Public
29 // License as published by the Free Software Foundation; either
30 // version 2.1 of the License, or (at your option) any later version.
31 //
32 // This library is distributed in the hope that it will be useful,
33 // but WITHOUT ANY WARRANTY; without even the implied warranty of
34 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
35 // Lesser General Public License for more details.
36 //
37 // You should have received a copy of the GNU Lesser General Public
38 // License along with this library; if not, write to the Free Software
39 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
40 //
42 
43 #include <stdexcept>
44 #include <string>
45 #include "cpu_detect.h"
46 
47 #ifndef __GNUC__
48 #error wrong platform - this source code file is for the GNU C compiler.
49 #endif
50 
51 #include "config.h"
52 
53 using namespace std;
54 
55 #include <stdio.h>
57 //
58 // processor instructions extension detection routines
59 //
61 
62 
63 // Flag variable indicating whick ISA extensions are disabled (for debugging)
64 static uint _dwDisabledISA = 0x00; // 0xffffffff; //<- use this to disable all extensions
65 
66 // Disables given set of instruction extensions. See SUPPORT_... defines.
67 void disableExtensions(uint dwDisableMask)
68 {
69  _dwDisabledISA = dwDisableMask;
70 }
71 
72 #if ARCH_X86
73 
74 #if ARCH_X86_64
75 # define REG_b "rbx"
76 # define REG_S "rsi"
77 #else
78 # define REG_b "ebx"
79 # define REG_S "esi"
80 #endif
81 
82 /* ebx saving is necessary for PIC. gcc seems unable to see it alone */
83 #define cpuid(index,eax,ebx,ecx,edx)\
84  __asm __volatile\
85  ("mov %%"REG_b", %%"REG_S"\n\t"\
86  "cpuid\n\t"\
87  "xchg %%"REG_b", %%"REG_S\
88  : "=a" (eax), "=S" (ebx),\
89  "=c" (ecx), "=d" (edx)\
90  : "0" (index));
91 
92 /* Function to test if multimedia instructions are supported... */
93 static int mm_support(void)
94 {
95  int rval = 0;
96  int eax, ebx, ecx, edx;
97  int max_std_level, max_ext_level, std_caps=0, ext_caps=0;
98  long a, c;
99 
100  __asm__ __volatile__ (
101  /* See if CPUID instruction is supported ... */
102  /* ... Get copies of EFLAGS into eax and ecx */
103  "pushf\n\t"
104  "pop %0\n\t"
105  "mov %0, %1\n\t"
106 
107  /* ... Toggle the ID bit in one copy and store */
108  /* to the EFLAGS reg */
109  "xor $0x200000, %0\n\t"
110  "push %0\n\t"
111  "popf\n\t"
112 
113  /* ... Get the (hopefully modified) EFLAGS */
114  "pushf\n\t"
115  "pop %0\n\t"
116  : "=a" (a), "=c" (c)
117  :
118  : "cc"
119  );
120 
121  if (a == c)
122  return 0; /* CPUID not supported */
123 
124  cpuid(0, max_std_level, ebx, ecx, edx);
125 
126  if(max_std_level >= 1){
127  cpuid(1, eax, ebx, ecx, std_caps);
128  if (std_caps & (1<<23))
129  rval |= MM_MMX;
130  if (std_caps & (1<<25))
131  rval |= MM_MMXEXT | MM_SSE;
132  if (std_caps & (1<<26))
133  rval |= MM_SSE2;
134  if (ecx & 1)
135  rval |= MM_SSE3;
136  if (ecx & 0x00000200 )
137  rval |= MM_SSSE3;
138  if (ecx & 0x00080000 )
139  rval |= MM_SSE4;
140  if (ecx & 0x00100000 )
141  rval |= MM_SSE42;
142  }
143 
144  cpuid(0x80000000, max_ext_level, ebx, ecx, edx);
145 
146  if(max_ext_level >= 0x80000001){
147  cpuid(0x80000001, eax, ebx, ecx, ext_caps);
148  if (ext_caps & (1<<31))
149  rval |= MM_3DNOW;
150  if (ext_caps & (1<<30))
151  rval |= MM_3DNOWEXT;
152  if (ext_caps & (1<<23))
153  rval |= MM_MMX;
154  }
155 
156  cpuid(0, eax, ebx, ecx, edx);
157  if ( ebx == 0x68747541 &&
158  edx == 0x69746e65 &&
159  ecx == 0x444d4163) {
160  /* AMD */
161  if(ext_caps & (1<<22))
162  rval |= MM_MMXEXT;
163  } else if (ebx == 0x746e6543 &&
164  edx == 0x48727561 &&
165  ecx == 0x736c7561) { /* "CentaurHauls" */
166  /* VIA C3 */
167  if(ext_caps & (1<<24))
168  rval |= MM_MMXEXT;
169  } else if (ebx == 0x69727943 &&
170  edx == 0x736e4978 &&
171  ecx == 0x64616574) {
172  /* Cyrix Section */
173  /* See if extended CPUID level 80000001 is supported */
174  /* The value of CPUID/80000001 for the 6x86MX is undefined
175  according to the Cyrix CPU Detection Guide (Preliminary
176  Rev. 1.01 table 1), so we'll check the value of eax for
177  CPUID/0 to see if standard CPUID level 2 is supported.
178  According to the table, the only CPU which supports level
179  2 is also the only one which supports extended CPUID levels.
180  */
181  if (eax < 2)
182  return rval;
183  if (ext_caps & (1<<24))
184  rval |= MM_MMXEXT;
185  }
186 #if 0
187  av_log(NULL, AV_LOG_DEBUG, "%s%s%s%s%s%s\n",
188  (rval&MM_MMX) ? "MMX ":"",
189  (rval&MM_MMXEXT) ? "MMX2 ":"",
190  (rval&MM_SSE) ? "SSE ":"",
191  (rval&MM_SSE2) ? "SSE2 ":"",
192  (rval&MM_3DNOW) ? "3DNow ":"",
193  (rval&MM_3DNOWEXT) ? "3DNowExt ":"");
194 #endif
195  return rval;
196 }
197 #endif
198 
201 {
202 #if !ARCH_X86
203  return 0; // always disable extensions on non-x86 platforms.
204 #else
205  return mm_support() & ~_dwDisabledISA;
206 #endif
207 }