210 lines
5.6 KiB
C
210 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.
|
||
|
*
|
||
|
* $Id: testcpuid.c,v 1.12 2008/05/13 13:17:24 steveu Exp $
|
||
|
*/
|
||
|
|
||
|
/*! \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__)
|
||
|
|
||
|
#define X86_EFLAGS_CF 0x00000001 /* Carry Flag */
|
||
|
#define X86_EFLAGS_PF 0x00000004 /* Parity Flag */
|
||
|
#define X86_EFLAGS_AF 0x00000010 /* Auxillary carry Flag */
|
||
|
#define X86_EFLAGS_ZF 0x00000040 /* Zero Flag */
|
||
|
#define X86_EFLAGS_SF 0x00000080 /* Sign Flag */
|
||
|
#define X86_EFLAGS_TF 0x00000100 /* Trap Flag */
|
||
|
#define X86_EFLAGS_IF 0x00000200 /* Interrupt Flag */
|
||
|
#define X86_EFLAGS_DF 0x00000400 /* Direction Flag */
|
||
|
#define X86_EFLAGS_OF 0x00000800 /* Overflow Flag */
|
||
|
#define X86_EFLAGS_IOPL 0x00003000 /* IOPL mask */
|
||
|
#define X86_EFLAGS_NT 0x00004000 /* Nested Task */
|
||
|
#define X86_EFLAGS_RF 0x00010000 /* Resume Flag */
|
||
|
#define X86_EFLAGS_VM 0x00020000 /* Virtual Mode */
|
||
|
#define X86_EFLAGS_AC 0x00040000 /* Alignment Check */
|
||
|
#define X86_EFLAGS_VIF 0x00080000 /* Virtual Interrupt Flag */
|
||
|
#define X86_EFLAGS_VIP 0x00100000 /* Virtual Interrupt Pending */
|
||
|
#define 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 ------------------------------------------------------------*/
|