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 assigment 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  EmuTime::param getTime() const {
38  return lastTick;
39  }
40 
44  bool before(EmuTime::param e) const {
45  return lastTick.time < e.time;
46  }
47 
51  unsigned getTicksTill(EmuTime::param e) const {
52  assert(e.time >= lastTick.time);
53  return divmod.div(e.time - lastTick.time);
54  }
55 
56  template<typename FIXED>
57  void getTicksTill(EmuTime::param e, FIXED& result) const {
58  assert(e.time >= lastTick.time);
59  uint64_t tmp = (e.time - lastTick.time) << FIXED::FRACTION_BITS;
60  result = FIXED::create(divmod.div(tmp + (getStep() / 2)));
61  }
62 
67  unsigned getTicksTillUp(EmuTime::param e) const {
68  assert(e.time >= lastTick.time);
69  return divmod.div(e.time - lastTick.time + (getStep() - 1));
70  }
71 
72  double getTicksTillDouble(EmuTime::param e) const {
73  assert(e.time >= lastTick.time);
74  return double(e.time - lastTick.time) / getStep();
75  }
76 
77  uint64_t getTotalTicks() const {
78  // note: don't use divmod.div() because that one only returns a
79  // 32 bit result. Maybe improve in the future.
80  return lastTick.time / getStep();
81  }
82 
86  void setFreq(unsigned freq) {
87  unsigned newStep = (MAIN_FREQ32 + (freq / 2)) / freq;
88  assert(newStep);
89  divmod.setDivisor(newStep);
90  }
94  void setFreq(unsigned freq_num, unsigned freq_denom) {
95  static_assert(MAIN_FREQ < (1ull << 32), "must fit in 32 bit");
96  uint64_t p = MAIN_FREQ * freq_denom + (freq_num / 2);
97  uint64_t newStep = p / freq_num;
98  assert(newStep < (1ull << 32));
99  assert(newStep);
100  divmod.setDivisor(unsigned(newStep));
101  }
102 
106  unsigned getFreq() const {
107  auto step = getStep();
108  return (MAIN_FREQ + (step / 2)) / step;
109  }
110 
114  return EmuDuration(uint64_t(getStep()));
115  }
116 
119  void reset(EmuTime::param e) {
120  lastTick.time = e.time;
121  }
122 
127  void advance(EmuTime::param e) {
128  assert(lastTick.time <= e.time);
129  lastTick.time = e.time - divmod.mod(e.time - lastTick.time);
130  }
131 
134  void operator+=(uint64_t n) {
135  lastTick.time += n * getStep();
136  }
137 
141  EmuTime operator+(uint64_t n) const {
142  return EmuTime(lastTick.time + n * getStep());
143  }
144 
151  void fastAdd(unsigned n) {
152  #ifdef DEBUG
153  // we don't even want this overhead in development versions
154  assert((uint64_t(n) * getStep()) < (1ull << 32));
155  #endif
156  lastTick.time += n * getStep();
157  }
158  EmuTime getFastAdd(unsigned n) const {
159  return add(lastTick, n);
160  }
161  EmuTime add(EmuTime::param time, unsigned n) const {
162  #ifdef DEBUG
163  assert((uint64_t(n) * getStep()) < (1ull << 32));
164  #endif
165  return EmuTime(time.time + n * getStep());
166  }
167 
168  template<typename Archive>
169  void serialize(Archive& ar, unsigned version);
170 
171 private:
178  unsigned getStep() const { return divmod.getDivisor(); }
179 
182  EmuTime lastTick;
183 
184  DivModBySame divmod;
185 };
186 
187 } // namespace openmsx
188 
189 #endif
double getTicksTillDouble(EmuTime::param e) const
Definition: DynamicClock.hh:72
uint64_t getTotalTicks() const
Definition: DynamicClock.hh:77
DynamicClock(EmuTime::param time, unsigned freq)
Create a new clock, which starts ticking at given time with given frequency.
Definition: DynamicClock.hh:29
constexpr unsigned MAIN_FREQ32
Definition: EmuDuration.hh:14
DynamicClock(EmuTime::param time)
Create a new clock, which starts ticking at given time.
Definition: DynamicClock.hh:24
void setFreq(unsigned freq_num, unsigned freq_denom)
Equivalent to setFreq(freq_num / freq_denom), but possibly with less rounding errors.
Definition: DynamicClock.hh:94
uint32_t getDivisor() const
Definition: DivModBySame.hh:27
EmuDuration getPeriod() const
Returns the length of one clock-cycle.
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:67
EmuTime::param getTime() const
Gets the time at which the last clock tick occurred.
Definition: DynamicClock.hh:37
void operator+=(uint64_t n)
Advance this clock by the given number of ticks.
constexpr auto step
Definition: eeprom.cc:9
uint32_t mod(uint64_t dividend) const
Definition: DivModBySame.hh:59
void serialize(Archive &ar, unsigned version)
Definition: DynamicClock.cc:7
void advance(EmuTime::param e)
Advance this clock in time until the last tick which is not past 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...
Represents a clock with a variable frequency.
Definition: DynamicClock.hh:15
unsigned getFreq() const
Returns the frequency (in Hz) at which this clock ticks.
void setFreq(unsigned freq)
Change the frequency at which this clock ticks.
Definition: DynamicClock.hh:86
Thanks to enen for testing this on a real cartridge:
Definition: Autofire.cc:5
void getTicksTill(EmuTime::param e, FIXED &result) const
Definition: DynamicClock.hh:57
uint32_t div(uint64_t dividend) const
Definition: DivModBySame.hh:29
EmuTime getFastAdd(unsigned n) const
constexpr uint64_t MAIN_FREQ
Definition: EmuDuration.hh:13
EmuTime add(EmuTime::param time, unsigned n) const
std::unique_ptr< IDEDevice > create(const DeviceConfig &config)
bool before(EmuTime::param e) const
Checks whether this clock&#39;s last tick is or is not before the given time stamp.
Definition: DynamicClock.hh:44
void fastAdd(unsigned n)
Advance this clock by the given number of ticks.
void reset(EmuTime::param e)
Reset the clock to start ticking at the given time.
unsigned getTicksTill(EmuTime::param e) const
Calculate the number of ticks for this clock until the given time.
Definition: DynamicClock.hh:51
Helper class to divide multiple times by the same number.
Definition: DivModBySame.hh:23
void setDivisor(uint32_t divisor)
Definition: DivModBySame.cc:7