From b2b8265a5d99c55953f48a2aaacc1575470ce8b7 Mon Sep 17 00:00:00 2001 From: koolsmoky <> Date: Sun, 12 Dec 2004 15:16:43 +0000 Subject: [PATCH] new cpuid --- glide2x/cvg/glide/src/cpuid.c | 337 ++++++++++++++++++++++++++++++++++ glide2x/cvg/incsrc/cpuid.h | 23 +++ 2 files changed, 360 insertions(+) create mode 100644 glide2x/cvg/glide/src/cpuid.c create mode 100644 glide2x/cvg/incsrc/cpuid.h diff --git a/glide2x/cvg/glide/src/cpuid.c b/glide2x/cvg/glide/src/cpuid.c new file mode 100644 index 0000000..3fbed94 --- /dev/null +++ b/glide2x/cvg/glide/src/cpuid.c @@ -0,0 +1,337 @@ +/* + * CPU detection code + * + * $Header$ + * $Log$ + * Revision 1.1.2.10 2004/10/05 14:54:29 dborca + * DOS/OpenWatcom woes + * + * Revision 1.1.2.9 2003/08/04 12:45:47 dborca + * Preparing for MinGW 2.0 + * + * Revision 1.1.2.8 2003/07/29 10:04:32 dborca + * Shamelessness. + * Safeguard in CPUID. + * Changed contact address! + * Koolsmoky's texture download fixes. + * + * Revision 1.1.2.7 2003/07/25 07:14:58 dborca + * ... in the name of the Linux, DRI and the sacred Glide... + * + * Revision 1.1.2.6 2003/07/24 13:13:03 koolsmoky + * use __try/__except mechanism for win32 to catch SSE sigillegal in win95 + * + * Revision 1.1.2.5 2003/07/01 11:16:42 dborca + * fixed a bug in GNUC code when running Intel; also removed detritus + * + * Revision 1.1.2.3 2003/06/13 07:22:58 dborca + * more fixes to NASM sources + * + */ + + +#include +#include +#include + +#include "cpuid.h" + +typedef unsigned long word32; + +/* These are the bit flags that get set on calling cpuid + * with register eax set to 1 + */ +#define _MMX_FEATURE_BIT 0x00800000 +#define _SSE_FEATURE_BIT 0x02000000 +#define _SSE2_FEATURE_BIT 0x04000000 + +/* This bit is set when cpuid is called with + * register set to 80000001h (only applicable to AMD) + */ +#define _3DNOW_FEATURE_BIT 0x80000000 +#define _3DNOWPLUS_FEATURE_BIT 0x40000000 +#define _MMXPLUS_FEATURE_BIT 0x00400000 + +/* Testing code: + * TEST_SSE = xorps xmm0, xmm0 + * TEST_SSE2 = xorpd xmm0, xmm0 + * TEST_3DNOW = femms + * TEST_MMX = emms + * TEST_3DNOWPLUS = femms | pswapd mm0, mm0 | femms + * TEST_MMXPLUS = emms | pminsw mm0, mm0 | emms + */ +#ifdef __GNUC__ +#define TEST_CPUID(f) __asm __volatile ("cpuid"::"a"(f):"%ebx", "%ecx", "%edx") +#define TEST_SSE() __asm __volatile (".byte 0x0f, 0x57, 0xc0") +#define TEST_SSE2() __asm __volatile (".byte 0x66, 0x0f, 0x57, 0xc0") +#define TEST_3DNOW() __asm __volatile (".byte 0x0f, 0x0e") +#define TEST_MMX() __asm __volatile (".byte 0x0f, 0x77") +#define TEST_3DNOWPLUS() __asm __volatile (".byte 0x0f, 0x0e, 0x0f, 0x0f, 0xc0, 0xbb, 0x0f, 0x0e") +#define TEST_MMXPLUS() __asm __volatile (".byte 0x0f, 0x77, 0x0f, 0xea, 0xc0, 0x0f, 0x77") +#else +#define TEST_CPUID(f) __asm { _asm mov eax, f _asm cpuid } +#define TEST_SSE() __asm { _asm _emit 0x0f _asm _emit 0x57 _asm _emit 0xc0 } +#define TEST_SSE2() __asm { _asm _emit 0x66 _asm _emit 0x0f _asm _emit 0x57 _asm _emit 0xc0 } +#define TEST_3DNOW() __asm { _asm _emit 0x0f _asm _emit 0x0e } +#define TEST_MMX() __asm { _asm _emit 0x0f _asm _emit 0x77 } +#define TEST_3DNOWPLUS() __asm { _asm _emit 0x0f _asm _emit 0x0e _asm _emit 0x0f _asm _emit 0x0f _asm _emit 0xc0 _asm _emit 0xbb _asm _emit 0x0f _asm _emit 0x0e } +#define TEST_MMXPLUS() __asm { _asm _emit 0x0f _asm _emit 0x77 _asm _emit 0x0f _asm _emit 0xea _asm _emit 0xc0 _asm _emit 0x0f _asm _emit 0x77 } +#endif + + +#ifndef __MSC__ +static jmp_buf j; + + + +/* Desc: signal handler + * + * In : signal number + * Out : - + * + * Note: returns by `longjmp'ing + */ +static void handler (int signal) +{ + longjmp(j, signal + 1); /* so we can tell... also ensure we don't pass 0 */ +} + + + +/* Desc: check if CPU has specific feature + * + * In : feature request + * Out : 0 == fail, input == pass + * + * Note: this should be in the `has_feature' body. The reason it isn't: + * under some systems (notably Linux), the `setjmp' may thrash EBX, + * which is used for PositionIndependentCode/GlobalOffsetTable system. + * Since EBX is non-volatile register, it should be restored upon return. + */ +static int check_feature (int feature) +{ + if (setjmp(j)) { + /* we got here only when `longjmp'ed by signal handlers */ + return 0; + } else { + /* we have signals and jump buffer set */ + switch (feature) { + case _CPU_HAS_CPUID: TEST_CPUID(0); break; + case _CPU_FEATURE_SSE: TEST_SSE(); break; + case _CPU_FEATURE_SSE2: TEST_SSE2(); break; + case _CPU_FEATURE_3DNOW: TEST_3DNOW(); break; + case _CPU_FEATURE_MMX: TEST_MMX(); break; + case _CPU_FEATURE_3DNOWPLUS: TEST_3DNOWPLUS(); break; + case _CPU_FEATURE_MMXPLUS: TEST_MMXPLUS(); break; + default: return 0; + } + return feature; + } +} +#endif + + + +/* Desc: perform (possibly faulting) instructions in a safe manner + * + * In : feature request + * Out : 0 == fail, input == pass + * + * Note: pure ANSI code; stupid Watcom cannot handle this. + */ +static int has_feature (int feature) +{ +#ifndef __MSC__ + int rv; + + /* register signal handlers */ + void (*old_sigill)(int) = signal(SIGILL, handler); + if (old_sigill == SIG_ERR) { + return 0; + } + + rv = check_feature(feature); + + /* restore the signal handlers */ + signal(SIGILL, old_sigill); + return rv; +#else + /* Use the non-standard __try/__except mechanism because win95 fails to catch + * sigillegal for SSE using standard signal mechanism. + * HACK ALERT! HACK ALERT! HACK ALERT! + * This means the MinGW version cannot be safely run under Win95! + */ +#define _TRY() __try { +#define _EXCEPTION() } __except(1) { return 0; } /* EXCEPTION_EXECUTE_HANDLER=1 */ + switch (feature) { + case _CPU_HAS_CPUID: _TRY() TEST_CPUID(0) _EXCEPTION() break; + case _CPU_FEATURE_SSE: _TRY() TEST_SSE() _EXCEPTION() break; + case _CPU_FEATURE_SSE2: _TRY() TEST_SSE2() _EXCEPTION() break; + case _CPU_FEATURE_3DNOW: _TRY() TEST_3DNOW() _EXCEPTION() break; + case _CPU_FEATURE_MMX: _TRY() TEST_MMX() _EXCEPTION() break; + case _CPU_FEATURE_3DNOWPLUS: _TRY() TEST_3DNOWPLUS() _EXCEPTION() break; + case _CPU_FEATURE_MMXPLUS: _TRY() TEST_MMXPLUS() _EXCEPTION() break; + default: return 0; + } + return feature; +#endif +} + + + +/* Desc: get CPU info + * + * In : pointer to _p_info + * Out : features + * + * Note: - + */ +int _cpuid (_p_info *pinfo) +{ + word32 dwId = 0; + word32 dwFeature = 0; + word32 dwExt = 0; + int feature = 0, os_support = 0; + char Ident[13]; + + if (!has_feature(_CPU_HAS_CPUID)) { + return 0; + } + +#ifdef __GNUC__ + __asm("\n\ + pushl %%ebx \n\ + /* get the vendor string */ \n\ + xorl %%eax, %%eax \n\ + cpuid \n\ + movl %%ebx, %3 \n\ + movl %%edx, %4 \n\ + movl %%ecx, %5 \n\ + /* get the Standard bits */ \n\ + movl $1, %%eax \n\ + cpuid \n\ + movl %%eax, %1 \n\ + movl %%edx, %2 \n\ + /* get AMD-specials */ \n\ + movl $0x80000000, %%eax \n\ + cpuid \n\ + cmpl $0x80000000, %%eax \n\ + jc 0f \n\ + movl $0x80000001, %%eax \n\ + cpuid \n\ + movl %%edx, %0 \n\ + 0: \n\ + popl %%ebx \n\ + ":"=g"(dwExt), "=g"(dwId), "=g"(dwFeature), + "=g"(((long *)Ident)[0]), "=g"(((long *)Ident)[1]), "=g"(((long *)Ident)[2]) + ::"%eax", "%ebx", "%ecx", "%edx"); +#else + _asm + { + push ebx + push ecx + push edx + + /* get the vendor string */ + xor eax,eax + cpuid + mov dword ptr [Ident],ebx + mov dword ptr [Ident+4],edx + mov dword ptr [Ident+8],ecx + + /* get the Standard bits */ + mov eax,1 + cpuid + mov dwId,eax + mov dwFeature,edx + + /* get AMD-specials */ + mov eax,80000000h + cpuid + cmp eax,80000000h + jc notamd + mov eax,80000001h + cpuid + mov dwExt,edx + +notamd: + pop ecx + pop ebx + pop edx + } +#endif + +#ifndef __WATCOMC__ + /* stupid watcom does not sigill... */ + if (dwFeature & _MMX_FEATURE_BIT) { + feature |= _CPU_FEATURE_MMX; + os_support |= has_feature(_CPU_FEATURE_MMX); + } + if (dwExt & _3DNOW_FEATURE_BIT) { + feature |= _CPU_FEATURE_3DNOW; + os_support |= has_feature(_CPU_FEATURE_3DNOW); + } + if (dwExt & _3DNOWPLUS_FEATURE_BIT) { + feature |= _CPU_FEATURE_3DNOWPLUS; + os_support |= has_feature(_CPU_FEATURE_3DNOWPLUS); + } + if (dwExt & _MMXPLUS_FEATURE_BIT) { + feature |= _CPU_FEATURE_MMXPLUS; + os_support |= has_feature(_CPU_FEATURE_MMXPLUS); + } + if (dwFeature & _SSE_FEATURE_BIT) { + feature |= _CPU_FEATURE_SSE; + os_support |= has_feature(_CPU_FEATURE_SSE); + } + if (dwFeature & _SSE2_FEATURE_BIT) { + feature |= _CPU_FEATURE_SSE2; + os_support |= has_feature(_CPU_FEATURE_SSE2); + } +#endif + + if (pinfo) { + memset(pinfo, 0, sizeof(_p_info)); + pinfo->os_support = os_support; + pinfo->feature = feature; + pinfo->family = (dwId >> 8) & 0xF; /* retrieving family */ + pinfo->model = (dwId >> 4) & 0xF; /* retrieving model */ + pinfo->stepping = dwId & 0xF; /* retrieving stepping */ + Ident[12] = 0; + strcpy(pinfo->v_name, Ident); + } + + return feature; +} + + + +#if CPUTEST +#include +/* Desc: + * + * In : + * Out : + * + * Note: + */ +int main (void) +{ + _p_info p; + _cpuid(&p); + printf("vendor : %s\n", p.v_name); + printf("family : %d\n", p.family); + printf("model : %d\n", p.model); + printf("stepping: %X\n", p.stepping); + printf("feature : %08x\n", p.feature); + printf("support : %08x\n", p.os_support); + printf("--------\n"); + printf("cpuid : %d\n", has_feature(_CPU_HAS_CPUID)); + printf("MMX : %d\n", has_feature(_CPU_FEATURE_MMX)); + printf("SSE : %d\n", has_feature(_CPU_FEATURE_SSE)); + printf("SSE2 : %d\n", has_feature(_CPU_FEATURE_SSE2)); + printf("3DNow! : %d\n", has_feature(_CPU_FEATURE_3DNOW)); + printf("3DNow!+ : %d\n", has_feature(_CPU_FEATURE_3DNOWPLUS)); + printf("MMX+ : %d\n", has_feature(_CPU_FEATURE_MMXPLUS)); + return 0; +} +#endif diff --git a/glide2x/cvg/incsrc/cpuid.h b/glide2x/cvg/incsrc/cpuid.h new file mode 100644 index 0000000..37c43fa --- /dev/null +++ b/glide2x/cvg/incsrc/cpuid.h @@ -0,0 +1,23 @@ +#ifndef CPUID_H_included +#define CPUID_H_included + +#define _CPU_HAS_CPUID 0xffff +#define _CPU_FEATURE_MMX 0x0001 +#define _CPU_FEATURE_SSE 0x0002 +#define _CPU_FEATURE_SSE2 0x0004 +#define _CPU_FEATURE_3DNOW 0x0008 +#define _CPU_FEATURE_3DNOWPLUS 0x0010 +#define _CPU_FEATURE_MMXPLUS 0x0020 + +typedef struct _processor_info { + char v_name[13]; /* vendor name */ + int family; /* family of the processor, eg. Intel_Pentium_Pro is family 6 processor */ + int model; /* madel of processor, eg. Intel_Pentium_Pro is model 1 of family 6 processor */ + int stepping; /* Processor revision number */ + int feature; /* processor Feature (same as return value). */ + int os_support; /* does OS Support the feature */ +} _p_info; + +int _cpuid (_p_info *); + +#endif