mirror of https://github.com/stella-emu/stella.git
Refactor StateManager and RewindManager for eventual use outside debugger.
This commit is contained in:
parent
5ca9b7912b
commit
eafe102daa
|
@ -0,0 +1,93 @@
|
|||
//============================================================================
|
||||
//
|
||||
// SSSS tt lll lll
|
||||
// SS SS tt ll ll
|
||||
// SS tttttt eeee ll ll aaaa
|
||||
// SSSS tt ee ee ll ll aa
|
||||
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
|
||||
// SS SS tt ee ll ll aa aa
|
||||
// SSSS ttt eeeee llll llll aaaaa
|
||||
//
|
||||
// Copyright (c) 1995-2017 by Bradford W. Mott, Stephen Anthony
|
||||
// and the Stella Team
|
||||
//
|
||||
// See the file "License.txt" for information on usage and redistribution of
|
||||
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||
//============================================================================
|
||||
|
||||
#include "OSystem.hxx"
|
||||
#include "Serializer.hxx"
|
||||
#include "StateManager.hxx"
|
||||
#include "TIA.hxx"
|
||||
|
||||
#include "RewindManager.hxx"
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
RewindManager::RewindManager(OSystem& system, StateManager& statemgr)
|
||||
: myOSystem(system),
|
||||
myStateManager(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];
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
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(s)
|
||||
{
|
||||
s.reset();
|
||||
if(myStateManager.saveState(s) && myOSystem.console().tia().saveDisplay(s))
|
||||
{
|
||||
// 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;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool RewindManager::rewindState()
|
||||
{
|
||||
if(mySize > 0)
|
||||
{
|
||||
mySize--;
|
||||
myTop = myTop == 0 ? MAX_SIZE - 1 : myTop - 1;
|
||||
Serializer& s = *(myStateList[myTop]);
|
||||
|
||||
s.reset();
|
||||
myStateManager.loadState(s);
|
||||
myOSystem.console().tia().loadDisplay(s);
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void RewindManager::clear()
|
||||
{
|
||||
for(int i = 0; i < MAX_SIZE; ++i)
|
||||
if(myStateList[i] != nullptr)
|
||||
myStateList[i]->reset();
|
||||
|
||||
myTop = mySize = 0;
|
||||
}
|
|
@ -0,0 +1,77 @@
|
|||
//============================================================================
|
||||
//
|
||||
// SSSS tt lll lll
|
||||
// SS SS tt ll ll
|
||||
// SS tttttt eeee ll ll aaaa
|
||||
// SSSS tt ee ee ll ll aa
|
||||
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
|
||||
// SS SS tt ee ll ll aa aa
|
||||
// SSSS ttt eeeee llll llll aaaaa
|
||||
//
|
||||
// Copyright (c) 1995-2017 by Bradford W. Mott, Stephen Anthony
|
||||
// and the Stella Team
|
||||
//
|
||||
// See the file "License.txt" for information on usage and redistribution of
|
||||
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||
//============================================================================
|
||||
|
||||
#ifndef REWIND_MANAGER_HXX
|
||||
#define REWIND_MANAGER_HXX
|
||||
|
||||
class OSystem;
|
||||
class StateManager;
|
||||
|
||||
/**
|
||||
This class is used to save (and later 'rewind') system save states.
|
||||
Essentially, it's a modified circular array-based stack that cleverly deals
|
||||
with allocation/deallocation of memory.
|
||||
|
||||
Since the stack is circular, the oldest states are automatically overwritten
|
||||
by new ones (up to MAX_SIZE, defined below).
|
||||
|
||||
@author Stephen Anthony
|
||||
*/
|
||||
class RewindManager
|
||||
{
|
||||
public:
|
||||
RewindManager(OSystem& system, StateManager& statemgr);
|
||||
virtual ~RewindManager();
|
||||
|
||||
public:
|
||||
/**
|
||||
Add a new state file with the given message; this message will be
|
||||
displayed when the state is rewound.
|
||||
|
||||
@param message Message to display when rewinding to this state
|
||||
*/
|
||||
bool addState(const string& message = "");
|
||||
|
||||
/**
|
||||
Rewind one level of the state list, and display the message associated
|
||||
with that state.
|
||||
*/
|
||||
bool rewindState();
|
||||
|
||||
bool empty() const { return mySize == 0; }
|
||||
void clear();
|
||||
|
||||
private:
|
||||
// Maximum number of states to save
|
||||
enum { MAX_SIZE = 100 };
|
||||
|
||||
OSystem& myOSystem;
|
||||
StateManager& myStateManager;
|
||||
|
||||
Serializer* myStateList[MAX_SIZE];
|
||||
uInt32 mySize, myTop;
|
||||
|
||||
private:
|
||||
// Following constructors and assignment operators not supported
|
||||
RewindManager() = delete;
|
||||
RewindManager(const RewindManager&) = delete;
|
||||
RewindManager(RewindManager&&) = delete;
|
||||
RewindManager& operator=(const RewindManager&) = delete;
|
||||
RewindManager& operator=(RewindManager&&) = delete;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -28,7 +28,7 @@
|
|||
|
||||
#include "StateManager.hxx"
|
||||
|
||||
#define STATE_HEADER "05000200state"
|
||||
#define STATE_HEADER "05000300state"
|
||||
#define MOVIE_HEADER "03030000movie"
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
@ -37,6 +37,7 @@ StateManager::StateManager(OSystem& osystem)
|
|||
myCurrentSlot(0),
|
||||
myActiveMode(kOffMode)
|
||||
{
|
||||
myRewindManager = make_unique<RewindManager>(myOSystem, *this);
|
||||
reset();
|
||||
}
|
||||
|
|
@ -20,6 +20,7 @@
|
|||
|
||||
class OSystem;
|
||||
|
||||
#include "RewindManager.hxx"
|
||||
#include "Serializer.hxx"
|
||||
|
||||
/**
|
||||
|
@ -95,6 +96,11 @@ class StateManager
|
|||
*/
|
||||
void reset();
|
||||
|
||||
/**
|
||||
The rewind facility for the state manager
|
||||
*/
|
||||
RewindManager& rewindManager() const { return *myRewindManager; }
|
||||
|
||||
private:
|
||||
enum Mode {
|
||||
kOffMode,
|
||||
|
@ -124,6 +130,9 @@ class StateManager
|
|||
Serializer myMovieWriter;
|
||||
Serializer myMovieReader;
|
||||
|
||||
// Stored savestates to be later rewound
|
||||
unique_ptr<RewindManager> myRewindManager;
|
||||
|
||||
private:
|
||||
// Following constructors and assignment operators not supported
|
||||
StateManager() = delete;
|
|
@ -10,10 +10,12 @@ MODULE_OBJS := \
|
|||
src/common/FSNodeZIP.o \
|
||||
src/common/PNGLibrary.o \
|
||||
src/common/MouseControl.o \
|
||||
src/common/RewindManager.o \
|
||||
src/common/StateManager.o \
|
||||
src/common/ZipHandler.o
|
||||
|
||||
MODULE_DIRS += \
|
||||
src/common
|
||||
|
||||
# Include common rules
|
||||
# Include common rules
|
||||
include $(srcdir)/common.rules
|
||||
|
|
|
@ -152,7 +152,6 @@ void Debugger::initialize()
|
|||
myDialog = new DebuggerDialog(myOSystem, *this, 0, 0, myWidth, myHeight);
|
||||
myBaseDialog = myDialog;
|
||||
|
||||
myRewindManager = make_unique<RewindManager>(myOSystem, myDialog->rewindButton());
|
||||
myCartDebug->setDebugWidget(&(myDialog->cartDebug()));
|
||||
}
|
||||
|
||||
|
@ -433,12 +432,16 @@ void Debugger::nextFrame(int frames)
|
|||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool Debugger::rewindState()
|
||||
{
|
||||
RewindManager& r = myOSystem.state().rewindManager();
|
||||
|
||||
mySystem.clearDirtyPages();
|
||||
|
||||
unlockBankswitchState();
|
||||
bool result = myRewindManager->rewindState();
|
||||
bool result = r.rewindState();
|
||||
lockBankswitchState();
|
||||
|
||||
myDialog->rewindButton().setEnabled(!r.empty());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -476,7 +479,12 @@ void Debugger::saveOldState(bool addrewind)
|
|||
myTiaDebug->saveOldState();
|
||||
|
||||
// Add another rewind level to the Undo list
|
||||
if(addrewind) myRewindManager->addState();
|
||||
if(addrewind)
|
||||
{
|
||||
RewindManager& r = myOSystem.state().rewindManager();
|
||||
r.addState();
|
||||
myDialog->rewindButton().setEnabled(!r.empty());
|
||||
}
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
@ -485,8 +493,11 @@ void Debugger::setStartState()
|
|||
// Lock the bus each time the debugger is entered, so we don't disturb anything
|
||||
lockBankswitchState();
|
||||
|
||||
// Start a new rewind list
|
||||
myRewindManager->clear();
|
||||
// If rewinding is not enabled, always start the debugger with a clean list
|
||||
RewindManager& r = myOSystem.state().rewindManager();
|
||||
if(0) // FIXME
|
||||
r.clear();
|
||||
myDialog->rewindButton().setEnabled(!r.empty());
|
||||
|
||||
// Save initial state, but don't add it to the rewind list
|
||||
saveOldState(false);
|
||||
|
@ -634,90 +645,3 @@ void Debugger::unlockBankswitchState()
|
|||
mySystem.unlockDataBus();
|
||||
myConsole.cartridge().unlockBank();
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
Debugger::RewindManager::RewindManager(OSystem& system, ButtonWidget& button)
|
||||
: myOSystem(system),
|
||||
myRewindButton(button),
|
||||
mySize(0),
|
||||
myTop(0)
|
||||
{
|
||||
for(int i = 0; i < MAX_SIZE; ++i)
|
||||
myStateList[i] = nullptr;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
Debugger::RewindManager::~RewindManager()
|
||||
{
|
||||
for(int i = 0; i < MAX_SIZE; ++i)
|
||||
delete myStateList[i];
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool Debugger::RewindManager::addState()
|
||||
{
|
||||
// Create a new Serializer object if we need one
|
||||
if(myStateList[myTop] == nullptr)
|
||||
myStateList[myTop] = new Serializer();
|
||||
Serializer& s = *(myStateList[myTop]);
|
||||
|
||||
if(s)
|
||||
{
|
||||
s.reset();
|
||||
if(myOSystem.state().saveState(s) && myOSystem.console().tia().saveDisplay(s))
|
||||
{
|
||||
// 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;
|
||||
myRewindButton.setEnabled(true);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool Debugger::RewindManager::rewindState()
|
||||
{
|
||||
if(mySize > 0)
|
||||
{
|
||||
mySize--;
|
||||
myTop = myTop == 0 ? MAX_SIZE - 1 : myTop - 1;
|
||||
Serializer& s = *(myStateList[myTop]);
|
||||
|
||||
s.reset();
|
||||
myOSystem.state().loadState(s);
|
||||
myOSystem.console().tia().loadDisplay(s);
|
||||
|
||||
if(mySize == 0)
|
||||
myRewindButton.setEnabled(false);
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool Debugger::RewindManager::empty()
|
||||
{
|
||||
return mySize == 0;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void Debugger::RewindManager::clear()
|
||||
{
|
||||
for(int i = 0; i < MAX_SIZE; ++i)
|
||||
if(myStateList[i] != nullptr)
|
||||
myStateList[i]->reset();
|
||||
|
||||
myTop = mySize = 0;
|
||||
|
||||
// We use Widget::clearFlags here instead of Widget::setEnabled(),
|
||||
// since the latter implies an immediate draw/update, but this method
|
||||
// might be called before any UI exists
|
||||
// TODO - fix this deficiency in the UI core; we shouldn't have to worry
|
||||
// about such things at this level
|
||||
myRewindButton.clearFlags(WIDGET_ENABLED);
|
||||
}
|
||||
|
|
|
@ -26,7 +26,6 @@ class TiaZoomWidget;
|
|||
class EditTextWidget;
|
||||
class RomWidget;
|
||||
class Expression;
|
||||
class Serializer;
|
||||
class PackedBitArray;
|
||||
class PromptWidget;
|
||||
class ButtonWidget;
|
||||
|
@ -295,38 +294,6 @@ class Debugger : public DialogContainer
|
|||
uInt32 myWidth;
|
||||
uInt32 myHeight;
|
||||
|
||||
// Class holding all rewind state functionality in the debugger
|
||||
// Essentially, it's a modified circular array-based stack
|
||||
// that cleverly deals with allocation/deallocation of memory
|
||||
class RewindManager
|
||||
{
|
||||
public:
|
||||
RewindManager(OSystem& system, ButtonWidget& button);
|
||||
virtual ~RewindManager();
|
||||
|
||||
public:
|
||||
bool addState();
|
||||
bool rewindState();
|
||||
bool empty();
|
||||
void clear();
|
||||
|
||||
private:
|
||||
enum { MAX_SIZE = 100 };
|
||||
OSystem& myOSystem;
|
||||
ButtonWidget& myRewindButton;
|
||||
Serializer* myStateList[MAX_SIZE];
|
||||
uInt32 mySize, myTop;
|
||||
|
||||
private:
|
||||
// Following constructors and assignment operators not supported
|
||||
RewindManager() = delete;
|
||||
RewindManager(const RewindManager&) = delete;
|
||||
RewindManager(RewindManager&&) = delete;
|
||||
RewindManager& operator=(const RewindManager&) = delete;
|
||||
RewindManager& operator=(RewindManager&&) = delete;
|
||||
};
|
||||
unique_ptr<RewindManager> myRewindManager;
|
||||
|
||||
private:
|
||||
// Following constructors and assignment operators not supported
|
||||
Debugger() = delete;
|
||||
|
|
|
@ -73,7 +73,6 @@ MODULE_OBJS := \
|
|||
src/emucore/Serializer.o \
|
||||
src/emucore/Settings.o \
|
||||
src/emucore/Switches.o \
|
||||
src/emucore/StateManager.o \
|
||||
src/emucore/System.o \
|
||||
src/emucore/TIASnd.o \
|
||||
src/emucore/TIASurface.o \
|
||||
|
|
Loading…
Reference in New Issue