diff --git a/src/emucore/CartCTY.cxx b/src/emucore/CartCTY.cxx new file mode 100644 index 000000000..0b74c7bef --- /dev/null +++ b/src/emucore/CartCTY.cxx @@ -0,0 +1,254 @@ +//============================================================================ +// +// 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 +#include + +#include "System.hxx" +#include "CartCTY.hxx" + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +CartridgeCTY::CartridgeCTY(const uInt8* image, uInt32 size, const Settings& settings) + : Cartridge(settings) +{ + // Copy the ROM image into my buffer + memcpy(myImage, image, BSPF_min(32768u, size)); + createCodeAccessBase(32768); + + // This cart contains 64 bytes extended RAM @ 0x1000 + registerRamArea(0x1000, 64, 0x40, 0x00); + + // Remember startup bank + myStartBank = 1; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +CartridgeCTY::~CartridgeCTY() +{ +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void CartridgeCTY::reset() +{ + // Initialize RAM + if(mySettings.getBool("ramrandom")) + for(uInt32 i = 0; i < 256; ++i) + myScoreRAM[i] = mySystem->randGenerator().next(); + else + memset(myScoreRAM, 0, 256); + + // Upon reset we switch to the startup bank + bank(myStartBank); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void CartridgeCTY::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(((0x1080 & mask) == 0) && ((0x1100 & 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 < 0x1080; j += (1 << shift)) + { + access.directPokeBase = &myScoreRAM[j & 0x007F]; + access.codeAccessBase = &myCodeAccessBase[j & 0x007F]; + 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 = 0x1080; k < 0x1100; k += (1 << shift)) + { + access.directPeekBase = &myScoreRAM[k & 0x007F]; + access.codeAccessBase = &myCodeAccessBase[0x80 + (k & 0x007F)]; + mySystem->setPageAccess(k >> shift, access); + } + + // Install pages for the startup bank + bank(myStartBank); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +uInt8 CartridgeCTY::peek(uInt16 address) +{ + uInt16 peekAddress = address; + address &= 0x0FFF; + + // Switch banks if necessary + if((address >= 0x0FF4) && (address <= 0x0FFB)) + bank(address - 0x0FF4); + + if(address < 0x0080) // Write port is at 0xF000 - 0xF080 (128 bytes) + { + // Reading from the write port triggers an unwanted write + uInt8 value = mySystem->getDataBusState(0xFF); + + if(bankLocked()) + return value; + else + { + triggerReadFromWritePort(peekAddress); + return myScoreRAM[address] = value; + } + } + + // 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 myImage[(myCurrentBank << 12) + address]; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +bool CartridgeCTY::poke(uInt16 address, uInt8) +{ + address &= 0x0FFF; + + // Switch banks if necessary + if((address >= 0x0FF4) && (address <= 0x0FFB)) + bank(address - 0x0FF4); + + // 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 CartridgeCTY::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 = (0x1FF4 & ~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 = 0x1100; address < (0x1FF4U & ~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 CartridgeCTY::bank() const +{ + return myCurrentBank; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +uInt16 CartridgeCTY::bankCount() const +{ + return 8; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +bool CartridgeCTY::patch(uInt16 address, uInt8 value) +{ + address &= 0x0FFF; + + if(address < 0x0100) + { + // Normally, a write to the read port won't do anything + // However, the patch command is special in that ignores such + // cart restrictions + myScoreRAM[address & 0x007F] = value; + } + else + myImage[(myCurrentBank << 12) + address] = value; + + return myBankChanged = true; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +const uInt8* CartridgeCTY::getImage(int& size) const +{ + size = 32768; + return myImage; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +bool CartridgeCTY::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)myScoreRAM[i]); + } + catch(const char* msg) + { + cerr << "ERROR: CartridgeCTY::save" << endl << " " << msg << endl; + return false; + } + + return true; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +bool CartridgeCTY::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) + myScoreRAM[i] = (uInt8) in.getByte(); + } + catch(const char* msg) + { + cerr << "ERROR: CartridgeCTY::load" << endl << " " << msg << endl; + return false; + } + + // Remember what bank we were in + bank(myCurrentBank); + + return true; +} diff --git a/src/emucore/CartCTY.hxx b/src/emucore/CartCTY.hxx new file mode 100644 index 000000000..5f940f1fb --- /dev/null +++ b/src/emucore/CartCTY.hxx @@ -0,0 +1,151 @@ +//============================================================================ +// +// 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 CARTRIDGECHETIRY_HXX +#define CARTRIDGECHETIRY_HXX + +class System; + +#include "bspf.hxx" +#include "Cart.hxx" + +/** + TODO - add description from cd-w. + + @author Stephen Anthony and Chris D. Walton + @version $Id$ +*/ +class CartridgeCTY : 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) + */ + CartridgeCTY(const uInt8* image, uInt32 size, const Settings& settings); + + /** + Destructor + */ + virtual ~CartridgeCTY(); + + 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 "CartridgeCTY"; } + + 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 16K ROM image of the cartridge + uInt8 myImage[32768]; + + // The 256 bytes of score-table RAM + uInt8 myScoreRAM[256]; + uInt8* myScorePtr; +}; + +#endif diff --git a/src/emucore/module.mk b/src/emucore/module.mk index 9ccddb4ff..c4d4bc60e 100644 --- a/src/emucore/module.mk +++ b/src/emucore/module.mk @@ -3,15 +3,17 @@ MODULE := src/emucore MODULE_OBJS := \ src/emucore/AtariVox.o \ src/emucore/Booster.o \ + src/emucore/Cart.o \ + src/emucore/Cart0840.o \ src/emucore/Cart2K.o \ - src/emucore/Cart3F.o \ src/emucore/Cart3E.o \ + src/emucore/Cart3F.o \ src/emucore/Cart4A50.o \ src/emucore/Cart4K.o \ src/emucore/CartAR.o \ - src/emucore/CartCV.o \ src/emucore/CartCM.o \ - src/emucore/Cart.o \ + src/emucore/CartCTY.o \ + src/emucore/CartCV.o \ src/emucore/CartDPC.o \ src/emucore/CartDPCPlus.o \ src/emucore/CartE0.o \ @@ -31,7 +33,6 @@ MODULE_OBJS := \ src/emucore/CartMC.o \ src/emucore/CartSB.o \ src/emucore/CartUA.o \ - src/emucore/Cart0840.o \ src/emucore/CartX07.o \ src/emucore/CompuMate.o \ src/emucore/Console.o \