www.pudn.com > zfxcengine-0.1.0.zip > ceMathInit.cpp


/* $Id: ceMathInit.cpp,v 1.4 2005/03/24 21:22:13 andreaskohn Exp $ */ 
#include  
#include "Math/ceMath.h" 
#include "SDL.h" 
#include "SDL_cpuinfo.h" 
 
namespace ZFXCE 
{ 
 
static CPUInfo_t CPUInfo; 
BOOL bUseInlineAsm=TRUE; 
 
// Enrico:  
// Copyright von diesem Assembler Code liegt bei Humus, emiper-8@student.luth.se 
// Leider fehlen mir die Kenntnisse, um das Plattformunabhängig selber zu schreiben. 
 
#if defined(WIN32) 
 
#define WIN32_LEAN_AND_MEAN 
#include "Windows.h" 
 
#define CPUID __asm _emit 0x0F __asm _emit 0xA2 
#define RDTSC __asm _emit 0x0F __asm _emit 0x31 
#define cpuid(func, a, b, c, d) cpuidAsm(func, &a, &b, &c, &d) 
 
#pragma warning(disable: 4035) 
  
typedef   signed __int64  int64; 
typedef unsigned __int64 uint64; 
 
void cpuidAsm(UINT func, UINT *a, UINT *b, UINT *c, UINT *d) 
{ 
	__asm { 
		PUSH	EAX 
		PUSH	EBX 
		PUSH	ECX 
		PUSH	EDX 
 
		MOV		EAX, func 
		CPUID 
		MOV		EDI, a 
		MOV		[EDI], EAX 
		MOV		EDI, b 
		MOV		[EDI], EBX 
		MOV		EDI, c 
		MOV		[EDI], ECX 
		MOV		EDI, d 
		MOV		[EDI], EDX 
 
		POP		EDX 
		POP		ECX 
		POP		EBX 
		POP		EAX 
	} 
} 
 
inline uint64 getCycleNumber() 
{ 
	__asm  
	{ 
		RDTSC 
	} 
} 
uint64 getHz() 
{ 
	LARGE_INTEGER t1,t2,tf; 
	uint64 c1,c2; 
 
	QueryPerformanceFrequency(&tf); 
	QueryPerformanceCounter(&t1); 
	c1 = getCycleNumber(); 
 
	// Some spin-wait 
	for (volatile int i = 0; i < 1000000; i++); 
 
	QueryPerformanceCounter(&t2); 
	c2 = getCycleNumber(); 
	 
	return ((c2 - c1) * tf.QuadPart / (t2.QuadPart - t1.QuadPart)); 
} 
 
 
#else  
/* Linux, *BSD, and all the others. */ 
 
#include  
 
 
#if 0 
// XXX: we need an asm guru for that. This code is basically i386, and it creates errors with recent gnu c++ compilers. 
 
#define cpuid(in,a,b,c,d)\ 
  asm volatile ("cpuid": "=a" (a), "=b" (b), "=c" (c), "=d" (d) : "a" (in)); 
 
#define rdtsc(a,d)\ 
  asm volatile ("rdtsc" : "=a" (a), "=d" (d)); 
 
#else 
 
#define cpuid(in,a,b,c,d) \ 
  (a)=0,(b)=0,(c)=0,(d)=0 
 
#define rdtsc(a,d) \ 
  (a)=0,(d)=0 
 
#endif 
 
typedef unsigned int uint; 
typedef   signed long long  int64; 
typedef unsigned long long uint64; 
 
inline uint64 getCycleNumber() 
{ 
	union { 
		struct { 
			unsigned int a,d; 
		} parts; 
		long long ad; 
	} ads; 
 
	rdtsc(ads.parts.a,ads.parts.d); 
	return ads.ad; 
} 
 
uint64 getHz(){ 
	static struct timeval t1, t2; 
	static struct timezone tz; 
	unsigned long long c1,c2; 
 
	gettimeofday(&t1, &tz); 
	c1 = getCycleNumber(); 
 
	// Some spin-wait 
	for (volatile int i = 0; i < 1000000; i++); 
 
	gettimeofday(&t2, &tz); 
	c2 = getCycleNumber(); 
 
	return (1000000 * (c2 - c1)) / ((t2.tv_usec - t1.tv_usec) + 1000000 * (t2.tv_sec - t1.tv_sec)); 
} 
#endif 
 
BOOL ceMathLibInit(BOOL bUseAsm, CPUInfo_t* pCPUInfo) 
{ 
	// Sobald wir irgendwann mal die Funktionen mit 3Dnow oder SSE implementiert haben, 
	// kann man mittels diesem Parameter den Assembler abschalten. Z.B. um 
	// Geschwindigkeitsvergleiche durchzuführen... 
	bUseInlineAsm = bUseAsm; 
 
	// Namen resetten 
	memset(&CPUInfo.strCPUName[0], 0, sizeof(char) * 49); 
	memset(&CPUInfo.strCPUVendor[0], 0, sizeof(char) * 13); 
 
	// Features rausfinden - neu seit SDL 1.2.7 
	CPUInfo.bHasMMX = SDL_HasMMX(); 
	CPUInfo.bHasMMXEx = SDL_HasMMXExt(); 
	CPUInfo.bHas3DNow = SDL_Has3DNow(); 
	CPUInfo.bHas3DNowExt = SDL_Has3DNowExt(); 
	CPUInfo.bHasSSE = SDL_HasSSE(); 
	CPUInfo.bHasSSE2 = SDL_HasSSE2(); 
 
	// Den Rest machen wir so 
	UINT maxi=0; 
	cpuid(0, maxi, ((UINT *) CPUInfo.strCPUVendor)[0],  
		((UINT *) CPUInfo.strCPUVendor)[2],  
		((UINT *) CPUInfo.strCPUVendor)[1]); 
 
	if (maxi >= 1) 
	{ 
		UINT a,b,c,d; 
		a = b = c = d = 0; 
		cpuid(1, a, b, c, d); 
		CPUInfo.iCPUFamily = (a >> 8) & 0x0F; 
 
		UINT maxei=0; 
		cpuid(0x80000000, maxei, b, c, d); 
		if (maxei >= 0x80000001) 
		{ 
			cpuid(0x80000001, a, b, c, d); 
 
			if (maxei >= 0x80000002) 
			{ 
				cpuid(0x80000002, ((UINT *) CPUInfo.strCPUName)[0], ((UINT *) CPUInfo.strCPUName)[1], ((UINT *) CPUInfo.strCPUName)[2], ((UINT *) CPUInfo.strCPUName)[3]); 
				CPUInfo.strCPUName[16] = '\0'; 
 
				if (maxei >= 0x80000003){ 
					cpuid(0x80000003, ((UINT *) CPUInfo.strCPUName)[4], ((UINT *) CPUInfo.strCPUName)[5], ((UINT *) CPUInfo.strCPUName)[6], ((UINT *) CPUInfo.strCPUName)[7]); 
					CPUInfo.strCPUName[32] = '\0'; 
 
					if (maxei >= 0x80000004){ 
						cpuid(0x80000004, ((UINT *) CPUInfo.strCPUName)[8], ((UINT *) CPUInfo.strCPUName)[9], ((UINT *) CPUInfo.strCPUName)[10], ((UINT *) CPUInfo.strCPUName)[11]); 
						CPUInfo.strCPUName[48] = '\0'; 
					} 
				} 
			} 
		} 
	} 
 
	// Sicher gehen, dass wir einen highperformance counter haben, ohne den können wir nicht die Mhz zählen 
	if( SDL_HasRDTSC() ) 
		CPUInfo.uiMhZ = (UINT) getHz() / 1000000; 
 
	// Wenn gewünscht, kopieren wir hier die Infos über die CPU 
	if(pCPUInfo) 
	{ 
		memcpy(pCPUInfo, &CPUInfo, sizeof(CPUInfo_t) ); 
	} 
 
	return TRUE; 
} 
 
} // Namespace ZFXCE