src/cpuinfo/SDL_cpuinfo.c
author Sam Lantinga <slouken@libsdl.org>
Mon, 29 May 2006 04:04:35 +0000
branchSDL-1.3
changeset 1668 4da1ee79c9af
parent 1662 782fd950bd46
child 1691 c901fd2a42da
permissions -rw-r--r--
more tweaking indent options
slouken@739
     1
/*
slouken@739
     2
    SDL - Simple DirectMedia Layer
slouken@1312
     3
    Copyright (C) 1997-2006 Sam Lantinga
slouken@739
     4
slouken@739
     5
    This library is free software; you can redistribute it and/or
slouken@1312
     6
    modify it under the terms of the GNU Lesser General Public
slouken@739
     7
    License as published by the Free Software Foundation; either
slouken@1312
     8
    version 2.1 of the License, or (at your option) any later version.
slouken@739
     9
slouken@739
    10
    This library is distributed in the hope that it will be useful,
slouken@739
    11
    but WITHOUT ANY WARRANTY; without even the implied warranty of
slouken@739
    12
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
slouken@1312
    13
    Lesser General Public License for more details.
slouken@739
    14
slouken@1312
    15
    You should have received a copy of the GNU Lesser General Public
slouken@1312
    16
    License along with this library; if not, write to the Free Software
slouken@1312
    17
    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
slouken@739
    18
slouken@739
    19
    Sam Lantinga
slouken@739
    20
    slouken@libsdl.org
slouken@739
    21
*/
slouken@1402
    22
#include "SDL_config.h"
slouken@739
    23
slouken@739
    24
/* CPU feature detection for SDL */
slouken@739
    25
slouken@1361
    26
#include "SDL.h"
slouken@1361
    27
#include "SDL_cpuinfo.h"
slouken@1361
    28
slouken@1590
    29
#if defined(__MACOSX__) && defined(__ppc__)
slouken@1662
    30
#include <sys/sysctl.h>         /* For AltiVec check */
slouken@1487
    31
#elif SDL_ALTIVEC_BLITTERS && HAVE_SETJMP
slouken@793
    32
#include <signal.h>
slouken@793
    33
#include <setjmp.h>
slouken@793
    34
#endif
slouken@793
    35
slouken@745
    36
#define CPU_HAS_RDTSC	0x00000001
slouken@745
    37
#define CPU_HAS_MMX	0x00000002
slouken@785
    38
#define CPU_HAS_MMXEXT	0x00000004
slouken@785
    39
#define CPU_HAS_3DNOW	0x00000010
slouken@785
    40
#define CPU_HAS_3DNOWEXT 0x00000020
slouken@785
    41
#define CPU_HAS_SSE	0x00000040
slouken@785
    42
#define CPU_HAS_SSE2	0x00000080
slouken@785
    43
#define CPU_HAS_ALTIVEC	0x00000100
slouken@739
    44
slouken@1487
    45
#if SDL_ALTIVEC_BLITTERS && HAVE_SETJMP && !__MACOSX__
slouken@793
    46
/* This is the brute force way of detecting instruction sets...
slouken@793
    47
   the idea is borrowed from the libmpeg2 library - thanks!
slouken@793
    48
 */
slouken@793
    49
static jmp_buf jmpbuf;
slouken@1662
    50
static void
slouken@1668
    51
illegal_instruction(int sig)
slouken@793
    52
{
slouken@1668
    53
    longjmp(jmpbuf, 1);
slouken@793
    54
}
slouken@1361
    55
#endif /* HAVE_SETJMP */
slouken@793
    56
slouken@1662
    57
static __inline__ int
slouken@1668
    58
CPU_haveCPUID(void)
slouken@745
    59
{
slouken@1662
    60
    int has_CPUID = 0;
slouken@745
    61
#if defined(__GNUC__) && defined(i386)
slouken@1668
    62
  __asm__("        pushfl                      # Get original EFLAGS             \n" "        popl    %%eax                                                 \n" "        movl    %%eax,%%ecx                                           \n" "        xorl    $0x200000,%%eax     # Flip ID bit in EFLAGS           \n" "        pushl   %%eax               # Save new EFLAGS value on stack  \n" "        popfl                       # Replace current EFLAGS value    \n" "        pushfl                      # Get new EFLAGS                  \n" "        popl    %%eax               # Store new EFLAGS in EAX         \n" "        xorl    %%ecx,%%eax         # Can not toggle ID bit,          \n" "        jz      1f                  # Processor=80486                 \n" "        movl    $1,%0               # We have CPUID support           \n" "1:                                                                    \n": "=m"(has_CPUID):
slouken@1662
    63
  :"%eax", "%ecx");
slouken@881
    64
#elif defined(__GNUC__) && defined(__x86_64__)
slouken@881
    65
/* Technically, if this is being compiled under __x86_64__ then it has 
slouken@881
    66
CPUid by definition.  But it's nice to be able to prove it.  :)      */
slouken@1668
    67
  __asm__("        pushfq                      # Get original EFLAGS             \n" "        popq    %%rax                                                 \n" "        movq    %%rax,%%rcx                                           \n" "        xorl    $0x200000,%%eax     # Flip ID bit in EFLAGS           \n" "        pushq   %%rax               # Save new EFLAGS value on stack  \n" "        popfq                       # Replace current EFLAGS value    \n" "        pushfq                      # Get new EFLAGS                  \n" "        popq    %%rax               # Store new EFLAGS in EAX         \n" "        xorl    %%ecx,%%eax         # Can not toggle ID bit,          \n" "        jz      1f                  # Processor=80486                 \n" "        movl    $1,%0               # We have CPUID support           \n" "1:                                                                    \n": "=m"(has_CPUID):
slouken@1662
    68
  :"%rax", "%rcx");
slouken@1442
    69
#elif (defined(_MSC_VER) && defined(_M_IX86)) || defined(__WATCOMC__)
slouken@1662
    70
    __asm {
slouken@1662
    71
        pushfd;
slouken@1662
    72
        Get original EFLAGS pop eax mov ecx, eax xor eax, 200000 h;
slouken@1662
    73
        Flip ID bit in EFLAGS push eax;
slouken@1662
    74
        Save new EFLAGS value on stack popfd;
slouken@1662
    75
        Replace current EFLAGS value pushfd;
slouken@1662
    76
        Get new EFLAGS pop eax;
slouken@1662
    77
        Store new EFLAGS in EAX xor eax, ecx;
slouken@1662
    78
        Can not toggle ID bit, jz done;
slouken@1662
    79
        Processor = 80486 mov has_CPUID, 1;
slouken@1662
    80
    We have CPUID support done:}
icculus@1229
    81
#elif defined(__sun) && defined(__x86)
slouken@1668
    82
    __asm("       pushfl                 \n"
slouken@1668
    83
          "	popl    %eax           \n"
slouken@1668
    84
          "	movl    %eax,%ecx      \n"
slouken@1668
    85
          "	xorl    $0x200000,%eax \n"
slouken@1668
    86
          "	pushl   %eax           \n"
slouken@1668
    87
          "	popfl                  \n"
slouken@1668
    88
          "	pushfl                 \n"
slouken@1668
    89
          "	popl    %eax           \n"
slouken@1668
    90
          "	xorl    %ecx,%eax      \n"
slouken@1668
    91
          "	jz      1f             \n"
slouken@1668
    92
          "	movl    $1,-8(%ebp)    \n"
slouken@1668
    93
          "1:                            \n");
icculus@1229
    94
#elif defined(__sun) && defined(__amd64)
slouken@1668
    95
    __asm("       pushfq                 \n"
slouken@1668
    96
          "       popq    %rax           \n"
slouken@1668
    97
          "       movq    %rax,%rcx      \n"
slouken@1668
    98
          "       xorl    $0x200000,%eax \n"
slouken@1668
    99
          "       pushq   %rax           \n"
slouken@1668
   100
          "       popfq                  \n"
slouken@1668
   101
          "       pushfq                 \n"
slouken@1668
   102
          "       popq    %rax           \n"
slouken@1668
   103
          "       xorl    %ecx,%eax      \n"
slouken@1668
   104
          "       jz      1f             \n"
slouken@1668
   105
          "       movl    $1,-8(%rbp)    \n"
slouken@1668
   106
          "1:                            \n");
slouken@745
   107
#endif
slouken@1662
   108
    return has_CPUID;
slouken@745
   109
}
slouken@745
   110
slouken@1662
   111
static __inline__ int
slouken@1668
   112
CPU_getCPUIDFeatures(void)
slouken@745
   113
{
slouken@1662
   114
    int features = 0;
slouken@881
   115
#if defined(__GNUC__) && ( defined(i386) || defined(__x86_64__) )
slouken@1668
   116
  __asm__("        movl    %%ebx,%%edi\n" "        xorl    %%eax,%%eax         # Set up for CPUID instruction    \n" "        cpuid                       # Get and save vendor ID          \n" "        cmpl    $1,%%eax            # Make sure 1 is valid input for CPUID\n" "        jl      1f                  # We dont have the CPUID instruction\n" "        xorl    %%eax,%%eax                                           \n" "        incl    %%eax                                                 \n" "        cpuid                       # Get family/model/stepping/features\n" "        movl    %%edx,%0                                              \n" "1:                                                                    \n" "        movl    %%edi,%%ebx\n": "=m"(features):
slouken@1662
   117
  :"%eax", "%ecx", "%edx", "%edi");
slouken@1442
   118
#elif (defined(_MSC_VER) && defined(_M_IX86)) || defined(__WATCOMC__)
slouken@1662
   119
    __asm {
slouken@1662
   120
        xor eax, eax;
slouken@1662
   121
    Set up for CPUID instruction
slouken@1662
   122
            cpuid; Get and save vendor ID
slouken@1662
   123
            cmp eax, 1; Make sure 1 is valid input for CPUID
slouken@1662
   124
            jl done; We dont have the CPUID instruction
slouken@1662
   125
            xor eax, eax
slouken@1662
   126
            inc eax
slouken@1662
   127
            cpuid; Get family / model / stepping / features
slouken@1662
   128
            mov features, edx done:}
icculus@1229
   129
#elif defined(__sun) && (defined(__x86) || defined(__amd64))
slouken@1662
   130
    __asm
slouken@1662
   131
        ("        movl    %ebx,%edi\n"
slouken@1662
   132
         "        xorl    %eax,%eax         \n"
slouken@1662
   133
         "        cpuid                     \n"
slouken@1662
   134
         "        cmpl    $1,%eax           \n"
slouken@1662
   135
         "        jl      1f                \n"
slouken@1662
   136
         "        xorl    %eax,%eax         \n"
slouken@1662
   137
         "        incl    %eax              \n"
slouken@1662
   138
         "        cpuid                     \n"
icculus@1229
   139
#ifdef __i386
slouken@1662
   140
         "        movl    %edx,-8(%ebp)     \n"
icculus@1229
   141
#else
slouken@1662
   142
         "        movl    %edx,-8(%rbp)     \n"
icculus@1229
   143
#endif
slouken@1662
   144
         "1:                                \n"
slouken@1662
   145
         "        movl    %edi,%ebx\n");
slouken@745
   146
#endif
slouken@1662
   147
    return features;
slouken@745
   148
}
slouken@745
   149
slouken@1662
   150
static __inline__ int
slouken@1668
   151
CPU_getCPUIDFeaturesExt(void)
slouken@785
   152
{
slouken@1662
   153
    int features = 0;
slouken@881
   154
#if defined(__GNUC__) && (defined(i386) || defined (__x86_64__) )
slouken@1668
   155
  __asm__("        movl    %%ebx,%%edi\n" "        movl    $0x80000000,%%eax   # Query for extended functions    \n" "        cpuid                       # Get extended function limit     \n" "        cmpl    $0x80000001,%%eax                                     \n" "        jl      1f                  # Nope, we dont have function 800000001h\n" "        movl    $0x80000001,%%eax   # Setup extended function 800000001h\n" "        cpuid                       # and get the information         \n" "        movl    %%edx,%0                                              \n" "1:                                                                    \n" "        movl    %%edi,%%ebx\n": "=m"(features):
slouken@1662
   156
  :"%eax", "%ecx", "%edx", "%edi");
slouken@1442
   157
#elif (defined(_MSC_VER) && defined(_M_IX86)) || defined(__WATCOMC__)
slouken@1662
   158
    __asm {
slouken@1662
   159
        mov eax, 80000000 h;
slouken@1662
   160
        Query for extended functions
slouken@1662
   161
            cpuid; Get extended function limit
slouken@1662
   162
            cmp eax, 80000001 h jl done; Nope
slouken@1662
   163
            , we dont have function 800000001 h mov eax, 80000001 h;
slouken@1662
   164
        Setup extended function 800000001 h cpuid;
slouken@1662
   165
    and get the information mov features, edx done:}
icculus@1229
   166
#elif defined(__sun) && ( defined(__i386) || defined(__amd64) )
slouken@1668
   167
    __asm("        movl    %ebx,%edi\n"
slouken@1668
   168
          "        movl    $0x80000000,%eax \n"
slouken@1668
   169
          "        cpuid                    \n"
slouken@1668
   170
          "        cmpl    $0x80000001,%eax \n"
slouken@1668
   171
          "        jl      1f               \n"
slouken@1668
   172
          "        movl    $0x80000001,%eax \n"
slouken@1668
   173
          "        cpuid                    \n"
icculus@1229
   174
#ifdef __i386
slouken@1668
   175
          "        movl    %edx,-8(%ebp)   \n"
icculus@1229
   176
#else
slouken@1668
   177
          "        movl    %edx,-8(%rbp)   \n"
icculus@1229
   178
#endif
slouken@1668
   179
          "1:                               \n"
slouken@1668
   180
          "        movl    %edi,%ebx\n");
slouken@785
   181
#endif
slouken@1662
   182
    return features;
slouken@785
   183
}
slouken@785
   184
slouken@1662
   185
static __inline__ int
slouken@1668
   186
CPU_haveRDTSC(void)
slouken@745
   187
{
slouken@1668
   188
    if (CPU_haveCPUID()) {
slouken@1668
   189
        return (CPU_getCPUIDFeatures() & 0x00000010);
slouken@1662
   190
    }
slouken@1662
   191
    return 0;
slouken@745
   192
}
slouken@745
   193
slouken@1662
   194
static __inline__ int
slouken@1668
   195
CPU_haveMMX(void)
slouken@745
   196
{
slouken@1668
   197
    if (CPU_haveCPUID()) {
slouken@1668
   198
        return (CPU_getCPUIDFeatures() & 0x00800000);
slouken@1662
   199
    }
slouken@1662
   200
    return 0;
slouken@745
   201
}
slouken@745
   202
slouken@1662
   203
static __inline__ int
slouken@1668
   204
CPU_haveMMXExt(void)
slouken@785
   205
{
slouken@1668
   206
    if (CPU_haveCPUID()) {
slouken@1668
   207
        return (CPU_getCPUIDFeaturesExt() & 0x00400000);
slouken@1662
   208
    }
slouken@1662
   209
    return 0;
slouken@785
   210
}
slouken@785
   211
slouken@1662
   212
static __inline__ int
slouken@1668
   213
CPU_have3DNow(void)
slouken@745
   214
{
slouken@1668
   215
    if (CPU_haveCPUID()) {
slouken@1668
   216
        return (CPU_getCPUIDFeaturesExt() & 0x80000000);
slouken@1662
   217
    }
slouken@1662
   218
    return 0;
slouken@785
   219
}
slouken@785
   220
slouken@1662
   221
static __inline__ int
slouken@1668
   222
CPU_have3DNowExt(void)
slouken@785
   223
{
slouken@1668
   224
    if (CPU_haveCPUID()) {
slouken@1668
   225
        return (CPU_getCPUIDFeaturesExt() & 0x40000000);
slouken@1662
   226
    }
slouken@1662
   227
    return 0;
slouken@745
   228
}
slouken@745
   229
slouken@1662
   230
static __inline__ int
slouken@1668
   231
CPU_haveSSE(void)
slouken@745
   232
{
slouken@1668
   233
    if (CPU_haveCPUID()) {
slouken@1668
   234
        return (CPU_getCPUIDFeatures() & 0x02000000);
slouken@1662
   235
    }
slouken@1662
   236
    return 0;
slouken@745
   237
}
slouken@739
   238
slouken@1662
   239
static __inline__ int
slouken@1668
   240
CPU_haveSSE2(void)
slouken@785
   241
{
slouken@1668
   242
    if (CPU_haveCPUID()) {
slouken@1668
   243
        return (CPU_getCPUIDFeatures() & 0x04000000);
slouken@1662
   244
    }
slouken@1662
   245
    return 0;
slouken@785
   246
}
slouken@785
   247
slouken@1662
   248
static __inline__ int
slouken@1668
   249
CPU_haveAltiVec(void)
slouken@778
   250
{
slouken@1662
   251
    volatile int altivec = 0;
slouken@1590
   252
#if defined(__MACOSX__) && defined(__ppc__)
slouken@1662
   253
    int selectors[2] = { CTL_HW, HW_VECTORUNIT };
slouken@1662
   254
    int hasVectorUnit = 0;
slouken@1668
   255
    size_t length = sizeof(hasVectorUnit);
slouken@1668
   256
    int error = sysctl(selectors, 2, &hasVectorUnit, &length, NULL, 0);
slouken@1662
   257
    if (0 == error)
slouken@1662
   258
        altivec = (hasVectorUnit != 0);
slouken@1361
   259
#elif SDL_ALTIVEC_BLITTERS && HAVE_SETJMP
slouken@1662
   260
    void (*handler) (int sig);
slouken@1668
   261
    handler = signal(SIGILL, illegal_instruction);
slouken@1668
   262
    if (setjmp(jmpbuf) == 0) {
slouken@1662
   263
        asm volatile ("mtspr 256, %0\n\t" "vand %%v0, %%v0, %%v0"::"r" (-1));
slouken@1662
   264
        altivec = 1;
slouken@1662
   265
    }
slouken@1668
   266
    signal(SIGILL, handler);
slouken@778
   267
#endif
slouken@1662
   268
    return altivec;
slouken@778
   269
}
slouken@778
   270
slouken@739
   271
static Uint32 SDL_CPUFeatures = 0xFFFFFFFF;
slouken@739
   272
slouken@1662
   273
static Uint32
slouken@1668
   274
SDL_GetCPUFeatures(void)
slouken@739
   275
{
slouken@1662
   276
    if (SDL_CPUFeatures == 0xFFFFFFFF) {
slouken@1662
   277
        SDL_CPUFeatures = 0;
slouken@1668
   278
        if (CPU_haveRDTSC()) {
slouken@1662
   279
            SDL_CPUFeatures |= CPU_HAS_RDTSC;
slouken@1662
   280
        }
slouken@1668
   281
        if (CPU_haveMMX()) {
slouken@1662
   282
            SDL_CPUFeatures |= CPU_HAS_MMX;
slouken@1662
   283
        }
slouken@1668
   284
        if (CPU_haveMMXExt()) {
slouken@1662
   285
            SDL_CPUFeatures |= CPU_HAS_MMXEXT;
slouken@1662
   286
        }
slouken@1668
   287
        if (CPU_have3DNow()) {
slouken@1662
   288
            SDL_CPUFeatures |= CPU_HAS_3DNOW;
slouken@1662
   289
        }
slouken@1668
   290
        if (CPU_have3DNowExt()) {
slouken@1662
   291
            SDL_CPUFeatures |= CPU_HAS_3DNOWEXT;
slouken@1662
   292
        }
slouken@1668
   293
        if (CPU_haveSSE()) {
slouken@1662
   294
            SDL_CPUFeatures |= CPU_HAS_SSE;
slouken@1662
   295
        }
slouken@1668
   296
        if (CPU_haveSSE2()) {
slouken@1662
   297
            SDL_CPUFeatures |= CPU_HAS_SSE2;
slouken@1662
   298
        }
slouken@1668
   299
        if (CPU_haveAltiVec()) {
slouken@1662
   300
            SDL_CPUFeatures |= CPU_HAS_ALTIVEC;
slouken@1662
   301
        }
slouken@1662
   302
    }
slouken@1662
   303
    return SDL_CPUFeatures;
slouken@739
   304
}
slouken@739
   305
slouken@1662
   306
SDL_bool
slouken@1668
   307
SDL_HasRDTSC(void)
slouken@745
   308
{
slouken@1668
   309
    if (SDL_GetCPUFeatures() & CPU_HAS_RDTSC) {
slouken@1662
   310
        return SDL_TRUE;
slouken@1662
   311
    }
slouken@1662
   312
    return SDL_FALSE;
slouken@745
   313
}
slouken@745
   314
slouken@1662
   315
SDL_bool
slouken@1668
   316
SDL_HasMMX(void)
slouken@739
   317
{
slouken@1668
   318
    if (SDL_GetCPUFeatures() & CPU_HAS_MMX) {
slouken@1662
   319
        return SDL_TRUE;
slouken@1662
   320
    }
slouken@1662
   321
    return SDL_FALSE;
slouken@739
   322
}
slouken@739
   323
slouken@1662
   324
SDL_bool
slouken@1668
   325
SDL_HasMMXExt(void)
slouken@804
   326
{
slouken@1668
   327
    if (SDL_GetCPUFeatures() & CPU_HAS_MMXEXT) {
slouken@1662
   328
        return SDL_TRUE;
slouken@1662
   329
    }
slouken@1662
   330
    return SDL_FALSE;
slouken@804
   331
}
slouken@804
   332
slouken@1662
   333
SDL_bool
slouken@1668
   334
SDL_Has3DNow(void)
slouken@739
   335
{
slouken@1668
   336
    if (SDL_GetCPUFeatures() & CPU_HAS_3DNOW) {
slouken@1662
   337
        return SDL_TRUE;
slouken@1662
   338
    }
slouken@1662
   339
    return SDL_FALSE;
slouken@739
   340
}
slouken@739
   341
slouken@1662
   342
SDL_bool
slouken@1668
   343
SDL_Has3DNowExt(void)
slouken@804
   344
{
slouken@1668
   345
    if (SDL_GetCPUFeatures() & CPU_HAS_3DNOWEXT) {
slouken@1662
   346
        return SDL_TRUE;
slouken@1662
   347
    }
slouken@1662
   348
    return SDL_FALSE;
slouken@804
   349
}
slouken@804
   350
slouken@1662
   351
SDL_bool
slouken@1668
   352
SDL_HasSSE(void)
slouken@739
   353
{
slouken@1668
   354
    if (SDL_GetCPUFeatures() & CPU_HAS_SSE) {
slouken@1662
   355
        return SDL_TRUE;
slouken@1662
   356
    }
slouken@1662
   357
    return SDL_FALSE;
slouken@739
   358
}
slouken@739
   359
slouken@1662
   360
SDL_bool
slouken@1668
   361
SDL_HasSSE2(void)
slouken@804
   362
{
slouken@1668
   363
    if (SDL_GetCPUFeatures() & CPU_HAS_SSE2) {
slouken@1662
   364
        return SDL_TRUE;
slouken@1662
   365
    }
slouken@1662
   366
    return SDL_FALSE;
slouken@804
   367
}
slouken@804
   368
slouken@1662
   369
SDL_bool
slouken@1668
   370
SDL_HasAltiVec(void)
slouken@778
   371
{
slouken@1668
   372
    if (SDL_GetCPUFeatures() & CPU_HAS_ALTIVEC) {
slouken@1662
   373
        return SDL_TRUE;
slouken@1662
   374
    }
slouken@1662
   375
    return SDL_FALSE;
slouken@778
   376
}
slouken@778
   377
slouken@739
   378
#ifdef TEST_MAIN
slouken@739
   379
slouken@739
   380
#include <stdio.h>
slouken@739
   381
slouken@1662
   382
int
slouken@1668
   383
main()
slouken@739
   384
{
slouken@1668
   385
    printf("RDTSC: %d\n", SDL_HasRDTSC());
slouken@1668
   386
    printf("MMX: %d\n", SDL_HasMMX());
slouken@1668
   387
    printf("MMXExt: %d\n", SDL_HasMMXExt());
slouken@1668
   388
    printf("3DNow: %d\n", SDL_Has3DNow());
slouken@1668
   389
    printf("3DNowExt: %d\n", SDL_Has3DNowExt());
slouken@1668
   390
    printf("SSE: %d\n", SDL_HasSSE());
slouken@1668
   391
    printf("SSE2: %d\n", SDL_HasSSE2());
slouken@1668
   392
    printf("AltiVec: %d\n", SDL_HasAltiVec());
slouken@1662
   393
    return 0;
slouken@739
   394
}
slouken@739
   395
slouken@739
   396
#endif /* TEST_MAIN */
slouken@1662
   397
/* vi: set ts=4 sw=4 expandtab: */