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)
{
// 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];
start -= start % size;

View File

@ -21,15 +21,19 @@
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Cartridge2K::Cartridge2K(const ByteBuffer& image, size_t size,
const string& md5, const Settings& settings)
: Cartridge(settings, md5)
: CartridgeEnhanced(image, size, md5, settings)
{
// 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
mySize = 1;
mySize = 1; myBankShift = 0;
while(mySize < size)
{
mySize <<= 1;
myBankShift++;
}
// Initialize ROM with illegal 6502 opcode that causes a real 6502 to jam
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)
std::copy_n(image.get(), mySize, myImage.get() + i);
mySize = System::PAGE_SIZE;
myBankShift = 6;
}
// update access arrays, bank size and mask based on new size
createRomAccessArrays(mySize);
// Set mask for accessing the image buffer
// This is guaranteed to work, as mySize is a power of two
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;
myBankSize = 1 << myBankShift; // e.g. = 2 ^ 11 = 2048 = 0x0800
myBankMask = myBankSize - 1; // e.g. = 0x07FF
}

View File

@ -21,7 +21,7 @@
class System;
#include "bspf.hxx"
#include "Cart.hxx"
#include "CartEnhanced.hxx"
#ifdef DEBUGGER_SUPPORT
#include "Cart2KWidget.hxx"
#endif
@ -33,9 +33,9 @@ class System;
data repeats in intervals based on the size of the ROM (which will
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;
@ -53,52 +53,6 @@ class Cartridge2K : public Cartridge
virtual ~Cartridge2K() = default;
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).
@ -118,22 +72,8 @@ class Cartridge2K : public Cartridge
}
#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:
// Pointer to a dynamically allocated ROM image of the cartridge
ByteBuffer myImage;
// Size of the ROM image
size_t mySize{0};
// Mask to use for mirroring
uInt16 myMask{0};
bool checkSwitchBank(uInt16 address, uInt8 value = 0) override { return false; };
private:
// Following constructors and assignment operators not supported

View File

@ -21,48 +21,7 @@
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Cartridge4K::Cartridge4K(const ByteBuffer& image, size_t size,
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 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();
cerr << "Cartridge4K" << endl;
}

View File

@ -21,7 +21,7 @@
class System;
#include "bspf.hxx"
#include "Cart.hxx"
#include "CartEnhanced.hxx"
#ifdef DEBUGGER_SUPPORT
#include "Cart4KWidget.hxx"
#endif
@ -30,9 +30,9 @@ class System;
This is the standard Atari 4K cartridge. These cartridges are
not bankswitched.
@author Bradford W. Mott
@author Bradford W. Mott, Thomas Jentzsch
*/
class Cartridge4K : public Cartridge
class Cartridge4K : public CartridgeEnhanced
{
friend class Cartridge4KWidget;
@ -50,52 +50,6 @@ class Cartridge4K : public Cartridge
virtual ~Cartridge4K() = default;
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).
@ -115,16 +69,8 @@ class Cartridge4K : public Cartridge
}
#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:
// The 4K ROM image for the cartridge
std::array<uInt8, 4_KB> myImage;
bool checkSwitchBank(uInt16 address, uInt8 value = 0) override { return false; };
private:
// Following constructors and assignment operators not supported

View File

@ -21,137 +21,7 @@
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Cartridge4KSC::Cartridge4KSC(const ByteBuffer& image, size_t size,
const string& md5, const Settings& settings)
: Cartridge(settings, md5)
: Cartridge4K(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 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;
myRamSize = RAM_SIZE;
}

View File

@ -21,7 +21,7 @@
class System;
#include "bspf.hxx"
#include "Cart.hxx"
#include "Cart4K.hxx"
#ifdef DEBUGGER_SUPPORT
#include "Cart4KSCWidget.hxx"
#endif
@ -29,9 +29,11 @@ class System;
/**
Cartridge class used for 4K games with 128 bytes of RAM.
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;
@ -49,52 +51,6 @@ class Cartridge4KSC : public Cartridge
virtual ~Cartridge4KSC() = 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;
/**
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).
@ -114,29 +70,9 @@ class Cartridge4KSC : public Cartridge
}
#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:
// The 4K ROM image of the cartridge
std::array<uInt8, 4_KB> myImage;
// The 128 bytes of RAM
std::array<uInt8, 128> myRAM;
// RAM size
static constexpr uInt16 RAM_SIZE = 0x80;
private:
// Following constructors and assignment operators not supported

View File

@ -24,19 +24,19 @@ CartridgeEnhanced::CartridgeEnhanced(const ByteBuffer& image, size_t size,
: Cartridge(settings, md5),
mySize(size)
{
// Allocate array for the ROM image
myImage = make_unique<uInt8[]>(mySize);
// Allocate array for the ROM image (at least 64 bytzes)
myImage = make_unique<uInt8[]>(std::max(uInt16(mySize), System::PAGE_SIZE));
// Copy the ROM image into my buffer
std::copy_n(image.get(), mySize, myImage.get());
// Copy the ROM image into my buffer
createRomAccessArrays(mySize);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CartridgeEnhanced::install(System& system)
{
// Copy the ROM image into my buffer
createRomAccessArrays(mySize);
// calculate bank switching and RAM sizes and masks
myBankSize = 1 << myBankShift; // e.g. = 2 ^ 12 = 4K = 0x1000
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)
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
bank(bankCount() - 1, myBankSegs - 1);
}
@ -149,7 +149,8 @@ bool CartridgeEnhanced::bank(uInt16 bank, uInt16 segment)
uInt16 hotspot = this->hotspot();
uInt16 hotSpotAddr;
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)
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
ByteBuffer myRAM{nullptr};
// The size of the ROM image
size_t mySize{0};
private:
// Calculated as: log(ROM bank segment size) / log(2)
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
static constexpr uInt16 RAM_SIZE = 0; // default = none
// The size of the ROM image
size_t mySize{0};
protected:
/**
Check hotspots and switch bank if triggered.