Improvements to the FA2 Harmony flash load/save functionality:

- delays are now emulated (0.5 ms for reads, 101 ms for writes)
  - the flash file is now saved according to the ROM name
  - correctly return values with bit 6 set to zero or one, instead
    of just using 0x00 or 0xff


git-svn-id: svn://svn.code.sf.net/p/stella/code/trunk@2440 8b62c5a3-ac7e-4cc8-8f21-d9a121418aba
This commit is contained in:
stephena 2012-04-14 19:28:53 +00:00
parent 967fb73d2d
commit 1dbefe043d
5 changed files with 79 additions and 23 deletions

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, const OSystem& system, Settings& settings) string& dtype, string& id, const OSystem& osystem, Settings& settings)
{ {
Cartridge* cartridge = 0; Cartridge* cartridge = 0;
string type = dtype; string type = dtype;
@ -177,8 +177,7 @@ 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, osystem);
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

@ -191,6 +191,14 @@ class Cartridge : public Device
*/ */
virtual string name() const = 0; virtual string name() const = 0;
/**
Informs the cartridge about the name of the ROM file used when
creating this cart.
@param name The properties file name of the ROM
*/
virtual void setRomName(const string& name) { }
protected: protected:
/** /**
Add the given area to the RamArea list for this cart. Add the given area to the RamArea list for this cart.

View File

@ -20,16 +20,16 @@
#include <cassert> #include <cassert>
#include <cstring> #include <cstring>
#include "OSystem.hxx"
#include "Serializer.hxx" #include "Serializer.hxx"
#include "System.hxx" #include "System.hxx"
#include "CartFA2.hxx" #include "CartFA2.hxx"
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
CartridgeFA2::CartridgeFA2(const uInt8* image, uInt32 size, CartridgeFA2::CartridgeFA2(const uInt8* image, uInt32 size, const OSystem& osystem)
const Settings& settings, const string& flashfile) : Cartridge(osystem.settings()),
: Cartridge(settings), myOSystem(osystem),
myRamRWFlag(false), myRamAccessTimeout(0),
myFlashFile(flashfile),
mySize(size) mySize(size)
{ {
// Allocate array for the ROM image // Allocate array for the ROM image
@ -349,24 +349,41 @@ bool CartridgeFA2::load(Serializer& in)
return true; return true;
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CartridgeFA2::setRomName(const string& name)
{
myFlashFile = myOSystem.eepromDir() + name + "_flash.dat";
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt8 CartridgeFA2::ramReadWrite() uInt8 CartridgeFA2::ramReadWrite()
{ {
/* The following algorithm implements accessing Harmony cart flash /* The following algorithm implements accessing Harmony cart flash
1. Wait for an access to hotspot location $1FF4 (return 1 on first access). 1. Wait for an access to hotspot location $1FF4 (return 1 in bit 6
while busy).
2. Read byte 256 of RAM+ memory to determine the operation requested 2. Read byte 256 of RAM+ memory to determine the operation requested
(1 = read, 2 = write). (1 = read, 2 = write).
3. Save or load the entire 256 bytes of RAM+ memory to a file. 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. 4. Set byte 256 of RAM+ memory to zero to indicate success (will
always happen in emulation).
5. Return 0 on the next access to $1FF4. 5. Return 0 (in bit 6) on the next access to $1FF4, if enough time has
passed to complete the operation on a real system (0.5 ms for read,
101 ms for write).
*/ */
if(!myRamRWFlag)
// First access sets the timer
if(myRamAccessTimeout == 0)
{ {
// Remember when the first access was made
myRamAccessTimeout = myOSystem.getTicks();
// We go ahead and do the access now, and only return when a sufficient
// amount of time has passed
Serializer serializer(myFlashFile); Serializer serializer(myFlashFile);
if(serializer.isValid()) if(serializer.isValid())
{ {
@ -381,6 +398,7 @@ uInt8 CartridgeFA2::ramReadWrite()
{ {
memset(myRAM, 0, 256); memset(myRAM, 0, 256);
} }
myRamAccessTimeout += 500; // Add 0.5 ms delay for read
} }
else if(myRAM[255] == 2) // write else if(myRAM[255] == 2) // write
{ {
@ -391,15 +409,27 @@ uInt8 CartridgeFA2::ramReadWrite()
} }
catch(const char* msg) catch(const char* msg)
{ {
// Maybe add logging here? // Maybe add logging here that save failed?
} }
myRamAccessTimeout += 101000; // Add 101 ms delay for write
} }
} }
return 1; // Bit 6 is 1, busy
return myImage[(myCurrentBank << 12) + 0xFF4] | 0x40;
} }
else else
{ {
myRamRWFlag = false; // Have we reached the timeout value yet?
return 0; if(myOSystem.getTicks() >= myRamAccessTimeout)
{
myRamAccessTimeout = 0; // Turn off timer
myRAM[255] = 0; // Successful operation
// Bit 6 is 0, ready/success
return myImage[(myCurrentBank << 12) + 0xFF4] & ~0x40;
}
else
// Bit 6 is 1, busy
return myImage[(myCurrentBank << 12) + 0xFF4] | 0x40;
} }
} }

View File

@ -29,7 +29,9 @@ class System;
This is an extended version of the CBS RAM Plus bankswitching scheme This is an extended version of the CBS RAM Plus bankswitching scheme
supported by the Harmony cartridge. supported by the Harmony cartridge.
There are six (or seven) 4K banks and 256 bytes of RAM. There are six (or seven) 4K banks and 256 bytes of RAM. The 256 bytes
of RAM can be loaded/saved to Harmony cart flash, which is emulated by
storing in a file.
@author Chris D. Walton @author Chris D. Walton
@version $Id$ @version $Id$
@ -42,11 +44,9 @@ 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 osystem A reference to the OSystem currently in use
@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 OSystem& osystem);
const string& flashfile);
/** /**
Destructor Destructor
@ -124,6 +124,14 @@ class CartridgeFA2 : public Cartridge
*/ */
string name() const { return "CartridgeFA2"; } string name() const { return "CartridgeFA2"; }
/**
Informs the cartridge about the name of the ROM file used when
creating this cart.
@param name The properties file name of the ROM
*/
void setRomName(const string& name);
public: public:
/** /**
Get the byte at the specified address. Get the byte at the specified address.
@ -145,10 +153,16 @@ class CartridgeFA2 : public Cartridge
/** /**
Either load or save internal RAM to Harmony flash (represented by Either load or save internal RAM to Harmony flash (represented by
a file in emulation). a file in emulation).
@return The value at $FF4 with bit 6 set or cleared (depending on
whether the RAM access was busy or successful)
*/ */
uInt8 ramReadWrite(); uInt8 ramReadWrite();
private: private:
// OSsytem currently in use
const OSystem& myOSystem;
// Indicates which bank is currently active // Indicates which bank is currently active
uInt16 myCurrentBank; uInt16 myCurrentBank;
@ -158,8 +172,11 @@ 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 // The time after which the first request of a load/save operation
bool myRamRWFlag; // will actually be completed
// Due to flash RAM constraints, a read/write isn't instantaneous,
// so we need to emulate the delay as well
uInt64 myRamAccessTimeout;
// Full pathname of the file to use when emulating load/save // Full pathname of the file to use when emulating load/save
// of internal RAM to Harmony cart flash // of internal RAM to Harmony cart flash

View File

@ -214,6 +214,8 @@ Console::Console(OSystem* osystem, Cartridge* cart, const Properties& props)
myConsoleInfo.Control0 = myControllers[0]->about(); myConsoleInfo.Control0 = myControllers[0]->about();
myConsoleInfo.Control1 = myControllers[1]->about(); myConsoleInfo.Control1 = myControllers[1]->about();
myConsoleInfo.BankSwitch = cart->about(); myConsoleInfo.BankSwitch = cart->about();
myCart->setRomName(myConsoleInfo.CartName);
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -