freeswitch/libs/spandsp/src/testcpuid.c
Steve Underwood 7b9e4ff674 Various updates to spandsp tests
spandsp logging now passes an opaque pointer to the logging routine, to
increase flexibility. Right now the pointer is set to NULL in all calls.
2012-03-28 23:36:30 +08:00

211 lines
5.6 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 ------------------------------------------------------------*/