refactor Cart2K and Cart4K(SC)

This commit is contained in:
thrust26 2020-04-07 08:24:06 +02:00
parent 53387c4b13
commit edd9cd0147
9 changed files with 44 additions and 435 deletions

View File

@ -25,7 +25,10 @@ Cartridge2KWidget::Cartridge2KWidget(
: CartDebugWidget(boss, lfont, nfont, x, y, w, h) : CartDebugWidget(boss, lfont, nfont, x, y, w, h)
{ {
// Eventually, we should query this from the debugger/disassembler // Eventually, we should query this from the debugger/disassembler
size_t size = cart.mySize; size_t size;
cart.getImage(size);
uInt16 start = (cart.myImage[size-3] << 8) | cart.myImage[size-4]; uInt16 start = (cart.myImage[size-3] << 8) | cart.myImage[size-4];
start -= start % size; start -= start % size;

View File

@ -21,15 +21,19 @@
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Cartridge2K::Cartridge2K(const ByteBuffer& image, size_t size, Cartridge2K::Cartridge2K(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)
{ {
// Size can be a maximum of 2K // Size can be a maximum of 2K
if(size > 2_KB) size = 2_KB; if(size > 2_KB)
size = 2_KB;
// Set image size to closest power-of-two for the given size // Set image size to closest power-of-two for the given size
mySize = 1; mySize = 1; myBankShift = 0;
while(mySize < size) while(mySize < size)
{
mySize <<= 1; mySize <<= 1;
myBankShift++;
}
// Initialize ROM with illegal 6502 opcode that causes a real 6502 to jam // Initialize ROM with illegal 6502 opcode that causes a real 6502 to jam
size_t bufSize = std::max<size_t>(mySize, System::PAGE_SIZE); size_t bufSize = std::max<size_t>(mySize, System::PAGE_SIZE);
@ -49,62 +53,12 @@ Cartridge2K::Cartridge2K(const ByteBuffer& image, size_t size,
for(size_t i = 0; i < System::PAGE_SIZE; i += mySize) for(size_t i = 0; i < System::PAGE_SIZE; i += mySize)
std::copy_n(image.get(), mySize, myImage.get() + i); std::copy_n(image.get(), mySize, myImage.get() + i);
mySize = System::PAGE_SIZE; mySize = System::PAGE_SIZE;
myBankShift = 6;
} }
// update access arrays, bank size and mask based on new size
createRomAccessArrays(mySize); createRomAccessArrays(mySize);
// Set mask for accessing the image buffer myBankSize = 1 << myBankShift; // e.g. = 2 ^ 11 = 2048 = 0x0800
// This is guaranteed to work, as mySize is a power of two myBankMask = myBankSize - 1; // e.g. = 0x07FF
myMask = static_cast<uInt16>(mySize) - 1;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Cartridge2K::reset()
{
myBankChanged = true;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Cartridge2K::install(System& system)
{
mySystem = &system;
// Map ROM image into the system
// Note that we don't need our own peek/poke methods, since the mapping
// takes care of the entire address space
System::PageAccess access(this, System::PageAccessType::READ);
for(uInt16 addr = 0x1000; addr < 0x2000; addr += System::PAGE_SIZE)
{
access.directPeekBase = &myImage[addr & myMask];
access.romAccessBase = &myRomAccessBase[addr & myMask];
access.romPeekCounter = &myRomAccessCounter[addr & myMask];
access.romPokeCounter = &myRomAccessCounter[(addr & myMask) + myAccessSize];
mySystem->setPageAccess(addr, access);
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool Cartridge2K::patch(uInt16 address, uInt8 value)
{
myImage[address & myMask] = value;
return myBankChanged = true;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
const uInt8* Cartridge2K::getImage(size_t& size) const
{
size = mySize;
return myImage.get();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool Cartridge2K::save(Serializer&) const
{
return true;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool Cartridge2K::load(Serializer&)
{
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 "Cart2KWidget.hxx" #include "Cart2KWidget.hxx"
#endif #endif
@ -33,9 +33,9 @@ class System;
data repeats in intervals based on the size of the ROM (which will data repeats in intervals based on the size of the ROM (which will
always be a power of 2). always be a power of 2).
@author Stephen Anthony @author Stephen Anthony, Thomas Jentzsch
*/ */
class Cartridge2K : public Cartridge class Cartridge2K : public CartridgeEnhanced
{ {
friend class Cartridge2KWidget; friend class Cartridge2KWidget;
@ -53,52 +53,6 @@ class Cartridge2K : public Cartridge
virtual ~Cartridge2K() = default; virtual ~Cartridge2K() = default;
public: public:
/**
Reset cartridge 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;
/**
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).
@ -118,22 +72,8 @@ class Cartridge2K : public Cartridge
} }
#endif #endif
/**
Get the byte at the specified address.
@return The byte at the specified address
*/
uInt8 peek(uInt16 address) override { return myImage[address & myMask]; }
private: private:
// Pointer to a dynamically allocated ROM image of the cartridge bool checkSwitchBank(uInt16 address, uInt8 value = 0) override { return false; };
ByteBuffer myImage;
// Size of the ROM image
size_t mySize{0};
// Mask to use for mirroring
uInt16 myMask{0};
private: private:
// Following constructors and assignment operators not supported // Following constructors and assignment operators not supported

View File

@ -21,48 +21,7 @@
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Cartridge4K::Cartridge4K(const ByteBuffer& image, size_t size, Cartridge4K::Cartridge4K(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 cerr << "Cartridge4K" << endl;
std::copy_n(image.get(), std::min(myImage.size(), size), myImage.begin());
createRomAccessArrays(myImage.size());
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Cartridge4K::reset()
{
myBankChanged = true;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Cartridge4K::install(System& system)
{
mySystem = &system;
// Map ROM image into the system
// Note that we don't need our own peek/poke methods, since the mapping
// takes care of the entire address space
System::PageAccess access(this, System::PageAccessType::READ);
for(uInt16 addr = 0x1000; addr < 0x2000; addr += System::PAGE_SIZE)
{
access.directPeekBase = &myImage[addr & 0x0FFF];
access.romAccessBase = &myRomAccessBase[addr & 0x0FFF];
access.romPeekCounter = &myRomAccessCounter[addr & 0x0FFF];
access.romPokeCounter = &myRomAccessCounter[(addr & 0x0FFF) + myAccessSize];
mySystem->setPageAccess(addr, access);
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool Cartridge4K::patch(uInt16 address, uInt8 value)
{
myImage[address & 0x0FFF] = value;
return myBankChanged = true;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
const uInt8* Cartridge4K::getImage(size_t& size) const
{
size = myImage.size();
return myImage.data();
} }

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 "Cart4KWidget.hxx" #include "Cart4KWidget.hxx"
#endif #endif
@ -30,9 +30,9 @@ class System;
This is the standard Atari 4K cartridge. These cartridges are This is the standard Atari 4K cartridge. These cartridges are
not bankswitched. not bankswitched.
@author Bradford W. Mott @author Bradford W. Mott, Thomas Jentzsch
*/ */
class Cartridge4K : public Cartridge class Cartridge4K : public CartridgeEnhanced
{ {
friend class Cartridge4KWidget; friend class Cartridge4KWidget;
@ -50,52 +50,6 @@ class Cartridge4K : public Cartridge
virtual ~Cartridge4K() = default; virtual ~Cartridge4K() = default;
public: public:
/**
Reset cartridge 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;
/**
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 { return true; }
/**
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 { return true; }
/** /**
Get a descriptor for the device name (used in error checking). Get a descriptor for the device name (used in error checking).
@ -115,16 +69,8 @@ class Cartridge4K : public Cartridge
} }
#endif #endif
/**
Get the byte at the specified address.
@return The byte at the specified address
*/
uInt8 peek(uInt16 address) override { return myImage[address & 0x0FFF]; }
private: private:
// The 4K ROM image for the cartridge bool checkSwitchBank(uInt16 address, uInt8 value = 0) override { return false; };
std::array<uInt8, 4_KB> myImage;
private: private:
// Following constructors and assignment operators not supported // Following constructors and assignment operators not supported

View File

@ -21,137 +21,7 @@
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Cartridge4KSC::Cartridge4KSC(const ByteBuffer& image, size_t size, Cartridge4KSC::Cartridge4KSC(const ByteBuffer& image, size_t size,
const string& md5, const Settings& settings) const string& md5, const Settings& settings)
: Cartridge(settings, md5) : Cartridge4K(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 Cartridge4KSC::reset()
{
initializeRAM(myRAM.data(), myRAM.size());
myBankChanged = true;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Cartridge4KSC::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);
}
// Map ROM image into the system
for(uInt16 addr = 0x1100; addr < 0x2000; addr += System::PAGE_SIZE)
{
access.directPeekBase = &myImage[addr & 0x0FFF];
access.romAccessBase = &myRomAccessBase[addr & 0x0FFF];
mySystem->setPageAccess(addr, access);
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt8 Cartridge4KSC::peek(uInt16 address)
{
// The only way we can get to this method is if we attempt to read from
// the write port (0xF000 - 0xF07F, 128 bytes), in which case an
// unwanted write is potentially triggered
return peekRAM(myRAM[address & 0x007F], address);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool Cartridge4KSC::poke(uInt16 address, uInt8 value)
{
if (!(address & 0x080))
{
pokeRAM(myRAM[address & 0x007F], address, value);
return true;
}
else
{
// Writing to the read port should be ignored, but trigger a break if option enabled
uInt8 dummy;
pokeRAM(dummy, address, value);
myRamWriteAccess = address;
return false;
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool Cartridge4KSC::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[address & 0xFFF] = value;
return myBankChanged = true;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
const uInt8* Cartridge4KSC::getImage(size_t& size) const
{
size = myImage.size();
return myImage.data();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool Cartridge4KSC::save(Serializer& out) const
{
try
{
out.putByteArray(myRAM.data(), myRAM.size());
}
catch(...)
{
cerr << "ERROR: Cartridge4KSC::save" << endl;
return false;
}
return true;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool Cartridge4KSC::load(Serializer& in)
{
try
{
in.getByteArray(myRAM.data(), myRAM.size());
}
catch(...)
{
cerr << "ERROR: Cartridge4KSC::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 "Cart4K.hxx"
#ifdef DEBUGGER_SUPPORT #ifdef DEBUGGER_SUPPORT
#include "Cart4KSCWidget.hxx" #include "Cart4KSCWidget.hxx"
#endif #endif
@ -29,9 +29,11 @@ class System;
/** /**
Cartridge class used for 4K games with 128 bytes of RAM. Cartridge class used for 4K games with 128 bytes of RAM.
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, Thomas Jentzsch
*/ */
class Cartridge4KSC : public Cartridge class Cartridge4KSC : public Cartridge4K
{ {
friend class Cartridge4KSCWidget; friend class Cartridge4KSCWidget;
@ -49,52 +51,6 @@ class Cartridge4KSC : public Cartridge
virtual ~Cartridge4KSC() = default; virtual ~Cartridge4KSC() = 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;
/**
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).
@ -114,29 +70,9 @@ class Cartridge4KSC : 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 4K ROM image of the cartridge // RAM size
std::array<uInt8, 4_KB> myImage; static constexpr uInt16 RAM_SIZE = 0x80;
// The 128 bytes of RAM
std::array<uInt8, 128> myRAM;
private: private:
// Following constructors and assignment operators not supported // Following constructors and assignment operators not supported

View File

@ -24,19 +24,19 @@ CartridgeEnhanced::CartridgeEnhanced(const ByteBuffer& image, size_t size,
: Cartridge(settings, md5), : Cartridge(settings, md5),
mySize(size) mySize(size)
{ {
// Allocate array for the ROM image // Allocate array for the ROM image (at least 64 bytzes)
myImage = make_unique<uInt8[]>(mySize); myImage = make_unique<uInt8[]>(std::max(uInt16(mySize), System::PAGE_SIZE));
// Copy the ROM image into my buffer // Copy the ROM image into my buffer
std::copy_n(image.get(), mySize, myImage.get()); std::copy_n(image.get(), mySize, myImage.get());
// Copy the ROM image into my buffer
createRomAccessArrays(mySize);
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CartridgeEnhanced::install(System& system) void CartridgeEnhanced::install(System& system)
{ {
// Copy the ROM image into my buffer
createRomAccessArrays(mySize);
// calculate bank switching and RAM sizes and masks // calculate bank switching and RAM sizes and masks
myBankSize = 1 << myBankShift; // e.g. = 2 ^ 12 = 4K = 0x1000 myBankSize = 1 << myBankShift; // e.g. = 2 ^ 12 = 4K = 0x1000
myBankMask = myBankSize - 1; // e.g. = 0x0FFF myBankMask = myBankSize - 1; // e.g. = 0x0FFF
@ -81,7 +81,7 @@ void CartridgeEnhanced::install(System& system)
// Install pages for the startup bank (TODO: currently only in first bank segment) // Install pages for the startup bank (TODO: currently only in first bank segment)
bank(startBank(), 0); bank(startBank(), 0);
if(myBankSegs > 1) if(mySize >= 4_KB && myBankSegs > 1)
// Setup the last bank segment to always point to the last ROM segment // Setup the last bank segment to always point to the last ROM segment
bank(bankCount() - 1, myBankSegs - 1); bank(bankCount() - 1, myBankSegs - 1);
} }
@ -149,7 +149,8 @@ bool CartridgeEnhanced::bank(uInt16 bank, uInt16 segment)
uInt16 hotspot = this->hotspot(); uInt16 hotspot = this->hotspot();
uInt16 hotSpotAddr; uInt16 hotSpotAddr;
uInt16 fromAddr = (segmentOffset + 0x1000 + myRamSize * 2) & ~System::PAGE_MASK; uInt16 fromAddr = (segmentOffset + 0x1000 + myRamSize * 2) & ~System::PAGE_MASK;
uInt16 toAddr = (segmentOffset + 0x1000 + myBankSize) & ~System::PAGE_MASK; // for ROMs < 4_KB, the whole address space will be mapped.
uInt16 toAddr = (segmentOffset + 0x1000 + (mySize < 4_KB ? 0x1000 : myBankSize)) & ~System::PAGE_MASK;
if(hotspot) if(hotspot)
hotSpotAddr = (hotspot & ~System::PAGE_MASK); hotSpotAddr = (hotspot & ~System::PAGE_MASK);

View File

@ -172,6 +172,9 @@ class CartridgeEnhanced : public Cartridge
// 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};
// The size of the ROM image
size_t mySize{0};
private: private:
// Calculated as: log(ROM bank segment size) / log(2) // Calculated as: log(ROM bank segment size) / log(2)
static constexpr uInt16 BANK_SHIFT = 12; // default = 4K static constexpr uInt16 BANK_SHIFT = 12; // default = 4K
@ -179,9 +182,6 @@ class CartridgeEnhanced : public Cartridge
// The size of extra RAM in ROM address space // The size of extra RAM in ROM address space
static constexpr uInt16 RAM_SIZE = 0; // default = none static constexpr uInt16 RAM_SIZE = 0; // default = none
// The size of the ROM image
size_t mySize{0};
protected: protected:
/** /**
Check hotspots and switch bank if triggered. Check hotspots and switch bank if triggered.