231 lines
8.3 KiB
C#
231 lines
8.3 KiB
C#
namespace MAME.Core
|
|
{
|
|
public struct Atime
|
|
{
|
|
public int seconds;
|
|
public long attoseconds;
|
|
public Atime(int i, long l)
|
|
{
|
|
seconds = i;
|
|
attoseconds = l;
|
|
}
|
|
}
|
|
public class Attotime
|
|
{
|
|
public static int ATTOTIME_MAX_SECONDS = 1000000000, ATTOSECONDS_PER_SECOND_SQRT = 1000000000;
|
|
public static long ATTOSECONDS_PER_SECOND = (long)(1e18);
|
|
public static Atime ATTOTIME_ZERO = new Atime(0, 0);
|
|
public static Atime ATTOTIME_NEVER = new Atime(1000000000, 0);
|
|
public static long ATTOSECONDS_PER_NANOSECOND = (long)1e9;
|
|
public static Atime ATTOTIME_IN_NSEC(long ns)
|
|
{
|
|
return new Atime((int)(ns / 1000000000), (long)((ns % 1000000000) * ATTOSECONDS_PER_NANOSECOND));
|
|
}
|
|
public static Atime ATTOTIME_IN_HZ(int hz)
|
|
{
|
|
return new Atime(0, (long)(ATTOSECONDS_PER_SECOND / hz));
|
|
}
|
|
public static long attotime_to_attoseconds(Atime _time)
|
|
{
|
|
if (_time.seconds == 0)
|
|
{
|
|
return _time.attoseconds;
|
|
}
|
|
else if (_time.seconds == -1)
|
|
{
|
|
return _time.attoseconds - Attotime.ATTOSECONDS_PER_SECOND;
|
|
}
|
|
else if (_time.seconds > 0)
|
|
{
|
|
return Attotime.ATTOSECONDS_PER_SECOND;
|
|
}
|
|
else
|
|
{
|
|
return -Attotime.ATTOSECONDS_PER_SECOND;
|
|
}
|
|
}
|
|
public static Atime attotime_add(Atime _time1, Atime _time2)
|
|
{
|
|
Atime result = new Atime();
|
|
|
|
/* 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;
|
|
}
|
|
public static Atime attotime_add_attoseconds(Atime _time1, long _attoseconds)
|
|
{
|
|
Atime 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;
|
|
}
|
|
public static Atime attotime_sub(Atime _time1, Atime _time2)
|
|
{
|
|
Atime 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;
|
|
}
|
|
public static Atime attotime_sub_attoseconds(Atime _time1, long _attoseconds)
|
|
{
|
|
Atime 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;
|
|
}
|
|
public static Atime attotime_mul(Atime _time1, uint factor)
|
|
{
|
|
uint attolo, attohi, reslo, reshi;
|
|
ulong 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((ulong)_time1.attoseconds, 1000000000, out attolo);
|
|
|
|
/* scale the lower half, then split into high/low parts */
|
|
temp = mulu_32x32(attolo, factor);
|
|
temp = divu_64x32_rem(temp, 1000000000, out reslo);
|
|
|
|
/* scale the upper half, then split into high/low parts */
|
|
temp += mulu_32x32(attohi, factor);
|
|
temp = divu_64x32_rem(temp, 1000000000, out reshi);
|
|
|
|
/* scale the seconds */
|
|
temp += mulu_32x32((uint)_time1.seconds, factor);
|
|
if (temp >= 1000000000)
|
|
return ATTOTIME_NEVER;
|
|
|
|
/* build the result */
|
|
return new Atime((int)temp, (long)reslo + mul_32x32((int)reshi, 1000000000));
|
|
}
|
|
private static uint divu_64x32_rem(ulong a, uint b, out uint remainder)
|
|
{
|
|
remainder = (uint)(a % (ulong)b);
|
|
return (uint)(a / (ulong)b);
|
|
}
|
|
private static ulong mulu_32x32(uint a, uint b)
|
|
{
|
|
return (ulong)a * (ulong)b;
|
|
}
|
|
private static long mul_32x32(int a, int b)
|
|
{
|
|
return (long)a * (long)b;
|
|
}
|
|
public static Atime attotime_div(Atime _time1, uint factor)
|
|
{
|
|
uint attolo, attohi, reshi, reslo, remainder;
|
|
Atime result;
|
|
ulong temp;
|
|
|
|
/* if one of the items is attotime_never, return attotime_never */
|
|
if (_time1.seconds >= ATTOTIME_MAX_SECONDS)
|
|
return new Atime(ATTOTIME_MAX_SECONDS, 0);
|
|
|
|
/* 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((ulong)_time1.attoseconds, 1000000000, out attolo);
|
|
|
|
/* divide the seconds and get the remainder */
|
|
result.seconds = (int)divu_64x32_rem((ulong)_time1.seconds, factor, out remainder);
|
|
|
|
/* combine the upper half of attoseconds with the remainder and divide that */
|
|
temp = (ulong)attohi + mulu_32x32(remainder, 1000000000);
|
|
reshi = divu_64x32_rem(temp, factor, out remainder);
|
|
|
|
/* combine the lower half of attoseconds with the remainder and divide that */
|
|
temp = attolo + mulu_32x32(remainder, 1000000000);
|
|
reslo = divu_64x32_rem(temp, factor, out remainder);
|
|
|
|
/* round based on the remainder */
|
|
result.attoseconds = (long)reslo + (long)mulu_32x32(reshi, 1000000000);
|
|
if (remainder >= factor / 2)
|
|
if (++result.attoseconds >= ATTOSECONDS_PER_SECOND)
|
|
{
|
|
result.attoseconds = 0;
|
|
result.seconds++;
|
|
}
|
|
return result;
|
|
}
|
|
public static int attotime_compare(Atime _time1, Atime _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;
|
|
}
|
|
}
|
|
} |