diff --git a/src/common/RewindManager.cxx b/src/common/RewindManager.cxx index 00c7272cb..197683ded 100644 --- a/src/common/RewindManager.cxx +++ b/src/common/RewindManager.cxx @@ -29,30 +29,31 @@ RewindManager::RewindManager(OSystem& system, StateManager& statemgr) mySize(0), myTop(0) { - for(int i = 0; i < MAX_SIZE; ++i) - myStateList[i] = nullptr; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - RewindManager::~RewindManager() { - for(int i = 0; i < MAX_SIZE; ++i) - delete myStateList[i]; + for(uInt8 i = 0; i < MAX_SIZE; ++i) + delete myStateList[i].data; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool RewindManager::addState(const string& message) { // Create a new Serializer object if we need one - if(myStateList[myTop] == nullptr) - myStateList[myTop] = new Serializer(); - Serializer& s = *(myStateList[myTop]); + if(myStateList[myTop].data == nullptr) + myStateList[myTop].data = new Serializer(); - if(s) + // And use it to store the serialized data and text message + if(myStateList[myTop].data != nullptr) { + Serializer& s = *(myStateList[myTop].data); s.reset(); if(myStateManager.saveState(s) && myOSystem.console().tia().saveDisplay(s)) { + myStateList[myTop].message = "Rewind " + message; + // Are we still within the allowable size, or are we overwriting an item? mySize++; if(mySize > MAX_SIZE) mySize = MAX_SIZE; myTop = (myTop + 1) % MAX_SIZE; @@ -70,12 +71,15 @@ bool RewindManager::rewindState() { mySize--; myTop = myTop == 0 ? MAX_SIZE - 1 : myTop - 1; - Serializer& s = *(myStateList[myTop]); + Serializer& s = *(myStateList[myTop].data); s.reset(); myStateManager.loadState(s); myOSystem.console().tia().loadDisplay(s); + // Show message indicating the rewind state + myOSystem.frameBuffer().showMessage(myStateList[myTop].message); + return true; } else @@ -85,9 +89,9 @@ bool RewindManager::rewindState() // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void RewindManager::clear() { - for(int i = 0; i < MAX_SIZE; ++i) - if(myStateList[i] != nullptr) - myStateList[i]->reset(); + for(uInt8 i = 0; i < MAX_SIZE; ++i) + if(myStateList[i].data != nullptr) + myStateList[i].data->reset(); myTop = mySize = 0; } diff --git a/src/common/RewindManager.hxx b/src/common/RewindManager.hxx index 88df9677e..615d76e2e 100644 --- a/src/common/RewindManager.hxx +++ b/src/common/RewindManager.hxx @@ -57,13 +57,20 @@ class RewindManager private: // Maximum number of states to save - enum { MAX_SIZE = 100 }; + static constexpr uInt8 MAX_SIZE = 100; OSystem& myOSystem; StateManager& myStateManager; - Serializer* myStateList[MAX_SIZE]; - uInt32 mySize, myTop; + struct SerialData { + Serializer* data; + string message; + + SerialData(Serializer* d = nullptr) : data(d) { } + }; + + SerialData myStateList[MAX_SIZE]; + uInt8 mySize, myTop; private: // Following constructors and assignment operators not supported diff --git a/src/debugger/Debugger.cxx b/src/debugger/Debugger.cxx index 838dc7cfd..5e69874f6 100644 --- a/src/debugger/Debugger.cxx +++ b/src/debugger/Debugger.cxx @@ -300,7 +300,7 @@ void Debugger::loadState(int state) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - int Debugger::step() { - saveOldState(); + saveOldState("1 step"); mySystem.clearDirtyPages(); uInt64 startCycle = mySystem.cycles(); @@ -313,7 +313,6 @@ int Debugger::step() } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // trace is just like step, except it treats a subroutine call as one // instruction. @@ -328,7 +327,7 @@ int Debugger::trace() // 32 is the 6502 JSR instruction: if(mySystem.peek(myCpuDebug->pc()) == 32) { - saveOldState(); + saveOldState("1 trace"); mySystem.clearDirtyPages(); uInt64 startCycle = mySystem.cycles(); @@ -401,7 +400,12 @@ bool Debugger::writeTrap(uInt16 t) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Debugger::nextScanline(int lines) { - saveOldState(); + ostringstream buf; + buf << lines << " scanline"; + if(lines > 1) + buf << "s"; + + saveOldState(buf.str()); mySystem.clearDirtyPages(); unlockBankswitchState(); @@ -418,7 +422,12 @@ void Debugger::nextScanline(int lines) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Debugger::nextFrame(int frames) { - saveOldState(); + ostringstream buf; + buf << frames << " frame"; + if(frames > 1) + buf << "s"; + + saveOldState(buf.str()); mySystem.clearDirtyPages(); unlockBankswitchState(); @@ -472,7 +481,7 @@ bool Debugger::patchROM(uInt16 addr, uInt8 value) } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void Debugger::saveOldState(bool addrewind) +void Debugger::saveOldState(string rewindMsg) { myCartDebug->saveOldState(); myCpuDebug->saveOldState(); @@ -480,10 +489,10 @@ void Debugger::saveOldState(bool addrewind) myTiaDebug->saveOldState(); // Add another rewind level to the Undo list - if(addrewind) + if(rewindMsg != "") { RewindManager& r = myOSystem.state().rewindManager(); - r.addState(); + r.addState(rewindMsg); myDialog->rewindButton().setEnabled(!r.empty()); } } @@ -501,7 +510,7 @@ void Debugger::setStartState() myDialog->rewindButton().setEnabled(!r.empty()); // Save initial state, but don't add it to the rewind list - saveOldState(false); + saveOldState(); // FIXME - rework this // Set the 're-disassemble' flag, but don't do it until the next scheduled time myDialog->rom().invalidate(false); diff --git a/src/debugger/Debugger.hxx b/src/debugger/Debugger.hxx index 0cc3731f1..945a56e9f 100644 --- a/src/debugger/Debugger.hxx +++ b/src/debugger/Debugger.hxx @@ -231,8 +231,11 @@ class Debugger : public DialogContainer private: /** Save state of each debugger subsystem. + + If a message is provided, we assume that a rewind state should + be saved with the given message. */ - void saveOldState(bool addrewind = true); + void saveOldState(string rewindMsg = ""); /** Set initial state before entering the debugger.