openMSX
DynamicClock.hh
Go to the documentation of this file.
1#ifndef DYNAMICCLOCK_HH
2#define DYNAMICCLOCK_HH
3
4#include "EmuTime.hh"
5#include "DivModBySame.hh"
6#include "narrow.hh"
7#include <cassert>
8
9namespace openmsx {
10
17{
18public:
19 // Note: default copy constructor and assignment operator are ok.
20
25 explicit DynamicClock(EmuTime::param time) : lastTick(time) {}
26
30 DynamicClock(EmuTime::param time, unsigned freq)
31 : lastTick(time)
32 {
33 setFreq(freq);
34 }
35
38 [[nodiscard]] EmuTime::param getTime() const {
39 return lastTick;
40 }
41
45 [[nodiscard]] bool before(EmuTime::param e) const {
46 return lastTick.time < e.time;
47 }
48
52 [[nodiscard]] unsigned getTicksTill(EmuTime::param e) const {
53 assert(e.time >= lastTick.time);
54 return divMod.div(e.time - lastTick.time);
55 }
65 unsigned integral;
67 };
68 [[nodiscard]] IntegralFractional getTicksTillAsIntFloat(EmuTime::param e) const {
69 assert(e.time >= lastTick.time);
70 auto dur = e.time - lastTick.time;
71 auto [q, r] = divMod.divMod(dur);
72 auto f = float(r) / float(getStep());
73 assert(0.0f <= f); assert(f < 1.0f);
74 return {q, f};
75 }
76
77 template<typename FIXED>
78 void getTicksTill(EmuTime::param e, FIXED& result) const {
79 assert(e.time >= lastTick.time);
80 uint64_t tmp = (e.time - lastTick.time) << FIXED::FRACTION_BITS;
81 result = FIXED::create(divMod.div(tmp + (getStep() / 2)));
82 }
83
88 [[nodiscard]] unsigned getTicksTillUp(EmuTime::param e) const {
89 assert(e.time >= lastTick.time);
90 return divMod.div(e.time - lastTick.time + (getStep() - 1));
91 }
92
93 [[nodiscard]] double getTicksTillDouble(EmuTime::param e) const {
94 assert(e.time >= lastTick.time);
95 return double(e.time - lastTick.time) / getStep();
96 }
97
98 [[nodiscard]] uint64_t getTotalTicks() const {
99 // note: don't use divMod.div() because that one only returns a
100 // 32 bit result. Maybe improve in the future.
101 return lastTick.time / getStep();
102 }
103
109 void setFreq(unsigned freq) {
110 unsigned newStep = (MAIN_FREQ32 + (freq / 2)) / freq;
111 setPeriod(EmuDuration(uint64_t(newStep)));
112 }
118 void setFreq(unsigned freq_num, unsigned freq_denom) {
119 static_assert(MAIN_FREQ < (1ULL << 32), "must fit in 32 bit");
120 uint64_t p = MAIN_FREQ * freq_denom + (freq_num / 2);
121 uint64_t newStep = p / freq_num;
122 setPeriod(EmuDuration(newStep));
123 }
124
128 [[nodiscard]] unsigned getFreq() const {
129 auto step = getStep();
130 return narrow<unsigned>((MAIN_FREQ + (step / 2)) / step);
131 }
132
135 [[nodiscard]] EmuDuration getPeriod() const {
136 return EmuDuration(uint64_t(getStep()));
137 }
138
140 void setPeriod(EmuDuration period) {
141 assert(period.length() < (1ULL << 32));
142 divMod.setDivisor(uint32_t(period.length()));
143 }
144
147 void reset(EmuTime::param e) {
148 lastTick.time = e.time;
149 }
150
155 void advance(EmuTime::param e) {
156 assert(lastTick.time <= e.time);
157 lastTick.time = e.time - divMod.mod(e.time - lastTick.time);
158 }
159
162 void operator+=(uint64_t n) {
163 lastTick.time += n * getStep();
164 }
165
169 // TODO should be friend, workaround for pre-gcc-13 bug
170 [[nodiscard]] EmuTime operator+(uint64_t n) const {
171 return EmuTime(lastTick.time + n * getStep());
172 }
173
180 void fastAdd(unsigned n) {
181 #ifdef DEBUG
182 // we don't even want this overhead in development versions
183 assert((uint64_t(n) * getStep()) < (1ULL << 32));
184 #endif
185 lastTick.time += n * getStep();
186 }
187 [[nodiscard]] EmuTime getFastAdd(unsigned n) const {
188 return add(lastTick, n);
189 }
190 [[nodiscard]] EmuTime add(EmuTime::param time, unsigned n) const {
191 #ifdef DEBUG
192 assert((uint64_t(n) * getStep()) < (1ULL << 32));
193 #endif
194 return EmuTime(time.time + n * getStep());
195 }
196
197 template<typename Archive>
198 void serialize(Archive& ar, unsigned version);
199
200private:
207 [[nodiscard]] unsigned getStep() const { return divMod.getDivisor(); }
208
209private:
212 EmuTime lastTick;
213
214 DivModBySame divMod;
215};
217
218} // namespace openmsx
219
220#endif
uint32_t div(uint64_t dividend) const
uint32_t mod(uint64_t dividend) const
uint32_t getDivisor() const
std::pair< uint32_t, uint32_t > divMod(uint64_t dividend) const
void setDivisor(uint32_t divisor)
Represents a clock with a variable frequency.
bool before(EmuTime::param e) const
Checks whether this clock's last tick is or is not before the given time stamp.
EmuTime getFastAdd(unsigned n) const
void serialize(Archive &ar, unsigned version)
uint64_t getTotalTicks() const
unsigned getTicksTill(EmuTime::param e) const
Calculate the number of ticks for this clock until the given time.
EmuDuration getPeriod() const
Returns the length of one clock-cycle.
DynamicClock(EmuTime::param time, unsigned freq)
Create a new clock, which starts ticking at given time with given frequency.
void getTicksTill(EmuTime::param e, FIXED &result) const
void operator+=(uint64_t n)
Advance this clock by the given number of ticks.
void setFreq(unsigned freq_num, unsigned freq_denom)
Equivalent to setFreq(freq_num / freq_denom), but possibly with less rounding errors.
void setPeriod(EmuDuration period)
Set the duration of a clock tick.
double getTicksTillDouble(EmuTime::param e) const
IntegralFractional getTicksTillAsIntFloat(EmuTime::param e) const
unsigned getFreq() const
Returns the frequency (in Hz) at which this clock ticks.
DynamicClock(EmuTime::param time)
Create a new clock, which starts ticking at given time.
unsigned getTicksTillUp(EmuTime::param e) const
Calculate the number of ticks this clock has to tick to reach or go past the given time.
EmuTime add(EmuTime::param time, unsigned n) const
void reset(EmuTime::param e)
Reset the clock to start ticking at the given time.
EmuTime operator+(uint64_t n) const
Calculate the time at which this clock will have ticked the given number of times (counted from its l...
void advance(EmuTime::param e)
Advance this clock in time until the last tick which is not past the given time.
void fastAdd(unsigned n)
Advance this clock by the given number of ticks.
void setFreq(unsigned freq)
Change the frequency at which this clock ticks.
EmuTime::param getTime() const
Gets the time at which the last clock tick occurred.
constexpr uint64_t length() const
This file implemented 3 utility functions:
Definition Autofire.cc:11
constexpr unsigned MAIN_FREQ32
constexpr uint64_t MAIN_FREQ
#define SERIALIZE_CLASS_VERSION(CLASS, VERSION)
Like getTicksTill(), but also returns the fractional part (in range [0, 1)).