Added 'continuous snapshot mode', currently tied to the Shift-F12

key.  This enables automatically taking snapshots every X seconds
while in emulation mode.  The interval (in seconds) can be set
with the 'ssdelay' commandline argument.

Some minor cleanups to the EventHandler methods, making them
const when possible.

Added latest DPC+ changes from Spiceware.

Fixed issue with ROMs that run entirely from ZP RAM; no disassembly
was being generated when entering the debugger.  For now, this
special case is detected, and the disassembly is generated for
the code that ran before the PC entered ZP RAM space.  Eventually,
this will go away when the Distella fully supports disassembling
below 0x1000.


git-svn-id: svn://svn.code.sf.net/p/stella/code/trunk@2009 8b62c5a3-ac7e-4cc8-8f21-d9a121418aba
This commit is contained in:
stephena 2010-04-14 15:41:42 +00:00
parent e37fa7f520
commit d0391c28f2
10 changed files with 139 additions and 51 deletions

View File

@ -133,6 +133,12 @@
This toggles showing of UI messages overlaid on the screen.
Critical messages are still shown, though.
* Added ability to take multiple snapshots in a given interval every
x seconds. This is currently tied to the 'Shift-F12' key and is not
remappable (for now). The interval can be set with the 'ssdelay'
commandline argument, and defaults to 2. Currently, this can't be
changed from within the UI.
* Many changes to the FrameBuffer and UI code for 'smaller' systems.
Stella will now scale correctly to small screens, down to 320x240
(which is the absolute lower limit supported). Related to this,

View File

@ -918,6 +918,11 @@
snapshot in unscaled (1x) mode.</td>
</tr>
<tr>
<td><pre>-ssdelay &lt;delay&gt;</pre></td>
<td>Set the delay in seconds between taking snapshots in continuous snapshot mode (currently, 1 - 10).</td>
</tr>
<tr>
<td><pre>-rominfo &lt;rom&gt;</pre></td>
<td>Display detailed information about the given ROM, and then exit
@ -2217,6 +2222,12 @@
<td>Control + l</td>
<td>Control + l</td>
</tr>
<tr>
<td>Save continuous PNG snapshots</td>
<td>Shift-F12</td>
<td>Shift-F12</td>
</tr>
</table>
<p><b>UI keys in Text Editing areas (cannot be remapped)</b></p>

View File

@ -206,30 +206,40 @@ bool CartDebug::disassemble(const string& resolvedata, bool force)
uInt16 PC = myDebugger.cpuDebug().pc();
int pcline = addressToLine(PC);
bool changed = (force || myConsole.cartridge().bankChanged() ||
(pcline == -1 && (PC & 0x1000)) ||
mySystem.isPageDirty(0x1000, 0x1FFF));
(pcline == -1) || mySystem.isPageDirty(0x1000, 0x1FFF));
if(changed)
{
// Look at previous accesses to this bank to begin
// If no previous address exists, use the current program counter
uInt16 start = myStartAddresses[getBank()];
if(start == 0 || pcline == -1)
if(start == 0 || (pcline == -1 && (PC & 0x1000)))
start = myStartAddresses[getBank()] = PC;
// For now, DiStella can't handle address space below 0x1000
if(!(start & 0x1000))
// However, we want to disassemble at least once, otherwise carts
// that run entirely from ZP RAM will have an empty disassembly
// TODO - this will be removed once Distella properly supports
// access below 0x1000
uInt16 search = PC;
if(!(PC & 0x1000))
{
if(myDisassembly.size() == 0)
search = start;
else
return false;
}
// Check whether to use the 'resolvedata' functionality from Distella
if(resolvedata == "never")
fillDisassemblyList(start, false, PC);
fillDisassemblyList(start, false, search);
else if(resolvedata == "always")
fillDisassemblyList(start, true, PC);
fillDisassemblyList(start, true, search);
else // 'auto'
{
// First try with resolvedata on, then turn off if PC isn't found
if(!fillDisassemblyList(start, true, PC))
fillDisassemblyList(start, false, PC);
if(!fillDisassemblyList(start, true, search))
fillDisassemblyList(start, false, search);
}
}

View File

@ -151,7 +151,7 @@ inline void CartridgeDPCPlus::updateMusicModeDataFetchers()
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
inline void CartridgeDPCPlus::writeByte(uInt8 value)
{
switch (mySelectByte)
switch (mySelectByte & 0x7F)
{
case 0x00:
{
@ -214,6 +214,9 @@ inline void CartridgeDPCPlus::writeByte(uInt8 value)
break;
}
}
if (mySelectByte & 0x80)
mySelectByte++;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -288,11 +291,10 @@ uInt8 CartridgeDPCPlus::peek(uInt16 address)
// Update the music data fetchers (counter & flag)
updateMusicModeDataFetchers();
uInt32 i = 0;
i = myMusicVolume + ((myMusicVolume >> 12) * (uInt8) (myMusicWaveforms[0] >> 31)) +
((myMusicVolume >> 16) * (uInt8) (myMusicWaveforms[1] >> 31)) +
((myMusicVolume >> 24) * (uInt8) (myMusicWaveforms[2] >> 31));
uInt32 i = myMusicVolume +
(((myMusicWaveforms[0] >> 31) & 1) ? (myMusicVolume >> 12): 0) +
(((myMusicWaveforms[1] >> 31) & 1) ? (myMusicVolume >> 16): 0) +
(((myMusicWaveforms[2] >> 31) & 1) ? (myMusicVolume >> 24): 0);
result = (uInt8)i;
break;

View File

@ -170,6 +170,8 @@ void EventHandler::reset(State state)
setEventState(state);
myEvent->clear();
myOSystem->state().reset();
setContinuousSnapshots(0);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -448,6 +450,26 @@ void EventHandler::poll(uInt64 time)
case SDLK_l:
myOSystem->frameBuffer().toggleFrameStats();
break;
case SDLK_F12: // TODO - make this remappable
if(myContSnapshotInterval == 0)
{
ostringstream buf;
uInt32 delay = myOSystem->settings().getInt("ssdelay");
buf << "Enabling shotshots in " << delay << " second intervals";
myOSystem->frameBuffer().showMessage(buf.str());
setContinuousSnapshots(delay);
}
else
{
ostringstream buf;
buf << "Disabling snapshots, generated "
<< (myContSnapshotCounter / myContSnapshotInterval)
<< " files";
myOSystem->frameBuffer().showMessage(buf.str());
setContinuousSnapshots(0);
}
break;
#if 0
// FIXME - these will be removed when a UI is added for event recording
case SDLK_e: // Alt-e starts/stops event recording
@ -759,6 +781,11 @@ void EventHandler::poll(uInt64 time)
for(unsigned int i = 0; i < cheats.size(); i++)
cheats[i]->evaluate();
#endif
// Handle continuous snapshots
if(myContSnapshotInterval > 0 &&
(++myContSnapshotCounter % myContSnapshotInterval == 0))
takeSnapshot(myContSnapshotCounter / myContSnapshotInterval);
}
}
else if(myOverlay)
@ -1680,7 +1707,7 @@ void EventHandler::saveJoyHatMapping()
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool EventHandler::isValidList(string& list, IntArray& map, uInt32 length)
bool EventHandler::isValidList(string& list, IntArray& map, uInt32 length) const
{
string key;
Event::Type event;
@ -1701,7 +1728,7 @@ bool EventHandler::isValidList(string& list, IntArray& map, uInt32 length)
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
inline bool EventHandler::eventIsAnalog(Event::Type event)
inline bool EventHandler::eventIsAnalog(Event::Type event) const
{
switch((int)event)
{
@ -1716,7 +1743,7 @@ inline bool EventHandler::eventIsAnalog(Event::Type event)
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
StringList EventHandler::getActionList(EventMode mode)
StringList EventHandler::getActionList(EventMode mode) const
{
StringList l;
@ -1738,7 +1765,7 @@ StringList EventHandler::getActionList(EventMode mode)
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Event::Type EventHandler::eventAtIndex(int idx, EventMode mode)
Event::Type EventHandler::eventAtIndex(int idx, EventMode mode) const
{
switch(mode)
{
@ -1761,7 +1788,7 @@ Event::Type EventHandler::eventAtIndex(int idx, EventMode mode)
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
string EventHandler::actionAtIndex(int idx, EventMode mode)
string EventHandler::actionAtIndex(int idx, EventMode mode) const
{
switch(mode)
{
@ -1784,7 +1811,7 @@ string EventHandler::actionAtIndex(int idx, EventMode mode)
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
string EventHandler::keyAtIndex(int idx, EventMode mode)
string EventHandler::keyAtIndex(int idx, EventMode mode) const
{
switch(mode)
{
@ -1807,11 +1834,12 @@ string EventHandler::keyAtIndex(int idx, EventMode mode)
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void EventHandler::takeSnapshot()
void EventHandler::takeSnapshot(uInt32 number)
{
// Figure out the correct snapshot name
string filename;
string sspath = myOSystem->snapshotDir();
bool showmessage = number == 0;
if(sspath.length() > 0)
if(sspath.substr(sspath.length()-1) != BSPF_PATH_SEPARATOR)
@ -1819,7 +1847,13 @@ void EventHandler::takeSnapshot()
sspath += myOSystem->console().properties().get(Cartridge_Name);
// Check whether we want multiple snapshots created
if(!myOSystem->settings().getBool("sssingle"))
if(number > 0)
{
ostringstream buf;
buf << sspath << "_" << number << ".png";
filename = buf.str();
}
else if(!myOSystem->settings().getBool("sssingle"))
{
// Determine if the file already exists, checking each successive filename
// until one doesn't exist
@ -1848,6 +1882,7 @@ void EventHandler::takeSnapshot()
string msg = Snapshot::savePNG(myOSystem->frameBuffer(),
myOSystem->console().tia(),
myOSystem->console().properties(), filename);
if(showmessage)
myOSystem->frameBuffer().showMessage(msg);
}
else
@ -1860,6 +1895,7 @@ void EventHandler::takeSnapshot()
// Re-enable old messages
myOSystem->frameBuffer().enableMessages(true);
if(showmessage)
myOSystem->frameBuffer().showMessage(msg);
}
}
@ -1882,6 +1918,13 @@ void EventHandler::setPaddleMode(int num, bool showmessage)
myMouseEnabled = false;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void EventHandler::setContinuousSnapshots(uInt32 interval)
{
myContSnapshotInterval = myOSystem->frameRate() * interval;
myContSnapshotCounter = 0;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void EventHandler::enterMenuMode(State state)
{

View File

@ -163,7 +163,7 @@ class EventHandler
@return The State type
*/
inline State state() { return myState; }
inline State state() const { return myState; }
/**
Resets the state machine of the EventHandler to the defaults
@ -185,7 +185,16 @@ class EventHandler
*/
void setPaddleMode(int num, bool showmessage = false);
inline bool kbdAlt(int mod)
/**
Set the number of seconds between taking a snapshot in
continuous snapshot mode. Setting an interval of 0 disables
continuous snapshots.
@param interval Interval in seconds between snapshots
*/
void setContinuousSnapshots(uInt32 interval);
inline bool kbdAlt(int mod) const
{
#ifndef MAC_OSX
return (mod & KMOD_ALT);
@ -194,12 +203,12 @@ class EventHandler
#endif
}
inline bool kbdControl(int mod)
inline bool kbdControl(int mod) const
{
return (mod & KMOD_CTRL) > 0;
}
inline bool kbdShift(int mod)
inline bool kbdShift(int mod) const
{
return (mod & KMOD_SHIFT);
}
@ -208,7 +217,7 @@ class EventHandler
void leaveMenuMode();
bool enterDebugMode();
void leaveDebugMode();
void takeSnapshot();
void takeSnapshot(uInt32 number = 0);
/**
Send an event directly to the event handler.
@ -219,24 +228,24 @@ class EventHandler
*/
void handleEvent(Event::Type type, Int32 value);
inline bool frying() { return myFryingFlag; }
inline bool frying() const { return myFryingFlag; }
inline SDL_Joystick* getJoystick(int i) { return ourJoysticks[i].stick; }
inline SDL_Joystick* getJoystick(int i) const { return ourJoysticks[i].stick; }
StringList getActionList(EventMode mode);
StringList getActionList(EventMode mode) const;
inline Event::Type eventForKey(int key, EventMode mode)
inline Event::Type eventForKey(int key, EventMode mode) const
{ return myKeyTable[key][mode]; }
inline Event::Type eventForJoyButton(int stick, int button, EventMode mode)
inline Event::Type eventForJoyButton(int stick, int button, EventMode mode) const
{ return myJoyTable[stick][button][mode]; }
inline Event::Type eventForJoyAxis(int stick, int axis, int value, EventMode mode)
inline Event::Type eventForJoyAxis(int stick, int axis, int value, EventMode mode) const
{ return myJoyAxisTable[stick][axis][(value > 0)][mode]; }
inline Event::Type eventForJoyHat(int stick, int hat, int value, EventMode mode)
inline Event::Type eventForJoyHat(int stick, int hat, int value, EventMode mode) const
{ return myJoyHatTable[stick][hat][value][mode]; }
Event::Type eventAtIndex(int idx, EventMode mode);
string actionAtIndex(int idx, EventMode mode);
string keyAtIndex(int idx, EventMode mode);
Event::Type eventAtIndex(int idx, EventMode mode) const;
string actionAtIndex(int idx, EventMode mode) const;
string keyAtIndex(int idx, EventMode mode) const;
/**
Bind a key to an event/action and regenerate the mapping array(s)
@ -384,7 +393,7 @@ class EventHandler
@return True if valid list, else false
*/
bool isValidList(string& list, IntArray& map, uInt32 length);
bool isValidList(string& list, IntArray& map, uInt32 length) const;
/**
Tests if a given event should use continuous/analog values.
@ -392,7 +401,7 @@ class EventHandler
@param event The event to test for analog processing
@return True if analog, else false
*/
inline bool eventIsAnalog(Event::Type event);
inline bool eventIsAnalog(Event::Type event) const;
void setEventState(State state);
@ -490,6 +499,10 @@ class EventHandler
// a Ctrl combo when it isn't wanted)
bool myUseCtrlKeyFlag;
// Used for continuous snapshot mode
uInt32 myContSnapshotInterval;
uInt32 myContSnapshotCounter;
// Indicates which paddle the mouse currently emulates
Int8 myPaddleMode;

View File

@ -47,8 +47,7 @@ FrameBuffer::FrameBuffer(OSystem* osystem)
myUsePhosphor(false),
myPhosphorBlend(77),
myInitializedCount(0),
myPausedCount(0),
mySurfaceCount(0)
myPausedCount(0)
{
myMsg.surface = myStatsMsg.surface = NULL;
myMsg.surfaceID = myStatsMsg.surfaceID = -1;
@ -317,7 +316,7 @@ void FrameBuffer::enableMessages(bool enable)
{
if(enable)
{
// Only re-anable frame stats if they were already enabled before
// Only re-enable frame stats if they were already enabled before
myStatsMsg.enabled = myOSystem->settings().getBool("stats");
}
else
@ -483,11 +482,10 @@ int FrameBuffer::allocateSurface(int w, int h, bool useBase)
FBSurface* surface = createSurface(w, h, useBase);
// Add it to the list
mySurfaceList.insert(make_pair(mySurfaceCount, surface));
mySurfaceCount++;
mySurfaceList.insert(make_pair(mySurfaceList.size(), surface));
// Return a reference to it
return mySurfaceCount - 1;
return mySurfaceList.size() - 1;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

View File

@ -575,7 +575,6 @@ class FrameBuffer
// Holds a reference to all the surfaces that have been created
map<int,FBSurface*> mySurfaceList;
int mySurfaceCount;
// Holds static strings for the remap menu (emulation and menu events)
static GraphicsMode ourGraphicsModes[GFX_NumModes];

View File

@ -92,6 +92,7 @@ Settings::Settings(OSystem* osystem)
setInternal("ssdir", "");
setInternal("sssingle", "false");
setInternal("ss1x", "false");
setInternal("ssdelay", "2");
// Config files and paths
setInternal("romdir", "~");
@ -269,6 +270,10 @@ void Settings::validate()
if(i < 1) setInternal("pspeed", "1");
else if(i > 15) setInternal("pspeed", "15");
i = getInt("ssdelay");
if(i < 1) setInternal("ssdelay", "2");
else if(i > 10) setInternal("ssdelay", "10");
s = getString("palette");
if(s != "standard" && s != "z26" && s != "user")
setInternal("palette", "standard");
@ -373,6 +378,7 @@ void Settings::usage()
<< " -ssdir <path> The directory to save snapshot files to\n"
<< " -sssingle <1|0> Generate single snapshot instead of many\n"
<< " -ss1x <1|0> Generate TIA snapshot in 1x mode (ignore scaling/effects)\n"
<< " -ssdelay <delay> Number of seconds between snapshots in continuous snapshot mode\n"
<< endl
<< " -rominfo <rom> Display detailed information for the given ROM\n"
<< " -listrominfo Display contents of stella.pro, one line per ROM entry\n"