AxibugEmuOnline/AxibugEmuOnline.Client/Assets/Plugins/Mame.Core/emu/Attotime.cs

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;
}
}
}