Removed 'md5instate' commandline argument (it was previously added

post-3.0), and reworked how state files are accessed.  The cart type
now determines if a state file is valid, meaning developers can use
one state file across multiple builds of their program.

Added 'runtopc' debugger command, and associated UI item in the
RomWidget area.  This steps the code until the PC matches the given
value.

Added '16in1' bankswitch scheme, which is useful for ROMs named
'128-in-1' in RomHunter database.  Also, all multicart schemes now
show the current ROM onscreen while switching between them.

Fixed bug in Serializer class when accessing files in read-only mode.
Such files would be created and set to zero size, even if only
reading was requested.


git-svn-id: svn://svn.code.sf.net/p/stella/code/trunk@1997 8b62c5a3-ac7e-4cc8-8f21-d9a121418aba
This commit is contained in:
stephena 2010-04-09 20:13:12 +00:00
parent af14afd274
commit 10c82a9457
22 changed files with 235 additions and 129 deletions

View File

@ -21,8 +21,9 @@
* Integrated Distella disassembler, completely replacing the previous
disassembler. The entire infrastructure has not been completely
ported yet. As a result, labels defined by the user or from a
DASM symbol file aren't actually used in the disassembly. This will
be addressed in a future release.
DASM symbol file aren't actually used in the disassembly, and almost
all distella config options are disabled. These will be addressed in
a future release.
* Completely reworked the debugger cartridge interface, so that
the disassembly is dynamic (ie, the debugger tracks when cart address
@ -37,10 +38,6 @@
bug in disassembler view when a failure to patch a ROM still showed
the (incorrect) patched results.
* Added debugger pseudo-register '_rwport', which traps on a read from
the write port. This differentiates from reads that are normally
part of a write cycle (ie, it traps only on inadvertent reads).
* Added ability to disable TIA object collisions, independent of
enabling/disabling the objects. Previously, one had to completely
disable an object to avoid collisions, but now an object can be
@ -48,18 +45,33 @@
actions are tied to the same keys as the enable ones, except the
'Shift' key is also used.
* Added support for bankswitching scheme DPC+, thanks to Darrell Spice
Jr and Fred Quimby.
* Added 'DPC+' bankswitching scheme, thanks to Darrell Spice Jr and
Fred Quimby.
* Added '16in1' bankswitching scheme, which works with various
ROMs labeled '128-in-1' (the database has been updated for these).
Related to this, switching between multicart ROMs for 2in1, 4in1,
8in1, 16in1 and 32in1 now shows a UI message indicating which
ROM is active.
* Reverted some of the TIA improvements with respect to 'starfield
effect' as seen in "Cosmic Ark" and "Stay Frosty". The emulation is
now more accurate as compared to the majority of consoles in use.
* Added debugger pseudo-register '_rwport', which traps on a read from
the write port. This differentiates from reads that are normally
part of a write cycle (ie, it traps only on inadvertent reads).
* Added 'autocode' commandline argument and associated UI item, used
to set the "automatic code determination" config option in Distella.
* Removed the 'loadlst' command and the ability to use a DASM .lst file.
With the recent disassembler improvements, this no longer makes sense.
* Added 'runtopc' debugger command, used to step until encountering the
given program counter. This is also available in the ROM disassembly
UI.
* Removed the 'loadlst' debugger command and the ability to use a
DASM .lst file. With the recent disassembler improvements, this
support is no longer feasible.
* Modified 'disasm' debugger command to accept a second argument
indicating the number of lines to disassemble.
@ -76,7 +88,7 @@
The application is now known as 'Stella' (instead of StellaOSX).
Two versions are available: the first is a 32-bit Universal Binary
for OSX 10.4 - 10.6, and the second is a 32/64-bit Intel-only for
for OSX 10.4 - 10.6, and the second is 32/64-bit Intel-only for
OSX 10.5 - 10.6 (64-bit requires 10.6). The Intel version is
compiled with the very latest compiler (Clang), resulting in
better performance.
@ -126,11 +138,12 @@
emulation of the behaviour of floating TIA pins is also much more
accurate.
* Added 'md5instate' commandline argument, which toggles saving the
MD5sum of the ROM with a save state. When disabled, a state file
is no longer tied to the exact instance of the ROM which created
it (useful during development when a small change in program code
would render a state file useless).
* Reworked state files so that they're associated with the cartridge
type used, not the MD5sum of the ROM. This is useful for developers,
since the same state file can now be loaded from different ROMs,
as long as the cart type stays the same. This also fixes a bug
where loading from a non-existent state file could cause Stella
to crash.
* Fixed bug in certain editable text fields, where pressing Return/Enter
would disable any further input.

View File

@ -883,12 +883,6 @@
saving a ROM state file.</td>
</tr>
<tr>
<td><pre>-md5instate &lt;1|0&gt;</pre></td>
<td>When loading state files, check if the MD5 of the current ROM matches that
saved in the state file. If disabled, no such check is performed.</td>
</tr>
<tr>
<td><pre>-stats &lt;1|0&gt;</pre></td>
<td>Overlay console info on the TIA image during emulation.</td>

View File

@ -1165,6 +1165,37 @@ void DebuggerParser::executeRunTo()
commandResult = buf.str();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// "runtopc"
void DebuggerParser::executeRunToPc()
{
ostringstream buf;
const CartDebug& cartdbg = debugger->cartDebug();
const CartDebug::DisassemblyList& list = cartdbg.disassemblyList();
uInt32 count = 0;
bool done = false;
do {
debugger->step();
// Update romlist to point to current PC
int pcline = cartdbg.addressToLine(debugger->cpuDebug().pc());
done = (pcline >= 0) && (list[pcline].address == args[0]);
++count;
} while(!done && count < list.size());
if(done)
buf << "set PC to " << hex << args[0] << " in "
<< debugger->valueToString(count, kBASE_10)
<< " disassembled instructions";
else
buf << "PC " << hex << args[0] << " not reached or found in "
<< debugger->valueToString(count, kBASE_10)
<< " disassembled instructions";
commandResult = buf.str();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// "s"
void DebuggerParser::executeS()
@ -1671,6 +1702,15 @@ DebuggerParser::Command DebuggerParser::commands[kNumCommands] = {
&DebuggerParser::executeRunTo
},
{
"runtopc",
"Run until PC is set to this value",
true,
true,
{ kARG_WORD, kARG_END_ARGS },
&DebuggerParser::executeRunToPc
},
{
"s",
"Set Stack Pointer to value xx",

View File

@ -79,8 +79,8 @@ class DebuggerParser
private:
enum {
kNumCommands = 55,
kMAX_ARG_TYPES = 10 // TODO: put in separate header file Command.hxx
kNumCommands = 56,
kMAX_ARG_TYPES = 10
};
// Constants for argument processing
@ -166,6 +166,7 @@ class DebuggerParser
void executeRom();
void executeRun();
void executeRunTo();
void executeRunToPc();
void executeS();
void executeSave();
void executeSaverom();

View File

@ -62,6 +62,7 @@ RomListWidget::RomListWidget(GuiObject* boss, const GUI::Font& font,
// l.push_back("Add bookmark");
l.push_back("Save ROM", "saverom");
l.push_back("Set PC", "setpc");
l.push_back("RunTo PC", "runtopc");
myMenu = new ContextMenu(this, font, l);
// Take advantage of a wide debugger window when possible
@ -213,10 +214,12 @@ void RomListWidget::handleMouseDown(int x, int y, int button, int clickCount)
if (!isEnabled())
return;
// Grab right mouse button for context menu, send left to base class
// Grab right mouse button for context menu, left for selection/edit mode
if(button == 2)
{
// Add menu at current x,y mouse location
// Set selected and add menu at current x,y mouse location
_selectedItem = findItem(x, y);
scrollToSelected();
myMenu->show(x + getAbsX(), y + getAbsY());
}
else

View File

@ -170,6 +170,8 @@ void RomWidget::handleCommand(CommandSender* sender, int cmd, int data, int id)
}
else if(rmb == "setpc")
setPC(myRomList->getSelected());
else if(rmb == "runtopc")
runtoPC(myRomList->getSelected());
break;
}
@ -221,6 +223,21 @@ void RomWidget::setPC(int disasm_line)
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void RomWidget::runtoPC(int disasm_line)
{
const CartDebug::DisassemblyList& list =
instance().debugger().cartDebug().disassemblyList();
if(disasm_line >= (int)list.size()) return;
if(list[disasm_line].address != 0)
{
ostringstream command;
command << "runtopc #" << list[disasm_line].address;
instance().debugger().run(command.str());
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void RomWidget::patchROM(int disasm_line, const string& bytes)
{

View File

@ -48,6 +48,7 @@ class RomWidget : public Widget, public CommandSender
private:
void setBreak(int disasm_line, bool state);
void setPC(int disasm_line);
void runtoPC(int disasm_line);
void patchROM(int disasm_line, const string& bytes);
void saveROM(const string& rom);

View File

@ -59,9 +59,10 @@
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Cartridge* Cartridge::create(const uInt8* image, uInt32 size, string& md5,
string& id, string type, Settings& settings)
string& dtype, string& id, Settings& settings)
{
Cartridge* cartridge = 0;
string type = dtype;
// First consider the ROMs that are special and don't have a properties entry
// Hopefully this list will be very small
@ -72,6 +73,7 @@ Cartridge* Cartridge::create(const uInt8* image, uInt32 size, string& md5,
// These two ROMs are normal 8K images, except they must be initialized
// from the opposite bank compared to normal ones
type = "F8 swapped";
dtype = type;
}
// Collect some info about the ROM
@ -97,6 +99,7 @@ Cartridge* Cartridge::create(const uInt8* image, uInt32 size, string& md5,
// Make sure we have a valid sized image
if(size == 2*2048 || size == 2*4096 || size == 2*8192 || size == 2*16384)
{
dtype = type;
type = createFromMultiCart(image, size, 2, md5, id, settings);
buf << id;
}
@ -107,6 +110,7 @@ Cartridge* Cartridge::create(const uInt8* image, uInt32 size, string& md5,
// Make sure we have a valid sized image
if(size == 4*2048 || size == 4*4096 || size == 4*8192)
{
dtype = type;
type = createFromMultiCart(image, size, 4, md5, id, settings);
buf << id;
}
@ -116,15 +120,27 @@ Cartridge* Cartridge::create(const uInt8* image, uInt32 size, string& md5,
// Make sure we have a valid sized image
if(size == 8*2048 || size == 8*4096 || size == 8*8192)
{
dtype = type;
type = createFromMultiCart(image, size, 8, md5, id, settings);
buf << id;
}
}
else if(type == "16IN1")
{
// Make sure we have a valid sized image
if(size == 16*2048 || size == 16*4096 || size == 16*8192)
{
dtype = type;
type = createFromMultiCart(image, size, 16, md5, id, settings);
buf << id;
}
}
else if(type == "32IN1")
{
// Make sure we have a valid sized image
if(size == 32*2048 || size == 32*4096)
{
dtype = type;
type = createFromMultiCart(image, size, 32, md5, id, settings);
buf << id;
}

View File

@ -57,12 +57,14 @@ class Cartridge : public Device
@param size The size of the ROM image
@param md5 The md5sum for the given ROM image (can be updated)
@param name The name of the ROM (can be updated)
@param type The bankswitch type of the ROM image
@param dtype The detected bankswitch type of the ROM image
@param id Any extra info about the ROM (currently which part
of a multiload game is being accessed
@param settings The settings associated with the system
@return Pointer to the new cartridge object allocated on the heap
*/
static Cartridge* create(const uInt8* image, uInt32 size, string& md5,
string& name, string type, Settings& settings);
string& dtype, string& id, Settings& settings);
/**
Create a new cartridge

View File

@ -165,22 +165,6 @@ class Controller : public Serializable
*/
virtual void systemCyclesReset() { };
/**
Saves the current state of this controller to the given Serializer.
@param out The serializer device to save to.
@return The result of the save. True on success, false on failure.
*/
virtual bool save(Serializer& out) const;
/**
Loads the current state of this controller from the given Serializer.
@param in The serializer device to load from.
@return The result of the load. True on success, false on failure.
*/
virtual bool load(Serializer& in);
/**
Returns the name of this controller.
*/
@ -191,6 +175,22 @@ class Controller : public Serializable
*/
virtual string about() const;
/**
Saves the current state of this controller to the given Serializer.
@param out The serializer device to save to.
@return The result of the save. True on success, false on failure.
*/
bool save(Serializer& out) const;
/**
Loads the current state of this controller from the given Serializer.
@param in The serializer device to load from.
@return The result of the load. True on success, false on failure.
*/
bool load(Serializer& in);
public:
/// Constant which represents maximum resistance for analog pins
static const Int32 maximumResistance;

View File

@ -201,7 +201,7 @@ static const char* DefProps[DEF_PROPS_SIZE][20] = {
{ "0d27c7f5db349b592f70f68daf5e8f3b", "", "", "Space Instigators (21-10-2002) (CT)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" },
{ "0d35618b6d76ddd46d2626e9e3e40db5", "", "", "X-Doom V.26 (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" },
{ "0d5af65ad3f19558e6f8e29bf2a9d0f8", "Atari, Adam Clayton, John Howard Palevich", "CX26151, CX26151P", "Dark Chambers (1988) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" },
{ "0d6b974fe58a1bdd453600401c407856", "Atari", "", "128-in-1 Junior Console (Chip 3 or 4) (1991) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" },
{ "0d6b974fe58a1bdd453600401c407856", "Atari", "", "128-in-1 Junior Console (Chip 3 or 4) (1991) (Atari) (PAL)", "", "", "", "16IN1", "", "", "", "", "", "", "", "", "", "", "", "" },
{ "0d786a41695e5fc8cffd05a6dbb3f659", "", "", "Scrolling Playfield With Score (10-02-2003) (Aaron Bergstrom)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" },
{ "0d7e630a14856f4d52c9666040961d4d", "", "", "Wavy Line Test (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" },
{ "0d90a0ee73d55539b7def24c88caa651", "Activision, Bob Whitehead", "AG-005, CAG-005, AG-005-04", "Skiing (1980) (Activision) (16K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" },
@ -347,7 +347,7 @@ static const char* DefProps[DEF_PROPS_SIZE][20] = {
{ "1802cc46b879b229272501998c5de04f", "Atari, Christopher H. Omarzu", "CX26104", "Big Bird's Egg Catch (1983) (Atari)", "Uses Kids/Keypad Controllers", "Rare", "", "", "", "", "", "", "KEYBOARD", "KEYBOARD", "", "", "", "", "", "" },
{ "180c234496f31a8671226277e0afbf2f", "", "", "Greeting Cart Mario And Luigi(PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" },
{ "183020a80848e06a1238a1ab74079d52", "Thomas Jentzsch", "", "Missile Command (Amiga Mouse) (2002) (TJ) (PAL)", "Uses Amiga Mouse Controller", "Homebrew", "", "", "", "", "", "", "AMIGAMOUSE", "", "", "", "", "", "YES", "" },
{ "1862fca4f98e66f363308b859b5863af", "Atari", "", "128-in-1 Junior Console (Chip 1 of 4) (1991) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" },
{ "1862fca4f98e66f363308b859b5863af", "Atari", "", "128-in-1 Junior Console (Chip 1 of 4) (1991) (Atari) (PAL)", "", "", "", "16IN1", "", "", "", "", "", "", "", "", "", "", "", "" },
{ "18760f1f9ca5e18610115cf7b815b824", "", "", "Star Fire (23-10-2002) (MP)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" },
{ "18a970bea7ac4d29707c8d5cd559d03a", "", "", "Bridge (208 in 1) (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" },
{ "18b28b386abdadb3a700ac8fb68e639a", "Manuel Polik", "", "Gunfight 2600 (MP) (PAL)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "" },
@ -1465,7 +1465,7 @@ static const char* DefProps[DEF_PROPS_SIZE][20] = {
{ "71464c54da46adae9447926fdbfc1abe", "M Network, Bruce Pedersen - INTV", "MT5663", "Lock 'n' Chase (1982) (M Network)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" },
{ "7146dd477e019f81eac654a79be96cb5", "Atari, Dan Hitchens", "CX2685", "Gravitar (1983) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" },
{ "714e13c08508ee9a7785ceac908ae831", "Home Vision - Gem Int'l Corp.", "VCS83123", "Parachute (1983) (Home Vision) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" },
{ "715dd9e0240638d441a3add49316c018", "Atari", "", "128-in-1 Junior Console (Chip 2 of 4) (1991) (Atari) (PAL)", "Uses the Driving Controllers", "", "", "", "", "", "", "", "DRIVING", "DRIVING", "", "", "", "", "", "" },
{ "715dd9e0240638d441a3add49316c018", "Atari", "", "128-in-1 Junior Console (Chip 2 of 4) (1991) (Atari) (PAL)", "", "", "", "16IN1", "", "", "", "", "", "", "", "", "", "", "", "" },
{ "7187118674ff3c0bb932e049d9dbb379", "Zirok", "", "Keystone Keypers (1983) (Zirok)", "AKA Keystone Kapers", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" },
{ "718ae62c70af4e5fd8e932fee216948a", "Data Age", "112-006", "Journey Escape (1982) (Data Age)", "", "", "", "", "", "", "", "", "", "", "", "", "", "230", "YES", "" },
{ "718ee85ea7ec27d5bea60d11f6d40030", "Thomas Jentzsch", "", "Ghostbusters II (1992) (Thomas Jentzsch)", "NTSC Conversion", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" },
@ -1647,7 +1647,7 @@ static const char* DefProps[DEF_PROPS_SIZE][20] = {
{ "7f0209cfcc3d181715463f4d6451cecf", "Atari - GCC, Betty Ryan Tylko, Douglas B. Macrae", "CX2694", "Pole Position (05-15-1983) (Atari) (Prototype)", "AKA RealSports Driving", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "" },
{ "7f07cd2e89dda5a3a90d3ab064bfd1f6", "Videospielkassette - Ariola", "PGP234", "Boxen (Ariola) (PAL)", "AKA Boxing", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" },
{ "7f430c33044e0354815392b53a9a772d", "HES", "", "2 Pak Special Magenta - Cavern Blaster, City War (1992) (HES) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" },
{ "7f525b07bc98080cc8950f7284e52ede", "Atari", "", "128-in-1 Junior Console (Chip 4 of 4) (1991) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "62", "", "", "" },
{ "7f525b07bc98080cc8950f7284e52ede", "Atari", "", "128-in-1 Junior Console (Chip 4 of 4) (1991) (Atari) (PAL)", "", "", "", "16IN1", "", "", "", "", "", "", "", "", "", "", "", "" },
{ "7f54fa6aa824001af415503c313262f2", "HES", "", "Boom Bang (HES) (PAL)", "AKA Crackpots", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" },
{ "7f6533386644c7d6358f871666c86e79", "CommaVid, Irwin Gaines", "CM-008", "Cakewalk (1983) (CommaVid)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" },
{ "7f73ac39e5e3e13e40fd8ad885561a0f", "", "", "Star Fire - Warping Star (13-04-2003) (MP)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" },

View File

@ -486,7 +486,8 @@ bool OSystem::createConsole(const string& romfile, const string& md5sum)
}
// Create an instance of the 2600 game console
myConsole = openConsole(myRomFile, myRomMD5);
string type, id;
myConsole = openConsole(myRomFile, myRomMD5, type, id);
if(myConsole)
{
#ifdef CHEATCODE_SUPPORT
@ -513,7 +514,12 @@ bool OSystem::createConsole(const string& romfile, const string& md5sum)
if(!audiofirst) myConsole->initializeAudio();
if(showmessage)
myFrameBuffer->showMessage("New console created");
{
if(id == "")
myFrameBuffer->showMessage("New console created");
else
myFrameBuffer->showMessage("Multicart " + type + ", loading ROM" + id);
}
if(mySettings->getBool("showinfo"))
cout << "Game console created:" << endl
<< " ROM file: " << myRomFile << endl << endl
@ -588,8 +594,8 @@ bool OSystem::createLauncher()
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
string OSystem::getROMInfo(const string& romfile)
{
string md5, result = "";
Console* console = openConsole(romfile, md5);
string md5, type, id, result = "";
Console* console = openConsole(romfile, md5, type, id);
if(console)
{
result = getROMInfo(console);
@ -616,7 +622,8 @@ string OSystem::MD5FromFile(const string& filename)
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Console* OSystem::openConsole(const string& romfile, string& md5)
Console* OSystem::openConsole(const string& romfile, string& md5,
string& type, string& id)
{
#define CMDLINE_PROPS_UPDATE(cl_name, prop_name) \
s = mySettings->getString(cl_name); \
@ -638,9 +645,10 @@ Console* OSystem::openConsole(const string& romfile, string& md5)
CMDLINE_PROPS_UPDATE("type", Cartridge_Type);
// Now create the cartridge
string id, cartmd5 = md5, type = props.get(Cartridge_Type);
string cartmd5 = md5;
type = props.get(Cartridge_Type);
Cartridge* cart =
Cartridge::create(image, size, cartmd5, id, type, *mySettings);
Cartridge::create(image, size, cartmd5, type, id, *mySettings);
// It's possible that the cart created was from a piece of the image,
// and that the md5 (and hence the cart) has changed

View File

@ -560,11 +560,13 @@ class OSystem
@param romfile The full pathname of the ROM to use
@param md5 The MD5sum of the ROM
@param type The bankswitch type of the ROM
@param id The additional id (if any) used by the ROM
@return The actual Console object, otherwise NULL
(calling method is responsible for deleting it)
*/
Console* openConsole(const string& romfile, string& md5);
Console* openConsole(const string& romfile, string& md5, string& type, string& id);
/**
Open the given ROM and return an array containing its contents.

View File

@ -19,31 +19,50 @@
#include <fstream>
#include <sstream>
#include "FSNode.hxx"
#include "Serializer.hxx"
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Serializer::Serializer(const string& filename)
Serializer::Serializer(const string& filename, bool readonly)
: myStream(NULL),
myUseFilestream(true)
{
// When using fstreams, we need to manually create the file first
// if we want to use it in read/write mode, since it won't be created
// if it doesn't already exist
// However, if it *does* exist, we don't want to overwrite it
// So we open in write and append mode - the write creates the file
// when necessary, and the append doesn't delete any data if it
// already exists
fstream temp(filename.c_str(), ios::out | ios::app);
temp.close();
fstream* str = new fstream(filename.c_str(), ios::in | ios::out | ios::binary);
if(str && str->is_open())
if(readonly)
{
myStream = str;
reset();
FilesystemNode node(filename);
if(!node.isDirectory() && node.isReadable())
{
fstream* str = new fstream(filename.c_str(), ios::in | ios::binary);
if(str && str->is_open())
{
myStream = str;
reset();
}
else
delete str;
}
}
else
delete str;
{
// When using fstreams, we need to manually create the file first
// if we want to use it in read/write mode, since it won't be created
// if it doesn't already exist
// However, if it *does* exist, we don't want to overwrite it
// So we open in write and append mode - the write creates the file
// when necessary, and the append doesn't delete any data if it
// already exists
fstream temp(filename.c_str(), ios::out | ios::app);
temp.close();
fstream* str = new fstream(filename.c_str(), ios::in | ios::out | ios::binary);
if(str && str->is_open())
{
myStream = str;
reset();
}
else
delete str;
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -148,9 +167,7 @@ bool Serializer::getBool(void)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Serializer::putByte(char value)
{
char buf[1];
buf[0] = value;
myStream->write(buf, 1);
myStream->write(&value, 1);
if(myStream->bad())
throw "Serializer::putByte() file write failed";
}

View File

@ -46,10 +46,12 @@ class Serializer
If a filename is provided, the stream will be to the given
filename. Otherwise, the stream will be in memory.
If a file is opened readonly, we can never write to it.
The isValid() method must immediately be called to verify the stream
was correctly initialized.
*/
Serializer(const string& filename);
Serializer(const string& filename, bool readonly = false);
Serializer(void);
/**

View File

@ -116,7 +116,6 @@ Settings::Settings(OSystem* osystem)
// Misc options
setInternal("autoslot", "false");
setInternal("md5instate", "true");
setInternal("showinfo", "false");
setInternal("tiadriven", "false");
setInternal("avoxport", "");
@ -367,7 +366,6 @@ void Settings::usage()
<< " -sa2 <left|right> Stelladaptor 2 emulates specified joystick port\n"
<< " -ctrlcombo <1|0> Use key combos involving the Control key (Control-Q for quit may be disabled!)\n"
<< " -autoslot <1|0> Automatically switch to next save slot when state saving\n"
<< " -md5instate <1|0> ROM MD5 information is saved in a state file, tying the state file to the ROM\n"
<< " -stats <1|0> Overlay console info during emulation\n"
<< " -audiofirst <1|0> Initial audio before video (required for some ATI video cards)\n"
<< " -fastscbios <1|0> Disable Supercharger BIOS progress loading bars\n"

View File

@ -176,15 +176,13 @@ void StateManager::loadState(int slot)
{
if(slot < 0) slot = myCurrentSlot;
const string& name = myOSystem->console().properties().get(Cartridge_Name);
const string& md5 = myOSystem->console().properties().get(Cartridge_MD5);
ostringstream buf;
buf << myOSystem->stateDir() << BSPF_PATH_SEPARATOR
<< name << ".st" << slot;
<< myOSystem->console().properties().get(Cartridge_Name)
<< ".st" << slot;
// Make sure the file can be opened for reading
Serializer in(buf.str());
// Make sure the file can be opened in read-only mode
Serializer in(buf.str(), true);
if(!in.isValid())
{
buf.str("");
@ -193,16 +191,14 @@ void StateManager::loadState(int slot)
return;
}
buf.str("");
// First test if we have a valid header
// If so, do a complete state load using the Console
buf.str("");
if(in.getString() != STATE_HEADER)
buf << "Incompatible state " << slot << " file";
else
{
const string& s = in.getString();
if(myOSystem->settings().getBool("md5instate") ? s == md5 : true)
if(in.getString() == myOSystem->console().cartridge().name())
{
if(myOSystem->console().load(in))
buf << "State " << slot << " loaded";
@ -224,12 +220,10 @@ void StateManager::saveState(int slot)
{
if(slot < 0) slot = myCurrentSlot;
const string& name = myOSystem->console().properties().get(Cartridge_Name);
const string& md5 = myOSystem->console().properties().get(Cartridge_MD5);
ostringstream buf;
buf << myOSystem->stateDir() << BSPF_PATH_SEPARATOR
<< name << ".st" << slot;
<< myOSystem->console().properties().get(Cartridge_Name)
<< ".st" << slot;
// Make sure the file can be opened for writing
Serializer out(buf.str());
@ -243,8 +237,8 @@ void StateManager::saveState(int slot)
// we'll know right away, without having to parse the rest of the file
out.putString(STATE_HEADER);
// Prepend the ROM md5 so this state file only works with that ROM
out.putString(md5);
// Sanity check; prepend the cart type/name
out.putString(myOSystem->console().cartridge().name());
// Do a complete state save using the Console
buf.str("");
@ -283,12 +277,11 @@ bool StateManager::loadState(Serializer& in)
// Make sure the file can be opened for reading
if(in.isValid())
{
// First test if we have a valid header
// First test if we have a valid header and cart type
// If so, do a complete state load using the Console
const string& md5 = myOSystem->console().properties().get(Cartridge_MD5);
if(in.getString() == STATE_HEADER && in.getString() == md5 &&
myOSystem->console().load(in))
return true;
return in.getString() == STATE_HEADER &&
in.getString() == myOSystem->console().cartridge().name() &&
myOSystem->console().load(in);
}
}
return false;
@ -308,8 +301,8 @@ bool StateManager::saveState(Serializer& out)
// we'll know right away, without having to parse the rest of the file
out.putString(STATE_HEADER);
// Prepend the ROM md5 so this state file only works with that ROM
out.putString(myOSystem->console().properties().get(Cartridge_MD5));
// Sanity check; prepend the cart type/name
out.putString(myOSystem->console().cartridge().name());
// Do a complete state save using the Console
if(myOSystem->console().save(out))

View File

@ -204,24 +204,6 @@ void System::clearDirtyPages()
myPageIsDirtyTable[i] = false;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
System::System(const System& s)
: myAddressMask(s.myAddressMask),
myPageShift(s.myPageShift),
myPageMask(s.myPageMask),
myNumberOfPages(s.myNumberOfPages)
{
assert(false);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
System& System::operator = (const System&)
{
assert(false);
return *this;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt8 System::peek(uInt16 addr)
{
@ -287,10 +269,9 @@ void System::unlockDataBus()
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool System::save(Serializer& out) const
{
const string& device = name();
try
{
out.putString(device);
out.putString(name());
out.putInt(myCycles);
if(!myM6502->save(out))
@ -313,10 +294,9 @@ bool System::save(Serializer& out) const
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool System::load(Serializer& in)
{
const string& device = name();
try
{
if(in.getString() != device)
if(in.getString() != name())
return false;
myCycles = (uInt32) in.getInt();
@ -338,3 +318,20 @@ bool System::load(Serializer& in)
return true;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
System::System(const System& s)
: myAddressMask(s.myAddressMask),
myPageShift(s.myPageShift),
myPageMask(s.myPageMask),
myNumberOfPages(s.myNumberOfPages)
{
assert(false);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
System& System::operator = (const System&)
{
assert(false);
return *this;
}

View File

@ -473,11 +473,13 @@
"Cartridge.MD5" "1862fca4f98e66f363308b859b5863af"
"Cartridge.Manufacturer" "Atari"
"Cartridge.Name" "128-in-1 Junior Console (Chip 1 of 4) (1991) (Atari) (PAL)"
"Cartridge.Type" "16IN1"
""
"Cartridge.MD5" "0d6b974fe58a1bdd453600401c407856"
"Cartridge.Manufacturer" "Atari"
"Cartridge.Name" "128-in-1 Junior Console (Chip 3 or 4) (1991) (Atari) (PAL)"
"Cartridge.Type" "16IN1"
""
"Cartridge.MD5" "09274c3fc1c43bf1e362fda436651fd8"
@ -1925,9 +1927,7 @@
"Cartridge.MD5" "715dd9e0240638d441a3add49316c018"
"Cartridge.Manufacturer" "Atari"
"Cartridge.Name" "128-in-1 Junior Console (Chip 2 of 4) (1991) (Atari) (PAL)"
"Cartridge.Note" "Uses the Driving Controllers"
"Controller.Left" "DRIVING"
"Controller.Right" "DRIVING"
"Cartridge.Type" "16IN1"
""
"Cartridge.MD5" "5b9c2e0012fbfd29efd3306359bbfc4a"
@ -9230,7 +9230,7 @@
"Cartridge.MD5" "7f525b07bc98080cc8950f7284e52ede"
"Cartridge.Manufacturer" "Atari"
"Cartridge.Name" "128-in-1 Junior Console (Chip 4 of 4) (1991) (Atari) (PAL)"
"Display.YStart" "62"
"Cartridge.Type" "16IN1"
""
"Cartridge.MD5" "7f430c33044e0354815392b53a9a772d"

View File

@ -138,6 +138,7 @@ GameInfoDialog::GameInfoDialog(
items.push_back("2IN1 Multicart (4-32K)", "2IN1" );
items.push_back("4IN1 Multicart (8-32K)", "4IN1" );
items.push_back("8IN1 Multicart (16-64K)", "8IN1" );
items.push_back("16IN1 Multicart (32-64K)", "16IN1");
items.push_back("32IN1 Multicart (64-128K)", "32IN1");
items.push_back("2K (64-2048 bytes Atari)", "2K" );
items.push_back("3E (32K Tigervision)", "3E" );

View File

@ -69,6 +69,7 @@ GlobalPropsDialog::
items.push_back("2IN1 Multicart (4-32K)", "2IN1" );
items.push_back("4IN1 Multicart (8-32K)", "4IN1" );
items.push_back("8IN1 Multicart (16-64K)", "8IN1" );
items.push_back("16IN1 Multicart (32-64K)", "16IN1");
items.push_back("32IN1 Multicart (64-128K)", "32IN1");
items.push_back("2K (64-2048 bytes Atari)", "2K" );
items.push_back("3E (32K Tigervision)", "3E" );

View File

@ -1806,7 +1806,7 @@
buildSettings = {
ARCHS = "$(ARCHS_STANDARD_64_BIT)";
COPY_PHASE_STRIP = YES;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
DEBUG_INFORMATION_FORMAT = dwarf;
FRAMEWORK_SEARCH_PATHS = (
.,
"$(HOME)/Library/Frameworks",