/* * SpanDSP - a series of DSP components for telephony * * testcpuid.c - Check the CPU type, to identify special features, like SSE. * * Written by Steve Underwood * 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 /* 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 ------------------------------------------------------------*/