1 // license:BSD-3-Clause
2 // copyright-holders:Aaron Giles
3 /**************************************************************************/
4 /**
5  * @file attotime.h
6  * Support functions for working with attotime data.
7  * @defgroup ATTOTIME
8  * @{
9  * Support functions for working with attotime data.
10  *
11  * @class attotime
12  *  Attotime is an attosecond-accurate timing system implemented as
13  *  96-bit integers.
14  *
15  *     1 second      = 1e0 seconds
16  *     1 millisecond = 1e-3 seconds
17  *     1 microsecond = 1e-6 seconds
18  *     1 nanosecond  = 1e-9 seconds
19  *     1 picosecond  = 1e-12 seconds
20  *     1 femtosecond = 1e-15 seconds
21  *     1 attosecond  = 1e-18 seconds
22  *
23  * This may seem insanely accurate, but it has its uses when multiple
24  * clocks in the system are run by independent crystals. It is also
25  * useful to compute the attotime for something small, say 1 clock tick,
26  * and still have it be accurate and useful for scaling.
27  *
28  * Attotime consists of a 32-bit seconds count and a 64-bit attoseconds
29  * count. Because the lower bits are kept as attoseconds and not as a
30  * full 64-bit value, there is headroom to make some operations simpler.
31  */
32 /**************************************************************************/
33 #ifndef MAME_EMU_ATTOTIME_H
34 #define MAME_EMU_ATTOTIME_H
35 
36 #pragma once
37 
38 #include "emucore.h"
39 #include "xtal.h"
40 
41 #include <cmath>
42 #undef min
43 #undef max
44 
45 //**************************************************************************
46 //  CONSTANTS
47 //**************************************************************************
48 
49 // core components of the attotime structure
50 typedef s64 attoseconds_t;
51 typedef s32 seconds_t;
52 
53 // core definitions
54 constexpr attoseconds_t ATTOSECONDS_PER_SECOND_SQRT = 1'000'000'000;
55 constexpr attoseconds_t ATTOSECONDS_PER_SECOND = ATTOSECONDS_PER_SECOND_SQRT * ATTOSECONDS_PER_SECOND_SQRT;
56 constexpr attoseconds_t ATTOSECONDS_PER_MILLISECOND = ATTOSECONDS_PER_SECOND / 1'000;
57 constexpr attoseconds_t ATTOSECONDS_PER_MICROSECOND = ATTOSECONDS_PER_SECOND / 1'000'000;
58 constexpr attoseconds_t ATTOSECONDS_PER_NANOSECOND = ATTOSECONDS_PER_SECOND / 1'000'000'000;
59 
60 constexpr seconds_t ATTOTIME_MAX_SECONDS = 1'000'000'000;
61 
62 
63 
64 //**************************************************************************
65 //  MACROS
66 //**************************************************************************
67 
68 // convert between a double and attoseconds
ATTOSECONDS_TO_DOUBLE(attoseconds_t x)69 inline constexpr double ATTOSECONDS_TO_DOUBLE(attoseconds_t x) { return double(x) * 1e-18; }
DOUBLE_TO_ATTOSECONDS(double x)70 inline constexpr attoseconds_t DOUBLE_TO_ATTOSECONDS(double x) { return attoseconds_t(x * 1e18); }
71 
72 // convert between hertz (as a double) and attoseconds
ATTOSECONDS_TO_HZ(attoseconds_t x)73 inline constexpr double ATTOSECONDS_TO_HZ(attoseconds_t x) { return double(ATTOSECONDS_PER_SECOND) / double(x); }
HZ_TO_ATTOSECONDS(T && x)74 template <typename T> inline constexpr attoseconds_t HZ_TO_ATTOSECONDS(T &&x) { return attoseconds_t(ATTOSECONDS_PER_SECOND / x); }
HZ_TO_ATTOSECONDS(const XTAL & x)75 inline constexpr attoseconds_t HZ_TO_ATTOSECONDS(const XTAL &x) { return attoseconds_t(ATTOSECONDS_PER_SECOND / x); }
76 
77 // macros for converting other seconds types to attoseconds
ATTOSECONDS_IN_SEC(T && x)78 template <typename T> inline constexpr attoseconds_t ATTOSECONDS_IN_SEC(T &&x) { return attoseconds_t(x) * ATTOSECONDS_PER_SECOND; }
ATTOSECONDS_IN_MSEC(T && x)79 template <typename T> inline constexpr attoseconds_t ATTOSECONDS_IN_MSEC(T &&x) { return attoseconds_t(x) * ATTOSECONDS_PER_MILLISECOND; }
ATTOSECONDS_IN_USEC(T && x)80 template <typename T> inline constexpr attoseconds_t ATTOSECONDS_IN_USEC(T &&x) { return attoseconds_t(x) * ATTOSECONDS_PER_MICROSECOND; }
ATTOSECONDS_IN_NSEC(T && x)81 template <typename T> inline constexpr attoseconds_t ATTOSECONDS_IN_NSEC(T &&x) { return attoseconds_t(x) * ATTOSECONDS_PER_NANOSECOND; }
82 
83 
84 
85 //**************************************************************************
86 //  TYPE DEFINITIONS
87 //***************************************************************************/
88 
89 // the attotime structure itself
90 class attotime
91 {
92 public:
93 	// construction/destruction
attotime()94 	constexpr attotime() noexcept : m_seconds(0), m_attoseconds(0) { }
95 
96 	/** Constructs with @p secs seconds and @p attos attoseconds. */
attotime(seconds_t secs,attoseconds_t attos)97 	constexpr attotime(seconds_t secs, attoseconds_t attos) noexcept : m_seconds(secs), m_attoseconds(attos) { }
98 
attotime(const attotime & that)99 	constexpr attotime(const attotime& that) noexcept : m_seconds(that.m_seconds), m_attoseconds(that.m_attoseconds) { }
100 
101 	// assignment
102 	attotime &operator=(const attotime& that) noexcept
103 	{
104 		this->m_seconds = that.m_seconds;
105 		this->m_attoseconds = that.m_attoseconds;
106 		return *this;
107 	}
108 
109 	// queries
is_zero()110 	constexpr bool is_zero() const noexcept { return (m_seconds == 0 && m_attoseconds == 0); }
111 	/** Test if value is above @ref ATTOTIME_MAX_SECONDS (considered an overflow) */
is_never()112 	constexpr bool is_never() const noexcept { return (m_seconds >= ATTOTIME_MAX_SECONDS); }
113 
114 	// conversion to other forms
as_double()115 	constexpr double as_double() const noexcept { return double(m_seconds) + ATTOSECONDS_TO_DOUBLE(m_attoseconds); }
116 	constexpr attoseconds_t as_attoseconds() const noexcept;
as_hz()117 	double as_hz() const noexcept { assert(!is_zero()); return m_seconds == 0 ? ATTOSECONDS_TO_HZ(m_attoseconds) : is_never() ? 0.0 : 1.0 / as_double(); }
as_khz()118 	double as_khz() const noexcept { assert(!is_zero()); return m_seconds == 0 ? double(ATTOSECONDS_PER_MILLISECOND) / double(m_attoseconds) : is_never() ? 0.0 : 1e-3 / as_double(); }
as_mhz()119 	double as_mhz() const noexcept { assert(!is_zero()); return m_seconds == 0 ? double(ATTOSECONDS_PER_MICROSECOND) / double(m_attoseconds) : is_never() ? 0.0 : 1e-6 / as_double(); }
120 	u64 as_ticks(u32 frequency) const;
as_ticks(const XTAL & xtal)121 	u64 as_ticks(const XTAL &xtal) const { return as_ticks(xtal.value()); }
122 	/** Convert to string using at @p precision */
123 	const char *as_string(int precision = 9) const;
124 
125 	/** Convert to string for human readability in logs */
126 	std::string to_string() const;
127 
128 	/** @return the attoseconds portion. */
attoseconds()129 	constexpr attoseconds_t attoseconds() const noexcept { return m_attoseconds; }
130 	/** @return the seconds portion. */
seconds()131 	constexpr seconds_t seconds() const noexcept { return m_seconds; }
132 
133 	static attotime from_double(double _time);
134 	static attotime from_ticks(u64 ticks, u32 frequency);
from_ticks(u64 ticks,const XTAL & xtal)135 	static attotime from_ticks(u64 ticks, const XTAL &xtal) { return from_ticks(ticks, xtal.value()); }
136 	/** Create an attotime from a integer count of seconds @seconds */
from_seconds(s32 seconds)137 	static constexpr attotime from_seconds(s32 seconds) { return attotime(seconds, 0); }
138 	/** Create an attotime from a integer count of milliseconds @msec */
from_msec(s64 msec)139 	static constexpr attotime from_msec(s64 msec) { return attotime(msec / 1000, (msec % 1000) * (ATTOSECONDS_PER_SECOND / 1000)); }
140 	/** Create an attotime from a integer count of microseconds @usec */
from_usec(s64 usec)141 	static constexpr attotime from_usec(s64 usec) { return attotime(usec / 1000000, (usec % 1000000) * (ATTOSECONDS_PER_SECOND / 1000000)); }
142 	/** Create an attotime from a integer count of nanoseconds @nsec */
from_nsec(s64 nsec)143 	static constexpr attotime from_nsec(s64 nsec) { return attotime(nsec / 1000000000, (nsec % 1000000000) * (ATTOSECONDS_PER_SECOND / 1000000000)); }
144 	/** Create an attotime from at the given frequency @frequency */
from_hz(u32 frequency)145 	static attotime from_hz(u32 frequency) { return (frequency > 1) ? attotime(0, HZ_TO_ATTOSECONDS(frequency)) : (frequency == 1) ? attotime(1, 0) : attotime::never; }
from_hz(int frequency)146 	static attotime from_hz(int frequency) { return (frequency > 0) ? from_hz(u32(frequency)) : attotime::never; }
from_hz(const XTAL & xtal)147 	static attotime from_hz(const XTAL &xtal) { return (xtal.dvalue() > 1.0) ? attotime(0, HZ_TO_ATTOSECONDS(xtal)) : from_hz(xtal.dvalue()); }
from_hz(double frequency)148 	static attotime from_hz(double frequency)
149 	{
150 		if (frequency > 1.0)
151 			return attotime(0, HZ_TO_ATTOSECONDS(frequency));
152 		else if (frequency > 0.0)
153 		{
154 			double i, f = modf(1.0 / frequency, &i);
155 			return attotime(i, f * ATTOSECONDS_PER_SECOND);
156 		}
157 		else
158 			return attotime::never;
159 	}
160 
161 	// math
162 	attotime &operator+=(const attotime &right) noexcept;
163 	attotime &operator-=(const attotime &right) noexcept;
164 	attotime &operator*=(u32 factor);
165 	attotime &operator/=(u32 factor);
166 
167 	// members
168 	seconds_t       m_seconds;
169 	attoseconds_t   m_attoseconds;
170 
171 	// constants
172 	static const attotime never;
173 	static const attotime zero;
174 };
175 /** @} */
176 
177 
178 //**************************************************************************
179 //  INLINE FUNCTIONS
180 //**************************************************************************
181 
182 /** handle addition between two attotimes */
183 inline attotime operator+(const attotime &left, const attotime &right) noexcept
184 {
185 	attotime result;
186 
187 	// if one of the items is never, return never
188 	if (left.m_seconds >= ATTOTIME_MAX_SECONDS || right.m_seconds >= ATTOTIME_MAX_SECONDS)
189 		return attotime::never;
190 
191 	// add the seconds and attoseconds
192 	result.m_attoseconds = left.m_attoseconds + right.m_attoseconds;
193 	result.m_seconds = left.m_seconds + right.m_seconds;
194 
195 	// normalize and return
196 	if (result.m_attoseconds >= ATTOSECONDS_PER_SECOND)
197 	{
198 		result.m_attoseconds -= ATTOSECONDS_PER_SECOND;
199 		result.m_seconds++;
200 	}
201 
202 	// overflow
203 	if (result.m_seconds >= ATTOTIME_MAX_SECONDS)
204 		return attotime::never;
205 	return result;
206 }
207 
208 inline attotime &attotime::operator+=(const attotime &right) noexcept
209 {
210 	// if one of the items is never, return never
211 	if (this->m_seconds >= ATTOTIME_MAX_SECONDS || right.m_seconds >= ATTOTIME_MAX_SECONDS)
212 		return *this = never;
213 
214 	// add the seconds and attoseconds
215 	m_attoseconds += right.m_attoseconds;
216 	m_seconds += right.m_seconds;
217 
218 	// normalize and return
219 	if (this->m_attoseconds >= ATTOSECONDS_PER_SECOND)
220 	{
221 		this->m_attoseconds -= ATTOSECONDS_PER_SECOND;
222 		this->m_seconds++;
223 	}
224 
225 	// overflow
226 	if (this->m_seconds >= ATTOTIME_MAX_SECONDS)
227 		return *this = never;
228 	return *this;
229 }
230 
231 
232 /** handle subtraction between two attotimes */
233 inline attotime operator-(const attotime &left, const attotime &right) noexcept
234 {
235 	attotime result;
236 
237 	// if time1 is never, return never
238 	if (left.m_seconds >= ATTOTIME_MAX_SECONDS)
239 		return attotime::never;
240 
241 	// add the seconds and attoseconds
242 	result.m_attoseconds = left.m_attoseconds - right.m_attoseconds;
243 	result.m_seconds = left.m_seconds - right.m_seconds;
244 
245 	// normalize and return
246 	if (result.m_attoseconds < 0)
247 	{
248 		result.m_attoseconds += ATTOSECONDS_PER_SECOND;
249 		result.m_seconds--;
250 	}
251 	return result;
252 }
253 
254 inline attotime &attotime::operator-=(const attotime &right) noexcept
255 {
256 	// if time1 is never, return never
257 	if (this->m_seconds >= ATTOTIME_MAX_SECONDS)
258 		return *this = never;
259 
260 	// add the seconds and attoseconds
261 	m_attoseconds -= right.m_attoseconds;
262 	m_seconds -= right.m_seconds;
263 
264 	// normalize and return
265 	if (this->m_attoseconds < 0)
266 	{
267 		this->m_attoseconds += ATTOSECONDS_PER_SECOND;
268 		this->m_seconds--;
269 	}
270 	return *this;
271 }
272 
273 
274 /** handle multiplication by an integral factor; defined in terms of the assignment operators */
275 inline attotime operator*(const attotime &left, u32 factor)
276 {
277 	attotime result = left;
278 	result *= factor;
279 	return result;
280 }
281 
282 inline attotime operator*(u32 factor, const attotime &right)
283 {
284 	attotime result = right;
285 	result *= factor;
286 	return result;
287 }
288 
289 /** handle division by an integral factor; defined in terms of the assignment operators */
290 inline attotime operator/(const attotime &left, u32 factor)
291 {
292 	attotime result = left;
293 	result /= factor;
294 	return result;
295 }
296 
297 
298 /** handle comparisons between attotimes */
299 inline constexpr bool operator==(const attotime &left, const attotime &right) noexcept
300 {
301 	return (left.m_seconds == right.m_seconds && left.m_attoseconds == right.m_attoseconds);
302 }
303 
304 inline constexpr bool operator!=(const attotime &left, const attotime &right) noexcept
305 {
306 	return (left.m_seconds != right.m_seconds || left.m_attoseconds != right.m_attoseconds);
307 }
308 
309 inline constexpr bool operator<(const attotime &left, const attotime &right) noexcept
310 {
311 	return (left.m_seconds < right.m_seconds || (left.m_seconds == right.m_seconds && left.m_attoseconds < right.m_attoseconds));
312 }
313 
314 inline constexpr bool operator<=(const attotime &left, const attotime &right) noexcept
315 {
316 	return (left.m_seconds < right.m_seconds || (left.m_seconds == right.m_seconds && left.m_attoseconds <= right.m_attoseconds));
317 }
318 
319 inline constexpr bool operator>(const attotime &left, const attotime &right) noexcept
320 {
321 	return (left.m_seconds > right.m_seconds || (left.m_seconds == right.m_seconds && left.m_attoseconds > right.m_attoseconds));
322 }
323 
324 inline constexpr bool operator>=(const attotime &left, const attotime &right) noexcept
325 {
326 	return (left.m_seconds > right.m_seconds || (left.m_seconds == right.m_seconds && left.m_attoseconds >= right.m_attoseconds));
327 }
328 
329 
330 /** Convert to an attoseconds value, clamping to +/- 1 second */
as_attoseconds()331 inline constexpr attoseconds_t attotime::as_attoseconds() const noexcept
332 {
333 	return
334 			(m_seconds == 0) ? m_attoseconds :                              // positive values between 0 and 1 second
335 			(m_seconds == -1) ? (m_attoseconds - ATTOSECONDS_PER_SECOND) :  // negative values between -1 and 0 seconds
336 			(m_seconds > 0) ? ATTOSECONDS_PER_SECOND :                      // out-of-range positive values
337 			-ATTOSECONDS_PER_SECOND;                                        // out-of-range negative values
338 }
339 
340 
341 /** as_ticks - convert to ticks at @p frequency */
as_ticks(u32 frequency)342 inline u64 attotime::as_ticks(u32 frequency) const
343 {
344 	u32 fracticks = (attotime(0, m_attoseconds) * frequency).m_seconds;
345 	return mulu_32x32(m_seconds, frequency) + fracticks;
346 }
347 
348 
349 /** Create an attotime from a tick count @ticks at the given frequency @frequency  */
from_ticks(u64 ticks,u32 frequency)350 inline attotime attotime::from_ticks(u64 ticks, u32 frequency)
351 {
352 	if (frequency > 0)
353 	{
354 		attoseconds_t attos_per_tick = HZ_TO_ATTOSECONDS(frequency);
355 
356 		if (ticks < frequency)
357 			return attotime(0, ticks * attos_per_tick);
358 
359 		u32 remainder;
360 		s32 secs = divu_64x32_rem(ticks, frequency, &remainder);
361 		return attotime(secs, u64(remainder) * attos_per_tick);
362 	}
363 	else
364 		return attotime::never;
365 }
366 
367 /** Create an attotime from floating point count of seconds @p _time */
from_double(double _time)368 inline attotime attotime::from_double(double _time)
369 {
370 	seconds_t secs = floor(_time);
371 	_time -= double(secs);
372 	attoseconds_t attos = DOUBLE_TO_ATTOSECONDS(_time);
373 	return attotime(secs, attos);
374 }
375 
376 
377 #endif // MAME_EMU_ATTOTIME_H
378