/****************************************************************************************/

/*  CPUInfo.C                                                                           */

/*                                                                                      */

/*  Author:  Mike Sandige, Ken Baird                                                    */

/*  Description:  simple cpu capabilities tests                                         */

/*                                                                                      */

/*  The contents of this file are subject to the Jet3D Public License                   */

/*  Version 1.02 (the "License"); you may not use this file except in                   */

/*  compliance with the License. You may obtain a copy of the License at                */

/*  http://www.jet3d.com                                                                */

/*                                                                                      */

/*  Software distributed under the License is distributed on an "AS IS"                 */

/*  basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.  See                */

/*  the License for the specific language governing rights and limitations              */

/*  under the License.                                                                  */

/*                                                                                      */

/*  The Original Code is Jet3D, released December 12, 1999.                             */

/*  Copyright (C) 1996-1999 Eclipse Entertainment, L.L.C. All Rights Reserved           */

/*                                                                                      */

/****************************************************************************************/



#ifdef WIN32

#define WIN32_LEAN_AND_MEAN

#pragma warning(disable : 4201 4214 4115)

#include <windows.h>		// EXCEPTION_EXECUTE_HANDLER

#include <string.h>			// strnlen

#pragma warning(default : 4201 4214 4115; disable : 4514)

#endif



#ifdef BUILD_BE

#include <string.h>

#endif



#include "CPUInfo.h"



#define CPUID _asm _emit 0fh _asm _emit 0a2h





static uint32	CPUInfo_GetCPUIDEAX(uint32 funcNum)

{

	uint32	retval;



#ifdef WIN32

	__try

	{

		_asm

		{

			mov	eax,funcNum

			CPUID

			mov	retval,eax

		}

	}__except(EXCEPTION_EXECUTE_HANDLER)

	{

		retval	=0;

	}

#endif



#ifdef BUILD_BE

	__asm__ __volatile__ ("

	push %%ebx //; appears to fix the crashes

	movl %1, %%eax

	CPUID

	movl %%eax, %0

	pop %%ebx"

	  : "=m" (retval)

	  : "g" (funcNum)

	  : "%eax");

#endif



	return	retval;

}



static uint32	CPUInfo_GetCPUIDEDX(uint32 funcNum)

{

	uint32	retval;



#ifdef WIN32

	__try

	{

		_asm

		{

			mov	eax,funcNum

			CPUID

			mov	retval,edx

		}

	}__except(EXCEPTION_EXECUTE_HANDLER)

	{

		retval	=0;

	}

#endif



#ifdef BUILD_BE

	__asm__  __volatile__("

	push %%ebx // these appear to fix the segfaults.

	movl %1, %%eax

	CPUID

	movl %%edx, %0

	pop %%ebx"

	  : "=m" (retval)

	  : "g" (funcNum)

	  : "%eax" , "%edx");

#endif



	return	retval;

}





static uint32	CPUInfo_GetCPUIDString(uint32 funcNum, char *szId)

{

	uint32	retval;

	

#ifdef WIN32

	__try

	{

		_asm

		{

			mov	eax,funcNum

			CPUID

			mov	retval,eax

			mov	eax,szId

			mov	dword ptr[eax],ebx

			mov	dword ptr[eax+4],edx

			mov	dword ptr[eax+8],ecx

		}

	}__except(EXCEPTION_EXECUTE_HANDLER)

	{

		retval	=0;

	}

#endif



#ifdef BUILD_BE

		__asm__ __volatile__ ("

			push %%ebx // these appear to fix the segfaults..

			movl $0, %%eax //; %2, %%eax

			cpuid

			mov %%eax, %0

			movl  %1, %%eax

			movl %%ebx, (%%eax)

			movl %%edx, 4(%%eax)

			movl %%ecx, 8(%%eax)

			pop %%ebx

			"

			: "=m" (retval) 

			: "m" (szId) , "m" (funcNum)

			: "%eax", "%ebx", "%ecx", "%edx", "memory" );

#endif



	return	retval;

}





#define CPUINFO_VENDOR_STRING_LENGTH 16

#define CPUINFO_AMD_ID_STRING   "AuthenticAMD"

#define CPUINFO_INTEL_ID_STRING "GenuineIntel"



jeBoolean CPUInfo_TestFor3DNow(void)

{

	char VendorString[CPUINFO_VENDOR_STRING_LENGTH];



	CPUInfo_GetCPUIDString(0, VendorString);

	if(strncmp(VendorString, CPUINFO_AMD_ID_STRING,strlen(CPUINFO_AMD_ID_STRING))==0)

		{

			uint32	TypeFlags	=CPUInfo_GetCPUIDEAX(0x80000000);

			if(TypeFlags)	//extended functions supported

				{

					TypeFlags	=CPUInfo_GetCPUIDEDX(0x80000001);

					if (TypeFlags & (1<<23))

						return JE_TRUE;

				}

		}

	return JE_FALSE;

}



jeBoolean CPUInfo_TestForMMX(void)

{

	char VendorString[CPUINFO_VENDOR_STRING_LENGTH];



	CPUInfo_GetCPUIDString(0, VendorString);

	if(strncmp(VendorString, CPUINFO_AMD_ID_STRING,strlen(CPUINFO_AMD_ID_STRING))==0)

		{

			uint32	TypeFlags	=CPUInfo_GetCPUIDEAX(0x80000000);

			if(TypeFlags)	//extended functions supported

				{

					TypeFlags	=CPUInfo_GetCPUIDEDX(0x80000001);

					if (TypeFlags & (1<<23))

						return JE_TRUE;

				}

		}

	else if(strncmp(VendorString, CPUINFO_INTEL_ID_STRING, strlen(CPUINFO_INTEL_ID_STRING))==0)

	{

		uint32	TypeFlags				=CPUInfo_GetCPUIDEDX(0x1);

		if (TypeFlags & (1<<23))

			return JE_TRUE;

	}



	return JE_FALSE;

}

