Added 'FA2' bankswitch support (from cdw) for upcoming Star Castle ROM.

git-svn-id: svn://svn.code.sf.net/p/stella/code/trunk@2361 8b62c5a3-ac7e-4cc8-8f21-d9a121418aba
This commit is contained in:
stephena 2012-01-21 13:11:08 +00:00
parent 16ad78f468
commit 3e4d82472b
5 changed files with 481 additions and 0 deletions

View File

@ -42,6 +42,9 @@
* Updated ROM properties database for all Sega Genesis controller * Updated ROM properties database for all Sega Genesis controller
compatible ROMs. compatible ROMs.
* Added 'FA2' bankswitch scheme, thanks to code from Chris D.
Walton. This scheme will be used in an upcoming 'Star Castle' ROM.
* Fixed compile issues in Irix when using the default compiler * Fixed compile issues in Irix when using the default compiler
instead of gcc. Thanks go to Rainer M. Canavan for this code. instead of gcc. Thanks go to Rainer M. Canavan for this code.

View File

@ -44,6 +44,7 @@
#include "CartF8.hxx" #include "CartF8.hxx"
#include "CartF8SC.hxx" #include "CartF8SC.hxx"
#include "CartFA.hxx" #include "CartFA.hxx"
#include "CartFA2.hxx"
#include "CartFE.hxx" #include "CartFE.hxx"
#include "CartMC.hxx" #include "CartMC.hxx"
#include "CartCV.hxx" #include "CartCV.hxx"
@ -175,6 +176,8 @@ Cartridge* Cartridge::create(const uInt8* image, uInt32 size, string& md5,
cartridge = new CartridgeF8SC(image, size, settings); cartridge = new CartridgeF8SC(image, size, settings);
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")
cartridge = new CartridgeFA2(image, size, settings);
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")
@ -377,6 +380,10 @@ string Cartridge::autodetectType(const uInt8* image, uInt32 size)
else else
type = "F6"; type = "F6";
} }
else if(size == 24*1024) // 24K
{
type = "FA2";
}
else if(size == 29*1024) // 29K else if(size == 29*1024) // 29K
{ {
type = "DPC+"; type = "DPC+";

317
src/emucore/CartFA2.cxx Normal file
View File

@ -0,0 +1,317 @@
//============================================================================
//
// SSSS tt lll lll
// SS SS tt ll ll
// SS tttttt eeee ll ll aaaa
// SSSS tt ee ee ll ll aa
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2012 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id$
//============================================================================
#include <cassert>
#include <cstring>
#include "System.hxx"
#include "CartFA2.hxx"
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
CartridgeFA2::CartridgeFA2(const uInt8* image, uInt32 size, const Settings& settings)
: Cartridge(settings)
{
// Copy the ROM image into my buffer
memcpy(myImage, image, BSPF_min(24576u, size));
createCodeAccessBase(24576);
// This cart contains 256 bytes extended RAM @ 0x1000
registerRamArea(0x1000, 256, 0x100, 0x00);
// Remember startup bank
myStartBank = 5;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
CartridgeFA2::~CartridgeFA2()
{
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CartridgeFA2::reset()
{
// Initialize RAM
if(mySettings.getBool("ramrandom"))
for(uInt32 i = 0; i < 256; ++i)
myRAM[i] = mySystem->randGenerator().next();
else
memset(myRAM, 0, 256);
// Upon reset we switch to the startup bank
bank(myStartBank);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CartridgeFA2::install(System& system)
{
mySystem = &system;
uInt16 shift = mySystem->pageShift();
uInt16 mask = mySystem->pageMask();
// Make sure the system we're being installed in has a page size that'll work
assert(((0x1100 & mask) == 0) && ((0x1200 & mask) == 0));
System::PageAccess access(0, 0, 0, this, System::PA_READ);
// Set the page accessing method for the RAM writing pages
access.type = System::PA_WRITE;
for(uInt32 j = 0x1000; j < 0x1100; j += (1 << shift))
{
access.directPokeBase = &myRAM[j & 0x00FF];
access.codeAccessBase = &myCodeAccessBase[j & 0x00FF];
mySystem->setPageAccess(j >> shift, access);
}
// Set the page accessing method for the RAM reading pages
access.directPokeBase = 0;
access.type = System::PA_READ;
for(uInt32 k = 0x1100; k < 0x1200; k += (1 << shift))
{
access.directPeekBase = &myRAM[k & 0x00FF];
access.codeAccessBase = &myCodeAccessBase[0x100 + (k & 0x00FF)];
mySystem->setPageAccess(k >> shift, access);
}
// Install pages for the startup bank
bank(myStartBank);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt8 CartridgeFA2::peek(uInt16 address)
{
uInt16 peekAddress = address;
address &= 0x0FFF;
// Switch banks if necessary
switch(address)
{
case 0x0FF5:
// Set the current bank to the first 4k bank
bank(0);
break;
case 0x0FF6:
// Set the current bank to the second 4k bank
bank(1);
break;
case 0x0FF7:
// Set the current bank to the third 4k bank
bank(2);
break;
case 0x0FF8:
// Set the current bank to the fourth 4k bank
bank(3);
break;
case 0x0FF9:
// Set the current bank to the fifth 4k bank
bank(4);
break;
case 0x0FFA:
// Set the current bank to the sixth 4k bank
bank(5);
break;
default:
break;
}
if(address < 0x0100) // Write port is at 0xF000 - 0xF100 (256 bytes)
{
// Reading from the write port triggers an unwanted write
uInt8 value = mySystem->getDataBusState(0xFF);
if(bankLocked())
return value;
else
{
triggerReadFromWritePort(peekAddress);
return myRAM[address] = value;
}
}
else
return myImage[(myCurrentBank << 12) + address];
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool CartridgeFA2::poke(uInt16 address, uInt8)
{
address &= 0x0FFF;
// Switch banks if necessary
switch(address)
{
case 0x0FF5:
// Set the current bank to the first 4k bank
bank(0);
break;
case 0x0FF6:
// Set the current bank to the second 4k bank
bank(1);
break;
case 0x0FF7:
// Set the current bank to the third 4k bank
bank(2);
break;
case 0x0FF8:
// Set the current bank to the fourth 4k bank
bank(3);
break;
case 0x0FF9:
// Set the current bank to the fifth 4k bank
bank(4);
break;
case 0x0FFA:
// Set the current bank to the sixth 4k bank
bank(5);
break;
default:
break;
}
// NOTE: This does not handle accessing RAM, however, this function
// should never be called for RAM because of the way page accessing
// has been setup
return false;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool CartridgeFA2::bank(uInt16 bank)
{
if(bankLocked()) return false;
// Remember what bank we're in
myCurrentBank = bank;
uInt16 offset = myCurrentBank << 12;
uInt16 shift = mySystem->pageShift();
uInt16 mask = mySystem->pageMask();
System::PageAccess access(0, 0, 0, this, System::PA_READ);
// Set the page accessing methods for the hot spots
for(uInt32 i = (0x1FF5 & ~mask); i < 0x2000; i += (1 << shift))
{
access.codeAccessBase = &myCodeAccessBase[offset + (i & 0x0FFF)];
mySystem->setPageAccess(i >> shift, access);
}
// Setup the page access methods for the current bank
for(uInt32 address = 0x1200; address < (0x1FF5U & ~mask);
address += (1 << shift))
{
access.directPeekBase = &myImage[offset + (address & 0x0FFF)];
access.codeAccessBase = &myCodeAccessBase[offset + (address & 0x0FFF)];
mySystem->setPageAccess(address >> shift, access);
}
return myBankChanged = true;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt16 CartridgeFA2::bank() const
{
return myCurrentBank;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt16 CartridgeFA2::bankCount() const
{
return 6;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool CartridgeFA2::patch(uInt16 address, uInt8 value)
{
address &= 0x0FFF;
if(address < 0x0200)
{
// Normally, a write to the read port won't do anything
// However, the patch command is special in that ignores such
// cart restrictions
myRAM[address & 0x00FF] = value;
}
else
myImage[(myCurrentBank << 12) + address] = value;
return myBankChanged = true;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
const uInt8* CartridgeFA2::getImage(int& size) const
{
size = 24576;
return myImage;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool CartridgeFA2::save(Serializer& out) const
{
try
{
out.putString(name());
out.putInt(myCurrentBank);
// The 256 bytes of RAM
out.putInt(256);
for(uInt32 i = 0; i < 256; ++i)
out.putByte((char)myRAM[i]);
}
catch(const char* msg)
{
cerr << "ERROR: CartridgeFA2::save" << endl << " " << msg << endl;
return false;
}
return true;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool CartridgeFA2::load(Serializer& in)
{
try
{
if(in.getString() != name())
return false;
myCurrentBank = (uInt16) in.getInt();
uInt32 limit = (uInt32) in.getInt();
for(uInt32 i = 0; i < limit; ++i)
myRAM[i] = (uInt8) in.getByte();
}
catch(const char* msg)
{
cerr << "ERROR: CartridgeFA2::load" << endl << " " << msg << endl;
return false;
}
// Remember what bank we were in
bank(myCurrentBank);
return true;
}

153
src/emucore/CartFA2.hxx Normal file
View File

@ -0,0 +1,153 @@
//============================================================================
//
// SSSS tt lll lll
// SS SS tt ll ll
// SS tttttt eeee ll ll aaaa
// SSSS tt ee ee ll ll aa
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2012 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id$
//============================================================================
#ifndef CARTRIDGEFA2_HXX
#define CARTRIDGEFA2_HXX
class System;
#include "bspf.hxx"
#include "Cart.hxx"
/**
This is an extended version of the CBS RAM Plus bankswitching scheme
supported by the Harmony cartridge.
There are six 4K banks and 256 bytes of RAM.
@author Chris D. Walton
@version $Id$
*/
class CartridgeFA2 : public Cartridge
{
public:
/**
Create a new cartridge using the specified image
@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)
*/
CartridgeFA2(const uInt8* image, uInt32 size, const Settings& settings);
/**
Destructor
*/
virtual ~CartridgeFA2();
public:
/**
Reset device to its power-on state
*/
void reset();
/**
Install cartridge in the specified system. Invoked by the system
when the cartridge is attached to it.
@param system The system the device should install itself in
*/
void install(System& system);
/**
Install pages for the specified bank in the system.
@param bank The bank that should be installed in the system
*/
bool bank(uInt16 bank);
/**
Get the current bank.
*/
uInt16 bank() const;
/**
Query the number of banks supported by the cartridge.
*/
uInt16 bankCount() const;
/**
Patch the cartridge ROM.
@param address The ROM address to patch
@param value The value to place into the address
@return Success or failure of the patch operation
*/
bool patch(uInt16 address, uInt8 value);
/**
Access the internal ROM image for this cartridge.
@param size Set to the size of the internal ROM image data
@return A pointer to the internal ROM image data
*/
const uInt8* getImage(int& size) const;
/**
Save the current state of this cart to the given Serializer.
@param out The Serializer object to use
@return False on any errors, else true
*/
bool save(Serializer& out) const;
/**
Load the current state of this cart from the given Serializer.
@param in The Serializer object to use
@return False on any errors, else true
*/
bool load(Serializer& in);
/**
Get a descriptor for the device name (used in error checking).
@return The name of the object
*/
string name() const { return "CartridgeFA2"; }
public:
/**
Get the byte at the specified address.
@return The byte at the specified address
*/
uInt8 peek(uInt16 address);
/**
Change the byte at the specified address to the given value
@param address The address where the value should be stored
@param value The value to be stored at the address
@return True if the poke changed the device address space, else false
*/
bool poke(uInt16 address, uInt8 value);
private:
// Indicates which bank is currently active
uInt16 myCurrentBank;
// The 24K ROM image of the cartridge
uInt8 myImage[24576];
// The 256 bytes of RAM on the cartridge
uInt8 myRAM[256];
};
#endif

View File

@ -26,6 +26,7 @@ MODULE_OBJS := \
src/emucore/CartF8.o \ src/emucore/CartF8.o \
src/emucore/CartF8SC.o \ src/emucore/CartF8SC.o \
src/emucore/CartFA.o \ src/emucore/CartFA.o \
src/emucore/CartFA2.o \
src/emucore/CartFE.o \ src/emucore/CartFE.o \
src/emucore/CartMC.o \ src/emucore/CartMC.o \
src/emucore/CartSB.o \ src/emucore/CartSB.o \