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

View File

@ -191,6 +191,14 @@ class Cartridge : public Device
*/
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:
/**
Add the given area to the RamArea list for this cart.

View File

@ -20,16 +20,16 @@
#include <cassert>
#include <cstring>
#include "OSystem.hxx"
#include "Serializer.hxx"
#include "System.hxx"
#include "CartFA2.hxx"
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
CartridgeFA2::CartridgeFA2(const uInt8* image, uInt32 size,
const Settings& settings, const string& flashfile)
: Cartridge(settings),
myRamRWFlag(false),
myFlashFile(flashfile),
CartridgeFA2::CartridgeFA2(const uInt8* image, uInt32 size, const OSystem& osystem)
: Cartridge(osystem.settings()),
myOSystem(osystem),
myRamAccessTimeout(0),
mySize(size)
{
// Allocate array for the ROM image
@ -349,24 +349,41 @@ bool CartridgeFA2::load(Serializer& in)
return true;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CartridgeFA2::setRomName(const string& name)
{
myFlashFile = myOSystem.eepromDir() + name + "_flash.dat";
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
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).
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
(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.
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);
if(serializer.isValid())
{
@ -381,6 +398,7 @@ uInt8 CartridgeFA2::ramReadWrite()
{
memset(myRAM, 0, 256);
}
myRamAccessTimeout += 500; // Add 0.5 ms delay for read
}
else if(myRAM[255] == 2) // write
{
@ -391,15 +409,27 @@ uInt8 CartridgeFA2::ramReadWrite()
}
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
{
myRamRWFlag = false;
return 0;
// Have we reached the timeout value yet?
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
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
@version $Id$
@ -42,11 +44,9 @@ class CartridgeFA2 : public Cartridge
@param image Pointer to the ROM image
@param size The size of the ROM image
@param settings A reference to the various settings (read-only)
@param flashfile The full pathname for the flash file storing internal RAM
@param osystem A reference to the OSystem currently in use
*/
CartridgeFA2(const uInt8* image, uInt32 size, const Settings& settings,
const string& flashfile);
CartridgeFA2(const uInt8* image, uInt32 size, const OSystem& osystem);
/**
Destructor
@ -124,6 +124,14 @@ class CartridgeFA2 : public Cartridge
*/
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:
/**
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
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();
private:
// OSsytem currently in use
const OSystem& myOSystem;
// Indicates which bank is currently active
uInt16 myCurrentBank;
@ -158,8 +172,11 @@ class CartridgeFA2 : public Cartridge
// The 256 bytes of RAM on the cartridge
uInt8 myRAM[256];
// An access has been made to load/save internal RAM
bool myRamRWFlag;
// The time after which the first request of a load/save operation
// 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
// 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.Control1 = myControllers[1]->about();
myConsoleInfo.BankSwitch = cart->about();
myCart->setRomName(myConsoleInfo.CartName);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -