openMSX
ReverseManager.hh
Go to the documentation of this file.
1 #ifndef REVERSEMANGER_HH
2 #define REVERSEMANGER_HH
3 
4 #include "Schedulable.hh"
5 #include "EventListener.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 <cstdint>
13 #include <deque>
14 #include <map>
15 #include <memory>
16 #include <vector>
17 
18 namespace openmsx {
19 
20 class EventDelay;
21 class EventDistributor;
22 class Interpreter;
23 class MSXMotherBoard;
24 class Keyboard;
25 class StateChange;
26 class TclObject;
27 
28 class ReverseManager final : private EventListener
29 {
30 public:
31  explicit ReverseManager(MSXMotherBoard& motherBoard);
33 
34  // Keyboard is special because we need to transfer the host keyboard
35  // state on 'reverse goto' to be able to resynchronize when replay
36  // stops. See Keyboard::transferHostKeyMatrix() for more info.
37  void registerKeyboard(Keyboard& keyboard_) {
38  keyboard = &keyboard_;
39  }
40 
41  // To not loose any events we need to flush delayed events before
42  // switching machine. See comments in goTo() for more info.
43  void registerEventDelay(EventDelay& eventDelay_) {
44  eventDelay = &eventDelay_;
45  }
46 
47  // Should only be used by MSXMotherBoard to be able to transfer
48  // reRecordCount to ReverseManager for version 2 of MSXMotherBoard
49  // serializers.
50  void setReRecordCount(unsigned count) {
51  reRecordCount = count;
52  }
53 
54  [[nodiscard]] bool isReplaying() const;
55  void stopReplay(EmuTime::param time) noexcept;
56 
57  template<typename T, typename... Args>
58  StateChange& record(EmuTime::param time, Args&& ...args) {
59  assert(!isReplaying());
60  ++replayIndex;
61  history.events.push_back(std::make_unique<T>(time, std::forward<Args>(args)...));
62  return *history.events.back();
63  }
64 
65 private:
66  struct ReverseChunk {
67  ReverseChunk() : time(EmuTime::zero()) {}
68 
69  EmuTime time;
70  std::vector<std::shared_ptr<DeltaBlock>> deltaBlocks;
71  MemBuffer<uint8_t> savestate;
72  size_t size;
73 
74  // Number of recorded events (or replay index) when this
75  // snapshot was created. So when going back replay should
76  // start at this index.
77  unsigned eventCount;
78  };
79  using Chunks = std::map<unsigned, ReverseChunk>;
80  using Events = std::deque<std::unique_ptr<StateChange>>;
81 
82  struct ReverseHistory {
83  void swap(ReverseHistory& other) noexcept;
84  void clear();
85  [[nodiscard]] unsigned getNextSeqNum(EmuTime::param time) const;
86 
87  Chunks chunks;
88  Events events;
89  LastDeltaBlocks lastDeltaBlocks;
90  };
91 
92  [[nodiscard]] bool isCollecting() const { return collecting; }
93 
94  void start();
95  void stop();
96  void status(TclObject& result) const;
97  void debugInfo(TclObject& result) const;
98  void goBack(span<const TclObject> tokens);
99  void goTo(span<const TclObject> tokens);
100  void saveReplay(Interpreter& interp,
101  span<const TclObject> tokens, TclObject& result);
102  void loadReplay(Interpreter& interp,
103  span<const TclObject> tokens, TclObject& result);
104 
105  void signalStopReplay(EmuTime::param time);
106  [[nodiscard]] EmuTime::param getEndTime(const ReverseHistory& history) const;
107  void goTo(EmuTime::param targetTime, bool novideo);
108  void goTo(EmuTime::param targetTime, bool novideo,
109  ReverseHistory& history, bool sameTimeLine);
110  void transferHistory(ReverseHistory& oldHistory,
111  unsigned oldEventCount);
112  void transferState(MSXMotherBoard& newBoard);
113  void takeSnapshot(EmuTime::param time);
114  void schedule(EmuTime::param time);
115  void replayNextEvent();
116  template<unsigned N> void dropOldSnapshots(unsigned count);
117 
118  // Schedulable
119  struct SyncNewSnapshot final : Schedulable {
120  friend class ReverseManager;
121  explicit SyncNewSnapshot(Scheduler& s) : Schedulable(s) {}
122  void executeUntil(EmuTime::param /*time*/) override {
123  auto& rm = OUTER(ReverseManager, syncNewSnapshot);
124  rm.execNewSnapshot();
125  }
126  } syncNewSnapshot;
127  struct SyncInputEvent final : Schedulable {
128  friend class ReverseManager;
129  explicit SyncInputEvent(Scheduler& s) : Schedulable(s) {}
130  void executeUntil(EmuTime::param /*time*/) override {
131  auto& rm = OUTER(ReverseManager, syncInputEvent);
132  rm.execInputEvent();
133  }
134  } syncInputEvent;
135 
136  void execNewSnapshot();
137  void execInputEvent();
138  [[nodiscard]] EmuTime::param getCurrentTime() const { return syncNewSnapshot.getCurrentTime(); }
139 
140  // EventListener
141  int signalEvent(const Event& event) noexcept override;
142 
143 private:
144  MSXMotherBoard& motherBoard;
145  EventDistributor& eventDistributor;
146 
147  struct ReverseCmd final : Command {
148  explicit ReverseCmd(CommandController& controller);
149  void execute(span<const TclObject> tokens, TclObject& result) override;
150  [[nodiscard]] std::string help(span<const TclObject> tokens) const override;
151  void tabCompletion(std::vector<std::string>& tokens) const override;
152  } reverseCmd;
153 
154  Keyboard* keyboard;
155  EventDelay* eventDelay;
156  ReverseHistory history;
157  unsigned replayIndex;
158  bool collecting;
159  bool pendingTakeSnapshot;
160 
161  unsigned reRecordCount;
162 
163  friend struct Replay;
164 };
165 
166 } // namespace openmsx
167 
168 #endif
void swap(openmsx::MemBuffer< T > &l, openmsx::MemBuffer< T > &r) noexcept
Definition: MemBuffer.hh:202
This class is responsible for translating host events into MSX events.
Definition: EventDelay.hh:27
void setReRecordCount(unsigned count)
StateChange & record(EmuTime::param time, Args &&...args)
void registerKeyboard(Keyboard &keyboard_)
void stopReplay(EmuTime::param time) noexcept
void registerEventDelay(EventDelay &eventDelay_)
ReverseManager(MSXMotherBoard &motherBoard)
Base class for all external MSX state changing events.
Definition: StateChange.hh:20
Definition: span.hh:126
ALWAYS_INLINE unsigned count(const uint8_t *pIn, const uint8_t *pMatch, const uint8_t *pInLimit)
Definition: lz4.cc:207
This file implemented 3 utility functions:
Definition: Autofire.cc:9
size_t size(std::string_view utf8)
#define OUTER(type, member)
Definition: outer.hh:41