1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
|
// license:BSD-3-Clause
// copyright-holders:Aaron Giles
/***************************************************************************
attotime.c
Support functions for working with attotime data.
***************************************************************************/
#include "emucore.h"
#include "eminline.h"
#include "attotime.h"
//**************************************************************************
// GLOBAL VARIABLES
//**************************************************************************
const attotime attotime::zero(0, 0);
const attotime attotime::never(ATTOTIME_MAX_SECONDS, 0);
//**************************************************************************
// CORE MATH FUNCTIONS
//**************************************************************************
//-------------------------------------------------
// operator*= - multiply an attotime by a
// constant
//-------------------------------------------------
attotime &attotime::operator*=(uint32_t factor)
{
// if one of the items is attotime::never, return attotime::never
if (m_seconds >= ATTOTIME_MAX_SECONDS)
return *this = never;
// 0 times anything is zero
if (factor == 0)
return *this = zero;
// split attoseconds into upper and lower halves which fit into 32 bits
uint32_t attolo;
uint32_t attohi = divu_64x32_rem(m_attoseconds, ATTOSECONDS_PER_SECOND_SQRT, &attolo);
// scale the lower half, then split into high/low parts
uint64_t temp = mulu_32x32(attolo, factor);
uint32_t reslo;
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);
uint32_t reshi;
temp = divu_64x32_rem(temp, ATTOSECONDS_PER_SECOND_SQRT, &reshi);
// scale the seconds
temp += mulu_32x32(m_seconds, factor);
if (temp >= ATTOTIME_MAX_SECONDS)
return *this = never;
// build the result
m_seconds = temp;
m_attoseconds = (attoseconds_t)reslo + mul_32x32(reshi, ATTOSECONDS_PER_SECOND_SQRT);
return *this;
}
//-------------------------------------------------
// operator/= - divide an attotime by a constant
//-------------------------------------------------
attotime &attotime::operator/=(uint32_t factor)
{
// if one of the items is attotime::never, return attotime::never
if (m_seconds >= ATTOTIME_MAX_SECONDS)
return *this = never;
// ignore divide by zero
if (factor == 0)
return *this;
// split attoseconds into upper and lower halves which fit into 32 bits
uint32_t attolo;
uint32_t attohi = divu_64x32_rem(m_attoseconds, ATTOSECONDS_PER_SECOND_SQRT, &attolo);
// divide the seconds and get the remainder
uint32_t remainder;
m_seconds = divu_64x32_rem(m_seconds, factor, &remainder);
// combine the upper half of attoseconds with the remainder and divide that
uint64_t temp = (int64_t)attohi + mulu_32x32(remainder, ATTOSECONDS_PER_SECOND_SQRT);
uint32_t 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);
uint32_t reslo = divu_64x32_rem(temp, factor, &remainder);
// round based on the remainder
m_attoseconds = (attoseconds_t)reslo + mulu_32x32(reshi, ATTOSECONDS_PER_SECOND_SQRT);
if (remainder >= factor / 2)
if (++m_attoseconds >= ATTOSECONDS_PER_SECOND)
{
m_attoseconds = 0;
m_seconds++;
}
return *this;
}
//-------------------------------------------------
// as_string - return a temporary printable
// string describing an attotime
//-------------------------------------------------
const char *attotime::as_string(int precision) const
{
static char buffers[8][30];
static int nextbuf;
char *buffer = &buffers[nextbuf++ % 8][0];
// special case: never
if (*this == never)
sprintf(buffer, "%-*s", precision, "(never)");
// case 1: we want no precision; seconds only
else if (precision == 0)
sprintf(buffer, "%d", m_seconds);
// case 2: we want 9 or fewer digits of precision
else if (precision <= 9)
{
uint32_t upper = m_attoseconds / ATTOSECONDS_PER_SECOND_SQRT;
int temp = precision;
while (temp < 9)
{
upper /= 10;
temp++;
}
sprintf(buffer, "%d.%0*d", m_seconds, precision, upper);
}
// case 3: more than 9 digits of precision
else
{
uint32_t lower;
uint32_t upper = divu_64x32_rem(m_attoseconds, ATTOSECONDS_PER_SECOND_SQRT, &lower);
int temp = precision;
while (temp < 18)
{
lower /= 10;
temp++;
}
sprintf(buffer, "%d.%09d%0*d", m_seconds, upper, precision - 9, lower);
}
return buffer;
}
|