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 
103  void setFreq(unsigned freq) {
104  unsigned newStep = (MAIN_FREQ32 + (freq / 2)) / freq;
105  assert(newStep);
106  divmod.setDivisor(newStep);
107  }
111  void setFreq(unsigned freq_num, unsigned freq_denom) {
112  static_assert(MAIN_FREQ < (1ull << 32), "must fit in 32 bit");
113  uint64_t p = MAIN_FREQ * freq_denom + (freq_num / 2);
114  uint64_t newStep = p / freq_num;
115  assert(newStep < (1ull << 32));
116  assert(newStep);
117  divmod.setDivisor(unsigned(newStep));
118  }
119 
123  unsigned getFreq() const {
124  auto step = getStep();
125  return (MAIN_FREQ + (step / 2)) / step;
126  }
127 
131  return EmuDuration(uint64_t(getStep()));
132  }
133 
136  void reset(EmuTime::param e) {
137  lastTick.time = e.time;
138  }
139 
144  void advance(EmuTime::param e) {
145  assert(lastTick.time <= e.time);
146  lastTick.time = e.time - divmod.mod(e.time - lastTick.time);
147  }
148 
151  void operator+=(uint64_t n) {
152  lastTick.time += n * getStep();
153  }
154 
158  EmuTime operator+(uint64_t n) const {
159  return EmuTime(lastTick.time + n * getStep());
160  }
161 
168  void fastAdd(unsigned n) {
169  #ifdef DEBUG
170  // we don't even want this overhead in development versions
171  assert((uint64_t(n) * getStep()) < (1ull << 32));
172  #endif
173  lastTick.time += n * getStep();
174  }
175  EmuTime getFastAdd(unsigned n) const {
176  return add(lastTick, n);
177  }
178  EmuTime add(EmuTime::param time, unsigned n) const {
179  #ifdef DEBUG
180  assert((uint64_t(n) * getStep()) < (1ull << 32));
181  #endif
182  return EmuTime(time.time + n * getStep());
183  }
184 
185  template<typename Archive>
186  void serialize(Archive& ar, unsigned version);
187 
188 private:
195  unsigned getStep() const { return divmod.getDivisor(); }
196 
199  EmuTime lastTick;
200 
201  DivModBySame divmod;
202 };
203 
204 } // namespace openmsx
205 
206 #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:144
openmsx::DynamicClock::setFreq
void setFreq(unsigned freq)
Change the frequency at which this clock ticks.
Definition: DynamicClock.hh:103
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:123
openmsx::DivModBySame::getDivisor
uint32_t getDivisor() const
Definition: DivModBySame.hh:28
openmsx::DynamicClock::serialize
void serialize(Archive &ar, unsigned version)
Definition: DynamicClock.cc:7
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:178
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::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::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:168
openmsx::DynamicClock::getPeriod
EmuDuration getPeriod() const
Returns the length of one clock-cycle.
Definition: DynamicClock.hh:130
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:111
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:151
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:136
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:158
openmsx
Thanks to enen for testing this on a real cartridge:
Definition: Autofire.cc:5
openmsx::DynamicClock::getFastAdd
EmuTime getFastAdd(unsigned n) const
Definition: DynamicClock.hh:175