OXYGENHUB
◆ main openmsx / src / Clock.hh
4.2 KiB · C++ · last changed chore(): initial commit 1 month ago source blame history raw
1
#ifndef CLOCK_HH
2
#define CLOCK_HH
3
4
#include "EmuDuration.hh"
5
#include "EmuTime.hh"
6
#include "serialize.hh"
7
8
#include <cassert>
9
10
namespace openmsx {
11
12
/** Represents a clock with a fixed frequency.
13
  * The frequency is in Hertz, so every tick is 1/frequency second.
14
  * A clock has a current time, which can be increased by
15
  * an integer number of ticks.
16
  */
17
template<unsigned FREQ_NUM, unsigned FREQ_DENOM = 1>
18
class Clock
19
{
20
private:
21
	// stuff below calculates:
22
	//   MASTER_TICKS = MAIN_FREQ / (FREQ_NUM / FREQ_DENOM) + 0.5
23
	static_assert(MAIN_FREQ < (1ULL << 32), "must fit in 32 bit");
24
	static constexpr uint64_t P = MAIN_FREQ * FREQ_DENOM + (FREQ_NUM / 2);
25
	static constexpr uint64_t MASTER_TICKS = P / FREQ_NUM;
26
	static_assert(MASTER_TICKS < (1ULL << 32), "must fit in 32 bit");
27
	static constexpr unsigned MASTER_TICKS32 = MASTER_TICKS;
28
29
public:
30
	// Note: default copy constructor and assignment operator are ok.
31
32
	/** Calculates the duration of the given number of ticks at this
33
	  * clock's frequency.
34
	  */
35
	[[nodiscard]] static constexpr EmuDuration duration(unsigned ticks) {
36
		return EmuDuration(ticks * MASTER_TICKS);
37
	}
38
39
	/** Create a new clock, which starts ticking at the given time.
40
	  */
41
	constexpr explicit Clock(EmuTime e)
42
		: lastTick(e) { }
43
44
	/** Gets the time at which the last clock tick occurred.
45
	  */
46
	[[nodiscard]] constexpr EmuTime getTime() const { return lastTick; }
47
48
	/** Checks whether this clock's last tick is or is not before the
49
	  * given time stamp.
50
	  */
51
	[[nodiscard]] constexpr bool before(EmuTime e) const {
52
		return lastTick.time < e.time;
53
	}
54
55
	/** Calculate the number of ticks for this clock until the given time.
56
	  * It is not allowed to call this method for a time in the past.
57
	  */
58
	[[nodiscard]] constexpr uint64_t getTicksTill(EmuTime e) const {
59
		assert(e.time >= lastTick.time);
60
		return (e.time - lastTick.time) / MASTER_TICKS;
61
	}
62
	/** Calculate the number of ticks this clock has to tick to reach
63
	  * or go past the given time.
64
	  * It is not allowed to call this method for a time in the past.
65
	  */
66
	[[nodiscard]] constexpr uint64_t getTicksTillUp(EmuTime e) const {
67
		assert(e.time >= lastTick.time);
68
		return (e.time - lastTick.time + MASTER_TICKS - 1) / MASTER_TICKS;
69
	}
70
71
	/** Calculate the time at which this clock will have ticked the given
72
	  * number of times (counted from its last tick).
73
	  */
74
	[[nodiscard]] constexpr friend EmuTime operator+(const Clock& c, uint64_t n) {
75
		return EmuTime::fromUint64(c.lastTick.toUint64() + n * MASTER_TICKS);
76
	}
77
78
	/** Like operator+() but faster, though the step can't be too big (max
79
	  * a little over 1 second). */
80
	[[nodiscard]] constexpr EmuTime getFastAdd(unsigned n) const {
81
		#ifdef DEBUG
82
		assert((uint64_t(n) * MASTER_TICKS) < (1ULL << 32));
83
		#endif
84
		return EmuTime(lastTick.time + n * MASTER_TICKS);
85
	}
86
87
	/** Reset the clock to start ticking at the given time.
88
	  */
89
	constexpr void reset(EmuTime e) {
90
		lastTick.time = e.time;
91
	}
92
93
	/** Advance this clock in time until the last tick which is not past
94
	  * the given time.
95
	  * It is not allowed to advance a clock to a time in the past.
96
	  */
97
	constexpr void advance(EmuTime e) {
98
		assert(lastTick.time <= e.time);
99
		lastTick.time = e.time - ((e.time - lastTick.time) % MASTER_TICKS);
100
	}
101
102
	/** Advance this clock by the given number of ticks.
103
	  */
104
	constexpr void operator+=(unsigned n) {
105
		lastTick.time += n * MASTER_TICKS;
106
	}
107
108
	/** Advance this clock by the given number of ticks.
109
	  * This method is similar to operator+=, but it's optimized for
110
	  * speed. OTOH the amount of ticks should not be too large,
111
	  * otherwise an overflow occurs. Use operator+() when the duration
112
	  * of the ticks approaches 1 second.
113
	  */
114
	constexpr void fastAdd(unsigned n) {
115
		#ifdef DEBUG
116
		// we don't even want this overhead in development versions
117
		assert((n * MASTER_TICKS) < (1ULL << 32));
118
		#endif
119
		lastTick.time += n * MASTER_TICKS32;
120
	}
121
122
	template<typename Archive>
123
	void serialize(Archive& ar, unsigned /*version*/)
124
	{
125
		ar.serialize("lastTick", lastTick);
126
	}
127
128
private:
129
	/** Time of this clock's last tick.
130
	  */
131
	EmuTime lastTick;
132
};
133
134
template<unsigned FREQ_NUM, unsigned FREQ_DENOM>
135
struct SerializeAsMemcpy<Clock<FREQ_NUM, FREQ_DENOM>> : std::true_type {};
136
137
} // namespace openmsx
138
139
#endif