diff options
Diffstat (limited to 'src/cpuinfo/SDL_cpuinfo.c')
-rw-r--r-- | src/cpuinfo/SDL_cpuinfo.c | 91 |
1 files changed, 87 insertions, 4 deletions
diff --git a/src/cpuinfo/SDL_cpuinfo.c b/src/cpuinfo/SDL_cpuinfo.c index 8a037f50..63c5c441 100644 --- a/src/cpuinfo/SDL_cpuinfo.c +++ b/src/cpuinfo/SDL_cpuinfo.c @@ -32,18 +32,37 @@ #include <sys/types.h> #include <sys/sysctl.h> #endif +#if defined(__MACOSX__) && (defined(__ppc__) || defined(__ppc64__)) +#include <sys/sysctl.h> /* For AltiVec check */ +#elif SDL_ALTIVEC_BLITTERS && HAVE_SETJMP +#include <signal.h> +#include <setjmp.h> +#endif #ifdef __WIN32__ #include "../core/windows/SDL_windows.h" #endif #define CPU_HAS_RDTSC 0x00000001 -#define CPU_HAS_MMX 0x00000002 +#define CPU_HAS_ALTIVEC 0x00000002 +#define CPU_HAS_MMX 0x00000004 +#define CPU_HAS_3DNOW 0x00000008 #define CPU_HAS_SSE 0x00000010 #define CPU_HAS_SSE2 0x00000020 #define CPU_HAS_SSE3 0x00000040 -#define CPU_HAS_SSE41 0x00000080 -#define CPU_HAS_SSE42 0x00000100 - +#define CPU_HAS_SSE41 0x00000100 +#define CPU_HAS_SSE42 0x00000200 + +#if SDL_ALTIVEC_BLITTERS && HAVE_SETJMP && !__MACOSX__ +/* This is the brute force way of detecting instruction sets... + the idea is borrowed from the libmpeg2 library - thanks! + */ +static jmp_buf jmpbuf; +static void +illegal_instruction(int sig) +{ + longjmp(jmpbuf, 1); +} +#endif /* HAVE_SETJMP */ static __inline__ int CPU_haveCPUID(void) @@ -193,6 +212,29 @@ CPU_haveRDTSC(void) } static __inline__ int +CPU_haveAltiVec(void) +{ + volatile int altivec = 0; +#if defined(__MACOSX__) && (defined(__ppc__) || defined(__ppc64__)) + int selectors[2] = { CTL_HW, HW_VECTORUNIT }; + int hasVectorUnit = 0; + size_t length = sizeof(hasVectorUnit); + int error = sysctl(selectors, 2, &hasVectorUnit, &length, NULL, 0); + if (0 == error) + altivec = (hasVectorUnit != 0); +#elif SDL_ALTIVEC_BLITTERS && HAVE_SETJMP + void (*handler) (int sig); + handler = signal(SIGILL, illegal_instruction); + if (setjmp(jmpbuf) == 0) { + asm volatile ("mtspr 256, %0\n\t" "vand %%v0, %%v0, %%v0"::"r" (-1)); + altivec = 1; + } + signal(SIGILL, handler); +#endif + return altivec; +} + +static __inline__ int CPU_haveMMX(void) { if (CPU_haveCPUID()) { @@ -202,6 +244,21 @@ CPU_haveMMX(void) } static __inline__ int +CPU_have3DNow(void) +{ + if (CPU_haveCPUID()) { + int a, b, c, d; + + cpuid(0x80000000, a, b, c, d); + if (a >= 0x80000001) { + cpuid(0x80000001, a, b, c, d); + return (d & 0x80000000); + } + } + return 0; +} + +static __inline__ int CPU_haveSSE(void) { if (CPU_haveCPUID()) { @@ -431,9 +488,15 @@ SDL_GetCPUFeatures(void) if (CPU_haveRDTSC()) { SDL_CPUFeatures |= CPU_HAS_RDTSC; } + if (CPU_haveAltiVec()) { + SDL_CPUFeatures |= CPU_HAS_ALTIVEC; + } if (CPU_haveMMX()) { SDL_CPUFeatures |= CPU_HAS_MMX; } + if (CPU_have3DNow()) { + SDL_CPUFeatures |= CPU_HAS_3DNOW; + } if (CPU_haveSSE()) { SDL_CPUFeatures |= CPU_HAS_SSE; } @@ -463,6 +526,15 @@ SDL_HasRDTSC(void) } SDL_bool +SDL_HasAltiVec(void) +{ + if (SDL_GetCPUFeatures() & CPU_HAS_ALTIVEC) { + return SDL_TRUE; + } + return SDL_FALSE; +} + +SDL_bool SDL_HasMMX(void) { if (SDL_GetCPUFeatures() & CPU_HAS_MMX) { @@ -472,6 +544,15 @@ SDL_HasMMX(void) } SDL_bool +SDL_Has3DNow(void) +{ + if (SDL_GetCPUFeatures() & CPU_HAS_3DNOW) { + return SDL_TRUE; + } + return SDL_FALSE; +} + +SDL_bool SDL_HasSSE(void) { if (SDL_GetCPUFeatures() & CPU_HAS_SSE) { @@ -528,7 +609,9 @@ main() printf("CPU name: %s\n", SDL_GetCPUName()); printf("CacheLine size: %d\n", SDL_GetCPUCacheLineSize()); printf("RDTSC: %d\n", SDL_HasRDTSC()); + printf("Altivec: %d\n", SDL_HasAltiVec()); printf("MMX: %d\n", SDL_HasMMX()); + printf("3DNow: %d\n", SDL_Has3DNow()); printf("SSE: %d\n", SDL_HasSSE()); printf("SSE2: %d\n", SDL_HasSSE2()); printf("SSE3: %d\n", SDL_HasSSE3()); |