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 <cassert>
7 
8 namespace openmsx {
9 
16 {
17 public:
18  // Note: default copy constructor and assignment operator are ok.
19 
24  explicit DynamicClock(EmuTime::param time) : lastTick(time) {}
25 
29  DynamicClock(EmuTime::param time, unsigned freq)
30  : lastTick(time)
31  {
32  setFreq(freq);
33  }
34 
37  [[nodiscard]] EmuTime::param getTime() const {
38  return lastTick;
39  }
40 
44  [[nodiscard]] bool before(EmuTime::param e) const {
45  return lastTick.time < e.time;
46  }
47 
51  [[nodiscard]] unsigned getTicksTill(EmuTime::param e) const {
52  assert(e.time >= lastTick.time);
53  return divmod.div(e.time - lastTick.time);
54  }
64  unsigned integral;
65  float fractional;
66  };
67  [[nodiscard]] IntegralFractional getTicksTillAsIntFloat(EmuTime::param e) const {
68  assert(e.time >= lastTick.time);
69  auto dur = e.time - lastTick.time;
70  auto [q, r] = divmod.divMod(dur);
71  auto f = float(r) / float(getStep());
72  assert(0.0f <= f); assert(f < 1.0f);
73  return {q, f};
74  }
75 
76  template<typename FIXED>
77  void getTicksTill(EmuTime::param e, FIXED& result) const {
78  assert(e.time >= lastTick.time);
79  uint64_t tmp = (e.time - lastTick.time) << FIXED::FRACTION_BITS;
80  result = FIXED::create(divmod.div(tmp + (getStep() / 2)));
81  }
82 
87  [[nodiscard]] unsigned getTicksTillUp(EmuTime::param e) const {
88  assert(e.time >= lastTick.time);
89  return divmod.div(e.time - lastTick.time + (getStep() - 1));
90  }
91 
92  [[nodiscard]] double getTicksTillDouble(EmuTime::param e) const {
93  assert(e.time >= lastTick.time);
94  return double(e.time - lastTick.time) / getStep();
95  }
96 
97  [[nodiscard]] uint64_t getTotalTicks() const {
98  // note: don't use divmod.div() because that one only returns a
99  // 32 bit result. Maybe improve in the future.
100  return lastTick.time / getStep();
101  }
102 
108  void setFreq(unsigned freq) {
109  unsigned newStep = (MAIN_FREQ32 + (freq / 2)) / freq;
110  setPeriod(EmuDuration(uint64_t(newStep)));
111  }
117  void setFreq(unsigned freq_num, unsigned freq_denom) {
118  static_assert(MAIN_FREQ < (1ull << 32), "must fit in 32 bit");
119  uint64_t p = MAIN_FREQ * freq_denom + (freq_num / 2);
120  uint64_t newStep = p / freq_num;
121  setPeriod(EmuDuration(newStep));
122  }
123 
127  [[nodiscard]] unsigned getFreq() const {
128  auto step = getStep();
129  return (MAIN_FREQ + (step / 2)) / step;
130  }
131 
134  [[nodiscard]] EmuDuration getPeriod() const {
135  return EmuDuration(uint64_t(getStep()));
136  }
137 
139  void setPeriod(EmuDuration period) {
140  assert(period.length() < (1ull << 32));
141  divmod.setDivisor(uint32_t(period.length()));
142  }
143 
146  void reset(EmuTime::param e) {
147  lastTick.time = e.time;
148  }
149 
154  void advance(EmuTime::param e) {
155  assert(lastTick.time <= e.time);
156  lastTick.time = e.time - divmod.mod(e.time - lastTick.time);
157  }
158 
161  void operator+=(uint64_t n) {
162  lastTick.time += n * getStep();
163  }
164 
168  [[nodiscard]] EmuTime operator+(uint64_t n) const {
169  return EmuTime(lastTick.time + n * getStep());
170  }
171 
178  void fastAdd(unsigned n) {
179  #ifdef DEBUG
180  // we don't even want this overhead in development versions
181  assert((uint64_t(n) * getStep()) < (1ull << 32));
182  #endif
183  lastTick.time += n * getStep();
184  }
185  [[nodiscard]] EmuTime getFastAdd(unsigned n) const {
186  return add(lastTick, n);
187  }
188  [[nodiscard]] EmuTime add(EmuTime::param time, unsigned n) const {
189  #ifdef DEBUG
190  assert((uint64_t(n) * getStep()) < (1ull << 32));
191  #endif
192  return EmuTime(time.time + n * getStep());
193  }
194 
195  template<typename Archive>
196  void serialize(Archive& ar, unsigned version);
197 
198 private:
205  [[nodiscard]] unsigned getStep() const { return divmod.getDivisor(); }
206 
207 private:
210  EmuTime lastTick;
211 
212  DivModBySame divmod;
213 };
215 
216 } // namespace openmsx
217 
218 #endif
uint32_t div(uint64_t dividend) const
Definition: DivModBySame.hh:30
uint32_t mod(uint64_t dividend) const
Definition: DivModBySame.hh:70
std::pair< uint32_t, uint32_t > divMod(uint64_t dividend) const
Definition: DivModBySame.hh:60
uint32_t getDivisor() const
Definition: DivModBySame.hh:28
void setDivisor(uint32_t divisor)
Definition: DivModBySame.cc:7
Represents a clock with a variable frequency.
Definition: DynamicClock.hh:16
bool before(EmuTime::param e) const
Checks whether this clock's last tick is or is not before the given time stamp.
Definition: DynamicClock.hh:44
EmuTime getFastAdd(unsigned n) const
void serialize(Archive &ar, unsigned version)
Definition: DynamicClock.cc:8
uint64_t getTotalTicks() const
Definition: DynamicClock.hh:97
unsigned getTicksTill(EmuTime::param e) const
Calculate the number of ticks for this clock until the given time.
Definition: DynamicClock.hh:51
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.
Definition: DynamicClock.hh:29
void getTicksTill(EmuTime::param e, FIXED &result) const
Definition: DynamicClock.hh:77
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
Definition: DynamicClock.hh:92
IntegralFractional getTicksTillAsIntFloat(EmuTime::param e) const
Definition: DynamicClock.hh:67
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.
Definition: DynamicClock.hh:24
unsigned getTicksTillUp(EmuTime::param e) const
Calculate the number of ticks this clock has to tick to reach or go past the given time.
Definition: DynamicClock.hh:87
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.
Definition: DynamicClock.hh:37
constexpr uint64_t length() const
Definition: EmuDuration.hh:50
constexpr auto step
Definition: eeprom.cc:9
std::unique_ptr< IDEDevice > create(const DeviceConfig &config)
This file implemented 3 utility functions:
Definition: Autofire.cc:9
constexpr unsigned MAIN_FREQ32
Definition: EmuDuration.hh:14
SERIALIZE_CLASS_VERSION(CassettePlayer, 2)
constexpr uint64_t MAIN_FREQ
Definition: EmuDuration.hh:13
Like getTicksTill(), but also returns the fractional part (in range [0, 1)).
Definition: DynamicClock.hh:63