gremlin/libs/glfw/lib/dos/dos_time.c
2011-01-04 18:11:59 +01:00

310 lines
8.1 KiB
C

//========================================================================
// GLFW - An OpenGL framework
// File: dos_time.c
// Platform: DOS
// API version: 2.6
// WWW: http://glfw.sourceforge.net
//------------------------------------------------------------------------
// Copyright (c) 2002-2006 Camilla Berglund
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would
// be appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such, and must not
// be misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source
// distribution.
//
//========================================================================
#include "internal.h"
// We use the __i386 define later in the code. Check if there are any
// other defines that hint that we are compiling for 32-bit x86.
#ifndef __i386
#if defined(__i386__) || defined(i386) || defined(X86) || defined(_M_IX86)
#define __i386
#endif
#endif // __i386
// Should we use inline x86 assembler?
#if defined(__i386) && defined(__GNUC__)
#define _USE_X86_ASM
#endif
//************************************************************************
//**** GLFW internal functions ****
//************************************************************************
// Functions for accessing upper and lower parts of 64-bit integers
// (Note: These are endian dependent, but ONLY used on x86 platforms!)
#define _HIGH(x) ((unsigned int*)&x)[1]
#define _LOW(x) *((unsigned int*)&x)
//========================================================================
// _glfwCPUID() - Execute x86 CPUID instruction
//========================================================================
#ifdef _USE_X86_ASM
static int _glfwCPUID( unsigned int ID, unsigned int *a, unsigned int *b,
unsigned int *c, unsigned int *d )
{
int has_cpuid;
unsigned int local_a, local_b, local_c, local_d;
// Inline assembly - GCC version
#if defined(__i386) && defined(__GNUC__)
// Detect CPUID support
asm(
"pushf\n\t"
"pop %%eax\n\t"
"movl %%eax,%%ebx\n\t"
"xorl $0x00200000,%%eax\n\t"
"push %%eax\n\t"
"popf\n\t"
"pushf\n\t"
"pop %%eax\n\t"
"xorl %%eax,%%ebx\n\t"
"movl %%eax,%0\n\t"
: "=m" (has_cpuid)
:
: "%eax", "%ebx"
);
if( !has_cpuid )
{
return GL_FALSE;
}
// Execute CPUID
asm(
"movl %4,%%eax\n\t"
"cpuid\n\t"
"movl %%eax,%0\n\t"
"movl %%ebx,%1\n\t"
"movl %%ecx,%2\n\t"
"movl %%edx,%3\n\t"
: "=m" (local_a), "=m" (local_b), "=m" (local_c), "=m" (local_d)
: "m" (ID)
: "%eax", "%ebx", "%ecx", "%edx"
);
#endif
// Common code for all compilers
*a = local_a;
*b = local_b;
*c = local_c;
*d = local_d;
return GL_TRUE;
}
#endif // _USE_X86_ASM
//========================================================================
// _glfwHasRDTSC() - Check for RDTSC availability AND usefulness
//========================================================================
static int _glfwHasRDTSC( void )
{
#ifdef _USE_X86_ASM
unsigned int cpu_name1, cpu_name2, cpu_name3;
unsigned int cpu_signature, cpu_brandID;
unsigned int max_base, feature_flags;
unsigned int dummy;
// Get processor vendor string (will return 0 if CPUID is not
// supported)
if( !_glfwCPUID( 0, &max_base, &cpu_name1, &cpu_name3, &cpu_name2 ) )
{
return GL_FALSE;
}
// Does the processor support base CPUID function 1?
if( max_base < 1 )
{
return GL_FALSE;
}
// Get CPU capabilities, CPU Brand ID & CPU Signature
_glfwCPUID( 1, &cpu_signature, &cpu_brandID, &dummy, &feature_flags );
// Is RDTSC supported?
if( !(feature_flags & 0x00000010) )
{
return GL_FALSE;
}
return GL_TRUE;
#else
// Not a supported compiler
return GL_FALSE;
#endif
}
//------------------------------------------------------------------------
// _RDTSC() - Get CPU cycle count using the RDTSC instruction
//------------------------------------------------------------------------
#if defined(__i386) && defined(__GNUC__)
// Read 64-bit processor Time Stamp Counter - GCC version
#define _RDTSC( hi, lo ) \
asm( \
"rdtsc\n\t" \
"movl %%edx,%0\n\t" \
"movl %%eax,%1" \
: "=m" (hi), "=m" (lo) \
: \
: "%edx", "%eax" \
);
#else
#define _RDTSC( hi, lo ) {hi=lo=0;}
#endif
//========================================================================
// _glfwInitTimer() - Initialize timer
//========================================================================
int _glfwInitTimer( void )
{
clock_t t, t1, t2;
long long c1, c2;
// Do we have RDTSC?
_glfwTimer.HasRDTSC = _glfwHasRDTSC();
if( _glfwTimer.HasRDTSC )
{
// Measure the CPU clock with the raw DOS clock (18.2 Hz)
t = clock();
while( (t1=clock()) == t );
_RDTSC( _HIGH(c1), _LOW(c1) );
t = t1+CLOCKS_PER_SEC/3;
while( (t2=clock()) < t );
_RDTSC( _HIGH(c2), _LOW(c2) );
// Calculate CPU clock period
_glfwTimer.Period = (double)(t2-t1) /
(CLOCKS_PER_SEC * (double)(c2-c1));
_RDTSC( _HIGH(_glfwTimer.t0), _LOW(_glfwTimer.t0) );
}
else
{
// Use the raw DOS clock (18.2 Hz)
_glfwTimer.Period = 1.0 / CLOCKS_PER_SEC;
_glfwTimer.t0 = clock();
}
return 1;
}
//========================================================================
// _glfwTerminateTimer() - Terminate timer
//========================================================================
void _glfwTerminateTimer( void )
{
// Nothing to do here
}
//************************************************************************
//**** Platform implementation functions ****
//************************************************************************
//========================================================================
// _glfwPlatformGetTime() - Return timer value in seconds
//========================================================================
double _glfwPlatformGetTime( void )
{
long long t_now;
// Get current clock count
if( _glfwTimer.HasRDTSC )
{
_RDTSC( _HIGH(t_now), _LOW(t_now) );
}
else
{
t_now = (long long) clock();
}
// Convert to seconds
return (t_now-_glfwTimer.t0) * _glfwTimer.Period;
}
//========================================================================
// _glfwPlatformSetTime() - Set timer value in seconds
//========================================================================
void _glfwPlatformSetTime( double t )
{
long long t_now;
// Get current clock count
if( _glfwTimer.HasRDTSC )
{
_RDTSC( _HIGH(t_now), _LOW(t_now) );
}
else
{
t_now = (long long) clock();
}
// Set timer
_glfwTimer.t0 = t_now - (long long)(t/_glfwTimer.Period);
}
//========================================================================
// _glfwPlatformSleep() - Put a thread to sleep for a specified amount of
// time
//========================================================================
void _glfwPlatformSleep( double time )
{
// TODO: Proper threaded version
if( time > 0 )
{
if( time < 0.001 )
{
delay( 1 );
}
else
{
delay( (unsigned int)(time*1000.0+0.5) );
}
}
}