Mercurial > sdl-ios-xcode
diff src/cpuinfo/gcpuinfo.c @ 739:22dbf364c017
Added SDL_HasMMX(), SDL_Has3DNow(), SDL_HasSSE() in SDL_cpuinfo.h
author | Sam Lantinga <slouken@libsdl.org> |
---|---|
date | Tue, 18 Nov 2003 01:27:06 +0000 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/cpuinfo/gcpuinfo.c Tue Nov 18 01:27:06 2003 +0000 @@ -0,0 +1,436 @@ +/**************************************************************************** +* +* SciTech OS Portability Manager Library +* +* ======================================================================== +* +* Copyright (C) 1991-2002 SciTech Software, Inc. All rights reserved. +* +* This file may be distributed and/or modified under the terms of the +* GNU Lesser General Public License version 2.1 as published by the Free +* Software Foundation and appearing in the file LICENSE.LGPL included +* in the packaging of this file. +* +* Licensees holding a valid Commercial License for this product from +* SciTech Software, Inc. may use this file in accordance with the +* Commercial License Agreement provided with the Software. +* +* This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING +* THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR +* PURPOSE. +* +* See http://www.scitechsoft.com/license/ for information about +* the licensing options available and how to purchase a Commercial +* License Agreement. +* +* Contact license@scitechsoft.com if any conditions of this licensing +* are not clear to you, or you have questions about licensing options. +* +* ======================================================================== +* +* Language: ANSI C +* Environment: Any +* +* Description: Main module to implement the Zen Timer support functions. +* +****************************************************************************/ + +#include "cpuinfo.h" +//#include "pmapi.h" +//#include "oshdr.h" + +/*----------------------------- Implementation ----------------------------*/ + +/* External Intel assembler functions */ +#ifdef __INTEL__ +/* {secret} */ +ibool _ASMAPI _CPU_haveCPUID(void); +/* {secret} */ +ibool _ASMAPI _CPU_check80386(void); +/* {secret} */ +ibool _ASMAPI _CPU_check80486(void); +/* {secret} */ +uint _ASMAPI _CPU_checkCPUID(void); +/* {secret} */ +uint _ASMAPI _CPU_getCPUIDModel(void); +/* {secret} */ +uint _ASMAPI _CPU_getCPUIDStepping(void); +/* {secret} */ +uint _ASMAPI _CPU_getCPUIDFeatures(void); +/* {secret} */ +uint _ASMAPI _CPU_getCacheSize(void); +/* {secret} */ +uint _ASMAPI _CPU_have3DNow(void); +/* {secret} */ +ibool _ASMAPI _CPU_checkClone(void); +/* {secret} */ +void _ASMAPI _CPU_readTimeStamp(CPU_largeInteger *time); +/* {secret} */ +void _ASMAPI _CPU_runBSFLoop(ulong iterations); +/* {secret} */ +ulong _ASMAPI _CPU_mulDiv(ulong a,ulong b,ulong c); +/* {secret} */ +#define CPU_HaveMMX 0x00800000 +#define CPU_HaveRDTSC 0x00000010 +#define CPU_HaveSSE 0x02000000 +#endif + +/*------------------------ Public interface routines ----------------------*/ + +#ifdef __INTEL__ +extern Uint8 PM_inpb(int port); +extern void PM_outpb(int port,Uint8 val); + +/**************************************************************************** +REMARKS: +Read an I/O port location. +****************************************************************************/ +static uchar rdinx( + int port, + int index) +{ + PM_outpb(port,(uchar)index); + return PM_inpb(port+1); +} + +/**************************************************************************** +REMARKS: +Write an I/O port location. +****************************************************************************/ +static void wrinx( + ushort port, + ushort index, + ushort value) +{ + PM_outpb(port,(uchar)index); + PM_outpb(port+1,(uchar)value); +} + +/**************************************************************************** +REMARKS: +Enables the Cyrix CPUID instruction to properly detect MediaGX and 6x86 +processors. +****************************************************************************/ +static void _CPU_enableCyrixCPUID(void) +{ + uchar ccr3; + + //PM_init(); + ccr3 = rdinx(0x22,0xC3); + wrinx(0x22,0xC3,(uchar)(ccr3 | 0x10)); + wrinx(0x22,0xE8,(uchar)(rdinx(0x22,0xE8) | 0x80)); + wrinx(0x22,0xC3,ccr3); +} +#endif + +/**************************************************************************** +DESCRIPTION: +Returns the type of processor in the system. + +HEADER: +cpuinfo.h + +RETURNS: +Numerical identifier for the installed processor + +REMARKS: +Returns the type of processor in the system. Note that if the CPU is an +unknown Pentium family processor that we don't have an enumeration for, +the return value will be greater than or equal to the value of CPU_UnkPentium +(depending on the value returned by the CPUID instruction). + +SEE ALSO: +CPU_getProcessorSpeed, CPU_haveMMX, CPU_getProcessorName +****************************************************************************/ +uint ZAPI CPU_getProcessorType(void) +{ +#if defined(__INTEL__) + uint cpu,vendor,model,cacheSize; + static ibool firstTime = true; + + if (_CPU_haveCPUID()) { + cpu = _CPU_checkCPUID(); + vendor = cpu & ~CPU_mask; + if (vendor == CPU_Intel) { + /* Check for Intel processors */ + switch (cpu & CPU_mask) { + case 4: cpu = CPU_i486; break; + case 5: cpu = CPU_Pentium; break; + case 6: + if ((model = _CPU_getCPUIDModel()) == 1) + cpu = CPU_PentiumPro; + else if (model <= 6) { + cacheSize = _CPU_getCacheSize(); + if ((model == 5 && cacheSize == 0) || + (model == 5 && cacheSize == 256) || + (model == 6 && cacheSize == 128)) + cpu = CPU_Celeron; + else + cpu = CPU_PentiumII; + } + else if (model >= 7) { + /* Model 7 == Pentium III */ + /* Model 8 == Celeron/Pentium III Coppermine */ + cacheSize = _CPU_getCacheSize(); + if ((model == 8 && cacheSize == 128)) + cpu = CPU_Celeron; + else + cpu = CPU_PentiumIII; + } + break; + case 7: + cpu = CPU_Pentium4; + break; + default: + cpu = CPU_UnkIntel; + break; + } + } + else if (vendor == CPU_Cyrix) { + /* Check for Cyrix processors */ + switch (cpu & CPU_mask) { + case 4: + if ((model = _CPU_getCPUIDModel()) == 4) + cpu = CPU_CyrixMediaGX; + else + cpu = CPU_UnkCyrix; + break; + case 5: + if ((model = _CPU_getCPUIDModel()) == 2) + cpu = CPU_Cyrix6x86; + else if (model == 4) + cpu = CPU_CyrixMediaGXm; + else + cpu = CPU_UnkCyrix; + break; + case 6: + if ((model = _CPU_getCPUIDModel()) <= 1) + cpu = CPU_Cyrix6x86MX; + else + cpu = CPU_UnkCyrix; + break; + default: + cpu = CPU_UnkCyrix; + break; + } + } + else if (vendor == CPU_AMD) { + /* Check for AMD processors */ + switch (cpu & CPU_mask) { + case 4: + if ((model = _CPU_getCPUIDModel()) == 0) + cpu = CPU_AMDAm5x86; + else + cpu = CPU_AMDAm486; + break; + case 5: + if ((model = _CPU_getCPUIDModel()) <= 3) + cpu = CPU_AMDK5; + else if (model <= 7) + cpu = CPU_AMDK6; + else if (model == 8) + cpu = CPU_AMDK6_2; + else if (model == 9) + cpu = CPU_AMDK6_III; + else if (model == 13) { + if (_CPU_getCPUIDStepping() <= 3) + cpu = CPU_AMDK6_IIIplus; + else + cpu = CPU_AMDK6_2plus; + } + else + cpu = CPU_UnkAMD; + break; + case 6: + if ((model = _CPU_getCPUIDModel()) == 3) + cpu = CPU_AMDDuron; + else + cpu = CPU_AMDAthlon; + break; + default: + cpu = CPU_UnkAMD; + break; + } + } + else if (vendor == CPU_IDT) { + /* Check for IDT WinChip processors */ + switch (cpu & CPU_mask) { + case 5: + if ((model = _CPU_getCPUIDModel()) <= 4) + cpu = CPU_WinChipC6; + else if (model == 8) + cpu = CPU_WinChip2; + else + cpu = CPU_UnkIDT; + break; + case 6: + vendor = CPU_VIA; + if ((model = _CPU_getCPUIDModel()) <= 6) + cpu = CPU_ViaCyrixIII; + else + cpu = CPU_UnkVIA; + break; + default: + vendor = CPU_VIA; + cpu = CPU_UnkVIA; + break; + } + } + else { + /* Assume a Pentium compatible Intel clone */ + cpu = CPU_Pentium; + } + return cpu | vendor | (_CPU_getCPUIDStepping() << CPU_steppingShift); + } + else { + if (_CPU_check80386()) + cpu = CPU_i386; + else if (_CPU_check80486()) { + /* If we get here we may have a Cyrix processor so we can try + * enabling the CPUID instruction and trying again. + */ + if (firstTime) { + firstTime = false; + _CPU_enableCyrixCPUID(); + return CPU_getProcessorType(); + } + cpu = CPU_i486; + } + else + cpu = CPU_Pentium; + if (!_CPU_checkClone()) + return cpu | CPU_Intel; + return cpu; + } +#elif defined(__ALPHA__) + return CPU_Alpha; +#elif defined(__MIPS__) + return CPU_Mips; +#elif defined(__PPC__) + return CPU_PowerPC; +#endif +} + +/**************************************************************************** +DESCRIPTION: +Returns true if the processor supports Intel MMX extensions. + +HEADER: +cpuinfo.h + +RETURNS: +True if MMX is available, false if not. + +REMARKS: +This function determines if the processor supports the Intel MMX extended +instruction set. + +SEE ALSO: +CPU_getProcessorType, CPU_getProcessorSpeed, CPU_have3DNow, CPU_haveSSE, +CPU_getProcessorName +****************************************************************************/ +ibool ZAPI CPU_haveMMX(void) +{ +#ifdef __INTEL__ + if (_CPU_haveCPUID()) + return (_CPU_getCPUIDFeatures() & CPU_HaveMMX) != 0; + return false; +#else + return false; +#endif +} + +/**************************************************************************** +DESCRIPTION: +Returns true if the processor supports AMD 3DNow! extensions. + +HEADER: +cpuinfo.h + +RETURNS: +True if 3DNow! is available, false if not. + +REMARKS: +This function determines if the processor supports the AMD 3DNow! extended +instruction set. + +SEE ALSO: +CPU_getProcessorType, CPU_getProcessorSpeed, CPU_haveMMX, CPU_haveSSE, +CPU_getProcessorName +****************************************************************************/ +ibool ZAPI CPU_have3DNow(void) +{ +#ifdef __INTEL__ + if (_CPU_haveCPUID()) + return _CPU_have3DNow(); + return false; +#else + return false; +#endif +} + +/**************************************************************************** +DESCRIPTION: +Returns true if the processor supports Intel SSE extensions. + +HEADER: +cpuinfo.h + +RETURNS: +True if Intel SSE is available, false if not. + +REMARKS: +This function determines if the processor supports the Intel SSE extended +instruction set. + +SEE ALSO: +CPU_getProcessorType, CPU_getProcessorSpeed, CPU_haveMMX, CPU_have3DNow, +CPU_getProcessorName +****************************************************************************/ +ibool ZAPI CPU_haveSSE(void) +{ +#ifdef __INTEL__ + if (_CPU_haveCPUID()) + return (_CPU_getCPUIDFeatures() & CPU_HaveSSE) != 0; + return false; +#else + return false; +#endif +} + +/**************************************************************************** +RETURNS: +True if the RTSC instruction is available, false if not. + +REMARKS: +This function determines if the processor supports the Intel RDTSC +instruction, for high precision timing. If the processor is not an Intel or +Intel clone CPU, this function will always return false. + +DESCRIPTION: +Returns true if the processor supports RDTSC extensions. + +HEADER: +cpuinfo.h + +RETURNS: +True if RTSC is available, false if not. + +REMARKS: +This function determines if the processor supports the RDTSC instruction +for reading the processor time stamp counter. + +SEE ALSO: +CPU_getProcessorType, CPU_getProcessorSpeed, CPU_haveMMX, CPU_have3DNow, +CPU_getProcessorName +****************************************************************************/ +ibool ZAPI CPU_haveRDTSC(void) +{ +#ifdef __INTEL__ + if (_CPU_haveCPUID()) + return (_CPU_getCPUIDFeatures() & CPU_HaveRDTSC) != 0; + return false; +#else + return false; +#endif +}