/***************************************************************************
attotime.c
Support functions for working with attotime data.
Copyright Nicola Salmoria and the MAME Team.
Visit http://mamedev.org for licensing and usage restrictions.
***************************************************************************/
#include "mamecore.h"
#include "attotime.h"
#include "eminline.h"
/***************************************************************************
GLOBAL VARIABLES
***************************************************************************/
const attotime attotime_zero = STATIC_ATTOTIME_IN_SEC(0);
const attotime attotime_never = STATIC_ATTOTIME_IN_SEC(ATTOTIME_MAX_SECONDS);
/***************************************************************************
CONVERSION HELPERS
***************************************************************************/
/*-------------------------------------------------
attotime_to_attoseconds - convert a attotime
to attoseconds, clamping to maximum positive/
negative values
-------------------------------------------------*/
attoseconds_t attotime_to_attoseconds(attotime _time)
{
/* positive values between 0 and 1 second */
if (_time.seconds == 0)
return _time.attoseconds;
/* negative values between -1 and 0 seconds */
else if (_time.seconds == -1)
return _time.attoseconds - ATTOSECONDS_PER_SECOND;
/* out-of-range positive values */
else if (_time.seconds > 0)
return ATTOSECONDS_PER_SECOND;
/* out-of-range negative values */
else
return -ATTOSECONDS_PER_SECOND;
}
/***************************************************************************
CORE MATH FUNCTIONS
***************************************************************************/
/*-------------------------------------------------
attotime_add - add two attotimes
-------------------------------------------------*/
attotime attotime_add(attotime _time1, attotime _time2)
{
attotime result;
/* if one of the items is attotime_never, return attotime_never */
if (_time1.seconds >= ATTOTIME_MAX_SECONDS || _time2.seconds >= ATTOTIME_MAX_SECONDS)
return attotime_never;
/* add the seconds and attoseconds */
result.attoseconds = _time1.attoseconds + _time2.attoseconds;
result.seconds = _time1.seconds + _time2.seconds;
/* normalize and return */
if (result.attoseconds >= ATTOSECONDS_PER_SECOND)
{
result.attoseconds -= ATTOSECONDS_PER_SECOND;
result.seconds++;
}
/* overflow */
if (result.seconds >= ATTOTIME_MAX_SECONDS)
return attotime_never;
return result;
}
/*-------------------------------------------------
attotime_add_attoseconds - add attoseconds
to a attotime
-------------------------------------------------*/
attotime attotime_add_attoseconds(attotime _time1, attoseconds_t _attoseconds)
{
attotime result;
/* if one of the items is attotime_never, return attotime_never */
if (_time1.seconds >= ATTOTIME_MAX_SECONDS)
return attotime_never;
/* add the seconds and attoseconds */
result.attoseconds = _time1.attoseconds + _attoseconds;
result.seconds = _time1.seconds;
/* normalize and return */
if (result.attoseconds >= ATTOSECONDS_PER_SECOND)
{
result.attoseconds -= ATTOSECONDS_PER_SECOND;
result.seconds++;
}
/* overflow */
if (result.seconds >= ATTOTIME_MAX_SECONDS)
return attotime_never;
return result;
}
/*-------------------------------------------------
attotime_sub - subtract two attotimes
-------------------------------------------------*/
attotime attotime_sub(attotime _time1, attotime _time2)
{
attotime result;
/* if time1 is attotime_never, return attotime_never */
if (_time1.seconds >= ATTOTIME_MAX_SECONDS)
return attotime_never;
/* add the seconds and attoseconds */
result.attoseconds = _time1.attoseconds - _time2.attoseconds;
result.seconds = _time1.seconds - _time2.seconds;
/* normalize and return */
if (result.attoseconds < 0)
{
result.attoseconds += ATTOSECONDS_PER_SECOND;
result.seconds--;
}
return result;
}
/*-------------------------------------------------
attotime_sub_attoseconds - subtract
attoseconds from a attotime
-------------------------------------------------*/
attotime attotime_sub_attoseconds(attotime _time1, attoseconds_t _attoseconds)
{
attotime result;
/* if time1 is attotime_never, return attotime_never */
if (_time1.seconds >= ATTOTIME_MAX_SECONDS)
return attotime_never;
/* add the seconds and attoseconds */
result.attoseconds = _time1.attoseconds - _attoseconds;
result.seconds = _time1.seconds;
/* normalize and return */
if (result.attoseconds < 0)
{
result.attoseconds += ATTOSECONDS_PER_SECOND;
result.seconds--;
}
return result;
}
/*-------------------------------------------------
attotime_mul - multiply an attotime by
a constant
-------------------------------------------------*/
attotime attotime_mul(attotime _time1, UINT32 factor)
{
UINT32 attolo, attohi, reslo, reshi;
UINT64 temp;
/* if one of the items is attotime_never, return attotime_never */
if (_time1.seconds >= ATTOTIME_MAX_SECONDS)
return attotime_never;
/* 0 times anything is zero */
if (factor == 0)
return attotime_zero;
/* split attoseconds into upper and lower halves which fit into 32 bits */
attohi = divu_64x32_rem(_time1.attoseconds, ATTOSECONDS_PER_SECOND_SQRT, &attolo);
/* scale the lower half, then split into high/low parts */
temp = mulu_32x32(attolo, factor);
temp = divu_64x32_rem(temp, ATTOSECONDS_PER_SECOND_SQRT, &reslo);
/* scale the upper half, then split into high/low parts */
temp += mulu_32x32(attohi, factor);
temp = divu_64x32_rem(temp, ATTOSECONDS_PER_SECOND_SQRT, &reshi);
/* scale the seconds */
temp += mulu_32x32(_time1.seconds, factor);
if (temp >= ATTOTIME_MAX_SECONDS)
return attotime_never;
/* build the result */
return attotime_make(temp, (attoseconds_t)reslo + mul_32x32(reshi, ATTOSECONDS_PER_SECOND_SQRT));
}
/*-------------------------------------------------
attotime_div - divide an attotime by
a constant
-------------------------------------------------*/
attotime attotime_div(attotime _time1, UINT32 factor)
{
UINT32 attolo, attohi, reshi, reslo, remainder;
attotime result;
UINT64 temp;
/* if one of the items is attotime_never, return attotime_never */
if (_time1.seconds >= ATTOTIME_MAX_SECONDS)
return attotime_never;
/* ignore divide by zero */
if (factor == 0)
return _time1;
/* split attoseconds into upper and lower halves which fit into 32 bits */
attohi = divu_64x32_rem(_time1.attoseconds, ATTOSECONDS_PER_SECOND_SQRT, &attolo);
/* divide the seconds and get the remainder */
result.seconds = divu_64x32_rem(_time1.seconds, factor, &remainder);
/* combine the upper half of attoseconds with the remainder and divide that */
temp = (INT64)attohi + mulu_32x32(remainder, ATTOSECONDS_PER_SECOND_SQRT);
reshi = divu_64x32_rem(temp, factor, &remainder);
/* combine the lower half of attoseconds with the remainder and divide that */
temp = attolo + mulu_32x32(remainder, ATTOSECONDS_PER_SECOND_SQRT);
reslo = divu_64x32_rem(temp, factor, &remainder);
/* round based on the remainder */
result.attoseconds = (attoseconds_t)reslo + mulu_32x32(reshi, ATTOSECONDS_PER_SECOND_SQRT);
if (remainder >= factor / 2)
if (++result.attoseconds >= ATTOSECONDS_PER_SECOND)
{
result.attoseconds = 0;
result.seconds++;
}
return result;
}
/*-------------------------------------------------
attotime_compare - compare two attotimes
-------------------------------------------------*/
int attotime_compare(attotime _time1, attotime _time2)
{
if (_time1.seconds > _time2.seconds)
return 1;
if (_time1.seconds < _time2.seconds)
return -1;
if (_time1.attoseconds > _time2.attoseconds)
return 1;
if (_time1.attoseconds < _time2.attoseconds)
return -1;
return 0;
}
/*-------------------------------------------------
attotime_min - return the minimum of two
attotimes
-------------------------------------------------*/
attotime attotime_min(attotime _time1, attotime _time2)
{
if (_time1.seconds > _time2.seconds)
return _time2;
if (_time1.seconds < _time2.seconds)
return _time1;
if (_time1.attoseconds > _time2.attoseconds)
return _time2;
return _time1;
}
/*-------------------------------------------------
attotime_max - return the maximum of two
attotimes
-------------------------------------------------*/
attotime attotime_max(attotime _time1, attotime _time2)
{
if (_time1.seconds > _time2.seconds)
return _time1;
if (_time1.seconds < _time2.seconds)
return _time2;
if (_time1.attoseconds > _time2.attoseconds)
return _time1;
return _time2;
}
/***************************************************************************
MISC UTILITIES
***************************************************************************/
/*-------------------------------------------------
attotime_compare - return a temporary
printable string describing an attotime
-------------------------------------------------*/
const char *attotime_string(attotime _time, int precision)
{
static char buffers[8][30];
static int nextbuf;
char *buffer = &buffers[nextbuf++ % 8][0];
/* case 1: we want no precision; seconds only */
if (precision == 0)
sprintf(buffer, "%d", _time.seconds);
/* case 2: we want 9 or fewer digits of precision */
else if (precision <= 9)
{
UINT32 upper = _time.attoseconds / ATTOSECONDS_PER_SECOND_SQRT;
sprintf(buffer, "%d.%0*d", _time.seconds, precision, upper);
}
/* case 3: more than 9 digits of precision */
else
{
UINT32 lower;
UINT32 upper = divu_64x32_rem(_time.attoseconds, ATTOSECONDS_PER_SECOND_SQRT, &lower);
sprintf(buffer, "%d.%09d%0*d", _time.seconds, upper, precision - 9, lower);
}
return buffer;
}