openMSX
Clock.hh
Go to the documentation of this file.
1 #ifndef CLOCK_HH
2 #define CLOCK_HH
3 
4 #include "EmuDuration.hh"
5 #include "EmuTime.hh"
6 #include "DivModByConst.hh"
7 #include "serialize.hh"
8 #include <cassert>
9 
10 namespace openmsx {
11 
17 template <unsigned FREQ_NUM, unsigned FREQ_DENOM = 1>
18 class Clock
19 {
20 private:
21  // stuff below calculates:
22  // MASTER_TICKS = MAIN_FREQ / (FREQ_NUM / FREQ_DENOM) + 0.5
23  static_assert(MAIN_FREQ < (1ull << 32), "must fit in 32 bit");
24  static constexpr uint64_t P = MAIN_FREQ * FREQ_DENOM + (FREQ_NUM / 2);
25  static constexpr uint64_t MASTER_TICKS = P / FREQ_NUM;
26  static_assert(MASTER_TICKS < (1ull << 32), "must fit in 32 bit");
27  static constexpr unsigned MASTER_TICKS32 = MASTER_TICKS;
28 
29 public:
30  // Note: default copy constructor and assigment operator are ok.
31 
35  static constexpr EmuDuration duration(unsigned ticks) {
36  return EmuDuration(ticks * MASTER_TICKS);
37  }
38 
41  constexpr explicit Clock(EmuTime::param e)
42  : lastTick(e) { }
43 
46  constexpr EmuTime::param getTime() const { return lastTick; }
47 
51  constexpr bool before(EmuTime::param e) const {
52  return lastTick.time < e.time;
53  }
54 
58  constexpr unsigned getTicksTill(EmuTime::param e) const {
59  assert(e.time >= lastTick.time);
60  uint64_t result = (e.time - lastTick.time) / MASTER_TICKS;
61 #ifdef DEBUG
62  // we don't even want this overhead in devel builds
63  assert(result == unsigned(result));
64 #endif
65  return unsigned(result);
66  }
70  constexpr unsigned getTicksTill_fast(EmuTime::param e) const {
71  assert(e.time >= lastTick.time);
73  return dm.div(e.time - lastTick.time);
74  }
79  constexpr uint64_t getTicksTillUp(EmuTime::param e) const {
80  assert(e.time >= lastTick.time);
81  return (e.time - lastTick.time + MASTER_TICKS - 1) / MASTER_TICKS;
82  }
83 
87  constexpr EmuTime operator+(uint64_t n) const {
88  return EmuTime(lastTick.time + n * MASTER_TICKS);
89  }
90 
93  constexpr EmuTime getFastAdd(unsigned n) const {
94  #ifdef DEBUG
95  assert((uint64_t(n) * MASTER_TICKS) < (1ull << 32));
96  #endif
97  return EmuTime(lastTick.time + n * MASTER_TICKS);
98  }
99 
102  constexpr void reset(EmuTime::param e) {
103  lastTick.time = e.time;
104  }
105 
110  constexpr void advance(EmuTime::param e) {
111  assert(lastTick.time <= e.time);
112  lastTick.time = e.time - ((e.time - lastTick.time) % MASTER_TICKS);
113  }
117  constexpr void advance_fast(EmuTime::param e) {
118  assert(lastTick.time <= e.time);
120  lastTick.time = e.time - dm.mod(e.time - lastTick.time);
121  }
122 
125  constexpr void operator+=(unsigned n) {
126  lastTick.time += n * MASTER_TICKS;
127  }
128 
135  constexpr void fastAdd(unsigned n) {
136  #ifdef DEBUG
137  // we don't even want this overhead in development versions
138  assert((n * MASTER_TICKS) < (1ull << 32));
139  #endif
140  lastTick.time += n * MASTER_TICKS32;
141  }
142 
143  template<typename Archive>
144  void serialize(Archive& ar, unsigned /*version*/)
145  {
146  ar.serialize("lastTick", lastTick);
147  }
148 
149 private:
152  EmuTime lastTick;
153 };
154 
155 template<unsigned FREQ_NUM, unsigned FREQ_DENOM>
156 struct SerializeAsMemcpy<Clock<FREQ_NUM, FREQ_DENOM>> : std::true_type {};
157 
158 } // namespace openmsx
159 
160 #endif
constexpr void reset(EmuTime::param e)
Reset the clock to start ticking at the given time.
Definition: Clock.hh:102
constexpr EmuTime getFastAdd(unsigned n) const
Like operator+() but faster, though the step can&#39;t be too big (max a little over 1 second)...
Definition: Clock.hh:93
constexpr void advance(EmuTime::param e)
Advance this clock in time until the last tick which is not past the given time.
Definition: Clock.hh:110
Represents a clock with a fixed frequency.
Definition: Clock.hh:18
static constexpr EmuDuration duration(unsigned ticks)
Calculates the duration of the given number of ticks at this clock&#39;s frequency.
Definition: Clock.hh:35
constexpr void operator+=(unsigned n)
Advance this clock by the given number of ticks.
Definition: Clock.hh:125
constexpr unsigned getTicksTill_fast(EmuTime::param e) const
Same as above, only faster, Though the time interval may not be too large.
Definition: Clock.hh:70
constexpr void fastAdd(unsigned n)
Advance this clock by the given number of ticks.
Definition: Clock.hh:135
constexpr void advance_fast(EmuTime::param e)
Same as above, only faster, Though the time interval may not be too large.
Definition: Clock.hh:117
Thanks to enen for testing this on a real cartridge:
Definition: Autofire.cc:5
constexpr unsigned getTicksTill(EmuTime::param e) const
Calculate the number of ticks for this clock until the given time.
Definition: Clock.hh:58
constexpr 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: Clock.hh:87
constexpr bool before(EmuTime::param e) const
Checks whether this clock&#39;s last tick is or is not before the given time stamp.
Definition: Clock.hh:51
constexpr Clock(EmuTime::param e)
Create a new clock, which starts ticking at the given time.
Definition: Clock.hh:41
void serialize(Archive &ar, unsigned)
Definition: Clock.hh:144
constexpr EmuTime::param getTime() const
Gets the time at which the last clock tick occurred.
Definition: Clock.hh:46
constexpr uint64_t MAIN_FREQ
Definition: EmuDuration.hh:13
constexpr uint32_t div(uint64_t dividend) const
constexpr uint32_t mod(uint64_t dividend) const
constexpr uint64_t getTicksTillUp(EmuTime::param e) const
Calculate the number of ticks this clock has to tick to reach or go past the given time...
Definition: Clock.hh:79