210 lines
5.9 KiB
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 ------------------------------------------------------------*/
|