add support for multi segment banking into CartEnhanced class

refactor more cart classes
This commit is contained in:
thrust26 2020-04-04 10:53:14 +02:00
parent 244fc3f7d3
commit 05901a2ad8
35 changed files with 183 additions and 1828 deletions

View File

@ -84,7 +84,7 @@ using ByteArray = std::vector<uInt8>;
using ShortArray = std::vector<uInt16>; using ShortArray = std::vector<uInt16>;
using StringList = std::vector<std::string>; using StringList = std::vector<std::string>;
using ByteBuffer = std::unique_ptr<uInt8[]>; // NOLINT using ByteBuffer = std::unique_ptr<uInt8[]>; // NOLINT
using WordBuffer = std::unique_ptr<uInt16[]>; // NOLINT using DWordBuffer = std::unique_ptr<uInt32[]>; // NOLINT
// We use KB a lot; let's make a literal for it // We use KB a lot; let's make a literal for it
constexpr uInt32 operator "" _KB(unsigned long long size) constexpr uInt32 operator "" _KB(unsigned long long size)

View File

@ -98,9 +98,9 @@ CartridgeE0Widget::CartridgeE0Widget(
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CartridgeE0Widget::loadConfig() void CartridgeE0Widget::loadConfig()
{ {
mySlice0->setSelectedIndex(myCart.myCurrentBank[0]); mySlice0->setSelectedIndex(myCart.myCurrentSegOffset[0] >> myCart.myBankShift);
mySlice1->setSelectedIndex(myCart.myCurrentBank[1]); mySlice1->setSelectedIndex(myCart.myCurrentSegOffset[1] >> myCart.myBankShift);
mySlice2->setSelectedIndex(myCart.myCurrentBank[2]); mySlice2->setSelectedIndex(myCart.myCurrentSegOffset[2] >> myCart.myBankShift);
CartDebugWidget::loadConfig(); CartDebugWidget::loadConfig();
} }
@ -136,9 +136,9 @@ string CartridgeE0Widget::bankState()
ostringstream& buf = buffer(); ostringstream& buf = buffer();
buf << "Slices: " << std::dec buf << "Slices: " << std::dec
<< seg0[myCart.myCurrentBank[0]] << " / " << seg0[myCart.myCurrentSegOffset[0] >> myCart.myBankShift] << " / "
<< seg1[myCart.myCurrentBank[1]] << " / " << seg1[myCart.myCurrentSegOffset[1] >> myCart.myBankShift] << " / "
<< seg2[myCart.myCurrentBank[2]]; << seg2[myCart.myCurrentSegOffset[2] >> myCart.myBankShift];
return buf.str(); return buf.str();
} }

View File

@ -617,7 +617,7 @@ void DebuggerDialog::addRomArea()
// The 'cart-specific' information tab (optional) // The 'cart-specific' information tab (optional)
tabID = myRomTab->addTab(" " + instance().console().cartridge().name() + " ", TabWidget::AUTO_WIDTH); tabID = myRomTab->addTab(" " + instance().console().cartridge().name() + " ", TabWidget::AUTO_WIDTH);
myCartInfo = instance().console().cartridge().infoWidget( myCartInfo = instance().console().cartridge().infoWidget(
myRomTab, *myLFont, *myNFont, 2, 2, tabWidth - 1, myRomTab, *myLFont, *myNFont, 2, 2, tabWidth - 1,
tabHeight - myRomTab->getTabHeight() - 2); tabHeight - myRomTab->getTabHeight() - 2);

View File

@ -21,33 +21,12 @@
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
CartridgeBF::CartridgeBF(const ByteBuffer& image, size_t size, CartridgeBF::CartridgeBF(const ByteBuffer& image, size_t size,
const string& md5, const Settings& settings) const string& md5, const Settings& settings)
: Cartridge(settings, md5) : CartridgeEnhanced(image, size, md5, settings)
{ {
// Copy the ROM image into my buffer
std::copy_n(image.get(), std::min(myImage.size(), size), myImage.begin());
createRomAccessArrays(myImage.size());
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CartridgeBF::reset() bool CartridgeBF::checkSwitchBank(uInt16 address, uInt8)
{
initializeStartBank(1);
// Upon reset we switch to the startup bank
bank(startBank());
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CartridgeBF::install(System& system)
{
mySystem = &system;
// Install pages for the startup bank
bank(startBank());
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt8 CartridgeBF::peek(uInt16 address)
{ {
// Due to the way addressing is set up, we will only get here if the // Due to the way addressing is set up, we will only get here if the
// address is in the hotspot range ($1F80 - $1FFF) // address is in the hotspot range ($1F80 - $1FFF)
@ -55,111 +34,9 @@ uInt8 CartridgeBF::peek(uInt16 address)
// Switch banks if necessary // Switch banks if necessary
if((address >= 0x0F80) && (address <= 0x0FBF)) if((address >= 0x0F80) && (address <= 0x0FBF))
{
bank(address - 0x0F80); bank(address - 0x0F80);
return true;
return myImage[myBankOffset + address]; }
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool CartridgeBF::poke(uInt16 address, uInt8)
{
// Due to the way addressing is set up, we will only get here if the
// address is in the hotspot range ($1F80 - $1FFF)
address &= 0x0FFF;
// Switch banks if necessary
if((address >= 0x0F80) && (address <= 0x0FBF))
bank(address - 0x0F80);
return false; return false;
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool CartridgeBF::bank(uInt16 bank)
{
if(bankLocked()) return false;
// Remember what bank we're in
myBankOffset = bank << 12;
System::PageAccess access(this, System::PageAccessType::READ);
// Set the page accessing methods for the hot spots
for(uInt16 addr = (0x1F80 & ~System::PAGE_MASK); addr < 0x2000;
addr += System::PAGE_SIZE)
{
access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)];
mySystem->setPageAccess(addr, access);
}
// Setup the page access methods for the current bank
for(uInt16 addr = 0x1000; addr < static_cast<uInt16>(0x1F80U & ~System::PAGE_MASK);
addr += System::PAGE_SIZE)
{
access.directPeekBase = &myImage[myBankOffset + (addr & 0x0FFF)];
access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)];
mySystem->setPageAccess(addr, access);
}
return myBankChanged = true;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt16 CartridgeBF::getBank(uInt16) const
{
return myBankOffset >> 12;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt16 CartridgeBF::bankCount() const
{
return 64;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool CartridgeBF::patch(uInt16 address, uInt8 value)
{
myImage[myBankOffset + (address & 0x0FFF)] = value;
return myBankChanged = true;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
const uInt8* CartridgeBF::getImage(size_t& size) const
{
size = myImage.size();
return myImage.data();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool CartridgeBF::save(Serializer& out) const
{
try
{
out.putInt(myBankOffset);
}
catch(...)
{
cerr << "ERROR: CartridgeBF::save" << endl;
return false;
}
return true;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool CartridgeBF::load(Serializer& in)
{
try
{
myBankOffset = in.getInt();
}
catch(...)
{
cerr << "ERROR: CartridgeBF::load" << endl;
return false;
}
// Remember what bank we were in
bank(myBankOffset >> 12);
return true;
}

View File

@ -21,7 +21,7 @@
class System; class System;
#include "bspf.hxx" #include "bspf.hxx"
#include "Cart.hxx" #include "CartEnhanced.hxx"
#ifdef DEBUGGER_SUPPORT #ifdef DEBUGGER_SUPPORT
#include "CartBFWidget.hxx" #include "CartBFWidget.hxx"
#endif #endif
@ -31,9 +31,9 @@ class System;
There are 64 4K banks (total of 256K ROM). There are 64 4K banks (total of 256K ROM).
Accessing $1F80 - $1FBF switches to each bank. Accessing $1F80 - $1FBF switches to each bank.
@author Mike Saarna @author Mike Saarna, Thomas Jentzsch
*/ */
class CartridgeBF : public Cartridge class CartridgeBF : public CartridgeEnhanced
{ {
friend class CartridgeBFWidget; friend class CartridgeBFWidget;
@ -51,71 +51,6 @@ class CartridgeBF : public Cartridge
virtual ~CartridgeBF() = default; virtual ~CartridgeBF() = default;
public: public:
/**
Reset device to its power-on state
*/
void reset() override;
/**
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) override;
/**
Install pages for the specified bank in the system.
@param bank The bank that should be installed in the system
*/
bool bank(uInt16 bank) override;
/**
Get the current bank.
@param address The address to use when querying the bank
*/
uInt16 getBank(uInt16 address = 0) const override;
/**
Query the number of banks supported by the cartridge.
*/
uInt16 bankCount() const override;
/**
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) override;
/**
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(size_t& size) const override;
/**
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 override;
/**
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) override;
/** /**
Get a descriptor for the device name (used in error checking). Get a descriptor for the device name (used in error checking).
@ -135,29 +70,12 @@ class CartridgeBF : public Cartridge
} }
#endif #endif
public:
/**
Get the byte at the specified address.
@return The byte at the specified address
*/
uInt8 peek(uInt16 address) override;
/**
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) override;
private: private:
// The 256K ROM image of the cartridge bool checkSwitchBank(uInt16 address, uInt8 value = 0) override;
std::array<uInt8, 256_KB> myImage;
// Indicates the offset into the ROM image (aligns to current bank) uInt16 romHotspot() const override { return 0x1F80; }
uInt32 myBankOffset{0};
uInt16 getStartBank() const override { return 1; }
private: private:
// Following constructors and assignment operators not supported // Following constructors and assignment operators not supported

View File

@ -21,197 +21,7 @@
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
CartridgeBFSC::CartridgeBFSC(const ByteBuffer& image, size_t size, CartridgeBFSC::CartridgeBFSC(const ByteBuffer& image, size_t size,
const string& md5, const Settings& settings) const string& md5, const Settings& settings)
: Cartridge(settings, md5) : CartridgeBF(image, size, md5, settings)
{ {
// Copy the ROM image into my buffer myRamSize = RAM_SIZE;
std::copy_n(image.get(), std::min(myImage.size(), size), myImage.begin());
createRomAccessArrays(myImage.size());
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CartridgeBFSC::reset()
{
initializeRAM(myRAM.data(), myRAM.size());
initializeStartBank(15);
// Upon reset we switch to the startup bank
bank(startBank());
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CartridgeBFSC::install(System& system)
{
mySystem = &system;
System::PageAccess access(this, System::PageAccessType::READ);
// Set the page accessing method for the RAM writing pages
// Map access to this class, since we need to inspect all accesses to
// check if RWP happens
access.type = System::PageAccessType::WRITE;
for(uInt16 addr = 0x1000; addr < 0x1080; addr += System::PAGE_SIZE)
{
access.romAccessBase = &myRomAccessBase[addr & 0x007F];
mySystem->setPageAccess(addr, access);
}
// Set the page accessing method for the RAM reading pages
access.type = System::PageAccessType::READ;
for(uInt16 addr = 0x1080; addr < 0x1100; addr += System::PAGE_SIZE)
{
access.directPeekBase = &myRAM[addr & 0x007F];
access.romAccessBase = &myRomAccessBase[0x80 + (addr & 0x007F)];
mySystem->setPageAccess(addr, access);
}
// Install pages for the startup bank
bank(startBank());
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt8 CartridgeBFSC::peek(uInt16 address)
{
uInt16 peekAddress = address;
address &= 0x0FFF;
// Switch banks if necessary
if((address >= 0x0F80) && (address <= 0x0FBF))
bank(address - 0x0F80);
if(address < 0x0080) // Write port is at 0xF000 - 0xF07F (128 bytes)
return peekRAM(myRAM[address], peekAddress);
else
return myImage[myBankOffset + address];
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool CartridgeBFSC::poke(uInt16 address, uInt8 value)
{
uInt16 pokeAddress = address;
address &= 0x0FFF;
// Switch banks if necessary
if((address >= 0x0F80) && (address <= 0x0FBF))
{
bank(address - 0x0F80);
return false;
}
if (!(address & 0x080))
{
pokeRAM(myRAM[address & 0x007F], pokeAddress, value);
return true;
}
else
{
// Writing to the read port should be ignored, but trigger a break if option enabled
uInt8 dummy;
pokeRAM(dummy, pokeAddress, value);
myRamWriteAccess = pokeAddress;
return false;
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool CartridgeBFSC::bank(uInt16 bank)
{
if(bankLocked()) return false;
// Remember what bank we're in
myBankOffset = bank << 12;
System::PageAccess access(this, System::PageAccessType::READ);
// Set the page accessing methods for the hot spots
for(uInt16 addr = (0x1F80 & ~System::PAGE_MASK); addr < 0x2000;
addr += System::PAGE_SIZE)
{
access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)];
mySystem->setPageAccess(addr, access);
}
// Setup the page access methods for the current bank
for(uInt16 addr = 0x1100; addr < static_cast<uInt16>(0x1F80U & ~System::PAGE_MASK);
addr += System::PAGE_SIZE)
{
access.directPeekBase = &myImage[myBankOffset + (addr & 0x0FFF)];
access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)];
mySystem->setPageAccess(addr, access);
}
return myBankChanged = true;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt16 CartridgeBFSC::getBank(uInt16) const
{
return myBankOffset >> 12;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt16 CartridgeBFSC::bankCount() const
{
return 64;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool CartridgeBFSC::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
myRAM[address & 0x007F] = value;
}
else
myImage[myBankOffset + address] = value;
return myBankChanged = true;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
const uInt8* CartridgeBFSC::getImage(size_t& size) const
{
size = myImage.size();
return myImage.data();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool CartridgeBFSC::save(Serializer& out) const
{
try
{
out.putInt(myBankOffset);
out.putByteArray(myRAM.data(), myRAM.size());
}
catch(...)
{
cerr << "ERROR: CartridgeBFSC::save" << endl;
return false;
}
return true;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool CartridgeBFSC::load(Serializer& in)
{
try
{
myBankOffset = in.getInt();
in.getByteArray(myRAM.data(), myRAM.size());
}
catch(...)
{
cerr << "ERROR: CartridgeBFSC::load" << endl;
return false;
}
// Remember what bank we were in
bank(myBankOffset >> 12);
return true;
} }

View File

@ -21,7 +21,7 @@
class System; class System;
#include "bspf.hxx" #include "bspf.hxx"
#include "Cart.hxx" #include "CartBF.hxx"
#ifdef DEBUGGER_SUPPORT #ifdef DEBUGGER_SUPPORT
#include "CartBFSCWidget.hxx" #include "CartBFSCWidget.hxx"
#endif #endif
@ -31,9 +31,9 @@ class System;
Accessing $1F80 - $1FBF switches to each bank. Accessing $1F80 - $1FBF switches to each bank.
RAM read port is $1080 - $10FF, write port is $1000 - $107F. RAM read port is $1080 - $10FF, write port is $1000 - $107F.
@author Stephen Anthony @author Stephen Anthony, Thomas Jentzsch
*/ */
class CartridgeBFSC : public Cartridge class CartridgeBFSC : public CartridgeBF
{ {
friend class CartridgeBFSCWidget; friend class CartridgeBFSCWidget;
@ -50,72 +50,6 @@ class CartridgeBFSC : public Cartridge
const Settings& settings); const Settings& settings);
virtual ~CartridgeBFSC() = default; virtual ~CartridgeBFSC() = default;
public:
/**
Reset device to its power-on state
*/
void reset() override;
/**
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) override;
/**
Install pages for the specified bank in the system.
@param bank The bank that should be installed in the system
*/
bool bank(uInt16 bank) override;
/**
Get the current bank.
@param address The address to use when querying the bank
*/
uInt16 getBank(uInt16 address = 0) const override;
/**
Query the number of banks supported by the cartridge.
*/
uInt16 bankCount() const override;
/**
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) override;
/**
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(size_t& size) const override;
/**
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 override;
/**
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) override;
/** /**
Get a descriptor for the device name (used in error checking). Get a descriptor for the device name (used in error checking).
@ -135,32 +69,12 @@ class CartridgeBFSC : public Cartridge
} }
#endif #endif
public: private:
/** uInt16 getStartBank() const override { return 15; }
Get the byte at the specified address.
@return The byte at the specified address
*/
uInt8 peek(uInt16 address) override;
/**
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) override;
private: private:
// The 256K ROM image of the cartridge // RAM size
std::array<uInt8, 256_KB> myImage; static constexpr uInt16 RAM_SIZE = 0x80;
// The 128 bytes of RAM
std::array<uInt8, 128> myRAM;
// Indicates the offset into the ROM image (aligns to current bank)
uInt32 myBankOffset{0};
private: private:
// Following constructors and assignment operators not supported // Following constructors and assignment operators not supported

View File

@ -21,145 +21,20 @@
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
CartridgeDF::CartridgeDF(const ByteBuffer& image, size_t size, CartridgeDF::CartridgeDF(const ByteBuffer& image, size_t size,
const string& md5, const Settings& settings) const string& md5, const Settings& settings)
: Cartridge(settings, md5) : CartridgeEnhanced(image, size, md5, settings)
{ {
// Copy the ROM image into my buffer
std::copy_n(image.get(), std::min(myImage.size(), size), myImage.begin());
createRomAccessArrays(myImage.size());
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CartridgeDF::reset() bool CartridgeDF::checkSwitchBank(uInt16 address, uInt8)
{
initializeStartBank(1);
// Upon reset we switch to the startup bank
bank(startBank());
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CartridgeDF::install(System& system)
{
mySystem = &system;
// Install pages for the startup bank
bank(startBank());
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt8 CartridgeDF::peek(uInt16 address)
{ {
address &= 0x0FFF; address &= 0x0FFF;
// Switch banks if necessary // Switch banks if necessary
if((address >= 0x0FC0) && (address <= 0x0FDF)) if((address >= 0x0FC0) && (address <= 0x0FDF))
{
bank(address - 0x0FC0); bank(address - 0x0FC0);
return true;
return myImage[myBankOffset + address]; }
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool CartridgeDF::poke(uInt16 address, uInt8)
{
address &= 0x0FFF;
// Switch banks if necessary
if((address >= 0x0FC0) && (address <= 0x0FDF))
bank(address - 0x0FC0);
return false; return false;
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool CartridgeDF::bank(uInt16 bank)
{
if(bankLocked()) return false;
// Remember what bank we're in
myBankOffset = bank << 12;
System::PageAccess access(this, System::PageAccessType::READ);
// Set the page accessing methods for the hot spots
for(uInt16 addr = (0x1FC0 & ~System::PAGE_MASK); addr < 0x2000;
addr += System::PAGE_SIZE)
{
access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)];
access.romPeekCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF)];
access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + myAccessSize];
mySystem->setPageAccess(addr, access);
}
// Setup the page access methods for the current bank
for(uInt16 addr = 0x1000; addr < static_cast<uInt16>(0x1FC0U & ~System::PAGE_MASK);
addr += System::PAGE_SIZE)
{
access.directPeekBase = &myImage[myBankOffset + (addr & 0x0FFF)];
access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)];
access.romPeekCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF)];
access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + myAccessSize];
mySystem->setPageAccess(addr, access);
}
return myBankChanged = true;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt16 CartridgeDF::getBank(uInt16) const
{
return myBankOffset >> 12;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt16 CartridgeDF::bankCount() const
{
return 32;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool CartridgeDF::patch(uInt16 address, uInt8 value)
{
myImage[myBankOffset + (address & 0x0FFF)] = value;
return myBankChanged = true;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
const uInt8* CartridgeDF::getImage(size_t& size) const
{
size = myImage.size();
return myImage.data();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool CartridgeDF::save(Serializer& out) const
{
try
{
out.putInt(myBankOffset);
}
catch(...)
{
cerr << "ERROR: CartridgeDF::save" << endl;
return false;
}
return true;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool CartridgeDF::load(Serializer& in)
{
try
{
myBankOffset = in.getInt();
}
catch(...)
{
cerr << "ERROR: CartridgeDF::load" << endl;
return false;
}
// Remember what bank we were in
bank(myBankOffset >> 12);
return true;
}

View File

@ -21,7 +21,7 @@
class System; class System;
#include "bspf.hxx" #include "bspf.hxx"
#include "Cart.hxx" #include "CartEnhanced.hxx"
#ifdef DEBUGGER_SUPPORT #ifdef DEBUGGER_SUPPORT
#include "CartDFWidget.hxx" #include "CartDFWidget.hxx"
#endif #endif
@ -31,9 +31,9 @@ class System;
There are 32 4K banks (total of 128K ROM). There are 32 4K banks (total of 128K ROM).
Accessing $1FC0 - $1FDF switches to each bank. Accessing $1FC0 - $1FDF switches to each bank.
@author Mike Saarna @author Mike Saarna, Thomas Jentzsch
*/ */
class CartridgeDF : public Cartridge class CartridgeDF : public CartridgeEnhanced
{ {
friend class CartridgeDFWidget; friend class CartridgeDFWidget;
@ -51,71 +51,6 @@ class CartridgeDF : public Cartridge
virtual ~CartridgeDF() = default; virtual ~CartridgeDF() = default;
public: public:
/**
Reset device to its power-on state
*/
void reset() override;
/**
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) override;
/**
Install pages for the specified bank in the system.
@param bank The bank that should be installed in the system
*/
bool bank(uInt16 bank) override;
/**
Get the current bank.
@param address The address to use when querying the bank
*/
uInt16 getBank(uInt16 address = 0) const override;
/**
Query the number of banks supported by the cartridge.
*/
uInt16 bankCount() const override;
/**
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) override;
/**
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(size_t& size) const override;
/**
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 override;
/**
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) override;
/** /**
Get a descriptor for the device name (used in error checking). Get a descriptor for the device name (used in error checking).
@ -135,29 +70,12 @@ class CartridgeDF : public Cartridge
} }
#endif #endif
public:
/**
Get the byte at the specified address.
@return The byte at the specified address
*/
uInt8 peek(uInt16 address) override;
/**
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) override;
private: private:
// The 128K ROM image of the cartridge bool checkSwitchBank(uInt16 address, uInt8 value = 0) override;
std::array<uInt8, 128_KB> myImage;
// Indicates the offset into the ROM image (aligns to current bank) uInt16 romHotspot() const override { return 0x1FC0; }
uInt32 myBankOffset{0};
uInt16 getStartBank() const override { return 15; }
private: private:
// Following constructors and assignment operators not supported // Following constructors and assignment operators not supported

View File

@ -21,205 +21,7 @@
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
CartridgeDFSC::CartridgeDFSC(const ByteBuffer& image, size_t size, CartridgeDFSC::CartridgeDFSC(const ByteBuffer& image, size_t size,
const string& md5, const Settings& settings) const string& md5, const Settings& settings)
: Cartridge(settings, md5) : CartridgeDF(image, size, md5, settings)
{ {
// Copy the ROM image into my buffer myRamSize = RAM_SIZE;
std::copy_n(image.get(), std::min(myImage.size(), size), myImage.begin());
createRomAccessArrays(myImage.size());
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CartridgeDFSC::reset()
{
initializeRAM(myRAM.data(), myRAM.size());
initializeStartBank(15);
// Upon reset we switch to the startup bank
bank(startBank());
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CartridgeDFSC::install(System& system)
{
mySystem = &system;
System::PageAccess access(this, System::PageAccessType::READ);
// Set the page accessing method for the RAM writing pages
// Map access to this class, since we need to inspect all accesses to
// check if RWP happens
access.type = System::PageAccessType::WRITE;
for(uInt16 addr = 0x1000; addr < 0x1080; addr += System::PAGE_SIZE)
{
access.romAccessBase = &myRomAccessBase[addr & 0x007F];
access.romPeekCounter = &myRomAccessCounter[addr & 0x007F];
access.romPokeCounter = &myRomAccessCounter[(addr & 0x007F) + myAccessSize];
mySystem->setPageAccess(addr, access);
}
// Set the page accessing method for the RAM reading pages
access.type = System::PageAccessType::READ;
for(uInt16 addr = 0x1080; addr < 0x1100; addr += System::PAGE_SIZE)
{
access.directPeekBase = &myRAM[addr & 0x007F];
access.romAccessBase = &myRomAccessBase[0x80 + (addr & 0x007F)];
access.romPeekCounter = &myRomAccessCounter[0x80 + (addr & 0x007F)];
access.romPokeCounter = &myRomAccessCounter[0x80 + (addr & 0x007F) + myAccessSize];
mySystem->setPageAccess(addr, access);
}
// Install pages for the startup bank
bank(startBank());
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt8 CartridgeDFSC::peek(uInt16 address)
{
uInt16 peekAddress = address;
address &= 0x0FFF;
// Switch banks if necessary
if((address >= 0x0FC0) && (address <= 0x0FDF))
bank(address - 0x0FC0);
if(address < 0x0080) // Write port is at 0xF000 - 0xF07F (128 bytes)
return peekRAM(myRAM[address], peekAddress);
else
return myImage[myBankOffset + address];
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool CartridgeDFSC::poke(uInt16 address, uInt8 value)
{
uInt16 pokeAddress = address;
address &= 0x0FFF;
// Switch banks if necessary
if((address >= 0x0FC0) && (address <= 0x0FDF))
{
bank(address - 0x0FC0);
return false;
}
if(!(address & 0x080))
{
pokeRAM(myRAM[address & 0x007F], pokeAddress, value);
return true;
}
else
{
// Writing to the read port should be ignored, but trigger a break if option enabled
uInt8 dummy;
pokeRAM(dummy, pokeAddress, value);
myRamWriteAccess = pokeAddress;
return false;
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool CartridgeDFSC::bank(uInt16 bank)
{
if(bankLocked()) return false;
// Remember what bank we're in
myBankOffset = bank << 12;
System::PageAccess access(this, System::PageAccessType::READ);
// Set the page accessing methods for the hot spots
for(uInt16 addr = (0x1FC0 & ~System::PAGE_MASK); addr < 0x2000;
addr += System::PAGE_SIZE)
{
access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)];
access.romPeekCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF)];
access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + myAccessSize];
mySystem->setPageAccess(addr, access);
}
// Setup the page access methods for the current bank
for(uInt16 addr = 0x1100; addr < static_cast<uInt16>(0x1FC0U & ~System::PAGE_MASK);
addr += System::PAGE_SIZE)
{
access.directPeekBase = &myImage[myBankOffset + (addr & 0x0FFF)];
access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)];
access.romPeekCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF)];
access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + myAccessSize];
mySystem->setPageAccess(addr, access);
}
return myBankChanged = true;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt16 CartridgeDFSC::getBank(uInt16) const
{
return myBankOffset >> 12;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt16 CartridgeDFSC::bankCount() const
{
return 32;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool CartridgeDFSC::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
myRAM[address & 0x007F] = value;
}
else
myImage[myBankOffset + address] = value;
return myBankChanged = true;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
const uInt8* CartridgeDFSC::getImage(size_t& size) const
{
size = myImage.size();
return myImage.data();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool CartridgeDFSC::save(Serializer& out) const
{
try
{
out.putInt(myBankOffset);
out.putByteArray(myRAM.data(), myRAM.size());
}
catch(...)
{
cerr << "ERROR: CartridgeDFSC::save" << endl;
return false;
}
return true;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool CartridgeDFSC::load(Serializer& in)
{
try
{
myBankOffset = in.getInt();
in.getByteArray(myRAM.data(), myRAM.size());
}
catch(...)
{
cerr << "ERROR: CartridgeDFSC::load" << endl;
return false;
}
// Remember what bank we were in
bank(myBankOffset >> 12);
return true;
} }

View File

@ -21,7 +21,7 @@
class System; class System;
#include "bspf.hxx" #include "bspf.hxx"
#include "Cart.hxx" #include "CartDF.hxx"
#ifdef DEBUGGER_SUPPORT #ifdef DEBUGGER_SUPPORT
#include "CartDFSCWidget.hxx" #include "CartDFSCWidget.hxx"
#endif #endif
@ -31,9 +31,9 @@ class System;
Accessing $1FC0 - $1FDF switches to each bank. Accessing $1FC0 - $1FDF switches to each bank.
RAM read port is $1080 - $10FF, write port is $1000 - $107F. RAM read port is $1080 - $10FF, write port is $1000 - $107F.
@author Stephen Anthony @author Stephen Anthony, Thomas Jentzsch
*/ */
class CartridgeDFSC : public Cartridge class CartridgeDFSC : public CartridgeDF
{ {
friend class CartridgeDFSCWidget; friend class CartridgeDFSCWidget;
@ -51,71 +51,6 @@ class CartridgeDFSC : public Cartridge
virtual ~CartridgeDFSC() = default; virtual ~CartridgeDFSC() = default;
public: public:
/**
Reset device to its power-on state
*/
void reset() override;
/**
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) override;
/**
Install pages for the specified bank in the system.
@param bank The bank that should be installed in the system
*/
bool bank(uInt16 bank) override;
/**
Get the current bank.
@param address The address to use when querying the bank
*/
uInt16 getBank(uInt16 address = 0) const override;
/**
Query the number of banks supported by the cartridge.
*/
uInt16 bankCount() const override;
/**
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) override;
/**
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(size_t& size) const override;
/**
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 override;
/**
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) override;
/** /**
Get a descriptor for the device name (used in error checking). Get a descriptor for the device name (used in error checking).
@ -135,34 +70,11 @@ class CartridgeDFSC : public Cartridge
} }
#endif #endif
public:
/**
Get the byte at the specified address.
@return The byte at the specified address
*/
uInt8 peek(uInt16 address) override;
/**
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) override;
private: private:
// The 128K ROM image of the cartridge // RAM size
std::array<uInt8, 128_KB> myImage; static constexpr uInt16 RAM_SIZE = 0x80;
// The 128 bytes of RAM private:
std::array<uInt8, 128> myRAM;
// Indicates the offset into the ROM image (aligns to current bank)
uInt32 myBankOffset{0};
private:
// Following constructors and assignment operators not supported // Following constructors and assignment operators not supported
CartridgeDFSC() = delete; CartridgeDFSC() = delete;
CartridgeDFSC(const CartridgeDFSC&) = delete; CartridgeDFSC(const CartridgeDFSC&) = delete;

View File

@ -21,11 +21,9 @@
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
CartridgeE0::CartridgeE0(const ByteBuffer& image, size_t size, CartridgeE0::CartridgeE0(const ByteBuffer& image, size_t size,
const string& md5, const Settings& settings) const string& md5, const Settings& settings)
: Cartridge(settings, md5) : CartridgeEnhanced(image, size, md5, settings)
{ {
// Copy the ROM image into my buffer myBankShift = BANK_SHIFT;
std::copy_n(image.get(), std::min(myImage.size(), size), myImage.begin());
createRomAccessArrays(myImage.size());
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -44,7 +42,7 @@ void CartridgeE0::reset()
bank(5, 1); bank(5, 1);
bank(6, 2); bank(6, 2);
} }
myCurrentBank[3] = bankCount() - 1; // fixed myCurrentSegOffset[3] = (bankCount() - 1) << myBankShift; // fixed
myBankChanged = true; myBankChanged = true;
} }
@ -52,7 +50,13 @@ void CartridgeE0::reset()
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CartridgeE0::install(System& system) void CartridgeE0::install(System& system)
{ {
mySystem = &system; //// Allocate array for the current bank segments slices
//myCurrentSegOffset = make_unique<uInt16[]>(myBankSegs);
//// Setup page access
//mySystem = &system;
CartridgeEnhanced::install(system);
System::PageAccess access(this, System::PageAccessType::READ); System::PageAccess access(this, System::PageAccessType::READ);
@ -79,127 +83,23 @@ void CartridgeE0::install(System& system)
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt16 CartridgeE0::getBank(uInt16 address) const bool CartridgeE0::checkSwitchBank(uInt16 address, uInt8)
{ {
return myCurrentBank[(address & 0xFFF) >> 10]; // 1K slices
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt16 CartridgeE0::bankCount() const
{
return 8;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt8 CartridgeE0::peek(uInt16 address)
{
address &= 0x0FFF;
// Switch banks if necessary
if((address >= 0x0FE0) && (address <= 0x0FE7))
{
bank(address & 0x0007, 0);
}
else if((address >= 0x0FE8) && (address <= 0x0FEF))
{
bank(address & 0x0007, 1);
}
else if((address >= 0x0FF0) && (address <= 0x0FF7))
{
bank(address & 0x0007, 2);
}
return myImage[(myCurrentBank[address >> 10] << 10) + (address & 0x03FF)];
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool CartridgeE0::poke(uInt16 address, uInt8)
{
address &= 0x0FFF;
// Switch banks if necessary // Switch banks if necessary
if((address >= 0x0FE0) && (address <= 0x0FE7)) if((address >= 0x0FE0) && (address <= 0x0FE7))
{ {
bank(address & 0x0007, 0); bank(address & 0x0007, 0);
return true;
} }
else if((address >= 0x0FE8) && (address <= 0x0FEF)) else if((address >= 0x0FE8) && (address <= 0x0FEF))
{ {
bank(address & 0x0007, 1); bank(address & 0x0007, 1);
return true;
} }
else if((address >= 0x0FF0) && (address <= 0x0FF7)) else if((address >= 0x0FF0) && (address <= 0x0FF7))
{ {
bank(address & 0x0007, 2); bank(address & 0x0007, 2);
return true;
} }
return false; return false;
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CartridgeE0::bank(uInt16 bank, uInt16 slice)
{
if(bankLocked()) return;
// Remember the new slice
myCurrentBank[slice] = bank;
uInt16 sliceOffset = slice * (1 << 10);
uInt16 bankOffset = bank << 10;
// Setup the page access methods for the current bank
System::PageAccess access(this, System::PageAccessType::READ);
for(uInt16 addr = 0x1000 + sliceOffset; addr < 0x1000 + sliceOffset + 0x400; addr += System::PAGE_SIZE)
{
access.directPeekBase = &myImage[bankOffset + (addr & 0x03FF)];
access.romAccessBase = &myRomAccessBase[bankOffset + (addr & 0x03FF)];
access.romPeekCounter = &myRomAccessCounter[bankOffset + (addr & 0x03FF)];
access.romPokeCounter = &myRomAccessCounter[bankOffset + (addr & 0x03FF) + myAccessSize];
mySystem->setPageAccess(addr, access);
}
myBankChanged = true;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool CartridgeE0::patch(uInt16 address, uInt8 value)
{
address &= 0x0FFF;
myImage[(myCurrentBank[address >> 10] << 10) + (address & 0x03FF)] = value;
return true;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
const uInt8* CartridgeE0::getImage(size_t& size) const
{
size = myImage.size();
return myImage.data();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool CartridgeE0::save(Serializer& out) const
{
try
{
out.putShortArray(myCurrentBank.data(), myCurrentBank.size());
}
catch(...)
{
cerr << "ERROR: CartridgeE0::save" << endl;
return false;
}
return true;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool CartridgeE0::load(Serializer& in)
{
try
{
in.getShortArray(myCurrentBank.data(), myCurrentBank.size());
}
catch(...)
{
cerr << "ERROR: CartridgeE0::load" << endl;
return false;
}
return true;
}

View File

@ -21,7 +21,7 @@
class System; class System;
#include "bspf.hxx" #include "bspf.hxx"
#include "Cart.hxx" #include "CartEnhanced.hxx"
#ifdef DEBUGGER_SUPPORT #ifdef DEBUGGER_SUPPORT
#include "CartE0Widget.hxx" #include "CartE0Widget.hxx"
#endif #endif
@ -39,9 +39,9 @@ class System;
only one actual bank, in which pieces of it can be swapped out in only one actual bank, in which pieces of it can be swapped out in
many different ways. many different ways.
@author Bradford W. Mott @author Bradford W. Mott, Thomas Jentzsch
*/ */
class CartridgeE0 : public Cartridge class CartridgeE0 : public CartridgeEnhanced
{ {
friend class CartridgeE0Widget; friend class CartridgeE0Widget;
@ -72,52 +72,6 @@ class CartridgeE0 : public Cartridge
*/ */
void install(System& system) override; void install(System& system) override;
/**
Get the current bank.
@param address The address to use when querying the bank
*/
uInt16 getBank(uInt16 address = 0) const override;
/**
Query the number of banks supported by the cartridge.
*/
uInt16 bankCount() const override;
/**
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) override;
/**
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(size_t& size) const override;
/**
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 override;
/**
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) override;
/** /**
Get a descriptor for the device name (used in error checking). Get a descriptor for the device name (used in error checking).
@ -137,37 +91,14 @@ class CartridgeE0 : public Cartridge
} }
#endif #endif
public: private:
/** bool checkSwitchBank(uInt16 address, uInt8 = 0) override;
Get the byte at the specified address.
@return The byte at the specified address uInt16 romHotspot() const override { return 0x1FE0; }
*/
uInt8 peek(uInt16 address) override;
/**
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) override;
private: private:
/** // log(ROM bank segment size) / log(2)
Install the specified slice for segment (bank) 0..2 static constexpr uInt16 BANK_SHIFT = 10; // = 1K = 0x0400
@param slice The slice to map into the segment
*/
void bank(uInt16 bank, uInt16 slice);
private:
// The 8K ROM image of the cartridge
std::array<uInt8, 8_KB> myImage;
// Indicates the slice mapped into each of the four segments
std::array<uInt16, 4> myCurrentBank;
private: private:
// Following constructors and assignment operators not supported // Following constructors and assignment operators not supported

View File

@ -21,145 +21,20 @@
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
CartridgeEF::CartridgeEF(const ByteBuffer& image, size_t size, CartridgeEF::CartridgeEF(const ByteBuffer& image, size_t size,
const string& md5, const Settings& settings) const string& md5, const Settings& settings)
: Cartridge(settings, md5) : CartridgeEnhanced(image, size, md5, settings)
{ {
// Copy the ROM image into my buffer
std::copy_n(image.get(), std::min(myImage.size(), size), myImage.begin());
createRomAccessArrays(myImage.size());
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CartridgeEF::reset() bool CartridgeEF::checkSwitchBank(uInt16 address, uInt8)
{
initializeStartBank(1);
// Upon reset we switch to the startup bank
bank(startBank());
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CartridgeEF::install(System& system)
{
mySystem = &system;
// Install pages for the startup bank
bank(startBank());
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt8 CartridgeEF::peek(uInt16 address)
{ {
address &= 0x0FFF; address &= 0x0FFF;
// Switch banks if necessary // Switch banks if necessary
if((address >= 0x0FE0) && (address <= 0x0FEF)) if((address >= 0x0FE0) && (address <= 0x0FEF))
{
bank(address - 0x0FE0); bank(address - 0x0FE0);
return true;
return myImage[myBankOffset + address]; }
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool CartridgeEF::poke(uInt16 address, uInt8)
{
address &= 0x0FFF;
// Switch banks if necessary
if((address >= 0x0FE0) && (address <= 0x0FEF))
bank(address - 0x0FE0);
return false; return false;
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool CartridgeEF::bank(uInt16 bank)
{
if(bankLocked()) return false;
// Remember what bank we're in
myBankOffset = bank << 12;
System::PageAccess access(this, System::PageAccessType::READ);
// Set the page accessing methods for the hot spots
for(uInt16 addr = (0x1FE0 & ~System::PAGE_MASK); addr < 0x2000;
addr += System::PAGE_SIZE)
{
access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)];
access.romPeekCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF)];
access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + myAccessSize];
mySystem->setPageAccess(addr, access);
}
// Setup the page access methods for the current bank
for(uInt16 addr = 0x1000; addr < static_cast<uInt16>(0x1FE0U & ~System::PAGE_MASK);
addr += System::PAGE_SIZE)
{
access.directPeekBase = &myImage[myBankOffset + (addr & 0x0FFF)];
access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)];
access.romPeekCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF)];
access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + myAccessSize];
mySystem->setPageAccess(addr, access);
}
return myBankChanged = true;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt16 CartridgeEF::getBank(uInt16) const
{
return myBankOffset >> 12;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt16 CartridgeEF::bankCount() const
{
return 16;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool CartridgeEF::patch(uInt16 address, uInt8 value)
{
myImage[myBankOffset + (address & 0x0FFF)] = value;
return myBankChanged = true;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
const uInt8* CartridgeEF::getImage(size_t& size) const
{
size = myImage.size();
return myImage.data();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool CartridgeEF::save(Serializer& out) const
{
try
{
out.putShort(myBankOffset);
}
catch(...)
{
cerr << "ERROR: CartridgeEF::save" << endl;
return false;
}
return true;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool CartridgeEF::load(Serializer& in)
{
try
{
myBankOffset = in.getShort();
}
catch(...)
{
cerr << "ERROR: CartridgeEF::load" << endl;
return false;
}
// Remember what bank we were in
bank(myBankOffset >> 12);
return true;
}

View File

@ -21,7 +21,7 @@
class System; class System;
#include "bspf.hxx" #include "bspf.hxx"
#include "Cart.hxx" #include "CartEnhanced.hxx"
#ifdef DEBUGGER_SUPPORT #ifdef DEBUGGER_SUPPORT
#include "CartEFWidget.hxx" #include "CartEFWidget.hxx"
#endif #endif
@ -31,9 +31,9 @@ class System;
There are 16 4K banks (total of 64K ROM). There are 16 4K banks (total of 64K ROM).
Accessing $1FE0 - $1FEF switches to each bank. Accessing $1FE0 - $1FEF switches to each bank.
@author Stephen Anthony @author Stephen Anthony, Thomas Jentzsch
*/ */
class CartridgeEF : public Cartridge class CartridgeEF : public CartridgeEnhanced
{ {
friend class CartridgeEFWidget; friend class CartridgeEFWidget;
@ -51,71 +51,6 @@ class CartridgeEF : public Cartridge
virtual ~CartridgeEF() = default; virtual ~CartridgeEF() = default;
public: public:
/**
Reset device to its power-on state
*/
void reset() override;
/**
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) override;
/**
Install pages for the specified bank in the system.
@param bank The bank that should be installed in the system
*/
bool bank(uInt16 bank) override;
/**
Get the current bank.
@param address The address to use when querying the bank
*/
uInt16 getBank(uInt16 address = 0) const override;
/**
Query the number of banks supported by the cartridge.
*/
uInt16 bankCount() const override;
/**
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) override;
/**
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(size_t& size) const override;
/**
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 override;
/**
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) override;
/** /**
Get a descriptor for the device name (used in error checking). Get a descriptor for the device name (used in error checking).
@ -135,29 +70,12 @@ class CartridgeEF : public Cartridge
} }
#endif #endif
public:
/**
Get the byte at the specified address.
@return The byte at the specified address
*/
uInt8 peek(uInt16 address) override;
/**
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) override;
private: private:
// The 64K ROM image of the cartridge bool checkSwitchBank(uInt16 address, uInt8 value = 0) override;
std::array<uInt8, 64_KB> myImage;
// Indicates the offset into the ROM image (aligns to current bank) uInt16 romHotspot() const override { return 0x1FE0; }
uInt16 myBankOffset{0};
uInt16 getStartBank() const override { return 1; }
private: private:
// Following constructors and assignment operators not supported // Following constructors and assignment operators not supported

View File

@ -21,205 +21,7 @@
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
CartridgeEFSC::CartridgeEFSC(const ByteBuffer& image, size_t size, CartridgeEFSC::CartridgeEFSC(const ByteBuffer& image, size_t size,
const string& md5, const Settings& settings) const string& md5, const Settings& settings)
: Cartridge(settings, md5) : CartridgeEF(image, size, md5, settings)
{ {
// Copy the ROM image into my buffer myRamSize = RAM_SIZE;
std::copy_n(image.get(), std::min(myImage.size(), size), myImage.begin());
createRomAccessArrays(myImage.size());
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CartridgeEFSC::reset()
{
initializeRAM(myRAM.data(), myRAM.size());
initializeStartBank(15);
// Upon reset we switch to the startup bank
bank(startBank());
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CartridgeEFSC::install(System& system)
{
mySystem = &system;
System::PageAccess access(this, System::PageAccessType::READ);
// Set the page accessing method for the RAM writing pages
// Map access to this class, since we need to inspect all accesses to
// check if RWP happens
access.type = System::PageAccessType::WRITE;
for(uInt16 addr = 0x1000; addr < 0x1080; addr += System::PAGE_SIZE)
{
access.romAccessBase = &myRomAccessBase[addr & 0x007F];
access.romPeekCounter = &myRomAccessCounter[addr & 0x007F];
access.romPokeCounter = &myRomAccessCounter[(addr & 0x007F) + myAccessSize];
mySystem->setPageAccess(addr, access);
}
// Set the page accessing method for the RAM reading pages
access.type = System::PageAccessType::READ;
for(uInt16 addr = 0x1080; addr < 0x1100; addr += System::PAGE_SIZE)
{
access.directPeekBase = &myRAM[addr & 0x007F];
access.romAccessBase = &myRomAccessBase[0x80 + (addr & 0x007F)];
access.romPeekCounter = &myRomAccessCounter[0x80 + (addr & 0x007F)];
access.romPokeCounter = &myRomAccessCounter[0x80 + (addr & 0x007F) + myAccessSize];
mySystem->setPageAccess(addr, access);
}
// Install pages for the startup bank
bank(startBank());
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt8 CartridgeEFSC::peek(uInt16 address)
{
uInt16 peekAddress = address;
address &= 0x0FFF;
// Switch banks if necessary
if((address >= 0x0FE0) && (address <= 0x0FEF))
bank(address - 0x0FE0);
if(address < 0x0080) // Write port is at 0xF000 - 0xF07F (128 bytes)
return peekRAM(myRAM[address], peekAddress);
else
return myImage[myBankOffset + address];
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool CartridgeEFSC::poke(uInt16 address, uInt8 value)
{
uInt16 pokeAddress = address;
address &= 0x0FFF;
// Switch banks if necessary
if((address >= 0x0FE0) && (address <= 0x0FEF))
{
bank(address - 0x0FE0);
return false;
}
if (!(address & 0x080))
{
pokeRAM(myRAM[address & 0x007F], pokeAddress, value);
return true;
}
else
{
// Writing to the read port should be ignored, but trigger a break if option enabled
uInt8 dummy;
pokeRAM(dummy, pokeAddress, value);
myRamWriteAccess = pokeAddress;
return false;
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool CartridgeEFSC::bank(uInt16 bank)
{
if(bankLocked()) return false;
// Remember what bank we're in
myBankOffset = bank << 12;
System::PageAccess access(this, System::PageAccessType::READ);
// Set the page accessing methods for the hot spots
for(uInt16 addr = (0x1FE0 & ~System::PAGE_MASK); addr < 0x2000;
addr += System::PAGE_SIZE)
{
access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)];
access.romPeekCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF)];
access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + myAccessSize];
mySystem->setPageAccess(addr, access);
}
// Setup the page access methods for the current bank
for(uInt16 addr = 0x1100; addr < static_cast<uInt16>(0x1FE0U & ~System::PAGE_MASK);
addr += System::PAGE_SIZE)
{
access.directPeekBase = &myImage[myBankOffset + (addr & 0x0FFF)];
access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)];
access.romPeekCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF)];
access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + myAccessSize];
mySystem->setPageAccess(addr, access);
}
return myBankChanged = true;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt16 CartridgeEFSC::getBank(uInt16) const
{
return myBankOffset >> 12;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt16 CartridgeEFSC::bankCount() const
{
return 16;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool CartridgeEFSC::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
myRAM[address & 0x007F] = value;
}
else
myImage[myBankOffset + address] = value;
return myBankChanged = true;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
const uInt8* CartridgeEFSC::getImage(size_t& size) const
{
size = myImage.size();
return myImage.data();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool CartridgeEFSC::save(Serializer& out) const
{
try
{
out.putShort(myBankOffset);
out.putByteArray(myRAM.data(), myRAM.size());
}
catch(...)
{
cerr << "ERROR: CartridgeEFSC::save" << endl;
return false;
}
return true;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool CartridgeEFSC::load(Serializer& in)
{
try
{
myBankOffset = in.getShort();
in.getByteArray(myRAM.data(), myRAM.size());
}
catch(...)
{
cerr << "ERROR: CartridgeEFSC::load" << endl;
return false;
}
// Remember what bank we were in
bank(myBankOffset >> 12);
return true;
} }

View File

@ -21,7 +21,7 @@
class System; class System;
#include "bspf.hxx" #include "bspf.hxx"
#include "Cart.hxx" #include "CartEF.hxx"
#ifdef DEBUGGER_SUPPORT #ifdef DEBUGGER_SUPPORT
#include "CartEFSCWidget.hxx" #include "CartEFSCWidget.hxx"
#endif #endif
@ -32,9 +32,9 @@ class System;
Accessing $1FE0 - $1FEF switches to each bank. Accessing $1FE0 - $1FEF switches to each bank.
RAM read port is $1080 - $10FF, write port is $1000 - $107F. RAM read port is $1080 - $10FF, write port is $1000 - $107F.
@author Stephen Anthony @author Stephen Anthony, Thomas Jentzsch
*/ */
class CartridgeEFSC : public Cartridge class CartridgeEFSC : public CartridgeEF
{ {
friend class CartridgeEFSCWidget; friend class CartridgeEFSCWidget;
@ -52,71 +52,6 @@ class CartridgeEFSC : public Cartridge
virtual ~CartridgeEFSC() = default; virtual ~CartridgeEFSC() = default;
public: public:
/**
Reset device to its power-on state
*/
void reset() override;
/**
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) override;
/**
Install pages for the specified bank in the system.
@param bank The bank that should be installed in the system
*/
bool bank(uInt16 bank) override;
/**
Get the current bank.
@param address The address to use when querying the bank
*/
uInt16 getBank(uInt16 address = 0) const override;
/**
Query the number of banks supported by the cartridge.
*/
uInt16 bankCount() const override;
/**
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) override;
/**
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(size_t& size) const override;
/**
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 override;
/**
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) override;
/** /**
Get a descriptor for the device name (used in error checking). Get a descriptor for the device name (used in error checking).
@ -136,32 +71,12 @@ class CartridgeEFSC : public Cartridge
} }
#endif #endif
public: private:
/** uInt16 getStartBank() const override { return 15; }
Get the byte at the specified address.
@return The byte at the specified address
*/
uInt8 peek(uInt16 address) override;
/**
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) override;
private: private:
// The 64K ROM image of the cartridge // RAM size
std::array<uInt8, 64_KB> myImage; static constexpr uInt16 RAM_SIZE = 0x80;
// The 128 bytes of RAM
std::array<uInt8, 128> myRAM;
// Indicates the offset into the ROM image (aligns to current bank)
uInt16 myBankOffset{0};
private: private:
// Following constructors and assignment operators not supported // Following constructors and assignment operators not supported

View File

@ -37,9 +37,14 @@ CartridgeEnhanced::CartridgeEnhanced(const ByteBuffer& image, size_t size,
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CartridgeEnhanced::install(System& system) void CartridgeEnhanced::install(System& system)
{ {
// calculate bank switching and RAM sizes and masks
myBankSize = 1 << myBankShift; // e.g. = 2 ^ 12 = 4K = 0x1000
myBankMask = myBankSize - 1; // e.g. = 0x0FFF
myBankSegs = 1 << (12 - myBankShift); // e.g. = 1
myRamMask = myRamSize - 1; // e.g. = 0xFFFF (doesn't matter for RAM size 0)
// Allocate array for the current bank segments slices // Allocate array for the current bank segments slices
myCurrentBankOffset = make_unique<uInt16[]>(BANK_SEGS); myCurrentSegOffset = make_unique<uInt32[]>(myBankSegs);
std::fill_n(myCurrentBankOffset.get(), BANK_SEGS, 0);
// Allocate array for the RAM area // Allocate array for the RAM area
myRAM = make_unique<uInt8[]>(myRamSize); myRAM = make_unique<uInt8[]>(myRamSize);
@ -93,24 +98,22 @@ void CartridgeEnhanced::reset()
uInt8 CartridgeEnhanced::peek(uInt16 address) uInt8 CartridgeEnhanced::peek(uInt16 address)
{ {
uInt16 peekAddress = address; uInt16 peekAddress = address;
address &= myBankMask;
checkSwitchBank(address); checkSwitchBank(address & 0x0FFF);
address &= myBankMask;
if(address < myRamSize) // Write port is at 0xF000 - 0xF07F (128 bytes) if(address < myRamSize) // Write port is at 0xF000 - 0xF07F (128 bytes)
return peekRAM(myRAM[address], peekAddress); return peekRAM(myRAM[address], peekAddress);
else else
return myImage[myBankOffset + address]; //return myImage[myBankOffset + address];
return myImage[myCurrentBankOffset[address >> BANK_SHIFT] + (address & BANK_MASK)]; return myImage[myCurrentSegOffset[(peekAddress & 0xFFF) >> myBankShift] + address];
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool CartridgeEnhanced::poke(uInt16 address, uInt8 value) bool CartridgeEnhanced::poke(uInt16 address, uInt8 value)
{ {
address &= myBankMask;
// Switch banks if necessary // Switch banks if necessary
if (checkSwitchBank(address & myBankMask)) if (checkSwitchBank(address & 0x0FFF))
return false; return false;
if(myRamSize) if(myRamSize)
@ -133,45 +136,34 @@ bool CartridgeEnhanced::poke(uInt16 address, uInt8 value)
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool CartridgeEnhanced::bank(uInt16 bank, uInt16 slice) bool CartridgeEnhanced::bank(uInt16 bank, uInt16 segment)
{ {
if(bankLocked()) return false; if(bankLocked()) return false;
// Remember what bank we're in // Remember what bank is in which segment
myBankOffset = bank << myBankShift; uInt32 bankOffset = myCurrentSegOffset[segment] = bank << myBankShift;
uInt16 segmentOffset = segment << myBankShift;
uInt16 romHotspot = this->romHotspot(); uInt16 romHotspot = this->romHotspot();
uInt16 fromAddr = 0x1000 + myRamSize * 2; uInt16 hotSpotAddr;
uInt16 toAddr; uInt16 fromAddr = (segmentOffset + 0x1000 + myRamSize * 2) & ~System::PAGE_MASK;
uInt16 toAddr = (segmentOffset + 0x1000 + myBankSize) & ~System::PAGE_MASK;
if(romHotspot) if(romHotspot)
{ hotSpotAddr = segmentOffset + (romHotspot & ~System::PAGE_MASK);
System::PageAccess access(this, System::PageAccessType::READ);
// Set the page accessing methods for the hot spots
for(uInt16 addr = (romHotspot & ~System::PAGE_MASK); addr < 0x1000 + myBankSize;
addr += System::PAGE_SIZE)
{
uInt16 offset = myBankOffset + (addr & myBankMask);
access.romAccessBase = &myRomAccessBase[offset];
access.romPeekCounter = &myRomAccessCounter[offset];
access.romPokeCounter = &myRomAccessCounter[offset + myAccessSize];
mySystem->setPageAccess(addr, access);
}
toAddr = romHotspot;
}
else else
toAddr = 0x1000 + myBankSize; hotSpotAddr = 0xFFFF; // none
System::PageAccess access(this, System::PageAccessType::READ); System::PageAccess access(this, System::PageAccessType::READ);
// Setup the page access methods for the current bank // Setup the page access methods for the current bank
for(uInt16 addr = (fromAddr & ~System::PAGE_MASK); addr < (toAddr & ~System::PAGE_MASK); for(uInt16 addr = fromAddr; addr < toAddr; addr += System::PAGE_SIZE)
addr += System::PAGE_SIZE)
{ {
uInt16 offset = myBankOffset + (addr & myBankMask); uInt32 offset = bankOffset + (addr & myBankMask);
if(myDirectPeek)
if(myDirectPeek && addr != hotSpotAddr)
access.directPeekBase = &myImage[offset]; access.directPeekBase = &myImage[offset];
else
access.directPeekBase = nullptr;
access.romAccessBase = &myRomAccessBase[offset]; access.romAccessBase = &myRomAccessBase[offset];
access.romPeekCounter = &myRomAccessCounter[offset]; access.romPeekCounter = &myRomAccessCounter[offset];
access.romPokeCounter = &myRomAccessCounter[offset + myAccessSize]; access.romPokeCounter = &myRomAccessCounter[offset + myAccessSize];
@ -182,9 +174,9 @@ bool CartridgeEnhanced::bank(uInt16 bank, uInt16 slice)
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt16 CartridgeEnhanced::getBank(uInt16) const uInt16 CartridgeEnhanced::getBank(uInt16 address) const
{ {
return myBankOffset >> myBankShift; return myCurrentSegOffset[(address & 0xFFF) >> myBankShift] >> myBankShift;
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -196,9 +188,7 @@ uInt16 CartridgeEnhanced::bankCount() const
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool CartridgeEnhanced::patch(uInt16 address, uInt8 value) bool CartridgeEnhanced::patch(uInt16 address, uInt8 value)
{ {
address &= myBankMask; if((address & myBankMask) < myRamSize * 2)
if(address < myRamSize * 2)
{ {
// Normally, a write to the read port won't do anything // Normally, a write to the read port won't do anything
// However, the patch command is special in that ignores such // However, the patch command is special in that ignores such
@ -206,7 +196,7 @@ bool CartridgeEnhanced::patch(uInt16 address, uInt8 value)
myRAM[address & myRamMask] = value; myRAM[address & myRamMask] = value;
} }
else else
myImage[myBankOffset + address] = value; myImage[myCurrentSegOffset[(address & 0xFFF) >> myBankShift] + (address & myBankMask)] = value;
return myBankChanged = true; return myBankChanged = true;
} }
@ -223,7 +213,7 @@ bool CartridgeEnhanced::save(Serializer& out) const
{ {
try try
{ {
out.putShort(myBankOffset); out.putIntArray(myCurrentSegOffset.get(), myBankSegs);
if(myRamSize) if(myRamSize)
out.putByteArray(myRAM.get(), myRamSize); out.putByteArray(myRAM.get(), myRamSize);
@ -242,7 +232,7 @@ bool CartridgeEnhanced::load(Serializer& in)
{ {
try try
{ {
myBankOffset = in.getShort(); in.getIntArray(myCurrentSegOffset.get(), myBankSegs);
if(myRamSize) if(myRamSize)
in.getByteArray(myRAM.get(), myRamSize); in.getByteArray(myRAM.get(), myRamSize);
} }
@ -251,9 +241,5 @@ bool CartridgeEnhanced::load(Serializer& in)
cerr << "ERROR: " << name() << "::load" << endl; cerr << "ERROR: " << name() << "::load" << endl;
return false; return false;
} }
// Remember what bank we were in
bank(myBankOffset >> myBankShift);
return true; return true;
} }

View File

@ -63,7 +63,7 @@ class CartridgeEnhanced : public Cartridge
@param bank The bank that should be installed in the system @param bank The bank that should be installed in the system
*/ */
bool bank(uInt16 bank, uInt16 slice); bool bank(uInt16 bank, uInt16 segment);
/** /**
Install pages for the specified bank in the system. Install pages for the specified bank in the system.
@ -135,62 +135,71 @@ class CartridgeEnhanced : public Cartridge
bool poke(uInt16 address, uInt8 value) override; bool poke(uInt16 address, uInt8 value) override;
protected: protected:
// The '2 ^ N = bank segment size' exponent
uInt16 myBankShift{BANK_SHIFT}; // default 12 (-> one 4K segment)
// The size of a bank's segment
uInt16 myBankSize{0};
// The mask for a bank segment
uInt16 myBankMask{0};
// The number of segments a bank is split into
uInt16 myBankSegs{0};
// The extra RAM size
uInt16 myRamSize{RAM_SIZE}; // default 0
// The mask for the extra RAM
uInt16 myRamMask{0}; // RAM_SIZE - 1, but doesn't matter when RAM_SIZE is 0
// Pointer to a dynamically allocated ROM image of the cartridge // Pointer to a dynamically allocated ROM image of the cartridge
ByteBuffer myImage{nullptr}; ByteBuffer myImage{nullptr};
// Contains the offset into the ROM image for each of the bank segments
DWordBuffer myCurrentSegOffset{nullptr};
// Indicates whether to use direct ROM peeks or not
bool myDirectPeek{true};
// Pointer to a dynamically allocated RAM area of the cartridge // Pointer to a dynamically allocated RAM area of the cartridge
ByteBuffer myRAM{nullptr}; ByteBuffer myRAM{nullptr};
uInt16 myBankShift{BANK_SHIFT};
uInt16 myBankSize{BANK_SIZE};
uInt16 myBankMask{BANK_MASK};
uInt16 myRamSize{RAM_SIZE};
uInt16 myRamMask{RAM_MASK};
bool myDirectPeek{true};
// Indicates the offset into the ROM image (aligns to current bank)
uInt16 myBankOffset{0};
// Indicates the slice mapped into each of the bank segments
WordBuffer myCurrentBankOffset{nullptr};
private: private:
// log(ROM bank size) / log(2) // Calculated as: log(ROM bank segment size) / log(2)
static constexpr uInt16 BANK_SHIFT = 12; static constexpr uInt16 BANK_SHIFT = 12; // default = 4K
// bank size // The size of extra RAM in ROM address space
static constexpr uInt16 BANK_SIZE = 1 << BANK_SHIFT; // 2 ^ 12 = 4K static constexpr uInt16 RAM_SIZE = 0; // default = none
// bank mask // The size of the ROM image
static constexpr uInt16 BANK_MASK = BANK_SIZE - 1;
// bank segments
static constexpr uInt16 BANK_SEGS = 1;
// RAM size
static constexpr uInt16 RAM_SIZE = 0;
// RAM mask
static constexpr uInt16 RAM_MASK = 0;
// Size of the ROM image
size_t mySize{0}; size_t mySize{0};
protected: protected:
/** /**
Check hotspots and switch bank if triggered. Check hotspots and switch bank if triggered.
@param address The address to check
@param value The optional value used to determine the bank switched to
@return True if a bank switch happened.
*/ */
virtual bool checkSwitchBank(uInt16 address, uInt8 value = 0) = 0; virtual bool checkSwitchBank(uInt16 address, uInt8 value = 0) = 0;
private: private:
/**
Get the ROM's startup bank.
@return The bank the ROM will start in
*/
virtual uInt16 getStartBank() const { return 0; } virtual uInt16 getStartBank() const { return 0; }
/**
Get the hotspot in ROM address space.
@return The first hotspot address in ROM space or 0
*/
virtual uInt16 romHotspot() const { return 0; } virtual uInt16 romHotspot() const { return 0; }
// TODO: handle cases where there the hotspots cover multiple pages
private: private:
// Following constructors and assignment operators not supported // Following constructors and assignment operators not supported

View File

@ -67,12 +67,11 @@ class CartridgeF0 : public CartridgeEnhanced
} }
#endif #endif
protected: private:
bool checkSwitchBank(uInt16 address, uInt8 value = 0); bool checkSwitchBank(uInt16 address, uInt8 value = 0);
uInt16 romHotspot() const override { return 0x1FF0; } uInt16 romHotspot() const override { return 0x1FF0; }
private:
uInt16 getStartBank() const override { return 15; } uInt16 getStartBank() const override { return 15; }
private: private:

View File

@ -66,7 +66,7 @@ class CartridgeF4 : public CartridgeEnhanced
} }
#endif #endif
protected: private:
bool checkSwitchBank(uInt16 address, uInt8 value = 0); bool checkSwitchBank(uInt16 address, uInt8 value = 0);
uInt16 romHotspot() const override { return 0x1FF4; } uInt16 romHotspot() const override { return 0x1FF4; }

View File

@ -23,5 +23,5 @@ CartridgeF4SC::CartridgeF4SC(const ByteBuffer& image, size_t size,
: CartridgeF4(image, size, md5, settings) : CartridgeF4(image, size, md5, settings)
{ {
myRamSize = RAM_SIZE; myRamSize = RAM_SIZE;
myRamMask = RAM_MASK; myRamMask = RAM_SIZE - 1;
} }

View File

@ -66,7 +66,7 @@ class CartridgeF6 : public CartridgeEnhanced
} }
#endif #endif
protected: private:
bool checkSwitchBank(uInt16 address, uInt8 value = 0) override; bool checkSwitchBank(uInt16 address, uInt8 value = 0) override;
uInt16 romHotspot() const override { return 0x1FF6; } uInt16 romHotspot() const override { return 0x1FF6; }

View File

@ -23,5 +23,5 @@ CartridgeF6SC::CartridgeF6SC(const ByteBuffer& image, size_t size,
: CartridgeF6(image, size, md5, settings) : CartridgeF6(image, size, md5, settings)
{ {
myRamSize = RAM_SIZE; myRamSize = RAM_SIZE;
myRamMask = RAM_MASK; myRamMask = RAM_SIZE - 1;
} }

View File

@ -66,12 +66,11 @@ class CartridgeF8 : public CartridgeEnhanced
} }
#endif #endif
protected: private:
bool checkSwitchBank(uInt16 address, uInt8 value = 0) override; bool checkSwitchBank(uInt16 address, uInt8 value = 0) override;
uInt16 romHotspot() const override { return 0x1FF8; } uInt16 romHotspot() const override { return 0x1FF8; }
private:
uInt16 getStartBank() const override { return 1; } uInt16 getStartBank() const override { return 1; }
private: private:

View File

@ -23,5 +23,4 @@ CartridgeF8SC::CartridgeF8SC(const ByteBuffer& image, size_t size,
: CartridgeF8(image, size, md5, settings) : CartridgeF8(image, size, md5, settings)
{ {
myRamSize = RAM_SIZE; myRamSize = RAM_SIZE;
myRamMask = RAM_MASK;
} }

View File

@ -71,9 +71,6 @@ class CartridgeF8SC : public CartridgeF8
// RAM size // RAM size
static constexpr uInt16 RAM_SIZE = 0x80; static constexpr uInt16 RAM_SIZE = 0x80;
// RAM mask
static constexpr uInt16 RAM_MASK = RAM_SIZE - 1;
private: private:
// Following constructors and assignment operators not supported // Following constructors and assignment operators not supported
CartridgeF8SC() = delete; CartridgeF8SC() = delete;

View File

@ -87,12 +87,11 @@ class CartridgeFC : public CartridgeEnhanced
*/ */
bool poke(uInt16 address, uInt8 value) override; bool poke(uInt16 address, uInt8 value) override;
protected: private:
bool checkSwitchBank(uInt16 address, uInt8 value = 0) override; bool checkSwitchBank(uInt16 address, uInt8 value = 0) override;
uInt16 romHotspot() const override { return 0x1FF8; } uInt16 romHotspot() const override { return 0x1FF8; }
private:
// Target bank defined by writing to $1FF8/9 // Target bank defined by writing to $1FF8/9
uInt16 myTargetBank{0}; uInt16 myTargetBank{0};

View File

@ -37,7 +37,7 @@ void CartridgeFE::reset()
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CartridgeFE::install(System& system) void CartridgeFE::install(System& system)
{ {
mySystem = &system; CartridgeEnhanced::install(system);
// The hotspot $01FE is in a mirror of zero-page RAM // The hotspot $01FE is in a mirror of zero-page RAM
// We need to claim access to it here, and deal with it in peek/poke below // We need to claim access to it here, and deal with it in peek/poke below
@ -63,7 +63,7 @@ bool CartridgeFE::checkSwitchBank(uInt16 address, uInt8 value)
uInt8 CartridgeFE::peek(uInt16 address) uInt8 CartridgeFE::peek(uInt16 address)
{ {
uInt8 value = (address < 0x200) ? mySystem->m6532().peek(address) : uInt8 value = (address < 0x200) ? mySystem->m6532().peek(address) :
myImage[myBankOffset + (address & myBankMask)]; myImage[myCurrentSegOffset[(address & 0xFFF) >> myBankShift] + (address & myBankMask)];
// Check if we hit hotspot // Check if we hit hotspot
checkSwitchBank(address, value); checkSwitchBank(address, value);

View File

@ -72,8 +72,8 @@ class System;
particular *why* the address $01FE will be placed on the address particular *why* the address $01FE will be placed on the address
bus after both the JSR and RTS opcodes. bus after both the JSR and RTS opcodes.
@author Stephen Anthony; with ideas/research from Christian Speckner and @author Stephen Anthony, Thomas Jentzsch; with ideas/research from Christian
alex_79 and TomSon (of AtariAge) Speckner and alex_79 and TomSon (of AtariAge)
*/ */
class CartridgeFE : public CartridgeEnhanced class CartridgeFE : public CartridgeEnhanced
{ {

View File

@ -30,7 +30,7 @@ CartridgeUA::CartridgeUA(const ByteBuffer& image, size_t size,
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CartridgeUA::install(System& system) void CartridgeUA::install(System& system)
{ {
mySystem = &system; CartridgeEnhanced::install(system);
// Get the page accessing methods for the hot spots since they overlap // Get the page accessing methods for the hot spots since they overlap
// areas within the TIA we'll need to forward requests to the TIA // areas within the TIA we'll need to forward requests to the TIA

View File

@ -97,7 +97,7 @@ class CartridgeUA : public CartridgeEnhanced
bool poke(uInt16 address, uInt8 value) override; bool poke(uInt16 address, uInt8 value) override;
protected: private:
bool checkSwitchBank(uInt16 address, uInt8 value = 0) override; bool checkSwitchBank(uInt16 address, uInt8 value = 0) override;
private: private:

Binary file not shown.