state compression improved

RewindManager class refactored for multiple rewinds/unwinds
additional keys for faster rewinding added
docs updated
This commit is contained in:
thrust26 2017-12-14 14:25:02 +01:00
parent 984e304f43
commit ba9d809109
13 changed files with 206 additions and 81 deletions

View File

@ -316,9 +316,11 @@ used.</p>
</ul>
<p>The larger button at the left top (labeled '&lt;') 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 '&gt;') performs the unwind operation, which will undo the
previous rewind operation. The rewind buffer is 100 levels deep by default.<p>
previous rewind operation. The rewind buffer is 100 levels deep by default, the
size can be configured e.g. in the
<b><a href="index.html#Debugger">Developer Settings</a> - States</b> dialog.<p>
<p>The other operations are Step, Trace, Scan+1, Frame+1 and Exit (debugger).</p>
@ -347,11 +349,27 @@ previous rewind operation. The rewind buffer is 100 levels deep by default.<p>
</tr>
<tr>
<td>Control-r</td>
<td>Rewind</td>
<td>Rewind 1</td>
</tr>
<tr>
<td>Shift-Control-r</td>
<td>Unwind</td>
<td>Control-Shift-r</td>
<td>Rewind 10</td>
</tr>
<tr>
<td>Control-Alt-r</td>
<td>Rewind all</td>
</tr>
<tr>
<td>Control-y</td>
<td>Unwind 1</td>
</tr>
<tr>
<td>Control-Shift-y</td>
<td>Unwind 10</td>
</tr>
<tr>
<td>Control-Alt-y</td>
<td>Unwind all</td>
</tr>
<tr>
<td>Backquote (`)</td>

View File

@ -1622,11 +1622,31 @@
<td>Alt + Left arrow</td>
<td>Cmd + Left arrow</td>
</tr>
<tr>
<td>Rewind by 10 states (pauses emulation)</td>
<td>Shift-Alt + Left arrow</td>
<td>Shift-Cmd + Left arrow</td>
</tr>
<tr>
<td>Rewind all states (pauses emulation)</td>
<td>Alt + Down arrow</td>
<td>Cmd + Down arrow</td>
</tr>
<tr>
<td>Unwind by one state (pauses emulation)</td>
<td>Alt + Right arrow</td>
<td>Cmd + Right arrow</td>
</tr>
<tr>
<td>Unwind by 10 states (pauses emulation)</td>
<td>Shift-Alt + Right arrow</td>
<td>Shift-Cmd + Right arrow</td>
</tr>
<tr>
<td>Unwind all states (pauses emulation)</td>
<td>Alt + Up arrow</td>
<td>Cmd + Up arrow</td>
</tr>
</table>
<p><b>UI keys in Text Editing areas (cannot be remapped)</b></p>

View File

@ -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.

View File

@ -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<RewindState>::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();

View File

@ -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<RewindState, INITIAL_SIZE> 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

View File

@ -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);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

View File

@ -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.

View File

@ -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);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

View File

@ -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);

View File

@ -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;

View File

@ -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()
{

View File

@ -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();

View File

@ -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: