From 07786e3faf861d9c80615f50f6e888a6f895d1b1 Mon Sep 17 00:00:00 2001 From: urchlay Date: Fri, 8 Jul 2005 04:00:09 +0000 Subject: [PATCH] Added support for 3E bankswitch scheme (3F plus 32K RAM). git-svn-id: svn://svn.code.sf.net/p/stella/code/trunk@618 8b62c5a3-ac7e-4cc8-8f21-d9a121418aba --- stella/src/emucore/Cart3E.cxx | 269 ++++++++++++++++++++++++++++++++++ stella/src/emucore/Cart3E.hxx | 160 ++++++++++++++++++++ stella/src/emucore/module.mk | 1 + 3 files changed, 430 insertions(+) create mode 100644 stella/src/emucore/Cart3E.cxx create mode 100644 stella/src/emucore/Cart3E.hxx diff --git a/stella/src/emucore/Cart3E.cxx b/stella/src/emucore/Cart3E.cxx new file mode 100644 index 000000000..20ca254ba --- /dev/null +++ b/stella/src/emucore/Cart3E.cxx @@ -0,0 +1,269 @@ +//============================================================================ +// +// 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-2005 by Bradford W. Mott and the Stella team +// +// See the file "license" for information on usage and redistribution of +// this file, and for a DISCLAIMER OF ALL WARRANTIES. +// +// $Id: Cart3E.cxx,v 1.1 2005-07-08 04:00:09 urchlay Exp $ +//============================================================================ + +#include +#include "Cart3E.hxx" +#include "System.hxx" +#include "Serializer.hxx" +#include "Deserializer.hxx" +#include + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Cartridge3E::Cartridge3E(const uInt8* image, uInt32 size) + : mySize(size) +{ + // Allocate array for the ROM image + myImage = new uInt8[mySize]; + + // Copy the ROM image into my buffer + for(uInt32 addr = 0; addr < mySize; ++addr) + { + myImage[addr] = image[addr]; + } +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Cartridge3E::~Cartridge3E() +{ + delete[] myImage; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +const char* Cartridge3E::name() const +{ + return "Cartridge3E"; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void Cartridge3E::reset() +{ + // We'll map bank 0 into the first segment upon reset + bank(0); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void Cartridge3E::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((0x1800 & mask) == 0); + + // Set the page accessing methods for the hot spots (for 100% emulation + // I would need to chain any accesses below 0x40 to the TIA but for + // now I'll just forget about them) + System::PageAccess access; + for(uInt32 i = 0x00; i < 0x40; i += (1 << shift)) + { + access.directPeekBase = 0; + access.directPokeBase = 0; + access.device = this; + mySystem->setPageAccess(i >> shift, access); + } + + // Setup the second segment to always point to the last ROM slice + for(uInt32 j = 0x1800; j < 0x2000; j += (1 << shift)) + { + access.device = this; + access.directPeekBase = &myImage[(mySize - 2048) + (j & 0x07FF)]; + access.directPokeBase = 0; + mySystem->setPageAccess(j >> shift, access); + } + + // Install pages for bank 0 into the first segment + bank(0); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +uInt8 Cartridge3E::peek(uInt16 address) +{ + address = address & 0x0FFF; + + if(address < 0x0800) + { + if(myCurrentBank < 256) + return myImage[(address & 0x07FF) + myCurrentBank * 2048]; + else + return myRam[(address & 0x03FF) + (myCurrentBank - 256) * 1024]; + } + else + { + return myImage[(address & 0x07FF) + mySize - 2048]; + } +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void Cartridge3E::poke(uInt16 address, uInt8 value) +{ + address = address & 0x0FFF; + + // Switch banks if necessary + if(address == 0x003F) + { + bank(value); + } + else if(address == 0x003E) + { + bank(value + 256); + } +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +bool Cartridge3E::patch(uInt16 address, uInt8 value) +{ + address = address & 0x0FFF; + if(address < 0x0800) + { + myImage[(address & 0x07FF) + myCurrentBank * 2048] = value; + } + else + { + myImage[(address & 0x07FF) + mySize - 2048] = value; + } + return true; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void Cartridge3E::bank(uInt16 bank) +{ + if(bank < 256) + { + // Make sure the bank they're asking for is reasonable + if((uInt32)bank * 2048 < mySize) + { + myCurrentBank = bank; + } + else + { + // Oops, the bank they're asking for isn't valid so let's wrap it + // around to a valid bank number + myCurrentBank = bank % (mySize / 2048); + } + + uInt32 offset = myCurrentBank * 2048; + uInt16 shift = mySystem->pageShift(); + + // Setup the page access methods for the current bank + System::PageAccess access; + access.device = this; + access.directPokeBase = 0; + + // Map ROM image into the system + for(uInt32 address = 0x1000; address < 0x1800; address += (1 << shift)) + { + access.directPeekBase = &myImage[offset + (address & 0x07FF)]; + mySystem->setPageAccess(address >> shift, access); + } + } + else + { + bank -= 256; + bank %= 32; + myCurrentBank = bank + 256; + + uInt32 offset = bank * 1024; + uInt16 shift = mySystem->pageShift(); + + // Setup the page access methods for the current bank + System::PageAccess access; + access.device = this; + access.directPokeBase = 0; + + // Map read-port RAM image into the system + for(uInt32 address = 0x1000; address < 0x1400; address += (1 << shift)) + { + access.directPeekBase = &myRam[offset + (address & 0x03FF)]; + mySystem->setPageAccess(address >> shift, access); + } + + access.directPeekBase = 0; + + // Map write-port RAM image into the system + for(uInt32 address = 0x1400; address < 0x1800; address += (1 << shift)) + { + access.directPokeBase = &myRam[offset + (address & 0x03FF)]; + mySystem->setPageAccess(address >> shift, access); + } + } +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +int Cartridge3E::bank() { + return myCurrentBank; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +int Cartridge3E::bankCount() { + return mySize/2048; +} + + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +bool Cartridge3E::save(Serializer& out) +{ + string cart = name(); + + try + { + out.putString(cart); + out.putLong(myCurrentBank); + } + catch(char *msg) + { + cerr << msg << endl; + return false; + } + catch(...) + { + cerr << "Unknown error in save state for " << cart << endl; + return false; + } + + return true; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +bool Cartridge3E::load(Deserializer& in) +{ + string cart = name(); + + try + { + if(in.getString() != cart) + return false; + + myCurrentBank = (uInt16) in.getLong(); + } + catch(char *msg) + { + cerr << msg << endl; + return false; + } + catch(...) + { + cerr << "Unknown error in load state for " << cart << endl; + return false; + } + + // Now, go to the current bank + bank(myCurrentBank); + + return true; +} diff --git a/stella/src/emucore/Cart3E.hxx b/stella/src/emucore/Cart3E.hxx new file mode 100644 index 000000000..1f3a2415d --- /dev/null +++ b/stella/src/emucore/Cart3E.hxx @@ -0,0 +1,160 @@ +//============================================================================ +// +// 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-2005 by Bradford W. Mott and the Stella team +// +// See the file "license" for information on usage and redistribution of +// this file, and for a DISCLAIMER OF ALL WARRANTIES. +// +// $Id: Cart3E.hxx,v 1.1 2005-07-08 04:00:09 urchlay Exp $ +//============================================================================ + +#ifndef CARTRIDGE3E_HXX +#define CARTRIDGE3E_HXX + +class Cartridge3E; +class Serializer; +class Deserializer; + +#include "bspf.hxx" +#include "Cart.hxx" + +/** + This is the cartridge class for Tigervision's bankswitched + games with RAM (basically, 3F plus up to 32K of RAM). This + code is basically Brad's Cart3F code plus 32K RAM support. + + In this bankswitching scheme the 2600's 4K cartridge + address space is broken into two 2K segments. The last 2K + segment always points to the last 2K of the ROM image. + + The lower 2K of address space maps to either one of the 2K ROM banks + (up to 256 of them, though only 240 are supposed to be used for + compatibility with the Kroko Cart and Cuttle Cart 2), or else one + of the 1K RAM banks (up to 32 of them). Like other carts with RAM, + this takes up twice the address space that it should: The lower 1K + is the read port, and the upper 1K is the write port (maps to the + same memory). + + To map ROM, the desired bank number of the first 2K segment is selected + by storing its value into $3F. To map RAM in the first 2K segment + instead, store the RAM bank number into $3E. + + This implementation of 3E bankswitching numbers the ROM banks 0 to + 256, and the RAM banks 256 to 287. This is done because the public + bankswitching interface requires us to use one bank number, not one + bank number plus the knowledge of whether it's RAM or ROM. + + All 32K of potential RAM is available to a game using this class, even + though real cartridges might not have the full 32K: We have no way to + tell how much RAM the game expects. This may change in the future (we + may add a stella.pro property for this), but for now it shouldn't cause + any problems. (Famous last words...) + + @author B. Watson + @version $Id: Cart3E.hxx,v 1.1 2005-07-08 04:00:09 urchlay Exp $ +*/ + +class Cartridge3E : public Cartridge +{ + public: + /** + Create a new cartridge using the specified image and size + + @param image Pointer to the ROM image + @param size The size of the ROM image + */ + Cartridge3E(const uInt8* image, uInt32 size); + + /** + Destructor + */ + virtual ~Cartridge3E(); + + public: + /** + Get a null terminated string which is the device's name (i.e. "M6532") + + @return The name of the device + */ + virtual const char* name() const; + + /** + Reset device to its power-on state + */ + virtual 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 + */ + virtual void install(System& system); + + /** + Saves the current state of this device 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); + + /** + Loads the current state of this device from the given Deserializer. + + @param in The deserializer device to load from. + @return The result of the load. True on success, false on failure. + */ + virtual bool load(Deserializer& in); + + public: + /** + Get the byte at the specified address + + @return The byte at the specified address + */ + virtual 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 + */ + virtual void poke(uInt16 address, uInt8 value); + + bool patch(uInt16 address, uInt8 value); + + /** + Map the specified bank into the first segment + + @param bank The bank that should be mapped + */ + void bank(uInt16 bank); + + int bank(); + int bankCount(); + + private: + // Indicates which bank is currently active for the first segment + uInt16 myCurrentBank; + + // Pointer to a dynamically allocated ROM image of the cartridge + uInt8* myImage; + + // RAM contents. For now every ROM gets all 32K of potential RAM + uInt8 myRam[32768]; + + // Size of the ROM image + uInt32 mySize; +}; +#endif + diff --git a/stella/src/emucore/module.mk b/stella/src/emucore/module.mk index 322e72b92..78326074d 100644 --- a/stella/src/emucore/module.mk +++ b/stella/src/emucore/module.mk @@ -4,6 +4,7 @@ MODULE_OBJS := \ src/emucore/Booster.o \ src/emucore/Cart2K.o \ src/emucore/Cart3F.o \ + src/emucore/Cart3E.o \ src/emucore/Cart4K.o \ src/emucore/CartAR.o \ src/emucore/CartCV.o \