///////////////////////////////////////////////////////////////////////////////
/// @file Functions.hpp
///
/// @brief Destiny3D assembly functions for Memory Manager
///
/// @author Lightning
///
/// This file is the intellectual property of Novus Delta, LLC.. Usage of the
/// contents of this file is subject to the Destiny3D Member License which
/// can be found at http://www.destiny3d.com.  Any other usage is prohibited.
///
/// This file is distributed "AS IS" without warranty of any kind.  Novus
/// Delta, LLC. does not guarantee the fitness of the contents of this file
/// for any particular purpose.
///
/// Copyright (C) 2001-2003 Novus Delta, LLC. All Rights Reserved.
///
/// <hr>
///                                 Change History
/// <hr>
///
/// @date Oct 2002
/// @author Lightning
/// @remarks Creation
///
///////////////////////////////////////////////////////////////////////////////

#include "Functions.hpp"

//the global structure entry for the internal functions usage
geMem_InternalFunctions *InternalFunctions;

//this file contains all the structs and returns for any asm function that we override
//this allows for quick access to the functions that we want instead of constantly checking
//for the type of function we want to call

//The normal asm function structure
static geMem_InternalFunctions geMem_ASM_APIs =
{
	Internal_ASM_memccpy,
	Internal_ASM_memchr,
	Internal_ASM_memcmp,
	Internal_ASM_memcpy,
	Internal_ASM_memset,
	Internal_ASM_strcmp,
	Internal_ASM_strlen,
};

//asm and mmx structure
static geMem_InternalFunctions geMem_ASM_MMX_APIs =
{
	Internal_ASM_memccpy,
	Internal_ASM_memchr,
	Internal_ASM_memcmp,
	Internal_ASM_MMX_memcpy,
	Internal_ASM_MMX_memset,
	Internal_ASM_strcmp,
	Internal_ASM_strlen,
};

//mmx and 3dnow! structure
static geMem_InternalFunctions geMem_ASM_AMD_MMX_APIs =
{
	Internal_ASM_memccpy,
	Internal_ASM_memchr,
	Internal_ASM_memcmp,
	Internal_ASM_AMD_MMX_memcpy,
	Internal_ASM_MMX_memset,
	Internal_ASM_strcmp,
	Internal_ASM_strlen,
};

//flags for what is supported
#define InternalFunctions_ASM			0x01
#define InternalFunctions_MMX_ASM		0x02
#define InternalFunctions_AMDMMX_ASM	0x04

deBoolean InitializeInternalFunctions()
{
	long				Flags;

	//initialize the internal memory functions that we use and others use. First find out if
	//the comp supports MMX
	
	__asm
	{
		//determine if CPUID exists, we need to find out if MMX or 3DNow! is allowed

		//set eax to the default value
		mov Flags, InternalFunctions_ASM

		//grab the flags
		pushfd
		pop eax

		//swap the 21st bit (bit 0 is the far right bit)
		xor eax, 200000h

		//put it back in the flags
		push eax
		popfd

		//grab flags again
		pushfd
		pop eax

		//see if the bit changed
		xor eax, ecx
		jz EndCPUCheck

		//cpuid supported, see if mmx is allowed
		mov eax, 1
		cpuid

		//check the flags, bit 23 is mmx flag
		test edx, 800000h
		jz EndCPUCheck

		//at least mmx supported
		or Flags, InternalFunctions_MMX_ASM

		//Intel doesnt support 3DNow!, only AMD, so make sure the chip is AMD
		xor eax, eax
		cpuid

		//check the vendor
		cmp ebx, 68747541h	//Auth
		jne EndCPUCheck

		cmp ecx, 69746E65h	//enti
		jne EndCPUCheck

		cmp edx, 444D4163h	//cAMD
		jne EndCPUCheck

		//AMD chip, check 3DNow! support

		//see if 3DNow! is supported
		mov eax, 80000000h
		cpuid

		//see if 80000001h is allowed for extended functions
		cmp eax, 80000000h
		jbe EndCPUCheck

		//allowed, get it
		mov eax, 80000001h
		cpuid

		//see if bit 31 is set
		test edx, 80000000h
		jz EndCPUCheck

		//3DNow! allowed
		or Flags, InternalFunctions_AMDMMX_ASM

	EndCPUCheck:
	}

	InternalFunctions = NULL;

	//see what flags are set. Select the best entry that works
	if(Flags & InternalFunctions_AMDMMX_ASM)
		//if 3DNow! is also allowed, go to it instead
		InternalFunctions = &geMem_ASM_AMD_MMX_APIs;
	else if(Flags & InternalFunctions_MMX_ASM)
		//if MMX is being allowed, use it
		InternalFunctions = &geMem_ASM_MMX_APIs;
	else
		//go with the standard functions
		InternalFunctions = &geMem_ASM_APIs;



	if(!InternalFunctions)
		return deFALSE;

	return deTRUE;
}

void ReleaseInternalFunctions()
{
	//wipe out our pointer to the internal functions
	InternalFunctions = NULL;
}