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
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
|
// license:BSD-3-Clause
// copyright-holders:Aaron Giles
/***************************************************************************
attotime.cpp
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*=(u32 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
u32 attolo;
u32 attohi = divu_64x32_rem(m_attoseconds, ATTOSECONDS_PER_SECOND_SQRT, attolo);
// scale the lower half, then split into high/low parts
u64 temp = mulu_32x32(attolo, factor);
u32 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);
u32 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/=(u32 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
u32 attolo;
u32 attohi = divu_64x32_rem(m_attoseconds, ATTOSECONDS_PER_SECOND_SQRT, attolo);
// divide the seconds and get the remainder
u32 remainder;
m_seconds = divu_64x32_rem(m_seconds, factor, remainder);
// combine the upper half of attoseconds with the remainder and divide that
u64 temp = s64(attohi) + mulu_32x32(remainder, ATTOSECONDS_PER_SECOND_SQRT);
u32 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);
u32 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)
snprintf(buffer, 30, "%-*s", precision, "(never)");
// case 1: we want no precision; seconds only
else if (precision == 0)
snprintf(buffer, 30, "%d", m_seconds);
// case 2: we want 9 or fewer digits of precision
else if (precision <= 9)
{
u32 upper = m_attoseconds / ATTOSECONDS_PER_SECOND_SQRT;
int temp = precision;
while (temp < 9)
{
upper /= 10;
temp++;
}
snprintf(buffer, 30, "%d.%0*d", m_seconds, precision, upper);
}
// case 3: more than 9 digits of precision
else
{
u32 lower;
u32 upper = divu_64x32_rem(m_attoseconds, ATTOSECONDS_PER_SECOND_SQRT, lower);
int temp = precision;
while (temp < 18)
{
lower /= 10;
temp++;
}
snprintf(buffer, 30, "%d.%09d%0*d", m_seconds, upper, precision - 9, lower);
}
return buffer;
}
//-------------------------------------------------
// to_string - return a human-readable string
// describing an attotime for use in logs
//-------------------------------------------------
std::string attotime::to_string() const
{
attotime t = *this;
const char *sign = "";
if(t.seconds() < 0) {
t = attotime::zero-t;
sign = "-";
}
int nsec = t.attoseconds() / ATTOSECONDS_PER_NANOSECOND;
return util::string_format("%s%04d.%03d,%03d,%03d", sign, int(t.seconds()), nsec/1000000, (nsec/1000)%1000, nsec % 1000);
}
|