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
+}