src/cpuinfo/SDL_cpuinfo.c
author Sam Lantinga <slouken@libsdl.org>
Mon, 24 Nov 2003 09:30:14 +0000
changeset 747 da36f59485da
parent 745 71ee03909f42
child 749 06cdd106d61c
permissions -rw-r--r--
Check for CPUID before checking for 3DNow!
     1 /*
     2     SDL - Simple DirectMedia Layer
     3     Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002  Sam Lantinga
     4 
     5     This library is free software; you can redistribute it and/or
     6     modify it under the terms of the GNU Library General Public
     7     License as published by the Free Software Foundation; either
     8     version 2 of the License, or (at your option) any later version.
     9 
    10     This library is distributed in the hope that it will be useful,
    11     but WITHOUT ANY WARRANTY; without even the implied warranty of
    12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    13     Library General Public License for more details.
    14 
    15     You should have received a copy of the GNU Library General Public
    16     License along with this library; if not, write to the Free
    17     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
    18 
    19     Sam Lantinga
    20     slouken@libsdl.org
    21 */
    22 
    23 #ifdef SAVE_RCSID
    24 static char rcsid =
    25  "@(#) $Id$";
    26 #endif
    27 
    28 /* CPU feature detection for SDL */
    29 
    30 #include "SDL.h"
    31 #include "SDL_cpuinfo.h"
    32 
    33 #define CPU_HAS_RDTSC	0x00000001
    34 #define CPU_HAS_MMX	0x00000002
    35 #define CPU_HAS_3DNOW	0x00000004
    36 #define CPU_HAS_SSE	0x00000008
    37 
    38 static __inline__ int CPU_haveCPUID()
    39 {
    40 	int has_CPUID = 0;
    41 #if defined(__GNUC__) && defined(i386)
    42 	__asm__ (
    43 "push %%ecx\n"
    44 "        pushfl                      # Get original EFLAGS             \n"
    45 "        popl    %%eax                                                 \n"
    46 "        movl    %%eax,%%ecx                                           \n"
    47 "        xorl    $0x200000,%%eax     # Flip ID bit in EFLAGS           \n"
    48 "        pushl   %%eax               # Save new EFLAGS value on stack  \n"
    49 "        popfl                       # Replace current EFLAGS value    \n"
    50 "        pushfl                      # Get new EFLAGS                  \n"
    51 "        popl    %%eax               # Store new EFLAGS in EAX         \n"
    52 "        xorl    %%ecx,%%eax         # Can not toggle ID bit,          \n"
    53 "        jz      1f                  # Processor=80486                 \n"
    54 "        movl    $1,%0               # We have CPUID support           \n"
    55 "1:                                                                    \n"
    56 "pop %%ecx\n"
    57 	: "=r" (has_CPUID)
    58 	:
    59 	: "%eax", "%ecx"
    60 	);
    61 #elif defined(_MSC_VER)
    62 	__asm__ {
    63         pushfd                      ; Get original EFLAGS
    64         pop     eax
    65         mov     ecx, eax
    66         xor     eax, 200000h        ; Flip ID bit in EFLAGS
    67         push    eax                 ; Save new EFLAGS value on stack
    68         popfd                       ; Replace current EFLAGS value
    69         pushfd                      ; Get new EFLAGS
    70         pop     eax                 ; Store new EFLAGS in EAX
    71         xor     eax, ecx            ; Can not toggle ID bit,
    72         jz      done                ; Processor=80486
    73         mov     has_CPUID,1         ; We have CPUID support
    74 done:
    75 	}
    76 #endif
    77 	return has_CPUID;
    78 }
    79 
    80 static __inline__ int CPU_getCPUIDFeatures()
    81 {
    82 	int features = 0;
    83 #if defined(__GNUC__) && defined(i386)
    84 	__asm__ (
    85 "push %%ebx\n"
    86 "push %%ecx\n"
    87 "push %%edx\n"
    88 "        xorl    %%eax,%%eax         # Set up for CPUID instruction    \n"
    89 "        cpuid                       # Get and save vendor ID          \n"
    90 "        cmpl    $1,%%eax            # Make sure 1 is valid input for CPUID\n"
    91 "        jl      1f                  # We dont have the CPUID instruction\n"
    92 "        xorl    %%eax,%%eax                                           \n"
    93 "        incl    %%eax                                                 \n"
    94 "        cpuid                       # Get family/model/stepping/features\n"
    95 "        movl    %%edx,%0                                              \n"
    96 "1:                                                                    \n"
    97 "pop %%edx\n"
    98 "pop %%ecx\n"
    99 "pop %%ebx\n"
   100 	: "=r" (features)
   101 	:
   102 	: "%eax", "%ebx", "%ecx", "%edx"
   103 	);
   104 #elif defined(_MSC_VER)
   105 	__asm__ {
   106         xor     eax, eax            ; Set up for CPUID instruction
   107         cpuid                       ; Get and save vendor ID
   108         cmp     eax, 1              ; Make sure 1 is valid input for CPUID
   109         jl      done                ; We dont have the CPUID instruction
   110         xor     eax, eax
   111         inc     eax
   112         cpuid                       ; Get family/model/stepping/features
   113         mov     features, edx
   114 done:
   115 	}
   116 #endif
   117 	return features;
   118 }
   119 
   120 static __inline__ int CPU_haveRDTSC()
   121 {
   122 	if ( CPU_haveCPUID() ) {
   123 		return (CPU_getCPUIDFeatures() & 0x00000010);
   124 	}
   125 	return 0;
   126 }
   127 
   128 static __inline__ int CPU_haveMMX()
   129 {
   130 	if ( CPU_haveCPUID() ) {
   131 		return (CPU_getCPUIDFeatures() & 0x00800000);
   132 	}
   133 	return 0;
   134 }
   135 
   136 static __inline__ int CPU_have3DNow()
   137 {
   138 	int has_3DNow = 0;
   139 	if ( !CPU_haveCPUID() ) {
   140 		return 0;
   141 	}
   142 #if defined(__GNUC__) && defined(i386)
   143 	__asm__ (
   144 "push %%ebx\n"
   145 "push %%ecx\n"
   146 "push %%edx\n"
   147 "        movl    $0x80000000,%%eax   # Query for extended functions    \n"
   148 "        cpuid                       # Get extended function limit     \n"
   149 "        cmpl    $0x80000001,%%eax                                     \n"
   150 "        jbe     1f                  # Nope, we dont have function 800000001h\n"
   151 "        movl    $0x80000001,%%eax   # Setup extended function 800000001h\n"
   152 "        cpuid                       # and get the information         \n"
   153 "        testl   $0x80000000,%%edx   # Bit 31 is set if 3DNow! present \n"
   154 "        jz      1f                  # Nope, we dont have 3DNow support\n"
   155 "        movl    $1,%0               # Yep, we have 3DNow! support!    \n"
   156 "1:                                                                    \n"
   157 "pop %%edx\n"
   158 "pop %%ecx\n"
   159 "pop %%ebx\n"
   160 	: "=r" (has_3DNow)
   161 	:
   162 	: "%eax", "%ebx", "%ecx", "%edx"
   163 	);
   164 #elif defined(_MSC_VER)
   165 	__asm__ {
   166         mov     eax,80000000h       ; Query for extended functions
   167         cpuid                       ; Get extended function limit
   168         cmp     eax,80000001h
   169         jbe     done                ; Nope, we dont have function 800000001h
   170         mov     eax,80000001h       ; Setup extended function 800000001h
   171         cpuid                       ; and get the information
   172         test    edx,80000000h       ; Bit 31 is set if 3DNow! present
   173         jz      done                ; Nope, we dont have 3DNow support
   174         mov     has_3DNow,1         ; Yep, we have 3DNow! support!
   175 done:
   176 	}
   177 #endif
   178 	return has_3DNow;
   179 }
   180 
   181 static __inline__ int CPU_haveSSE()
   182 {
   183 	if ( CPU_haveCPUID() ) {
   184 		return (CPU_getCPUIDFeatures() & 0x02000000);
   185 	}
   186 	return 0;
   187 }
   188 
   189 static Uint32 SDL_CPUFeatures = 0xFFFFFFFF;
   190 
   191 static Uint32 SDL_GetCPUFeatures()
   192 {
   193 	if ( SDL_CPUFeatures == 0xFFFFFFFF ) {
   194 		SDL_CPUFeatures = 0;
   195 		if ( CPU_haveRDTSC() ) {
   196 			SDL_CPUFeatures |= CPU_HAS_RDTSC;
   197 		}
   198 		if ( CPU_haveMMX() ) {
   199 			SDL_CPUFeatures |= CPU_HAS_MMX;
   200 		}
   201 		if ( CPU_have3DNow() ) {
   202 			SDL_CPUFeatures |= CPU_HAS_3DNOW;
   203 		}
   204 		if ( CPU_haveSSE() ) {
   205 			SDL_CPUFeatures |= CPU_HAS_SSE;
   206 		}
   207 	}
   208 	return SDL_CPUFeatures;
   209 }
   210 
   211 SDL_bool SDL_HasRDTSC()
   212 {
   213 	if ( SDL_GetCPUFeatures() & CPU_HAS_RDTSC ) {
   214 		return SDL_TRUE;
   215 	}
   216 	return SDL_FALSE;
   217 }
   218 
   219 SDL_bool SDL_HasMMX()
   220 {
   221 	if ( SDL_GetCPUFeatures() & CPU_HAS_MMX ) {
   222 		return SDL_TRUE;
   223 	}
   224 	return SDL_FALSE;
   225 }
   226 
   227 SDL_bool SDL_Has3DNow()
   228 {
   229 	if ( SDL_GetCPUFeatures() & CPU_HAS_3DNOW ) {
   230 		return SDL_TRUE;
   231 	}
   232 	return SDL_FALSE;
   233 }
   234 
   235 SDL_bool SDL_HasSSE()
   236 {
   237 	if ( SDL_GetCPUFeatures() & CPU_HAS_SSE ) {
   238 		return SDL_TRUE;
   239 	}
   240 	return SDL_FALSE;
   241 }
   242 
   243 #ifdef TEST_MAIN
   244 
   245 #include <stdio.h>
   246 
   247 int main()
   248 {
   249 	printf("MMX: %d\n", SDL_HasMMX());
   250 	printf("3DNow: %d\n", SDL_Has3DNow());
   251 	printf("SSE: %d\n", SDL_HasSSE());
   252 	return 0;
   253 }
   254 
   255 #endif /* TEST_MAIN */