src/cpuinfo/SDL_cpuinfo.c
author Sam Lantinga <slouken@libsdl.org>
Mon, 24 Nov 2003 09:16:52 +0000
changeset 745 71ee03909f42
parent 739 22dbf364c017
child 747 da36f59485da
permissions -rw-r--r--
Greatly simplified the SDL CPU info code
     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 defined(__GNUC__) && defined(i386)
   140 	__asm__ (
   141 "push %%ebx\n"
   142 "push %%ecx\n"
   143 "push %%edx\n"
   144 "        movl    $0x80000000,%%eax   # Query for extended functions    \n"
   145 "        cpuid                       # Get extended function limit     \n"
   146 "        cmpl    $0x80000001,%%eax                                     \n"
   147 "        jbe     1f                  # Nope, we dont have function 800000001h\n"
   148 "        movl    $0x80000001,%%eax   # Setup extended function 800000001h\n"
   149 "        cpuid                       # and get the information         \n"
   150 "        testl   $0x80000000,%%edx   # Bit 31 is set if 3DNow! present \n"
   151 "        jz      1f                  # Nope, we dont have 3DNow support\n"
   152 "        movl    $1,%0               # Yep, we have 3DNow! support!    \n"
   153 "1:                                                                    \n"
   154 "pop %%edx\n"
   155 "pop %%ecx\n"
   156 "pop %%ebx\n"
   157 	: "=r" (has_3DNow)
   158 	:
   159 	: "%eax", "%ebx", "%ecx", "%edx"
   160 	);
   161 #elif defined(_MSC_VER)
   162 	__asm__ {
   163         mov     eax,80000000h       ; Query for extended functions
   164         cpuid                       ; Get extended function limit
   165         cmp     eax,80000001h
   166         jbe     done                ; Nope, we dont have function 800000001h
   167         mov     eax,80000001h       ; Setup extended function 800000001h
   168         cpuid                       ; and get the information
   169         test    edx,80000000h       ; Bit 31 is set if 3DNow! present
   170         jz      done                ; Nope, we dont have 3DNow support
   171         mov     has_3DNow,1         ; Yep, we have 3DNow! support!
   172 done:
   173 	}
   174 #endif
   175 	return has_3DNow;
   176 }
   177 
   178 static __inline__ int CPU_haveSSE()
   179 {
   180 	if ( CPU_haveCPUID() ) {
   181 		return (CPU_getCPUIDFeatures() & 0x02000000);
   182 	}
   183 	return 0;
   184 }
   185 
   186 static Uint32 SDL_CPUFeatures = 0xFFFFFFFF;
   187 
   188 static Uint32 SDL_GetCPUFeatures()
   189 {
   190 	if ( SDL_CPUFeatures == 0xFFFFFFFF ) {
   191 		SDL_CPUFeatures = 0;
   192 		if ( CPU_haveRDTSC() ) {
   193 			SDL_CPUFeatures |= CPU_HAS_RDTSC;
   194 		}
   195 		if ( CPU_haveMMX() ) {
   196 			SDL_CPUFeatures |= CPU_HAS_MMX;
   197 		}
   198 		if ( CPU_have3DNow() ) {
   199 			SDL_CPUFeatures |= CPU_HAS_3DNOW;
   200 		}
   201 		if ( CPU_haveSSE() ) {
   202 			SDL_CPUFeatures |= CPU_HAS_SSE;
   203 		}
   204 	}
   205 	return SDL_CPUFeatures;
   206 }
   207 
   208 SDL_bool SDL_HasRDTSC()
   209 {
   210 	if ( SDL_GetCPUFeatures() & CPU_HAS_RDTSC ) {
   211 		return SDL_TRUE;
   212 	}
   213 	return SDL_FALSE;
   214 }
   215 
   216 SDL_bool SDL_HasMMX()
   217 {
   218 	if ( SDL_GetCPUFeatures() & CPU_HAS_MMX ) {
   219 		return SDL_TRUE;
   220 	}
   221 	return SDL_FALSE;
   222 }
   223 
   224 SDL_bool SDL_Has3DNow()
   225 {
   226 	if ( SDL_GetCPUFeatures() & CPU_HAS_3DNOW ) {
   227 		return SDL_TRUE;
   228 	}
   229 	return SDL_FALSE;
   230 }
   231 
   232 SDL_bool SDL_HasSSE()
   233 {
   234 	if ( SDL_GetCPUFeatures() & CPU_HAS_SSE ) {
   235 		return SDL_TRUE;
   236 	}
   237 	return SDL_FALSE;
   238 }
   239 
   240 #ifdef TEST_MAIN
   241 
   242 #include <stdio.h>
   243 
   244 int main()
   245 {
   246 	printf("MMX: %d\n", SDL_HasMMX());
   247 	printf("3DNow: %d\n", SDL_Has3DNow());
   248 	printf("SSE: %d\n", SDL_HasSSE());
   249 	return 0;
   250 }
   251 
   252 #endif /* TEST_MAIN */