cpu.c
上传用户:riyaled888
上传日期:2009-03-27
资源大小:7338k
文件大小:9k
源码类别:

多媒体

开发平台:

MultiPlatform

  1. /*****************************************************************************
  2.  * cpu.c: CPU detection code
  3.  *****************************************************************************
  4.  * Copyright (C) 1998-2004 VideoLAN
  5.  * $Id: cpu.c 8442 2004-08-16 12:51:11Z titer $
  6.  *
  7.  * Authors: Samuel Hocevar <sam@zoy.org>
  8.  *          Christophe Massiot <massiot@via.ecp.fr>
  9.  *          Eugenio Jarosiewicz <ej0@cise.ufl.eduEujenio>
  10.  *
  11.  * This program is free software; you can redistribute it and/or modify
  12.  * it under the terms of the GNU General Public License as published by
  13.  * the Free Software Foundation; either version 2 of the License, or
  14.  * (at your option) any later version.
  15.  *
  16.  * This program is distributed in the hope that it will be useful,
  17.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  18.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  19.  * GNU General Public License for more details.
  20.  *
  21.  * You should have received a copy of the GNU General Public License
  22.  * along with this program; if not, write to the Free Software
  23.  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
  24.  *****************************************************************************/
  25. /*****************************************************************************
  26.  * Preamble
  27.  *****************************************************************************/
  28. #include <vlc/vlc.h>
  29. #ifdef HAVE_SIGNAL_H
  30. #   include <signal.h>                            /* SIGHUP, SIGINT, SIGKILL */
  31. #   include <setjmp.h>                                    /* longjmp, setjmp */
  32. #endif
  33. #ifdef SYS_DARWIN
  34. #include <sys/sysctl.h>
  35. #endif
  36. #include "vlc_cpu.h"
  37. /*****************************************************************************
  38.  * Local prototypes
  39.  *****************************************************************************/
  40. #ifdef HAVE_SIGNAL_H
  41. static void SigHandler   ( int );
  42. #endif
  43. /*****************************************************************************
  44.  * Global variables - they're needed for signal handling
  45.  *****************************************************************************/
  46. #ifdef HAVE_SIGNAL_H
  47. static jmp_buf env;
  48. static int     i_illegal;
  49. #if defined( __i386__ )
  50. static char   *psz_capability;
  51. #endif
  52. #endif
  53. /*****************************************************************************
  54.  * CPUCapabilities: get the CPU capabilities
  55.  *****************************************************************************
  56.  * This function is called to list extensions the CPU may have.
  57.  *****************************************************************************/
  58. uint32_t CPUCapabilities( void )
  59. {
  60.     volatile uint32_t i_capabilities = CPU_CAPABILITY_NONE;
  61. #if defined( SYS_DARWIN )
  62.     int selectors[2] = { CTL_HW, HW_VECTORUNIT };
  63.     int i_has_altivec = 0;
  64.     size_t i_length = sizeof( i_has_altivec );
  65.     int i_error = sysctl( selectors, 2, &i_has_altivec, &i_length, NULL, 0);
  66.     i_capabilities |= CPU_CAPABILITY_FPU;
  67.     if( i_error == 0 && i_has_altivec != 0 )
  68.         i_capabilities |= CPU_CAPABILITY_ALTIVEC;
  69.     return i_capabilities;
  70. #elif defined( __i386__ )
  71.     volatile unsigned int  i_eax, i_ebx, i_ecx, i_edx;
  72.     volatile vlc_bool_t    b_amd;
  73.     /* Needed for x86 CPU capabilities detection */
  74. #   define cpuid( reg )                    
  75.         asm volatile ( "pushl %%ebxnt"   
  76.                        "cpuidnt"         
  77.                        "movl %%ebx,%1nt" 
  78.                        "popl %%ebxnt"    
  79.                      : "=a" ( i_eax ),     
  80.                        "=r" ( i_ebx ),     
  81.                        "=c" ( i_ecx ),     
  82.                        "=d" ( i_edx )      
  83.                      : "a"  ( reg )        
  84.                      : "cc" );
  85. #   if defined( CAN_COMPILE_SSE ) || defined ( CAN_COMPILE_3DNOW ) 
  86.      && defined( HAVE_SIGNAL_H )
  87.     void (*pf_sigill) (int) = signal( SIGILL, SigHandler );
  88. #   endif
  89.     i_capabilities |= CPU_CAPABILITY_FPU;
  90.     /* test for a 486 CPU */
  91.     asm volatile ( "pushl %%ebxnt"
  92.                    "pushflnt"
  93.                    "popl %%eaxnt"
  94.                    "movl %%eax, %%ebxnt"
  95.                    "xorl $0x200000, %%eaxnt"
  96.                    "pushl %%eaxnt"
  97.                    "popflnt"
  98.                    "pushflnt"
  99.                    "popl %%eaxnt"
  100.                    "movl %%ebx,%1nt"
  101.                    "popl %%ebxnt"
  102.                  : "=a" ( i_eax ),
  103.                    "=r" ( i_ebx )
  104.                  :
  105.                  : "cc" );
  106.     if( i_eax == i_ebx )
  107.     {
  108. #   if defined( CAN_COMPILE_SSE ) || defined ( CAN_COMPILE_3DNOW ) 
  109.      && defined( HAVE_SIGNAL_H )
  110.         signal( SIGILL, pf_sigill );
  111. #   endif
  112.         return i_capabilities;
  113.     }
  114.     i_capabilities |= CPU_CAPABILITY_486;
  115.     /* the CPU supports the CPUID instruction - get its level */
  116.     cpuid( 0x00000000 );
  117.     if( !i_eax )
  118.     {
  119. #   if defined( CAN_COMPILE_SSE ) || defined ( CAN_COMPILE_3DNOW ) 
  120.      && defined( HAVE_SIGNAL_H )
  121.         signal( SIGILL, pf_sigill );
  122. #   endif
  123.         return i_capabilities;
  124.     }
  125.     /* FIXME: this isn't correct, since some 486s have cpuid */
  126.     i_capabilities |= CPU_CAPABILITY_586;
  127.     /* borrowed from mpeg2dec */
  128.     b_amd = ( i_ebx == 0x68747541 ) && ( i_ecx == 0x444d4163 )
  129.                     && ( i_edx == 0x69746e65 );
  130.     /* test for the MMX flag */
  131.     cpuid( 0x00000001 );
  132.     if( ! (i_edx & 0x00800000) )
  133.     {
  134. #   if defined( CAN_COMPILE_SSE ) || defined ( CAN_COMPILE_3DNOW ) 
  135.      && defined( HAVE_SIGNAL_H )
  136.         signal( SIGILL, pf_sigill );
  137. #   endif
  138.         return i_capabilities;
  139.     }
  140.     i_capabilities |= CPU_CAPABILITY_MMX;
  141.     if( i_edx & 0x02000000 )
  142.     {
  143.         i_capabilities |= CPU_CAPABILITY_MMXEXT;
  144. #   ifdef CAN_COMPILE_SSE
  145.         /* We test if OS supports the SSE instructions */
  146.         psz_capability = "SSE";
  147.         i_illegal = 0;
  148.         if( setjmp( env ) == 0 )
  149.         {
  150.             /* Test a SSE instruction */
  151.             __asm__ __volatile__ ( "xorps %%xmm0,%%xmm0n" : : );
  152.         }
  153.         if( i_illegal == 0 )
  154.         {
  155.             i_capabilities |= CPU_CAPABILITY_SSE;
  156.         }
  157. #   endif
  158.     }
  159.     if( i_edx & 0x04000000 )
  160.     {
  161. #   if defined(CAN_COMPILE_SSE)
  162.         /* We test if OS supports the SSE instructions */
  163.         psz_capability = "SSE2";
  164.         i_illegal = 0;
  165.         if( setjmp( env ) == 0 )
  166.         {
  167.             /* Test a SSE2 instruction */
  168.             __asm__ __volatile__ ( "movupd %%xmm0, %%xmm0n" : : );
  169.         }
  170.         if( i_illegal == 0 )
  171.         {
  172.             i_capabilities |= CPU_CAPABILITY_SSE2;
  173.         }
  174. #   endif
  175.     }
  176.     /* test for additional capabilities */
  177.     cpuid( 0x80000000 );
  178.     if( i_eax < 0x80000001 )
  179.     {
  180. #   if defined( CAN_COMPILE_SSE ) || defined ( CAN_COMPILE_3DNOW ) 
  181.      && defined( HAVE_SIGNAL_H )
  182.         signal( SIGILL, pf_sigill );
  183. #   endif
  184.         return i_capabilities;
  185.     }
  186.     /* list these additional capabilities */
  187.     cpuid( 0x80000001 );
  188. #   ifdef CAN_COMPILE_3DNOW
  189.     if( i_edx & 0x80000000 )
  190.     {
  191.         psz_capability = "3D Now!";
  192.         i_illegal = 0;
  193.         if( setjmp( env ) == 0 )
  194.         {
  195.             /* Test a 3D Now! instruction */
  196.             __asm__ __volatile__ ( "pfadd %%mm0,%%mm0n" "femmsn" : : );
  197.         }
  198.         if( i_illegal == 0 )
  199.         {
  200.             i_capabilities |= CPU_CAPABILITY_3DNOW;
  201.         }
  202.     }
  203. #   endif
  204.     if( b_amd && ( i_edx & 0x00400000 ) )
  205.     {
  206.         i_capabilities |= CPU_CAPABILITY_MMXEXT;
  207.     }
  208. #   if defined( CAN_COMPILE_SSE ) || defined ( CAN_COMPILE_3DNOW ) 
  209.      && defined( HAVE_SIGNAL_H )
  210.     signal( SIGILL, pf_sigill );
  211. #   endif
  212.     return i_capabilities;
  213. #elif defined( __powerpc__ )
  214. #   ifdef CAN_COMPILE_ALTIVEC && defined( HAVE_SIGNAL_H )
  215.     void (*pf_sigill) (int) = signal( SIGILL, SigHandler );
  216.     i_capabilities |= CPU_CAPABILITY_FPU;
  217.     i_illegal = 0;
  218.     if( setjmp( env ) == 0 )
  219.     {
  220.         asm volatile ("mtspr 256, %0nt"
  221.                       "vand %%v0, %%v0, %%v0"
  222.                       :
  223.                       : "r" (-1));
  224.     }
  225.     if( i_illegal == 0 )
  226.     {
  227.         i_capabilities |= CPU_CAPABILITY_ALTIVEC;
  228.     }
  229.     signal( SIGILL, pf_sigill );
  230. #   endif
  231.     return i_capabilities;
  232. #elif defined( __sparc__ )
  233.     i_capabilities |= CPU_CAPABILITY_FPU;
  234.     return i_capabilities;
  235. #elif defined( _MSC_VER )
  236.     i_capabilities |= CPU_CAPABILITY_FPU;
  237.     return i_capabilities;
  238. #else
  239.     /* default behaviour */
  240.     return i_capabilities;
  241. #endif
  242. }
  243. /*****************************************************************************
  244.  * SigHandler: system signal handler
  245.  *****************************************************************************
  246.  * This function is called when an illegal instruction signal is received by
  247.  * the program. We use this function to test OS and CPU capabilities
  248.  *****************************************************************************/
  249. #if defined( HAVE_SIGNAL_H )
  250. static void SigHandler( int i_signal )
  251. {
  252.     /* Acknowledge the signal received */
  253.     i_illegal = 1;
  254. #ifdef HAVE_SIGRELSE
  255.     sigrelse( i_signal );
  256. #endif
  257. #if defined( __i386__ )
  258.     fprintf( stderr, "warning: your CPU has %s instructions, but not your "
  259.                      "operating system.n", psz_capability );
  260.     fprintf( stderr, "         some optimizations will be disabled unless "
  261.                      "you upgrade your OSn" );
  262. #   if defined( SYS_LINUX )
  263.     fprintf( stderr, "         (for instance Linux kernel 2.4.x or later)n" );
  264. #   endif
  265. #endif
  266.     longjmp( env, 1 );
  267. }
  268. #endif