Clock.hh 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  1. #ifndef CLOCK_HH
  2. #define CLOCK_HH
  3. #include "EmuDuration.hh"
  4. #include "EmuTime.hh"
  5. #include "DivModByConst.hh"
  6. #include "serialize.hh"
  7. #include <cassert>
  8. namespace openmsx {
  9. /** Represents a clock with a fixed frequency.
  10. * The frequency is in Hertz, so every tick is 1/frequency second.
  11. * A clock has a current time, which can be increased by
  12. * an integer number of ticks.
  13. */
  14. template <unsigned FREQ_NUM, unsigned FREQ_DENOM = 1>
  15. class Clock
  16. {
  17. private:
  18. // stuff below calculates:
  19. // MASTER_TICKS = MAIN_FREQ / (FREQ_NUM / FREQ_DENOM) + 0.5
  20. static_assert(MAIN_FREQ < (1ull << 32), "must fit in 32 bit");
  21. static constexpr uint64_t P = MAIN_FREQ * FREQ_DENOM + (FREQ_NUM / 2);
  22. static constexpr uint64_t MASTER_TICKS = P / FREQ_NUM;
  23. static_assert(MASTER_TICKS < (1ull << 32), "must fit in 32 bit");
  24. static constexpr unsigned MASTER_TICKS32 = MASTER_TICKS;
  25. public:
  26. // Note: default copy constructor and assigment operator are ok.
  27. /** Calculates the duration of the given number of ticks at this
  28. * clock's frequency.
  29. */
  30. static constexpr EmuDuration duration(unsigned ticks) {
  31. return EmuDuration(ticks * MASTER_TICKS);
  32. }
  33. /** Create a new clock, which starts ticking at the given time.
  34. */
  35. constexpr explicit Clock(EmuTime::param e)
  36. : lastTick(e) { }
  37. /** Gets the time at which the last clock tick occurred.
  38. */
  39. constexpr EmuTime::param getTime() const { return lastTick; }
  40. /** Checks whether this clock's last tick is or is not before the
  41. * given time stamp.
  42. */
  43. constexpr bool before(EmuTime::param e) const {
  44. return lastTick.time < e.time;
  45. }
  46. /** Calculate the number of ticks for this clock until the given time.
  47. * It is not allowed to call this method for a time in the past.
  48. */
  49. constexpr unsigned getTicksTill(EmuTime::param e) const {
  50. assert(e.time >= lastTick.time);
  51. uint64_t result = (e.time - lastTick.time) / MASTER_TICKS;
  52. #ifdef DEBUG
  53. // we don't even want this overhead in devel builds
  54. assert(result == unsigned(result));
  55. #endif
  56. return unsigned(result);
  57. }
  58. /** Same as above, only faster, Though the time interval may not
  59. * be too large.
  60. */
  61. constexpr unsigned getTicksTill_fast(EmuTime::param e) const {
  62. assert(e.time >= lastTick.time);
  63. DivModByConst<MASTER_TICKS32> dm;
  64. return dm.div(e.time - lastTick.time);
  65. }
  66. /** Calculate the number of ticks this clock has to tick to reach
  67. * or go past the given time.
  68. * It is not allowed to call this method for a time in the past.
  69. */
  70. constexpr uint64_t getTicksTillUp(EmuTime::param e) const {
  71. assert(e.time >= lastTick.time);
  72. return (e.time - lastTick.time + MASTER_TICKS - 1) / MASTER_TICKS;
  73. }
  74. /** Calculate the time at which this clock will have ticked the given
  75. * number of times (counted from its last tick).
  76. */
  77. constexpr EmuTime operator+(uint64_t n) const {
  78. return EmuTime(lastTick.time + n * MASTER_TICKS);
  79. }
  80. /** Like operator+() but faster, though the step can't be too big (max
  81. * a little over 1 second). */
  82. constexpr EmuTime getFastAdd(unsigned n) const {
  83. #ifdef DEBUG
  84. assert((uint64_t(n) * MASTER_TICKS) < (1ull << 32));
  85. #endif
  86. return EmuTime(lastTick.time + n * MASTER_TICKS);
  87. }
  88. /** Reset the clock to start ticking at the given time.
  89. */
  90. constexpr void reset(EmuTime::param e) {
  91. lastTick.time = e.time;
  92. }
  93. /** Advance this clock in time until the last tick which is not past
  94. * the given time.
  95. * It is not allowed to advance a clock to a time in the past.
  96. */
  97. constexpr void advance(EmuTime::param e) {
  98. assert(lastTick.time <= e.time);
  99. lastTick.time = e.time - ((e.time - lastTick.time) % MASTER_TICKS);
  100. }
  101. /** Same as above, only faster, Though the time interval may not
  102. * be too large.
  103. */
  104. constexpr void advance_fast(EmuTime::param e) {
  105. assert(lastTick.time <= e.time);
  106. DivModByConst<MASTER_TICKS32> dm;
  107. lastTick.time = e.time - dm.mod(e.time - lastTick.time);
  108. }
  109. /** Advance this clock by the given number of ticks.
  110. */
  111. constexpr void operator+=(unsigned n) {
  112. lastTick.time += n * MASTER_TICKS;
  113. }
  114. /** Advance this clock by the given number of ticks.
  115. * This method is similar to operator+=, but it's optimized for
  116. * speed. OTOH the amount of ticks should not be too large,
  117. * otherwise an overflow occurs. Use operator+() when the duration
  118. * of the ticks approaches 1 second.
  119. */
  120. constexpr void fastAdd(unsigned n) {
  121. #ifdef DEBUG
  122. // we don't even want this overhead in development versions
  123. assert((n * MASTER_TICKS) < (1ull << 32));
  124. #endif
  125. lastTick.time += n * MASTER_TICKS32;
  126. }
  127. template<typename Archive>
  128. void serialize(Archive& ar, unsigned /*version*/)
  129. {
  130. ar.serialize("lastTick", lastTick);
  131. }
  132. private:
  133. /** Time of this clock's last tick.
  134. */
  135. EmuTime lastTick;
  136. };
  137. template<unsigned FREQ_NUM, unsigned FREQ_DENOM>
  138. struct SerializeAsMemcpy<Clock<FREQ_NUM, FREQ_DENOM>> : std::true_type {};
  139. } // namespace openmsx
  140. #endif