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 #include <utility>
8 
9 namespace openmsx {
10 
17 {
18 public:
19  // Note: default copy constructor and assigment 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  EmuTime::param getTime() const {
39  return lastTick;
40  }
41 
45  bool before(EmuTime::param e) const {
46  return lastTick.time < e.time;
47  }
48 
52  unsigned getTicksTill(EmuTime::param e) const {
53  assert(e.time >= lastTick.time);
54  return divmod.div(e.time - lastTick.time);
55  }
64  std::pair<unsigned, float> getTicksTillAsIntFloat(EmuTime::param e) const {
65  assert(e.time >= lastTick.time);
66  auto dur = e.time - lastTick.time;
67  auto [q, r] = divmod.divMod(dur);
68  auto f = float(r) / float(getStep());
69  assert(0.0f <= f); assert(f < 1.0f);
70  return {q, f};
71  }
72 
73  template<typename FIXED>
74  void getTicksTill(EmuTime::param e, FIXED& result) const {
75  assert(e.time >= lastTick.time);
76  uint64_t tmp = (e.time - lastTick.time) << FIXED::FRACTION_BITS;
77  result = FIXED::create(divmod.div(tmp + (getStep() / 2)));
78  }
79 
84  unsigned getTicksTillUp(EmuTime::param e) const {
85  assert(e.time >= lastTick.time);
86  return divmod.div(e.time - lastTick.time + (getStep() - 1));
87  }
88 
89  double getTicksTillDouble(EmuTime::param e) const {
90  assert(e.time >= lastTick.time);
91  return double(e.time - lastTick.time) / getStep();
92  }
93 
94  uint64_t getTotalTicks() const {
95  // note: don't use divmod.div() because that one only returns a
96  // 32 bit result. Maybe improve in the future.
97  return lastTick.time / getStep();
98  }
99 
105  void setFreq(unsigned freq) {
106  unsigned newStep = (MAIN_FREQ32 + (freq / 2)) / freq;
107  setPeriod(EmuDuration(uint64_t(newStep)));
108  }
114  void setFreq(unsigned freq_num, unsigned freq_denom) {
115  static_assert(MAIN_FREQ < (1ull << 32), "must fit in 32 bit");
116  uint64_t p = MAIN_FREQ * freq_denom + (freq_num / 2);
117  uint64_t newStep = p / freq_num;
118  setPeriod(EmuDuration(newStep));
119  }
120 
124  unsigned getFreq() const {
125  auto step = getStep();
126  return (MAIN_FREQ + (step / 2)) / step;
127  }
128 
132  return EmuDuration(uint64_t(getStep()));
133  }
134 
136  void setPeriod(EmuDuration period) {
137  assert(period.length() < (1ull << 32));
138  divmod.setDivisor(uint32_t(period.length()));
139  }
140 
143  void reset(EmuTime::param e) {
144  lastTick.time = e.time;
145  }
146 
151  void advance(EmuTime::param e) {
152  assert(lastTick.time <= e.time);
153  lastTick.time = e.time - divmod.mod(e.time - lastTick.time);
154  }
155 
158  void operator+=(uint64_t n) {
159  lastTick.time += n * getStep();
160  }
161 
165  EmuTime operator+(uint64_t n) const {
166  return EmuTime(lastTick.time + n * getStep());
167  }
168 
175  void fastAdd(unsigned n) {
176  #ifdef DEBUG
177  // we don't even want this overhead in development versions
178  assert((uint64_t(n) * getStep()) < (1ull << 32));
179  #endif
180  lastTick.time += n * getStep();
181  }
182  EmuTime getFastAdd(unsigned n) const {
183  return add(lastTick, n);
184  }
185  EmuTime add(EmuTime::param time, unsigned n) const {
186  #ifdef DEBUG
187  assert((uint64_t(n) * getStep()) < (1ull << 32));
188  #endif
189  return EmuTime(time.time + n * getStep());
190  }
191 
192  template<typename Archive>
193  void serialize(Archive& ar, unsigned version);
194 
195 private:
202  unsigned getStep() const { return divmod.getDivisor(); }
203 
206  EmuTime lastTick;
207 
208  DivModBySame divmod;
209 };
211 
212 } // namespace openmsx
213 
214 #endif
openmsx::DynamicClock::advance
void advance(EmuTime::param e)
Advance this clock in time until the last tick which is not past the given time.
Definition: DynamicClock.hh:151
openmsx::DynamicClock::setFreq
void setFreq(unsigned freq)
Change the frequency at which this clock ticks.
Definition: DynamicClock.hh:105
openmsx::DynamicClock::DynamicClock
DynamicClock(EmuTime::param time, unsigned freq)
Create a new clock, which starts ticking at given time with given frequency.
Definition: DynamicClock.hh:30
openmsx::EmuDuration
Definition: EmuDuration.hh:19
openmsx::MAIN_FREQ32
constexpr unsigned MAIN_FREQ32
Definition: EmuDuration.hh:14
openmsx::DynamicClock::getFreq
unsigned getFreq() const
Returns the frequency (in Hz) at which this clock ticks.
Definition: DynamicClock.hh:124
openmsx::DivModBySame::getDivisor
uint32_t getDivisor() const
Definition: DivModBySame.hh:28
openmsx::DynamicClock::serialize
void serialize(Archive &ar, unsigned version)
Definition: DynamicClock.cc:8
openmsx::DivModBySame::mod
uint32_t mod(uint64_t dividend) const
Definition: DivModBySame.hh:70
openmsx::DynamicClock::add
EmuTime add(EmuTime::param time, unsigned n) const
Definition: DynamicClock.hh:185
openmsx::EmuDuration::length
constexpr uint64_t length() const
Definition: EmuDuration.hh:50
DivModBySame.hh
openmsx::DivModBySame::divMod
std::pair< uint32_t, uint32_t > divMod(uint64_t dividend) const
Definition: DivModBySame.hh:60
step
constexpr auto step
Definition: eeprom.cc:9
openmsx::DynamicClock::getTotalTicks
uint64_t getTotalTicks() const
Definition: DynamicClock.hh:94
openmsx::DynamicClock::before
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:45
openmsx::SERIALIZE_CLASS_VERSION
SERIALIZE_CLASS_VERSION(CassettePlayer, 2)
openmsx::DynamicClock
Represents a clock with a variable frequency.
Definition: DynamicClock.hh:17
openmsx::IDEDeviceFactory::create
std::unique_ptr< IDEDevice > create(const DeviceConfig &config)
Definition: IDEDeviceFactory.cc:11
openmsx::DynamicClock::setPeriod
void setPeriod(EmuDuration period)
Set the duration of a clock tick.
Definition: DynamicClock.hh:136
openmsx::DivModBySame::setDivisor
void setDivisor(uint32_t divisor)
Definition: DivModBySame.cc:7
openmsx::DynamicClock::getTicksTill
void getTicksTill(EmuTime::param e, FIXED &result) const
Definition: DynamicClock.hh:74
openmsx::DynamicClock::getTicksTillUp
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:84
openmsx::DivModBySame::div
uint32_t div(uint64_t dividend) const
Definition: DivModBySame.hh:30
openmsx::DynamicClock::fastAdd
void fastAdd(unsigned n)
Advance this clock by the given number of ticks.
Definition: DynamicClock.hh:175
openmsx::DynamicClock::getPeriod
EmuDuration getPeriod() const
Returns the length of one clock-cycle.
Definition: DynamicClock.hh:131
openmsx::DynamicClock::getTicksTillDouble
double getTicksTillDouble(EmuTime::param e) const
Definition: DynamicClock.hh:89
openmsx::DynamicClock::DynamicClock
DynamicClock(EmuTime::param time)
Create a new clock, which starts ticking at given time.
Definition: DynamicClock.hh:25
EmuTime.hh
openmsx::DynamicClock::setFreq
void setFreq(unsigned freq_num, unsigned freq_denom)
Equivalent to setFreq(freq_num / freq_denom), but possibly with less rounding errors.
Definition: DynamicClock.hh:114
openmsx::DynamicClock::getTime
EmuTime::param getTime() const
Gets the time at which the last clock tick occurred.
Definition: DynamicClock.hh:38
openmsx::DynamicClock::getTicksTillAsIntFloat
std::pair< unsigned, float > getTicksTillAsIntFloat(EmuTime::param e) const
Like getTicksTill(), but also returns the fractional part (in range [0, 1)).
Definition: DynamicClock.hh:64
openmsx::DynamicClock::operator+=
void operator+=(uint64_t n)
Advance this clock by the given number of ticks.
Definition: DynamicClock.hh:158
openmsx::MAIN_FREQ
constexpr uint64_t MAIN_FREQ
Definition: EmuDuration.hh:13
openmsx::DynamicClock::reset
void reset(EmuTime::param e)
Reset the clock to start ticking at the given time.
Definition: DynamicClock.hh:143
openmsx::DynamicClock::getTicksTill
unsigned getTicksTill(EmuTime::param e) const
Calculate the number of ticks for this clock until the given time.
Definition: DynamicClock.hh:52
openmsx::DynamicClock::operator+
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...
Definition: DynamicClock.hh:165
openmsx
This file implemented 3 utility functions:
Definition: Autofire.cc:5
openmsx::DynamicClock::getFastAdd
EmuTime getFastAdd(unsigned n) const
Definition: DynamicClock.hh:182