diff --git a/docs/debugger.html b/docs/debugger.html
index 2e808cc45..332843089 100644
--- a/docs/debugger.html
+++ b/docs/debugger.html
@@ -316,9 +316,11 @@ used.
The larger button at the left top (labeled '<') performs the rewind operation,
-which will undo the previous Step/Trace/Scan/Frame advance, the smaller button at
+which will undo the previous Step/Trace/Scan/Frame... advance, the smaller button at
the left bottom (labeled '>') performs the unwind operation, which will undo the
-previous rewind operation. The rewind buffer is 100 levels deep by default.
+previous rewind operation. The rewind buffer is 100 levels deep by default, the
+size can be configured e.g. in the
+Developer Settings - States dialog.
The other operations are Step, Trace, Scan+1, Frame+1 and Exit (debugger).
@@ -347,11 +349,27 @@ previous rewind operation. The rewind buffer is 100 levels deep by default.
Control-r |
- Rewind |
+ Rewind 1 |
- Shift-Control-r |
- Unwind |
+ Control-Shift-r |
+ Rewind 10 |
+
+
+ Control-Alt-r |
+ Rewind all |
+
+
+ Control-y |
+ Unwind 1 |
+
+
+ Control-Shift-y |
+ Unwind 10 |
+
+
+ Control-Alt-y |
+ Unwind all |
Backquote (`) |
diff --git a/docs/index.html b/docs/index.html
index 8bb086b80..4c8ac198a 100644
--- a/docs/index.html
+++ b/docs/index.html
@@ -1622,11 +1622,31 @@
Alt + Left arrow |
Cmd + Left arrow |
+
+ Rewind by 10 states (pauses emulation) |
+ Shift-Alt + Left arrow |
+ Shift-Cmd + Left arrow |
+
+
+ Rewind all states (pauses emulation) |
+ Alt + Down arrow |
+ Cmd + Down arrow |
+
Unwind by one state (pauses emulation) |
Alt + Right arrow |
Cmd + Right arrow |
+
+ Unwind by 10 states (pauses emulation) |
+ Shift-Alt + Right arrow |
+ Shift-Cmd + Right arrow |
+
+
+ Unwind all states (pauses emulation) |
+ Alt + Up arrow |
+ Cmd + Up arrow |
+
UI keys in Text Editing areas (cannot be remapped)
diff --git a/src/common/LinkedObjectPool.hxx b/src/common/LinkedObjectPool.hxx
index d3484bc26..46205c6f1 100644
--- a/src/common/LinkedObjectPool.hxx
+++ b/src/common/LinkedObjectPool.hxx
@@ -175,26 +175,22 @@ class LinkedObjectPool
moveToPrevious(); // if so, move to the previous node
}
-#if 0
/**
- Convenience method to remove a single element from the active list at
- position of the iterator +- the offset.
+ Remove a single element from the active list at position of the iterator.
*/
- void remove(const_iter i, Int32 offset = 0) {
- myPool.splice(myPool.end(), myList,
- offset >= 0 ? std::next(i, offset) : std::prev(i, -offset));
+ void remove(const_iter i) {
+ myPool.splice(myPool.end(), myList, i);
}
-#endif
+
/**
- Convenience method to remove a single element from the active list by
- index, offset from the beginning of the list. (ie, '0' means first
- element, '1' is second, and so on).
+ Remove a single element from the active list by index, offset from
+ the beginning of the list. (ie, '0' means first element, '1' is second,
+ and so on).
*/
void remove(uInt32 index) {
myPool.splice(myPool.end(), myList, std::next(myList.begin(), index));
}
-
/**
Remove range of elements from the beginning of the active list to
the 'current' node.
diff --git a/src/common/RewindManager.cxx b/src/common/RewindManager.cxx
index f2314645c..7189e05c8 100644
--- a/src/common/RewindManager.cxx
+++ b/src/common/RewindManager.cxx
@@ -130,59 +130,90 @@ bool RewindManager::addState(const string& message, bool continuous)
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-bool RewindManager::rewindState()
+uInt32 RewindManager::rewindState(uInt32 numStates)
{
- if(!atFirst())
+ uInt64 startCycles = myOSystem.console().tia().cycles();
+ uInt32 i;
+ string message;
+
+ for(i = 0; i < numStates; ++i)
{
- if (!myLastContinuousAdd)
- // Set internal current iterator to previous state (back in time),
- // since we will now processed this state
- myStateList.moveToPrevious();
- myLastContinuousAdd = false;
+ if(!atFirst())
+ {
+ if(!myLastContinuousAdd)
+ // Set internal current iterator to previous state (back in time),
+ // since we will now processed this state
+ myStateList.moveToPrevious();
+ myLastContinuousAdd = false;
- //RewindState& lastState = myStateList.current();
+ RewindState& state = myStateList.current();
+ Serializer& s = state.data;
+//cerr << "rewind " << state.count << endl;
+ s.rewind(); // rewind Serializer internal buffers
+ }
+ else
+ break;
+ }
+ if(i)
+ {
RewindState& state = myStateList.current();
Serializer& s = state.data;
- string message = getMessage(state);
-//cerr << "rewind " << state.count << endl;
- s.rewind(); // rewind Serializer internal buffers
myStateManager.loadState(s);
myOSystem.console().tia().loadDisplay(s);
- // Show message indicating the rewind state
- myOSystem.frameBuffer().showMessage(message);
- return true;
+ // Get message indicating the rewind state
+ message = getMessage(startCycles, i);
}
- myOSystem.frameBuffer().showMessage("Rewind not possible");
- return false;
+ else
+ message = "Rewind not possible";
+
+ myOSystem.frameBuffer().showMessage(message);
+ return i;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-bool RewindManager::unwindState()
+uInt32 RewindManager::unwindState(uInt32 numStates)
{
- if(!atLast())
- {
- // Set internal current iterator to nextCycles state (forward in time),
- // since we've now processed this state
- myStateList.moveToNext();
+ uInt64 startCycles = myOSystem.console().tia().cycles();
+ uInt32 i;
+ string message;
+ for(i = 0; i < numStates; ++i)
+ {
+ if(!atLast())
+ {
+ // Set internal current iterator to nextCycles state (forward in time),
+ // since we've now processed this state
+ myStateList.moveToNext();
+
+ RewindState& state = myStateList.current();
+ Serializer& s = state.data;
+//cerr << "unwind " << state.count << endl;
+ s.rewind(); // rewind Serializer internal buffers
+ }
+ else
+ break;
+ }
+
+ if(i)
+ {
RewindState& state = myStateList.current();
Serializer& s = state.data;
- string message = getMessage(state);
-//cerr << "unwind " << state.count << endl;
- s.rewind(); // rewind Serializer internal buffers
myStateManager.loadState(s);
myOSystem.console().tia().loadDisplay(s);
- // Show message indicating the rewind state
+ // Get message indicating the rewind state
+ message = getMessage(startCycles, i);
myOSystem.frameBuffer().showMessage(message);
- return true;
}
- myOSystem.frameBuffer().showMessage("Unwind not possible");
- return false;
+ else
+ message = "Unwind not possible";
+
+ myOSystem.frameBuffer().showMessage(message);
+ return i;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@@ -191,8 +222,8 @@ void RewindManager::compressStates()
uInt64 currentCycles = myOSystem.console().tia().cycles();
double expectedCycles = myInterval * myFactor * (1 + myFactor);
double maxError = 1;
- uInt32 removeIdx = 0;
uInt32 idx = myStateList.size() - 2;
+ Common::LinkedObjectPool::const_iter removeIter = myStateList.first();
//cerr << "idx: " << idx << endl;
// iterate from last but one to first but one
@@ -211,7 +242,7 @@ void RewindManager::compressStates()
if(error > maxError)
{
maxError = error;
- removeIdx = idx;
+ removeIter = it;
}
}
--idx;
@@ -224,22 +255,23 @@ void RewindManager::compressStates()
}
else
{
- myStateList.remove(removeIdx); // remove
+ myStateList.remove(removeIter); // remove
//cerr << "remove " << removeIdx << endl;
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-string RewindManager::getMessage(RewindState& state)
+string RewindManager::getMessage(Int64 startCycles, uInt32 numStates)
{
- Int64 diff = myOSystem.console().tia().cycles() - state.cycles;
+ RewindState& state = myStateList.current();
+ Int64 diff = startCycles - state.cycles;
stringstream message;
message << (diff >= 0 ? "Rewind" : "Unwind") << " " << getUnitString(diff);
-
message << " [" << myStateList.currentIdx() << "/" << myStateList.size() << "]";
+
// add optional message
- if(!state.message.empty())
+ if(numStates == 1 && !state.message.empty())
message << " (" << state.message << ")";
return message.str();
diff --git a/src/common/RewindManager.hxx b/src/common/RewindManager.hxx
index f4e67debb..49c0bd1c4 100644
--- a/src/common/RewindManager.hxx
+++ b/src/common/RewindManager.hxx
@@ -99,6 +99,7 @@ class RewindManager
};
/**
+ Initializes state list and calculates compression factor.
*/
void setup();
@@ -113,14 +114,20 @@ class RewindManager
/**
Rewind one level of the state list, and display the message associated
with that state.
+
+ @param numStates Number of states to rewind
+ @return Number of states to rewinded
*/
- bool rewindState();
+ uInt32 rewindState(uInt32 numStates = 1);
/**
Unwind one level of the state list, and display the message associated
with that state.
+
+ @param numStates Number of states to unwind
+ @return Number of states to unwinded
*/
- bool unwindState();
+ uInt32 unwindState(uInt32 numStates = 1);
bool atFirst() const { return myStateList.atFirst(); }
bool atLast() const { return myStateList.atLast(); }
@@ -167,9 +174,17 @@ class RewindManager
// frequent (de)-allocations)
Common::LinkedObjectPool myStateList;
+ /**
+ Remove a save state from the list
+ */
void compressStates();
- string getMessage(RewindState& state);
+ /**
+ Get the message string for the rewind/unwind
+
+ @return The message
+ */
+ string getMessage(Int64 startCycles, uInt32 numStates);
private:
// Following constructors and assignment operators not supported
diff --git a/src/common/StateManager.cxx b/src/common/StateManager.cxx
index d31c56aaf..2ffcbbec6 100644
--- a/src/common/StateManager.cxx
+++ b/src/common/StateManager.cxx
@@ -142,17 +142,17 @@ void StateManager::toggleRewindMode()
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-bool StateManager::rewindState()
+bool StateManager::rewindState(uInt32 numStates)
{
RewindManager& r = myOSystem.state().rewindManager();
- return r.rewindState();
+ return r.rewindState(numStates);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-bool StateManager::unwindState()
+bool StateManager::unwindState(uInt32 numStates)
{
RewindManager& r = myOSystem.state().rewindManager();
- return r.unwindState();
+ return r.unwindState(numStates);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
diff --git a/src/common/StateManager.hxx b/src/common/StateManager.hxx
index 5e7b83c10..910b0e7a9 100644
--- a/src/common/StateManager.hxx
+++ b/src/common/StateManager.hxx
@@ -74,12 +74,12 @@ class StateManager
/**
Rewinds one state; this uses the RewindManager for its functionality.
*/
- bool rewindState();
+ bool rewindState(uInt32 numStates = 1);
/**
Unwinds one state; this uses the RewindManager for its functionality.
*/
- bool unwindState();
+ bool unwindState(uInt32 numStates = 1);
/**
Updates the state of the system based on the currently active mode.
diff --git a/src/debugger/Debugger.cxx b/src/debugger/Debugger.cxx
index 38f462bbe..08a2c251f 100644
--- a/src/debugger/Debugger.cxx
+++ b/src/debugger/Debugger.cxx
@@ -526,7 +526,7 @@ void Debugger::updateRewindbuttons(const RewindManager& r)
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-uInt16 Debugger::windStates(uInt16 states, bool unwind, string& message)
+uInt16 Debugger::windStates(uInt16 numStates, bool unwind, string& message)
{
RewindManager& r = myOSystem.state().rewindManager();
@@ -534,13 +534,8 @@ uInt16 Debugger::windStates(uInt16 states, bool unwind, string& message)
unlockBankswitchState();
- uInt16 winds = 0;
uInt64 startCycles = myOSystem.console().tia().cycles();
- for(uInt16 i = 0; i < states; ++i)
- if(unwind ? r.unwindState() : r.rewindState())
- winds++;
- else
- break;
+ uInt16 winds = unwind ? r.unwindState(numStates) : r.rewindState(numStates);
message = r.getUnitString(myOSystem.console().tia().cycles() - startCycles);
lockBankswitchState();
@@ -550,15 +545,15 @@ uInt16 Debugger::windStates(uInt16 states, bool unwind, string& message)
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-uInt16 Debugger::rewindStates(const uInt16 states, string& message)
+uInt16 Debugger::rewindStates(const uInt16 numStates, string& message)
{
- return windStates(states, false, message);
+ return windStates(numStates, false, message);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-uInt16 Debugger::unwindStates(const uInt16 states, string& message)
+uInt16 Debugger::unwindStates(const uInt16 numStates, string& message)
{
- return windStates(states, true, message);
+ return windStates(numStates, true, message);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
diff --git a/src/debugger/Debugger.hxx b/src/debugger/Debugger.hxx
index 01ba1f890..f3fdcd30c 100644
--- a/src/debugger/Debugger.hxx
+++ b/src/debugger/Debugger.hxx
@@ -262,8 +262,8 @@ class Debugger : public DialogContainer
int trace();
void nextScanline(int lines);
void nextFrame(int frames);
- uInt16 rewindStates(const uInt16 states, string& message);
- uInt16 unwindStates(const uInt16 states, string& message);
+ uInt16 rewindStates(const uInt16 numStates, string& message);
+ uInt16 unwindStates(const uInt16 numStates, string& message);
void toggleBreakPoint(uInt16 bp);
@@ -321,7 +321,7 @@ class Debugger : public DialogContainer
private:
// rewind/unwind n states
- uInt16 windStates(uInt16 states, bool unwind, string& message);
+ uInt16 windStates(uInt16 numStates, bool unwind, string& message);
// update the rewind/unwind button state
void updateRewindbuttons(const RewindManager& r);
diff --git a/src/debugger/DebuggerParser.cxx b/src/debugger/DebuggerParser.cxx
index 58837e270..9f90d3570 100644
--- a/src/debugger/DebuggerParser.cxx
+++ b/src/debugger/DebuggerParser.cxx
@@ -2177,7 +2177,6 @@ void DebuggerParser::executeWatch()
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// wrapper function for rewind/unwind commands
-// TODO: return and output (formatted) cycles
void DebuggerParser::executeWinds(bool unwind)
{
uInt16 states;
diff --git a/src/debugger/gui/DebuggerDialog.cxx b/src/debugger/gui/DebuggerDialog.cxx
index 8f30cfc06..8d6a07d95 100644
--- a/src/debugger/gui/DebuggerDialog.cxx
+++ b/src/debugger/gui/DebuggerDialog.cxx
@@ -97,8 +97,18 @@ void DebuggerDialog::handleKeyDown(StellaKey key, StellaMod mod)
switch(key)
{
case KBDK_R:
- if(!instance().eventHandler().kbdShift(mod))
+ if(instance().eventHandler().kbdAlt(mod))
+ doRewindAll();
+ else if(instance().eventHandler().kbdShift(mod))
+ doRewind10();
+ else
doRewind();
+ break;
+ case KBDK_Y:
+ if(instance().eventHandler().kbdAlt(mod))
+ doUnwindAll();
+ else if(instance().eventHandler().kbdShift(mod))
+ doUnwind10();
else
doUnwind();
break;
@@ -212,6 +222,30 @@ void DebuggerDialog::doUnwind()
instance().debugger().parser().run("unwind");
}
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+void DebuggerDialog::doRewind10()
+{
+ instance().debugger().parser().run("rewind #10");
+}
+
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+void DebuggerDialog::doUnwind10()
+{
+ instance().debugger().parser().run("unwind #10");
+}
+
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+void DebuggerDialog::doRewindAll()
+{
+ instance().debugger().parser().run("rewind #1000");
+}
+
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+void DebuggerDialog::doUnwindAll()
+{
+ instance().debugger().parser().run("unwind #1000");
+}
+
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void DebuggerDialog::doExitDebugger()
{
diff --git a/src/debugger/gui/DebuggerDialog.hxx b/src/debugger/gui/DebuggerDialog.hxx
index 0442870e1..996f198dc 100644
--- a/src/debugger/gui/DebuggerDialog.hxx
+++ b/src/debugger/gui/DebuggerDialog.hxx
@@ -84,6 +84,10 @@ class DebuggerDialog : public Dialog
void doAdvance();
void doRewind();
void doUnwind();
+ void doRewind10();
+ void doUnwind10();
+ void doRewindAll();
+ void doUnwindAll();
void doExitDebugger();
void doExitRom();
diff --git a/src/emucore/EventHandler.cxx b/src/emucore/EventHandler.cxx
index ac3957a8d..6d591b81d 100644
--- a/src/emucore/EventHandler.cxx
+++ b/src/emucore/EventHandler.cxx
@@ -298,16 +298,28 @@ void EventHandler::handleKeyEvent(StellaKey key, StellaMod mod, bool state)
{
switch(key)
{
- case KBDK_LEFT: // Alt-left rewinds states
+ case KBDK_LEFT: // Alt-left(-shift) rewinds 1(10) states
myOSystem.frameBuffer().resetPauseDelay();
setEventState(S_PAUSE);
- myOSystem.state().rewindState();
+ myOSystem.state().rewindState((kbdShift(mod) && state) ? 10 : 1);
break;
- case KBDK_RIGHT: // Alt-right unwinds states
+ case KBDK_RIGHT: // Alt-right(-shift) unwinds 1(10) states
myOSystem.frameBuffer().resetPauseDelay();
setEventState(S_PAUSE);
- myOSystem.state().unwindState();
+ myOSystem.state().unwindState((kbdShift(mod) && state) ? 10 : 1);
+ break;
+
+ case KBDK_DOWN: // Alt-down rewinds to start of list
+ myOSystem.frameBuffer().resetPauseDelay();
+ setEventState(S_PAUSE);
+ myOSystem.state().rewindState(1000);
+ break;
+
+ case KBDK_UP: // Alt-up rewinds to end of list
+ myOSystem.frameBuffer().resetPauseDelay();
+ setEventState(S_PAUSE);
+ myOSystem.state().unwindState(1000);
break;
default: