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  return MAIN_FREQ32 / getStep();
108  }
109 
113  return EmuDuration(uint64_t(getStep()));
114  }
115 
118  void reset(EmuTime::param e) {
119  lastTick.time = e.time;
120  }
121 
126  void advance(EmuTime::param e) {
127  assert(lastTick.time <= e.time);
128  lastTick.time = e.time - divmod.mod(e.time - lastTick.time);
129  }
130 
133  void operator+=(uint64_t n) {
134  lastTick.time += n * getStep();
135  }
136 
140  const EmuTime operator+(uint64_t n) const {
141  return EmuTime(lastTick.time + n * getStep());
142  }
143 
150  void fastAdd(unsigned n) {
151  #ifdef DEBUG
152  // we don't even want this overhead in development versions
153  assert((uint64_t(n) * getStep()) < (1ull << 32));
154  #endif
155  lastTick.time += n * getStep();
156  }
157  EmuTime getFastAdd(unsigned n) const {
158  return add(lastTick, n);
159  }
160  EmuTime add(EmuTime::param time, unsigned n) const {
161  #ifdef DEBUG
162  assert((uint64_t(n) * getStep()) < (1ull << 32));
163  #endif
164  return EmuTime(time.time + n * getStep());
165  }
166 
167  template<typename Archive>
168  void serialize(Archive& ar, unsigned version);
169 
170 private:
177  unsigned getStep() const { return divmod.getDivisor(); }
178 
181  EmuTime lastTick;
182 
183  DivModBySame divmod;
184 };
185 
186 } // namespace openmsx
187 
188 #endif
const 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...
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
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:28
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.
uint32_t mod(uint64_t dividend) const
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.
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:30
EmuTime getFastAdd(unsigned n) const
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:24
void setDivisor(uint32_t divisor)
Definition: DivModBySame.cc:17