Load/save from Harmony cart flash RAM is now supported for the FA2

bankswitch scheme (currently, only the 256 internal RAM is used).


git-svn-id: svn://svn.code.sf.net/p/stella/code/trunk@2439 8b62c5a3-ac7e-4cc8-8f21-d9a121418aba
This commit is contained in:
stephena 2012-04-12 23:23:12 +00:00
parent 186fa5c1be
commit 967fb73d2d
6 changed files with 111 additions and 9 deletions

View File

@ -12,7 +12,7 @@
Release History Release History
=========================================================================== ===========================================================================
3.6 to 3.7: (April xx, 2012) 3.6.1 to 3.7: (April xx, 2012)
* Updated the CompuMate keyboard handler to recognize more keys on an * Updated the CompuMate keyboard handler to recognize more keys on an
actual keyboard, instead of having to remember the weird combinations actual keyboard, instead of having to remember the weird combinations
@ -21,11 +21,23 @@
* Added emulation for MindLink controller; the Bionic Breakthrough * Added emulation for MindLink controller; the Bionic Breakthrough
ROM now works. ROM now works.
* Updated FA2 bankswitch scheme (Star Castle) to emulate load/save
high score functionality to the Harmony cart flash RAM.
* Updated internal database for 'Juno First' ROMs; they will now use
an AtariVox/SaveKey when possible.
* Updated included PNG library to latest stable version. * Updated included PNG library to latest stable version.
-Have fun! -Have fun!
3.6 to 3.6.1: (March 30, 2012)
* Extended FA2 bankswitch scheme to handle 28K ROMs (in addition to
the previously supported 24K ROMs).
3.5.5 to 3.6: (March 16, 2012) 3.5.5 to 3.6: (March 16, 2012)
* Added support for 2600-daptor II device, including native support * Added support for 2600-daptor II device, including native support

View File

@ -62,7 +62,7 @@
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Cartridge* Cartridge::create(const uInt8* image, uInt32 size, string& md5, Cartridge* Cartridge::create(const uInt8* image, uInt32 size, string& md5,
string& dtype, string& id, Settings& settings) string& dtype, string& id, const OSystem& system, Settings& settings)
{ {
Cartridge* cartridge = 0; Cartridge* cartridge = 0;
string type = dtype; string type = dtype;
@ -177,7 +177,8 @@ Cartridge* Cartridge::create(const uInt8* image, uInt32 size, string& md5,
else if(type == "FA" || type == "FASC") else if(type == "FA" || type == "FASC")
cartridge = new CartridgeFA(image, size, settings); cartridge = new CartridgeFA(image, size, settings);
else if(type == "FA2") else if(type == "FA2")
cartridge = new CartridgeFA2(image, size, settings); cartridge = new CartridgeFA2(image, size, settings,
system.eepromDir() + "FA2_flash.dat");
else if(type == "FE") else if(type == "FE")
cartridge = new CartridgeFE(image, size, settings); cartridge = new CartridgeFE(image, size, settings);
else if(type == "MC") else if(type == "MC")

View File

@ -61,11 +61,13 @@ class Cartridge : public Device
@param dtype The detected 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 @param id Any extra info about the ROM (currently which part
of a multiload game is being accessed of a multiload game is being accessed
@param system The osystem associated with the system
@param settings The settings associated with the system @param settings The settings associated with the system
@return Pointer to the new cartridge object allocated on the heap @return Pointer to the new cartridge object allocated on the heap
*/ */
static Cartridge* create(const uInt8* image, uInt32 size, string& md5, static Cartridge* create(const uInt8* image, uInt32 size, string& md5,
string& dtype, string& id, Settings& settings); string& dtype, string& id,
const OSystem& system, Settings& settings);
/** /**
Create a new cartridge Create a new cartridge

View File

@ -20,12 +20,16 @@
#include <cassert> #include <cassert>
#include <cstring> #include <cstring>
#include "Serializer.hxx"
#include "System.hxx" #include "System.hxx"
#include "CartFA2.hxx" #include "CartFA2.hxx"
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
CartridgeFA2::CartridgeFA2(const uInt8* image, uInt32 size, const Settings& settings) CartridgeFA2::CartridgeFA2(const uInt8* image, uInt32 size,
const Settings& settings, const string& flashfile)
: Cartridge(settings), : Cartridge(settings),
myRamRWFlag(false),
myFlashFile(flashfile),
mySize(size) mySize(size)
{ {
// Allocate array for the ROM image // Allocate array for the ROM image
@ -106,6 +110,12 @@ uInt8 CartridgeFA2::peek(uInt16 address)
// Switch banks if necessary // Switch banks if necessary
switch(address) switch(address)
{ {
case 0x0FF4:
// Load/save RAM to/from Harmony cart flash
if(mySize == 28*1024 && !bankLocked())
return ramReadWrite();
break;
case 0x0FF5: case 0x0FF5:
// Set the current bank to the first 4k bank // Set the current bank to the first 4k bank
bank(0); bank(0);
@ -171,6 +181,12 @@ bool CartridgeFA2::poke(uInt16 address, uInt8)
// Switch banks if necessary // Switch banks if necessary
switch(address) switch(address)
{ {
case 0x0FF4:
// Load/save RAM to/from Harmony cart flash
if(mySize == 28*1024 && !bankLocked())
ramReadWrite();
break;
case 0x0FF5: case 0x0FF5:
// Set the current bank to the first 4k bank // Set the current bank to the first 4k bank
bank(0); bank(0);
@ -231,14 +247,14 @@ bool CartridgeFA2::bank(uInt16 bank)
System::PageAccess access(0, 0, 0, this, System::PA_READ); System::PageAccess access(0, 0, 0, this, System::PA_READ);
// Set the page accessing methods for the hot spots // Set the page accessing methods for the hot spots
for(uInt32 i = (0x1FF5 & ~mask); i < 0x2000; i += (1 << shift)) for(uInt32 i = (0x1FF4 & ~mask); i < 0x2000; i += (1 << shift))
{ {
access.codeAccessBase = &myCodeAccessBase[offset + (i & 0x0FFF)]; access.codeAccessBase = &myCodeAccessBase[offset + (i & 0x0FFF)];
mySystem->setPageAccess(i >> shift, access); mySystem->setPageAccess(i >> shift, access);
} }
// Setup the page access methods for the current bank // Setup the page access methods for the current bank
for(uInt32 address = 0x1200; address < (0x1FF5U & ~mask); for(uInt32 address = 0x1200; address < (0x1FF4U & ~mask);
address += (1 << shift)) address += (1 << shift))
{ {
access.directPeekBase = &myImage[offset + (address & 0x0FFF)]; access.directPeekBase = &myImage[offset + (address & 0x0FFF)];
@ -332,3 +348,58 @@ bool CartridgeFA2::load(Serializer& in)
return true; return true;
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt8 CartridgeFA2::ramReadWrite()
{
/* The following algorithm implements accessing Harmony cart flash
1. Wait for an access to hotspot location $1FF4 (return 1 on first access).
2. Read byte 256 of RAM+ memory to determine the operation requested
(1 = read, 2 = write).
3. Save or load the entire 256 bytes of RAM+ memory to a file.
4. Set byte 256 of RAM+ memory to zero to indicate success.
5. Return 0 on the next access to $1FF4.
*/
if(!myRamRWFlag)
{
Serializer serializer(myFlashFile);
if(serializer.isValid())
{
if(myRAM[255] == 1) // read
{
try
{
for(uInt32 i = 0; i < 256; ++i)
myRAM[i] = (uInt8) serializer.getByte();
}
catch(const char* msg)
{
memset(myRAM, 0, 256);
}
}
else if(myRAM[255] == 2) // write
{
try
{
for(uInt32 i = 0; i < 256; ++i)
serializer.putByte((char)myRAM[i]);
}
catch(const char* msg)
{
// Maybe add logging here?
}
}
}
return 1;
}
else
{
myRamRWFlag = false;
return 0;
}
}

View File

@ -43,8 +43,10 @@ class CartridgeFA2 : public Cartridge
@param image Pointer to the ROM image @param image Pointer to the ROM image
@param size The size of the ROM image @param size The size of the ROM image
@param settings A reference to the various settings (read-only) @param settings A reference to the various settings (read-only)
@param flashfile The full pathname for the flash file storing internal RAM
*/ */
CartridgeFA2(const uInt8* image, uInt32 size, const Settings& settings); CartridgeFA2(const uInt8* image, uInt32 size, const Settings& settings,
const string& flashfile);
/** /**
Destructor Destructor
@ -139,6 +141,13 @@ class CartridgeFA2 : public Cartridge
*/ */
bool poke(uInt16 address, uInt8 value); bool poke(uInt16 address, uInt8 value);
private:
/**
Either load or save internal RAM to Harmony flash (represented by
a file in emulation).
*/
uInt8 ramReadWrite();
private: private:
// Indicates which bank is currently active // Indicates which bank is currently active
uInt16 myCurrentBank; uInt16 myCurrentBank;
@ -149,6 +158,13 @@ class CartridgeFA2 : public Cartridge
// The 256 bytes of RAM on the cartridge // The 256 bytes of RAM on the cartridge
uInt8 myRAM[256]; uInt8 myRAM[256];
// An access has been made to load/save internal RAM
bool myRamRWFlag;
// Full pathname of the file to use when emulating load/save
// of internal RAM to Harmony cart flash
string myFlashFile;
// Size of the ROM image // Size of the ROM image
uInt32 mySize; uInt32 mySize;
}; };

View File

@ -693,7 +693,7 @@ Console* OSystem::openConsole(const string& romfile, string& md5,
string cartmd5 = md5; string cartmd5 = md5;
type = props.get(Cartridge_Type); type = props.get(Cartridge_Type);
Cartridge* cart = Cartridge* cart =
Cartridge::create(image, size, cartmd5, type, id, *mySettings); Cartridge::create(image, size, cartmd5, type, id, *this, *mySettings);
// It's possible that the cart created was from a piece of the image, // It's possible that the cart created was from a piece of the image,
// and that the md5 (and hence the cart) has changed // and that the md5 (and hence the cart) has changed