1 /*
2  * SpanDSP - a series of DSP components for telephony
3  *
4  * testcpuid.c - Check the CPU type, to identify special features, like SSE.
5  *
6  * Written by Steve Underwood <steveu@coppice.org>
7  * Stitched together from bits of testing code found here and there
8  *
9  * Copyright (C) 2004 Steve Underwood
10  *
11  * All rights reserved.
12  *
13  * This program is free software; you can redistribute it and/or modify
14  * it under the terms of the GNU Lesser General Public License version 2.1,
15  * as published by the Free Software Foundation.
16  *
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU Lesser General Public License for more details.
21  *
22  * You should have received a copy of the GNU Lesser General Public
23  * License along with this program; if not, write to the Free Software
24  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25  *
26  * $Id: testcpuid.c,v 1.12 2008/05/13 13:17:24 steveu Exp $
27  */
28 
29 /*! \file */
30 
31 #if defined(HAVE_CONFIG_H)
32 #include <config.h>
33 #endif
34 
35 #include <inttypes.h>
36 
37 /* Make this file just disappear if we are not on an x86 machine */
38 #if defined(__i386__) //  ||  defined(__x86_64__)
39 
40 #define X86_EFLAGS_CF   0x00000001 /* Carry Flag */
41 #define X86_EFLAGS_PF   0x00000004 /* Parity Flag */
42 #define X86_EFLAGS_AF   0x00000010 /* Auxillary carry Flag */
43 #define X86_EFLAGS_ZF   0x00000040 /* Zero Flag */
44 #define X86_EFLAGS_SF   0x00000080 /* Sign Flag */
45 #define X86_EFLAGS_TF   0x00000100 /* Trap Flag */
46 #define X86_EFLAGS_IF   0x00000200 /* Interrupt Flag */
47 #define X86_EFLAGS_DF   0x00000400 /* Direction Flag */
48 #define X86_EFLAGS_OF   0x00000800 /* Overflow Flag */
49 #define X86_EFLAGS_IOPL 0x00003000 /* IOPL mask */
50 #define X86_EFLAGS_NT   0x00004000 /* Nested Task */
51 #define X86_EFLAGS_RF   0x00010000 /* Resume Flag */
52 #define X86_EFLAGS_VM   0x00020000 /* Virtual Mode */
53 #define X86_EFLAGS_AC   0x00040000 /* Alignment Check */
54 #define X86_EFLAGS_VIF  0x00080000 /* Virtual Interrupt Flag */
55 #define X86_EFLAGS_VIP  0x00100000 /* Virtual Interrupt Pending */
56 #define X86_EFLAGS_ID   0x00200000 /* CPUID detection flag */
57 
58 /* Standard macro to see if a specific flag is changeable */
flag_is_changeable_p(uint32_t flag)59 static __inline__ int flag_is_changeable_p(uint32_t flag)
60 {
61     uint32_t f1;
62     uint32_t f2;
63 
64     __asm__ __volatile__ (
65         " pushfl\n"
66         " pushfl\n"
67         " popl %0\n"
68         " movl %0,%1\n"
69         " xorl %2,%0\n"
70         " pushl %0\n"
71         " popfl\n"
72         " pushfl\n"
73         " popl %0\n"
74         " popfl\n"
75         : "=&r" (f1), "=&r" (f2)
76         : "ir" (flag));
77 
78     return ((f1^f2) & flag) != 0;
79 }
80 /*- End of function --------------------------------------------------------*/
81 
82 /* Probe for the CPUID instruction */
have_cpuid_p(void)83 static int have_cpuid_p(void)
84 {
85     return flag_is_changeable_p(X86_EFLAGS_ID);
86 }
87 /*- End of function --------------------------------------------------------*/
88 
has_MMX(void)89 int has_MMX(void)
90 {
91     int result;
92 
93     if (!have_cpuid_p())
94         return  0;
95     /*endif*/
96     __asm__ __volatile__ (
97         " push  %%ebx;\n"
98 	" mov	$1,%%eax;\n"
99 	" cpuid;\n"
100 	" xor   %%eax,%%eax;\n"
101 	" test	$0x800000,%%edx;\n"
102 	" jz	1f;\n"	            /* no MMX support */
103 	" inc   %%eax;\n"	    /* MMX support */
104         "1:\n"
105         " pop  %%ebx;\n"
106 	: "=a" (result)
107         :
108         : "ecx", "edx");
109     return  result;
110 }
111 /*- End of function --------------------------------------------------------*/
112 
has_SIMD(void)113 int has_SIMD(void)
114 {
115     int result;
116 
117     if (!have_cpuid_p())
118         return  0;
119     /*endif*/
120     __asm__ __volatile__ (
121         " push  %%ebx;\n"
122 	" mov	$1,%%eax;\n"
123 	" cpuid;\n"
124 	" xor   %%eax,%%eax;\n"
125 	" test	$0x02000000,%%edx;\n"
126 	" jz	1f;\n"		        /* no SIMD support */
127 	" inc	%%eax;\n"		/* SIMD support */
128         "1:\n"
129         " pop  %%ebx;\n"
130 	: "=a" (result)
131         :
132         : "ecx", "edx");
133     return  result;
134 }
135 /*- End of function --------------------------------------------------------*/
136 
has_SIMD2(void)137 int has_SIMD2(void)
138 {
139     int result;
140 
141     if (!have_cpuid_p())
142         return  0;
143     /*endif*/
144     __asm__ __volatile__ (
145         " push  %%ebx;\n"
146 	" mov	$1,%%eax;\n"
147 	" cpuid;\n"
148 	" xor   %%eax,%%eax;\n"
149 	" test	$0x04000000,%%edx;\n"
150 	" jz	1f;\n"		        /* no SIMD2 support */
151 	" inc	%%eax;\n"		/* SIMD2 support */
152         "1:\n"
153         " pop  %%ebx;\n"
154 	: "=a" (result)
155         :
156         : "ecx", "edx");
157     return  result;
158 }
159 /*- End of function --------------------------------------------------------*/
160 
has_3DNow(void)161 int has_3DNow(void)
162 {
163     int result;
164 
165     if (!have_cpuid_p())
166         return  0;
167     /*endif*/
168     __asm__ __volatile__ (
169         " push  %%ebx;\n"
170 	" mov	$0x80000000,%%eax;\n"
171 	" cpuid;\n"
172         " xor   %%ecx,%%ecx;\n"
173 	" cmp	$0x80000000,%%eax;\n"
174 	" jbe	1f;\n"		        /* no extended MSR(1), so no 3DNow! */
175 	" mov	$0x80000001,%%eax;\n"
176 	" cpuid;\n"
177         " xor   %%ecx,%%ecx;\n"
178 	" test	$0x80000000,%%edx;\n"
179 	" jz	1f;\n"		        /* no 3DNow! support */
180 	" inc   %%ecx;\n"		/* 3DNow! support */
181         "1:\n"
182         " pop  %%ebx;\n"
183 	: "=c" (result)
184         :
185         : "eax", "edx");
186     return  result;
187 }
188 /*- End of function --------------------------------------------------------*/
189 
190 #if defined(TESTBED)
main(int argc,char * argv[])191 int main(int argc, char *argv[])
192 {
193     int result;
194 
195     result = has_MMX();
196     printf("MMX is %x\n", result);
197     result = has_SIMD();
198     printf("SIMD is %x\n", result);
199     result = has_SIMD2();
200     printf("SIMD2 is %x\n", result);
201     result = has_3DNow();
202     printf("3DNow is %x\n", result);
203     return  0;
204 }
205 /*- End of function --------------------------------------------------------*/
206 #endif
207 
208 #endif
209 /*- End of file ------------------------------------------------------------*/
210