cputest.c 4 KB
Newer Older
Fabrice Bellard's avatar
Fabrice Bellard committed
1
/* Cpu detection code, extracted from mmx.h ((c)1997-99 by H. Dietz
2
   and R. Fisher). Converted to C and improved by Fabrice Bellard */
Fabrice Bellard's avatar
Fabrice Bellard committed
3 4 5 6

#include <stdlib.h>
#include "../dsputil.h"

7 8
/* ebx saving is necessary for PIC. gcc seems unable to see it alone */
#define cpuid(index,eax,ebx,ecx,edx)\
9 10
    __asm __volatile\
	("movl %%ebx, %%esi\n\t"\
11 12 13 14
         "cpuid\n\t"\
         "xchgl %%ebx, %%esi"\
         : "=a" (eax), "=S" (ebx),\
           "=c" (ecx), "=d" (edx)\
15
         : "0" (index));
Fabrice Bellard's avatar
Fabrice Bellard committed
16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46

/* Function to test if multimedia instructions are supported...  */
int mm_support(void)
{
    int rval;
    int eax, ebx, ecx, edx;
    
    __asm__ __volatile__ (
                          /* See if CPUID instruction is supported ... */
                          /* ... Get copies of EFLAGS into eax and ecx */
                          "pushf\n\t"
                          "popl %0\n\t"
                          "movl %0, %1\n\t"
                          
                          /* ... Toggle the ID bit in one copy and store */
                          /*     to the EFLAGS reg */
                          "xorl $0x200000, %0\n\t"
                          "push %0\n\t"
                          "popf\n\t"
                          
                          /* ... Get the (hopefully modified) EFLAGS */
                          "pushf\n\t"
                          "popl %0\n\t"
                          : "=a" (eax), "=c" (ecx)
                          :
                          : "cc" 
                          );
    
    if (eax == ecx)
        return 0; /* CPUID not supported */
    
47
    cpuid(0, eax, ebx, ecx, edx);
Fabrice Bellard's avatar
Fabrice Bellard committed
48 49 50 51 52 53 54

    if (ebx == 0x756e6547 &&
        edx == 0x49656e69 &&
        ecx == 0x6c65746e) {
        
        /* intel */
    inteltest:
55
        cpuid(1, eax, ebx, ecx, edx);
Fabrice Bellard's avatar
Fabrice Bellard committed
56 57 58 59 60 61 62 63 64 65 66 67
        if ((edx & 0x00800000) == 0)
            return 0;
        rval = MM_MMX;
        if (edx & 0x02000000) 
            rval |= MM_MMXEXT | MM_SSE;
        if (edx & 0x04000000) 
            rval |= MM_SSE2;
        return rval;
    } else if (ebx == 0x68747541 &&
               edx == 0x69746e65 &&
               ecx == 0x444d4163) {
        /* AMD */
68
        cpuid(0x80000000, eax, ebx, ecx, edx);
Fabrice Bellard's avatar
Fabrice Bellard committed
69 70
        if ((unsigned)eax < 0x80000001)
            goto inteltest;
71
        cpuid(0x80000001, eax, ebx, ecx, edx);
Fabrice Bellard's avatar
Fabrice Bellard committed
72 73 74 75 76 77 78 79
        if ((edx & 0x00800000) == 0)
            return 0;
        rval = MM_MMX;
        if (edx & 0x80000000)
            rval |= MM_3DNOW;
        if (edx & 0x00400000)
            rval |= MM_MMXEXT;
        return rval;
80 81 82 83 84 85 86 87 88 89 90 91 92 93
    } else if (ebx == 0x746e6543 &&
               edx == 0x48727561 &&
               ecx == 0x736c7561) {  /*  "CentaurHauls" */
        /* VIA C3 */
        cpuid(0x80000000, eax, ebx, ecx, edx);
        if ((unsigned)eax < 0x80000001)
            goto inteltest;	
	cpuid(0x80000001, eax, ebx, ecx, edx);
	rval = 0;      
	if( edx & ( 1 << 31) )
	  rval |= MM_3DNOW;
	if( edx & ( 1 << 23) )
	  rval |= MM_MMX;
	if( edx & ( 1 << 24) )
94 95
	  rval |= MM_MMXEXT;
	return rval;
Fabrice Bellard's avatar
Fabrice Bellard committed
96 97 98 99 100 101 102 103 104 105 106 107 108 109
    } else if (ebx == 0x69727943 &&
               edx == 0x736e4978 &&
               ecx == 0x64616574) {
        /* Cyrix Section */
        /* See if extended CPUID level 80000001 is supported */
        /* The value of CPUID/80000001 for the 6x86MX is undefined
           according to the Cyrix CPU Detection Guide (Preliminary
           Rev. 1.01 table 1), so we'll check the value of eax for
           CPUID/0 to see if standard CPUID level 2 is supported.
           According to the table, the only CPU which supports level
           2 is also the only one which supports extended CPUID levels.
        */
        if (eax != 2) 
            goto inteltest;
110
        cpuid(0x80000001, eax, ebx, ecx, edx);
Fabrice Bellard's avatar
Fabrice Bellard committed
111 112 113 114 115 116 117 118 119 120
        if ((eax & 0x00800000) == 0)
            return 0;
        rval = MM_MMX;
        if (eax & 0x01000000)
            rval |= MM_MMXEXT;
        return rval;
    } else {
        return 0;
    }
}
121 122 123 124 125 126 127 128 129 130

#ifdef __TEST__
int main ( void )
{
  int mm_flags;
  mm_flags = mm_support();
  printf("mm_support = 0x%08u\n",mm_flags);
  return 0;
}
#endif