ReverseManager.hh 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  1. #ifndef REVERSEMANGER_HH
  2. #define REVERSEMANGER_HH
  3. #include "Schedulable.hh"
  4. #include "EventListener.hh"
  5. #include "StateChangeListener.hh"
  6. #include "Command.hh"
  7. #include "EmuTime.hh"
  8. #include "MemBuffer.hh"
  9. #include "DeltaBlock.hh"
  10. #include "span.hh"
  11. #include "outer.hh"
  12. #include <vector>
  13. #include <map>
  14. #include <memory>
  15. #include <cstdint>
  16. namespace openmsx {
  17. class MSXMotherBoard;
  18. class Keyboard;
  19. class EventDelay;
  20. class EventDistributor;
  21. class TclObject;
  22. class Interpreter;
  23. class ReverseManager final : private EventListener, private StateChangeRecorder
  24. {
  25. public:
  26. explicit ReverseManager(MSXMotherBoard& motherBoard);
  27. ~ReverseManager();
  28. // Keyboard is special because we need to transfer the host keyboard
  29. // state on 'reverse goto' to be able to resynchronize when replay
  30. // stops. See Keyboard::transferHostKeyMatrix() for more info.
  31. void registerKeyboard(Keyboard& keyboard_) {
  32. keyboard = &keyboard_;
  33. }
  34. // To not loose any events we need to flush delayed events before
  35. // switching machine. See comments in goTo() for more info.
  36. void registerEventDelay(EventDelay& eventDelay_) {
  37. eventDelay = &eventDelay_;
  38. }
  39. // Should only be used by MSXMotherBoard to be able to transfer
  40. // reRecordCount to ReverseManager for version 2 of MSXMotherBoard
  41. // serializers.
  42. void setReRecordCount(unsigned count) {
  43. reRecordCount = count;
  44. }
  45. private:
  46. struct ReverseChunk {
  47. ReverseChunk() : time(EmuTime::zero()) {}
  48. EmuTime time;
  49. std::vector<std::shared_ptr<DeltaBlock>> deltaBlocks;
  50. MemBuffer<uint8_t> savestate;
  51. size_t size;
  52. // Number of recorded events (or replay index) when this
  53. // snapshot was created. So when going back replay should
  54. // start at this index.
  55. unsigned eventCount;
  56. };
  57. using Chunks = std::map<unsigned, ReverseChunk>;
  58. using Events = std::vector<std::shared_ptr<StateChange>>;
  59. struct ReverseHistory {
  60. void swap(ReverseHistory& other);
  61. void clear();
  62. unsigned getNextSeqNum(EmuTime::param time) const;
  63. Chunks chunks;
  64. Events events;
  65. LastDeltaBlocks lastDeltaBlocks;
  66. };
  67. bool isCollecting() const { return collecting; }
  68. void start();
  69. void stop();
  70. void status(TclObject& result) const;
  71. void debugInfo(TclObject& result) const;
  72. void goBack(span<const TclObject> tokens);
  73. void goTo(span<const TclObject> tokens);
  74. void saveReplay(Interpreter& interp,
  75. span<const TclObject> tokens, TclObject& result);
  76. void loadReplay(Interpreter& interp,
  77. span<const TclObject> tokens, TclObject& result);
  78. void signalStopReplay(EmuTime::param time);
  79. EmuTime::param getEndTime(const ReverseHistory& history) const;
  80. void goTo(EmuTime::param targetTime, bool novideo);
  81. void goTo(EmuTime::param targetTime, bool novideo,
  82. ReverseHistory& history, bool sameTimeLine);
  83. void transferHistory(ReverseHistory& oldHistory,
  84. unsigned oldEventCount);
  85. void transferState(MSXMotherBoard& newBoard);
  86. void takeSnapshot(EmuTime::param time);
  87. void schedule(EmuTime::param time);
  88. void replayNextEvent();
  89. template<unsigned N> void dropOldSnapshots(unsigned count);
  90. // Schedulable
  91. struct SyncNewSnapshot final : Schedulable {
  92. friend class ReverseManager;
  93. explicit SyncNewSnapshot(Scheduler& s) : Schedulable(s) {}
  94. void executeUntil(EmuTime::param /*time*/) override {
  95. auto& rm = OUTER(ReverseManager, syncNewSnapshot);
  96. rm.execNewSnapshot();
  97. }
  98. } syncNewSnapshot;
  99. struct SyncInputEvent final : Schedulable {
  100. friend class ReverseManager;
  101. explicit SyncInputEvent(Scheduler& s) : Schedulable(s) {}
  102. void executeUntil(EmuTime::param /*time*/) override {
  103. auto& rm = OUTER(ReverseManager, syncInputEvent);
  104. rm.execInputEvent();
  105. }
  106. } syncInputEvent;
  107. void execNewSnapshot();
  108. void execInputEvent();
  109. EmuTime::param getCurrentTime() const { return syncNewSnapshot.getCurrentTime(); }
  110. // EventListener
  111. int signalEvent(const std::shared_ptr<const Event>& event) override;
  112. // StateChangeRecorder
  113. void signalStateChange(const std::shared_ptr<StateChange>& event) override;
  114. void stopReplay(EmuTime::param time) override;
  115. bool isReplaying() const override;
  116. MSXMotherBoard& motherBoard;
  117. EventDistributor& eventDistributor;
  118. struct ReverseCmd final : Command {
  119. explicit ReverseCmd(CommandController& controller);
  120. void execute(span<const TclObject> tokens, TclObject& result) override;
  121. std::string help(const std::vector<std::string>& tokens) const override;
  122. void tabCompletion(std::vector<std::string>& tokens) const override;
  123. } reverseCmd;
  124. Keyboard* keyboard;
  125. EventDelay* eventDelay;
  126. ReverseHistory history;
  127. unsigned replayIndex;
  128. bool collecting;
  129. bool pendingTakeSnapshot;
  130. unsigned reRecordCount;
  131. friend struct Replay;
  132. };
  133. } // namespace openmsx
  134. #endif