VDPAccessSlots.hh 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103
  1. #ifndef VDPACCESSSLOTS_HH
  2. #define VDPACCESSSLOTS_HH
  3. #include "VDP.hh"
  4. #include "likely.hh"
  5. #include <cassert>
  6. #include <cstdint>
  7. namespace openmsx::VDPAccessSlots {
  8. constexpr int TICKS = VDP::TICKS_PER_LINE;
  9. enum Delta : int {
  10. DELTA_0 = 0 * TICKS,
  11. DELTA_1 = 1 * TICKS,
  12. DELTA_16 = 2 * TICKS,
  13. DELTA_24 = 3 * TICKS,
  14. DELTA_28 = 4 * TICKS,
  15. DELTA_32 = 5 * TICKS,
  16. DELTA_40 = 6 * TICKS,
  17. DELTA_48 = 7 * TICKS,
  18. DELTA_64 = 8 * TICKS,
  19. DELTA_72 = 9 * TICKS,
  20. DELTA_88 = 10 * TICKS,
  21. DELTA_104 = 11 * TICKS,
  22. DELTA_120 = 12 * TICKS,
  23. DELTA_128 = 13 * TICKS,
  24. DELTA_136 = 14 * TICKS,
  25. NUM_DELTAS = 15,
  26. };
  27. /** VDP-VRAM access slot calculator, meant to be used in the inner loops of the
  28. * VDPCmdEngine commands. Code optimized for the case that:
  29. * - timing remains constant (sprites/display enable/disable)
  30. * - there are more calls to next() and limitReached() than to getTime()
  31. */
  32. class Calculator
  33. {
  34. public:
  35. /** This shouldn't be called directly, instead use getCalculator(). */
  36. Calculator(EmuTime::param frame, EmuTime::param time,
  37. EmuTime::param limit_, const uint8_t* tab_)
  38. : ref(frame), tab(tab_)
  39. {
  40. assert(frame <= time);
  41. assert(frame <= limit_);
  42. // not required that time <= limit
  43. ticks = ref.getTicksTill_fast(time);
  44. limit = ref.getTicksTill_fast(limit_);
  45. int lines = ticks / TICKS;
  46. ticks -= lines * TICKS;
  47. limit -= lines * TICKS; // might be negative
  48. ref += lines * TICKS;
  49. assert(0 <= ticks); assert(ticks < TICKS);
  50. }
  51. /** Has 'time' advanced to or past 'limit'? */
  52. inline bool limitReached() const {
  53. return ticks >= limit;
  54. }
  55. /** Get the current time. Initially this will return the 'time'
  56. * constructor parameter. Each call to next() will increase this
  57. * value. */
  58. inline EmuTime getTime() const {
  59. return ref.getFastAdd(ticks);
  60. }
  61. /** Advance time to the earliest access slot that is at least 'delta'
  62. * ticks later than the current time. */
  63. inline void next(Delta delta) {
  64. ticks += tab[delta + ticks];
  65. if (unlikely(ticks >= TICKS)) {
  66. ticks -= TICKS;
  67. limit -= TICKS;
  68. ref += TICKS;
  69. }
  70. }
  71. private:
  72. int ticks;
  73. int limit;
  74. VDP::VDPClock ref;
  75. const uint8_t* const tab;
  76. };
  77. /** Return the time of the next available access slot that is at least 'delta'
  78. * cycles later than 'time'. The start of the current 'frame' is needed for
  79. * reference. */
  80. EmuTime getAccessSlot(EmuTime::param frame, EmuTime::param time, Delta delta,
  81. const VDP& vdp);
  82. /** When many calls to getAccessSlot() are needed, it's more efficient to
  83. * instead use this function. */
  84. Calculator getCalculator(
  85. EmuTime::param frame, EmuTime::param time, EmuTime::param limit,
  86. const VDP& vdp);
  87. } // namespace openmsx::VDPAccessSlots
  88. #endif