freeswitch/libs/spandsp/src/testcpuid.c

210 lines
5.9 KiB
C

/*
* SpanDSP - a series of DSP components for telephony
*
* testcpuid.c - Check the CPU type, to identify special features, like SSE.
*
* Written by Steve Underwood <steveu@coppice.org>
* Stitched together from bits of testing code found here and there
*
* Copyright (C) 2004 Steve Underwood
*
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 2.1,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/*! \file */
#if defined(HAVE_CONFIG_H)
#include "config.h"
#endif
#include <inttypes.h>
/* Make this file just disappear if we are not on an x86 machine */
#if defined(__i386__) // || defined(__x86_64__)
enum
{
X86_EFLAGS_CF = 0x00000001, /* Carry Flag */
X86_EFLAGS_PF = 0x00000004, /* Parity Flag */
X86_EFLAGS_AF = 0x00000010, /* Auxillary carry Flag */
X86_EFLAGS_ZF = 0x00000040, /* Zero Flag */
X86_EFLAGS_SF = 0x00000080, /* Sign Flag */
X86_EFLAGS_TF = 0x00000100, /* Trap Flag */
X86_EFLAGS_IF = 0x00000200, /* Interrupt Flag */
X86_EFLAGS_DF = 0x00000400, /* Direction Flag */
X86_EFLAGS_OF = 0x00000800, /* Overflow Flag */
X86_EFLAGS_IOPL = 0x00003000, /* IOPL mask */
X86_EFLAGS_NT = 0x00004000, /* Nested Task */
X86_EFLAGS_RF = 0x00010000, /* Resume Flag */
X86_EFLAGS_VM = 0x00020000, /* Virtual Mode */
X86_EFLAGS_AC = 0x00040000, /* Alignment Check */
X86_EFLAGS_VIF = 0x00080000, /* Virtual Interrupt Flag */
X86_EFLAGS_VIP = 0x00100000, /* Virtual Interrupt Pending */
X86_EFLAGS_ID = 0x00200000 /* CPUID detection flag */
};
/* Standard macro to see if a specific flag is changeable */
static __inline__ int flag_is_changeable_p(uint32_t flag)
{
uint32_t f1;
uint32_t f2;
__asm__ __volatile__(
" pushfl\n"
" pushfl\n"
" popl %0\n"
" movl %0,%1\n"
" xorl %2,%0\n"
" pushl %0\n"
" popfl\n"
" pushfl\n"
" popl %0\n"
" popfl\n"
: "=&r" (f1), "=&r" (f2)
: "ir" (flag));
return ((f1^f2) & flag) != 0;
}
/*- End of function --------------------------------------------------------*/
/* Probe for the CPUID instruction */
static int have_cpuid_p(void)
{
return flag_is_changeable_p(X86_EFLAGS_ID);
}
/*- End of function --------------------------------------------------------*/
int has_MMX(void)
{
int result;
if (!have_cpuid_p())
return 0;
/*endif*/
__asm__ __volatile__(
" push %%ebx;\n"
" mov $1,%%eax;\n"
" cpuid;\n"
" xor %%eax,%%eax;\n"
" test $0x800000,%%edx;\n"
" jz 1f;\n" /* no MMX support */
" inc %%eax;\n" /* MMX support */
"1:\n"
" pop %%ebx;\n"
: "=a" (result)
:
: "ecx", "edx");
return result;
}
/*- End of function --------------------------------------------------------*/
int has_SIMD(void)
{
int result;
if (!have_cpuid_p())
return 0;
/*endif*/
__asm__ __volatile__(
" push %%ebx;\n"
" mov $1,%%eax;\n"
" cpuid;\n"
" xor %%eax,%%eax;\n"
" test $0x02000000,%%edx;\n"
" jz 1f;\n" /* no SIMD support */
" inc %%eax;\n" /* SIMD support */
"1:\n"
" pop %%ebx;\n"
: "=a" (result)
:
: "ecx", "edx");
return result;
}
/*- End of function --------------------------------------------------------*/
int has_SIMD2(void)
{
int result;
if (!have_cpuid_p())
return 0;
/*endif*/
__asm__ __volatile__(
" push %%ebx;\n"
" mov $1,%%eax;\n"
" cpuid;\n"
" xor %%eax,%%eax;\n"
" test $0x04000000,%%edx;\n"
" jz 1f;\n" /* no SIMD2 support */
" inc %%eax;\n" /* SIMD2 support */
"1:\n"
" pop %%ebx;\n"
: "=a" (result)
:
: "ecx", "edx");
return result;
}
/*- End of function --------------------------------------------------------*/
int has_3DNow(void)
{
int result;
if (!have_cpuid_p())
return 0;
/*endif*/
__asm__ __volatile__(
" push %%ebx;\n"
" mov $0x80000000,%%eax;\n"
" cpuid;\n"
" xor %%ecx,%%ecx;\n"
" cmp $0x80000000,%%eax;\n"
" jbe 1f;\n" /* no extended MSR(1), so no 3DNow! */
" mov $0x80000001,%%eax;\n"
" cpuid;\n"
" xor %%ecx,%%ecx;\n"
" test $0x80000000,%%edx;\n"
" jz 1f;\n" /* no 3DNow! support */
" inc %%ecx;\n" /* 3DNow! support */
"1:\n"
" pop %%ebx;\n"
: "=c" (result)
:
: "eax", "edx");
return result;
}
/*- End of function --------------------------------------------------------*/
#if defined(TESTBED)
int main(int argc, char *argv[])
{
int result;
result = has_MMX();
printf("MMX is %x\n", result);
result = has_SIMD();
printf("SIMD is %x\n", result);
result = has_SIMD2();
printf("SIMD2 is %x\n", result);
result = has_3DNow();
printf("3DNow is %x\n", result);
return 0;
}
/*- End of function --------------------------------------------------------*/
#endif
#endif
/*- End of file ------------------------------------------------------------*/