add RAM bank support to CartEnhanced

refactor Cart3E
differentiate between ROM and RAM banks (TODO: check debugger)
This commit is contained in:
thrust26 2020-04-15 14:53:05 +02:00
parent ca5b6a6fe7
commit 00e67f1a51
42 changed files with 313 additions and 504 deletions

View File

@ -72,12 +72,18 @@ CartDebug::CartDebug(Debugger& dbg, Console& console, const OSystem& osystem)
// Create bank information for each potential bank, and an extra one for ZP RAM
BankInfo info;
for(uInt32 i = 0; i < myConsole.cartridge().bankCount(); ++i)
for(uInt32 i = 0; i < myConsole.cartridge().romBankCount(); ++i)
{
info.size = myConsole.cartridge().bankSize(i);
myBankInfo.push_back(info);
}
for(uInt32 i = 0; i < myConsole.cartridge().ramBankCount(); ++i)
{
info.size = myConsole.cartridge().bankSize(i) >> 1;
myBankInfo.push_back(info);
}
info.size = 128; // ZP RAM
myBankInfo.push_back(info);
@ -235,9 +241,10 @@ string CartDebug::toString()
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool CartDebug::disassemble(bool force)
bool CartDebug::disassemblePC(bool force)
{
uInt16 PC = myDebugger.cpuDebug().pc();
// ROM/RAM bank or ZP-RAM?
int bank = (PC & 0x1000) ? getBank(PC) : int(myBankInfo.size()) - 1;
return disassemble(bank, PC, force);
@ -414,7 +421,7 @@ bool CartDebug::addDirective(Device::AccessType type,
bank = (myDebugger.cpuDebug().pc() & 0x1000) ?
getBank(myDebugger.cpuDebug().pc()) : int(myBankInfo.size())-1;
bank = std::min(bank, bankCount());
bank = std::min(bank, romBankCount());
BankInfo& info = myBankInfo[bank];
DirectiveList& list = info.directiveList;
@ -546,9 +553,9 @@ int CartDebug::getPCBank()
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
int CartDebug::bankCount() const
int CartDebug::romBankCount() const
{
return myConsole.cartridge().bankCount();
return myConsole.cartridge().romBankCount();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -955,7 +962,7 @@ string CartDebug::loadConfigFile()
myDebugger.rom().invalidate();
stringstream retVal;
if(myConsole.cartridge().bankCount() > 1)
if(myConsole.cartridge().romBankCount() > 1)
retVal << DebuggerParser::red("config file for multi-bank ROM not fully supported\n");
retVal << "config file '" << node.getShortPath() << "' loaded OK";
return retVal.str();
@ -990,14 +997,14 @@ string CartDebug::saveConfigFile()
out << "// Stella.pro: \"" << name << "\"" << endl
<< "// MD5: " << md5 << endl
<< endl;
for(uInt32 b = 0; b < myConsole.cartridge().bankCount(); ++b)
for(uInt32 b = 0; b < myConsole.cartridge().romBankCount(); ++b)
{
out << "[" << b << "]" << endl;
getBankDirectives(out, myBankInfo[b]);
}
stringstream retVal;
if(myConsole.cartridge().bankCount() > 1)
if(myConsole.cartridge().romBankCount() > 1)
retVal << DebuggerParser::red("config file for multi-bank ROM not fully supported\n");
retVal << "config file '" << cfg.getShortPath() << "' saved OK";
return retVal.str();
@ -1058,14 +1065,14 @@ string CartDebug::saveDisassembly()
Disassembly disasm;
disasm.list.reserve(2048);
uInt16 bankCount = myConsole.cartridge().bankCount();
uInt16 romBankCount = myConsole.cartridge().romBankCount();
uInt16 oldBank = myConsole.cartridge().getBank();
// prepare for switching banks
myConsole.cartridge().unlockBank();
uInt32 origin = 0;
for(int bank = 0; bank < bankCount; ++bank)
for(int bank = 0; bank < romBankCount; ++bank)
{
// TODO: not every CartDebugWidget does it like that, we need a method
myConsole.cartridge().unlockBank();
@ -1082,8 +1089,8 @@ string CartDebug::saveDisassembly()
buf << "\n\n;***********************************************************\n"
<< "; Bank " << bank;
if (bankCount > 1)
buf << " / 0.." << bankCount - 1;
if (romBankCount > 1)
buf << " / 0.." << romBankCount - 1;
buf << "\n;***********************************************************\n\n";
@ -1097,7 +1104,7 @@ string CartDebug::saveDisassembly()
buf << " SEG CODE\n";
if(bankCount == 1)
if(romBankCount == 1)
buf << " ORG $" << Base::HEX4 << info.offset << "\n\n";
else
buf << " ORG $" << Base::HEX4 << origin << "\n"
@ -1327,7 +1334,7 @@ string CartDebug::saveDisassembly()
out << buf.str();
stringstream retVal;
if(myConsole.cartridge().bankCount() > 1)
if(myConsole.cartridge().romBankCount() > 1)
retVal << DebuggerParser::red("disassembly for multi-bank ROM not fully supported\n");
retVal << "saved " << node.getShortPath() << " OK";
return retVal.str();
@ -1367,8 +1374,8 @@ string CartDebug::saveAccessFile()
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
string CartDebug::listConfig(int bank)
{
uInt32 startbank = 0, endbank = bankCount();
if(bank >= 0 && bank < bankCount())
uInt32 startbank = 0, endbank = romBankCount();
if(bank >= 0 && bank < romBankCount())
{
startbank = bank;
endbank = startbank + 1;
@ -1392,7 +1399,7 @@ string CartDebug::listConfig(int bank)
getBankDirectives(buf, info);
}
if(myConsole.cartridge().bankCount() > 1)
if(myConsole.cartridge().romBankCount() > 1)
buf << DebuggerParser::red("config file for multi-bank ROM not fully supported") << endl;
return buf.str();
@ -1401,8 +1408,8 @@ string CartDebug::listConfig(int bank)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
string CartDebug::clearConfig(int bank)
{
uInt32 startbank = 0, endbank = bankCount();
if(bank >= 0 && bank < bankCount())
uInt32 startbank = 0, endbank = romBankCount();
if(bank >= 0 && bank < romBankCount())
{
startbank = bank;
endbank = startbank + 1;

View File

@ -95,7 +95,7 @@ class CartDebug : public DebuggerSystem
int lastWriteBaseAddress();
// TODO
bool disassemble(bool force = false);
bool disassemblePC(bool force = false);
bool disassembleBank(int bank);
// First, a call is made to disassemble(), which updates the disassembly
@ -159,7 +159,7 @@ class CartDebug : public DebuggerSystem
/**
Get the total number of banks supported by the cartridge.
*/
int bankCount() const;
int romBankCount() const;
/**
Add a label and associated address.

View File

@ -763,7 +763,7 @@ void DebuggerParser::executeBreak()
{
uInt16 addr;
uInt8 bank;
uInt32 bankCount = debugger.cartDebug().bankCount();
uInt32 romBankCount = debugger.cartDebug().romBankCount();
if(argCount == 0)
addr = debugger.cpuDebug().pc();
@ -775,7 +775,7 @@ void DebuggerParser::executeBreak()
else
{
bank = args[1];
if(bank >= bankCount && bank != 0xff)
if(bank >= romBankCount && bank != 0xff)
{
commandResult << red("invalid bank");
return;
@ -791,12 +791,12 @@ void DebuggerParser::executeBreak()
commandResult << "cleared";
commandResult << " breakpoint at $" << Base::HEX4 << addr << " + mirrors";
if(bankCount > 1)
if(romBankCount > 1)
commandResult << " in bank #" << std::dec << int(bank);
}
else
{
for(int i = 0; i < debugger.cartDebug().bankCount(); ++i)
for(int i = 0; i < debugger.cartDebug().romBankCount(); ++i)
{
bool set = debugger.toggleBreakPoint(addr, i);
@ -809,7 +809,7 @@ void DebuggerParser::executeBreak()
commandResult << "cleared";
commandResult << " breakpoint at $" << Base::HEX4 << addr << " + mirrors";
if(bankCount > 1)
if(romBankCount > 1)
commandResult << " in bank #" << std::dec << int(bank);
}
}
@ -1459,11 +1459,11 @@ void DebuggerParser::executeListbreaks()
{
stringstream buf;
int count = 0;
uInt32 bankCount = debugger.cartDebug().bankCount();
uInt32 romBankCount = debugger.cartDebug().romBankCount();
for(const auto& bp : debugger.breakPoints().getBreakpoints())
{
if(bankCount == 1)
if(romBankCount == 1)
{
buf << debugger.cartDebug().getLabel(bp.addr, true, 4) << " ";
if(!(++count % 8)) buf << endl;

View File

@ -25,8 +25,8 @@ Cartridge3EWidget::Cartridge3EWidget(
int x, int y, int w, int h, Cartridge3E& cart)
: CartDebugWidget(boss, lfont, nfont, x, y, w, h),
myCart(cart),
myNumRomBanks(uInt32(cart.mySize >> 11)),
myNumRamBanks(32)
myNumRomBanks(myCart.romBankCount()),
myNumRamBanks(myCart.ramBankCount())
{
size_t size = cart.mySize;
@ -93,21 +93,21 @@ void Cartridge3EWidget::saveOldState()
for(uInt32 i = 0; i < internalRamSize(); ++i)
myOldState.internalram.push_back(myCart.myRAM[i]);
myOldState.bank = myCart.myCurrentBank;
myOldState.bank = myCart.getBank();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Cartridge3EWidget::loadConfig()
{
if(myCart.myCurrentBank < 256)
if(myCart.getBank() < myCart.romBankCount())
{
myROMBank->setSelectedIndex(myCart.myCurrentBank % myNumRomBanks, myOldState.bank != myCart.myCurrentBank);
myRAMBank->setSelectedMax(myOldState.bank >= 256);
myROMBank->setSelectedIndex(myCart.getBank() % myNumRomBanks, myOldState.bank != myCart.getBank());
myRAMBank->setSelectedMax(myOldState.bank >= myCart.romBankCount());
}
else
{
myROMBank->setSelectedMax(myOldState.bank < 256);
myRAMBank->setSelectedIndex(myCart.myCurrentBank - 256, myOldState.bank != myCart.myCurrentBank);
myROMBank->setSelectedMax(myOldState.bank < myCart.romBankCount());
myRAMBank->setSelectedIndex(myCart.getBank() - myCart.romBankCount(), myOldState.bank != myCart.getBank());
}
CartDebugWidget::loadConfig();
@ -128,7 +128,7 @@ void Cartridge3EWidget::handleCommand(CommandSender* sender,
}
else
{
bank = 256; // default to first RAM bank
bank = myCart.romBankCount(); // default to first RAM bank
myRAMBank->setSelectedIndex(0);
}
}
@ -137,7 +137,7 @@ void Cartridge3EWidget::handleCommand(CommandSender* sender,
if(myRAMBank->getSelected() < int(myNumRamBanks))
{
myROMBank->setSelectedMax();
bank = myRAMBank->getSelected() + 256;
bank = myRAMBank->getSelected() + myCart.romBankCount();
}
else
{
@ -157,8 +157,8 @@ string Cartridge3EWidget::bankState()
{
ostringstream& buf = buffer();
uInt16& bank = myCart.myCurrentBank;
if(bank < 256)
uInt16 bank = myCart.getBank();
if(bank < myCart.romBankCount())
buf << "ROM bank #" << std::dec << bank % myNumRomBanks << ", RAM inactive";
else
buf << "ROM inactive, RAM bank #" << std::dec << bank % myNumRomBanks;

View File

@ -44,7 +44,7 @@ Cartridge3FWidget::Cartridge3FWidget(
ypos = addBaseInformation(size, "TigerVision", info.str()) + myLineHeight;
VariantList items;
for(uInt16 i = 0; i < cart.bankCount(); ++i)
for(uInt16 i = 0; i < cart.romBankCount(); ++i)
VarList::push_back(items, Variant(i).toString() + " ($3F)");
ostringstream label;

View File

@ -38,7 +38,7 @@ CartridgeFA2Widget::CartridgeFA2Widget(
<< "Startup bank = " << cart.startBank() << " or undetermined\n";
// Eventually, we should query this from the debugger/disassembler
for(uInt32 i = 0, offset = 0xFFC, spot = 0xFF5; i < cart.bankCount();
for(uInt32 i = 0, offset = 0xFFC, spot = 0xFF5; i < cart.romBankCount();
++i, offset += 0x1000)
{
uInt16 start = (cart.myImage[offset+1] << 8) | cart.myImage[offset];
@ -58,7 +58,7 @@ CartridgeFA2Widget::CartridgeFA2Widget(
VarList::push_back(items, "3 ($FFF8)");
VarList::push_back(items, "4 ($FFF9)");
VarList::push_back(items, "5 ($FFFA)");
if(cart.bankCount() == 7)
if(cart.romBankCount() == 7)
VarList::push_back(items, "6 ($FFFB)");
myBank =

View File

@ -26,7 +26,7 @@ CartridgeFCWidget::CartridgeFCWidget(
: CartDebugWidget(boss, lfont, nfont, x, y, w, h),
myCart(cart)
{
uInt16 size = cart.bankCount() * 4096;
uInt16 size = cart.romBankCount() * 4096;
ostringstream info;
info << "FC cartridge, up to eight 4K banks\n"
@ -42,7 +42,7 @@ CartridgeFCWidget::CartridgeFCWidget(
ypos = addBaseInformation(size, "Amiga Corp.", info.str()) + myLineHeight;
VariantList items;
for (uInt16 i = 0; i < cart.bankCount(); ++i)
for (uInt16 i = 0; i < cart.romBankCount(); ++i)
VarList::push_back(items, Variant(i).toString() +
" ($FFF8 = " + Variant(i & 0b11).toString() +
"/$FFF9 = " + Variant(i >> 2).toString() +")");

View File

@ -40,7 +40,7 @@ CartridgeMDMWidget::CartridgeMDMWidget(
ypos = addBaseInformation(size, "Edwin Blink", info.str(), 15) + myLineHeight;
VariantList items;
for(uInt32 i = 0x800; i < (0x800U + myCart.bankCount()); ++i)
for(uInt32 i = 0x800; i < (0x800U + myCart.romBankCount()); ++i)
{
info.str("");
info << std::dec << (i & 0xFF) << " ($" << Common::Base::HEX4 << i << ")";

View File

@ -35,14 +35,14 @@ CartridgeMNetworkWidget::CartridgeMNetworkWidget(
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CartridgeMNetworkWidget::initialize(GuiObject* boss, CartridgeMNetwork& cart, ostringstream& info)
{
uInt32 size = cart.bankCount() * cart.BANK_SIZE;
uInt32 size = cart.romBankCount() * cart.BANK_SIZE;
int xpos = 2,
ypos = addBaseInformation(size, "M-Network", info.str(), 15) +
myLineHeight;
VariantList items0, items1;
for(int i = 0; i < cart.bankCount(); ++i)
for(int i = 0; i < cart.romBankCount(); ++i)
VarList::push_back(items0, getSpotLower(i));
for(int i = 0; i < 4; ++i)
VarList::push_back(items1, getSpotUpper(i));

View File

@ -33,12 +33,12 @@ CartridgeSBWidget::CartridgeSBWidget(
myCart.getImage(size);
info << "SB SUPERbanking, 32 or 64 4K banks\n"
<< "Hotspots are from $800 to $"
<< Common::Base::HEX2 << (0x800 + myCart.bankCount() - 1) << ", including\n"
<< Common::Base::HEX2 << (0x800 + myCart.romBankCount() - 1) << ", including\n"
<< "mirrors ($900, $A00, $B00, ...)\n"
<< "Startup bank = " << std::dec << cart.startBank() << "\n";
// Eventually, we should query this from the debugger/disassembler
for(uInt32 i = 0, offset = 0xFFC, spot = 0x800; i < myCart.bankCount();
for(uInt32 i = 0, offset = 0xFFC, spot = 0x800; i < myCart.romBankCount();
++i, offset += 0x1000, ++spot)
{
uInt16 start = (cart.myImage[offset+1] << 8) | cart.myImage[offset];

View File

@ -68,7 +68,7 @@ void RomWidget::loadConfig()
const CartState& oldstate = static_cast<const CartState&>(cart.getOldState());
// Fill romlist the current bank of source or disassembly
myListIsDirty |= cart.disassemble(myListIsDirty);
myListIsDirty |= cart.disassemblePC(myListIsDirty);
if(myListIsDirty)
{
myRomList->setList(cart.disassembly());

View File

@ -83,7 +83,7 @@ uInt16 Cartridge::bankSize(uInt16 bank) const
getImage(size);
return std::min(uInt32(size) / bankCount(), 4_KB); // assuming that each bank has the same size
return std::min(uInt32(size) / romBankCount(), 4_KB); // assuming that each bank has the same size
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -145,13 +145,13 @@ string Cartridge::getAccessCounters() const
ostringstream out;
uInt32 offset = 0;
for(uInt16 bank = 0; bank < bankCount(); ++bank)
for(uInt16 bank = 0; bank < romBankCount(); ++bank)
{
uInt16 origin = bankOrigin(bank);
uInt16 bankSize = this->bankSize(bank);
out << "Bank " << Common::Base::toString(bank, Common::Base::Fmt::_10_8) << " / 0.."
<< Common::Base::toString(bankCount() - 1, Common::Base::Fmt::_10_8) << " reads:\n";
<< Common::Base::toString(romBankCount() - 1, Common::Base::Fmt::_10_8) << " reads:\n";
for(uInt16 addr = 0; addr < bankSize; ++addr)
{
out << Common::Base::HEX4 << (addr | origin) << ","
@ -159,7 +159,7 @@ string Cartridge::getAccessCounters() const
}
out << "\n";
out << "Bank " << Common::Base::toString(bank, Common::Base::Fmt::_10_8) << " / 0.."
<< Common::Base::toString(bankCount() - 1, Common::Base::Fmt::_10_8) << " writes:\n";
<< Common::Base::toString(romBankCount() - 1, Common::Base::Fmt::_10_8) << " writes:\n";
for(uInt16 addr = 0; addr < bankSize; ++addr)
{
out << Common::Base::HEX4 << (addr | origin) << ","
@ -230,11 +230,11 @@ uInt16 Cartridge::initializeStartBank(uInt16 defaultBank)
int propsBank = myStartBankFromPropsFunc();
if(randomStartBank())
return myStartBank = mySystem->randGenerator().next() % bankCount();
return myStartBank = mySystem->randGenerator().next() % romBankCount();
else if(propsBank >= 0)
return myStartBank = BSPF::clamp(propsBank, 0, bankCount() - 1);
return myStartBank = BSPF::clamp(propsBank, 0, romBankCount() - 1);
else
return myStartBank = BSPF::clamp(int(defaultBank), 0, bankCount() - 1);
return myStartBank = BSPF::clamp(int(defaultBank), 0, romBankCount() - 1);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

View File

@ -180,7 +180,7 @@ class Cartridge : public Device
virtual uInt16 getBank(uInt16 address = 0) const { return 0; }
/**
Query the number of 'banks' supported by the cartridge. Note that
Query the number of ROM 'banks' supported by the cartridge. Note that
this information is cart-specific, where each cart basically defines
what a 'bank' is.
@ -192,7 +192,15 @@ class Cartridge : public Device
RAM slices at multiple access points) is so complicated that the
cart will report having only one 'virtual' bank.
*/
virtual uInt16 bankCount() const { return 1; }
virtual uInt16 romBankCount() const { return 1; }
/**
Query the number of RAM 'banks' supported by the cartridge. Note that
this information is cart-specific, where each cart basically defines
what a 'bank' is.
*/
virtual uInt16 ramBankCount() const { return 0; }
/**
Get the size of a bank.

View File

@ -22,52 +22,42 @@
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Cartridge3E::Cartridge3E(const ByteBuffer& image, size_t size,
const string& md5, const Settings& settings)
: Cartridge(settings, md5),
mySize(size),
myRomBanks(256/*uInt16(size) >> 11*/)
: CartridgeEnhanced(image, size, md5, settings)
{
// Allocate array for the ROM image
myImage = make_unique<uInt8[]>(mySize);
// Copy the ROM image into my buffer
std::copy_n(image.get(), mySize, myImage.get());
createRomAccessArrays(mySize + myRAM.size());
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Cartridge3E::reset()
{
initializeRAM(myRAM.data(), myRAM.size());
initializeStartBank(0);
// We'll map the startup bank into the first segment upon reset
bank(startBank());
myBankShift = BANK_SHIFT;
myRamSize = RAM_SIZE;
myRamBankCount = RAM_BANKS;
myRamWpHigh = RAM_HIGH_WP;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Cartridge3E::install(System& system)
{
mySystem = &system;
CartridgeEnhanced::install(system);
System::PageAccess access(this, System::PageAccessType::READWRITE);
// The hotspots ($3E and $3F) are in TIA address space, so we claim it here
for(uInt16 addr = 0x00; addr < 0x40; addr += System::PAGE_SIZE)
mySystem->setPageAccess(addr, access);
}
// Setup the second segment to always point to the last ROM slice
access.type = System::PageAccessType::READ;
for(uInt16 addr = 0x1800; addr < 0x2000; addr += System::PAGE_SIZE)
{
access.directPeekBase = &myImage[(mySize - 2048) + (addr & 0x07FF)];
access.romAccessBase = &myRomAccessBase[(mySize - 2048) + (addr & 0x07FF)];
access.romPeekCounter = &myRomAccessCounter[(mySize - 2048) + (addr & 0x07FF)];
access.romPokeCounter = &myRomAccessCounter[(mySize - 2048) + (addr & 0x07FF) + myAccessSize];
mySystem->setPageAccess(addr, access);
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool Cartridge3E::checkSwitchBank(uInt16 address, uInt8 value)
{
// Switch banks if necessary
if(address == 0x003F) {
// Switch ROM bank into segment 0
bank(value);
return true;
}
// Install pages for the startup bank into the first segment
bank(startBank());
else if(address == 0x003E)
{
// Switch RAM bank into segment 0
bank(value + romBankCount());
return true;
}
return false;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -76,215 +66,8 @@ uInt8 Cartridge3E::peek(uInt16 address)
uInt16 peekAddress = address;
address &= 0x0FFF;
// Due to the way paging is set up, the only way to get here is a TIA read or
// attempting to read from the RAM write port
if(address < 0x0040) // TIA access
return mySystem->tia().peek(address);
else if(myCurrentBank >= myRomBanks)
{
// Reading from the write port triggers an unwanted write
return peekRAM(myRAM[(address & 0x03FF) + ((myCurrentBank - myRomBanks) << 10)], peekAddress);
}
// Make compiler happy; should never get here
return myImage[(address & 0x07FF) + mySize - 2048];
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool Cartridge3E::poke(uInt16 address, uInt8 value)
{
uInt16 pokeAddress = address;
address &= 0x0FFF;
// Switch banks if necessary. Armin (Kroko) says there are no mirrored
// hotspots.
if(address < 0x0040)
{
if(address == 0x003F)
bank(value);
else if(address == 0x003E)
bank(value + myRomBanks);
return mySystem->tia().poke(address, value);
}
else if(myCurrentBank >= myRomBanks)
{
if(address & 0x0400)
{
pokeRAM(myRAM[(address & 0x03FF) + ((myCurrentBank - myRomBanks) << 10)],
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;
}
}
return false;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool Cartridge3E::bank(uInt16 bank)
{
if(bankLocked()) return false;
if(bank < myRomBanks)
{
// Make sure the bank they're asking for is reasonable
if((uInt32(bank) << 11) < mySize)
{
myCurrentBank = bank;
}
else
{
// Oops, the bank they're asking for isn't valid so let's wrap it
// around to a valid bank number
myCurrentBank = bank % (mySize >> 11);
}
uInt32 offset = myCurrentBank << 11;
// Setup the page access methods for the current bank
System::PageAccess access(this, System::PageAccessType::READ);
// Map ROM image into the system
for(uInt16 addr = 0x1000; addr < 0x1800; addr += System::PAGE_SIZE)
{
access.directPeekBase = &myImage[offset + (addr & 0x07FF)];
access.romAccessBase = &myRomAccessBase[offset + (addr & 0x07FF)];
access.romPeekCounter = &myRomAccessCounter[offset + (addr & 0x07FF)];
access.romPokeCounter = &myRomAccessCounter[offset + (addr & 0x07FF) + myAccessSize];
mySystem->setPageAccess(addr, access);
}
}
else
{
bank -= myRomBanks;
bank %= myRamBanks;
myCurrentBank = bank + myRomBanks;
uInt32 offset = bank << 10;
// Setup the page access methods for the current bank
System::PageAccess access(this, System::PageAccessType::READ);
// Map read-port RAM image into the system
// Writes are mapped to poke(), to check for write to the read port
for(uInt16 addr = 0x1000; addr < 0x1400; addr += System::PAGE_SIZE)
{
access.directPeekBase = &myRAM[offset + (addr & 0x03FF)];
access.romAccessBase = &myRomAccessBase[mySize + offset + (addr & 0x03FF)];
access.romPeekCounter = &myRomAccessCounter[mySize + offset + (addr & 0x03FF)];
access.romPokeCounter = &myRomAccessCounter[mySize + offset + (addr & 0x03FF) + myAccessSize];
mySystem->setPageAccess(addr, access);
}
access.directPeekBase = nullptr;
access.type = System::PageAccessType::WRITE;
// Map write-port RAM image into the system
// Reads are mapped to peek(), to check for read from write port
for(uInt16 addr = 0x1400; addr < 0x1800; addr += System::PAGE_SIZE)
{
access.romAccessBase = &myRomAccessBase[mySize + offset + (addr & 0x03FF)];
access.romPeekCounter = &myRomAccessCounter[mySize + offset + (addr & 0x03FF)];
access.romPokeCounter = &myRomAccessCounter[mySize + offset + (addr & 0x03FF) + myAccessSize];
mySystem->setPageAccess(addr, access);
}
}
return myBankChanged = true;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt16 Cartridge3E::getBank(uInt16 address) const
{
if (address & 0x800)
return myRomBanks - 1; // 2K slices, fixed bank
else
return myCurrentBank;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt16 Cartridge3E::bankCount() const
{
// Because the RAM banks always start at 256 and above, we require the
// number of ROM banks to be 256
// If the RAM banks were simply appended to the number of actual
// ROM banks, bank numbers would be ambiguous (ie, would bank 128 be
// the last bank of ROM, or one of the banks of RAM?)
return myRomBanks + myRamBanks;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt16 Cartridge3E::bankSize(uInt16 bank) const
{
return 2_KB; // we cannot use bankCount() here, because it delivers wrong numbers
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool Cartridge3E::patch(uInt16 address, uInt8 value)
{
address &= 0x0FFF;
if(address < 0x0800)
{
if(myCurrentBank < myRomBanks)
myImage[(address & 0x07FF) + (myCurrentBank << 11)] = value;
else
myRAM[(address & 0x03FF) + ((myCurrentBank - myRomBanks) << 10)] = value;
}
else
myImage[(address & 0x07FF) + mySize - 2048] = value;
return myBankChanged = true;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
const uInt8* Cartridge3E::getImage(size_t& size) const
{
size = mySize;
return myImage.get();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool Cartridge3E::save(Serializer& out) const
{
try
{
out.putShort(myCurrentBank);
out.putByteArray(myRAM.data(), myRAM.size());
}
catch(...)
{
cerr << "ERROR: Cartridge3E::save" << endl;
return false;
}
return true;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool Cartridge3E::load(Serializer& in)
{
try
{
myCurrentBank = in.getShort();
in.getByteArray(myRAM.data(), myRAM.size());
}
catch(...)
{
cerr << "ERROR: Cartridge3E::load" << endl;
return false;
}
// Now, go to the current bank
bank(myCurrentBank);
return true;
return CartridgeEnhanced::peek(peekAddress);
}

View File

@ -21,7 +21,7 @@
class System;
#include "bspf.hxx"
#include "Cart.hxx"
#include "CartEnhanced.hxx"
#ifdef DEBUGGER_SUPPORT
#include "Cart3EWidget.hxx"
#endif
@ -47,10 +47,8 @@ class System;
by storing its value into $3F. To map RAM in the first 2K segment
instead, store the RAM bank number into $3E.
This implementation of 3E bankswitching numbers the ROM banks 0 to
255, and the RAM banks 256 to 287. This is done because the public
bankswitching interface requires us to use one bank number, not one
bank number plus the knowledge of whether it's RAM or ROM.
This implementation of 3E bankswitching numbers the RAM banks (up to 32)
after the ROM banks (up to 256).
All 32K of potential RAM is available to a game using this class, even
though real cartridges might not have the full 32K: We have no way to
@ -58,10 +56,10 @@ class System;
may add a stella.pro property for this), but for now it shouldn't cause
any problems. (Famous last words...)
@author B. Watson
@author B. Watson, Thomas Jentzsch
*/
class Cartridge3E : public Cartridge
class Cartridge3E : public CartridgeEnhanced
{
friend class Cartridge3EWidget;
@ -79,10 +77,6 @@ class Cartridge3E : public Cartridge
virtual ~Cartridge3E() = default;
public:
/**
Reset device to its power-on state
*/
void reset() override;
/**
Install cartridge in the specified system. Invoked by the system
@ -92,66 +86,6 @@ class Cartridge3E : public Cartridge
*/
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;
/**
Get the size of a bank.
@param bank The bank to get the size for
@return The bank's size
*/
virtual uInt16 bankSize(uInt16 bank = 0) const;
/**
Patch the cartridge ROM.
@param address The ROM address to patch
@param value The value to place into the address
@return Success or failure of the patch operation
*/
bool patch(uInt16 address, uInt8 value) 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).
@ -179,33 +113,21 @@ class Cartridge3E : public Cartridge
*/
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:
bool checkSwitchBank(uInt16 address, uInt8 value) override;
private:
// Pointer to a dynamically allocated ROM image of the cartridge
ByteBuffer myImage;
// log(ROM bank segment size) / log(2)
static constexpr uInt16 BANK_SHIFT = 11; // = 2K = 0x0800
// RAM contents. For now every ROM gets all 32K of potential RAM
std::array<uInt8, 32_KB> myRAM;
// The size of extra RAM in ROM address space
static constexpr uInt16 RAM_BANKS = 32;
// Size of the ROM image
size_t mySize{0};
// RAM size
static constexpr uInt16 RAM_SIZE = RAM_BANKS << (BANK_SHIFT - 1); // = 32K = 0x4000;
// Size of the ROM image
uInt16 myRomBanks{0};
// Size of the ROM image
uInt16 myRamBanks{32};
// Indicates which bank is currently active for the first segment
uInt16 myCurrentBank{0};
// Write port for extra RAM is at high address
static constexpr bool RAM_HIGH_WP = true;
private:
// Following constructors and assignment operators not supported

View File

@ -85,7 +85,7 @@ uInt16 Cartridge3EPlus::getBank(uInt16 address) const
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt16 Cartridge3EPlus::bankCount() const
uInt16 Cartridge3EPlus::romBankCount() const
{
return uInt16(mySize >> 10); // 1K slices
}

View File

@ -80,7 +80,7 @@ class Cartridge3EPlus: public Cartridge
/**
Query the number of banks supported by the cartridge.
*/
uInt16 bankCount() const override;
uInt16 romBankCount() const override;
/**
Patch the cartridge ROM.

View File

@ -46,7 +46,7 @@ bool Cartridge3F::checkSwitchBank(uInt16 address, uInt8 value)
if(address <= 0x003F)
{
// Make sure the bank they're asking for is reasonable
bank(value % bankCount(), 0);
bank(value % romBankCount(), 0);
return true;
}
return false;

View File

@ -406,7 +406,7 @@ uInt16 CartridgeAR::getBank(uInt16) const
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt16 CartridgeAR::bankCount() const
uInt16 CartridgeAR::romBankCount() const
{
return 32;
}

View File

@ -87,7 +87,7 @@ class CartridgeAR : public Cartridge
/**
Query the number of banks supported by the cartridge.
*/
uInt16 bankCount() const override;
uInt16 romBankCount() const override;
/**
Patch the cartridge ROM.

View File

@ -457,7 +457,7 @@ uInt16 CartridgeBUS::getBank(uInt16) const
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt16 CartridgeBUS::bankCount() const
uInt16 CartridgeBUS::romBankCount() const
{
return 7;
}

View File

@ -98,7 +98,7 @@ class CartridgeBUS : public Cartridge
/**
Query the number of banks supported by the cartridge.
*/
uInt16 bankCount() const override;
uInt16 romBankCount() const override;
/**
Patch the cartridge ROM.

View File

@ -430,7 +430,7 @@ uInt16 CartridgeCDF::getBank(uInt16) const
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt16 CartridgeCDF::bankCount() const
uInt16 CartridgeCDF::romBankCount() const
{
return 7;
}

View File

@ -104,7 +104,7 @@ class CartridgeCDF : public Cartridge
/**
Query the number of banks supported by the cartridge.
*/
uInt16 bankCount() const override;
uInt16 romBankCount() const override;
/**
Patch the cartridge ROM.

View File

@ -163,7 +163,7 @@ uInt16 CartridgeCM::getBank(uInt16) const
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt16 CartridgeCM::bankCount() const
uInt16 CartridgeCM::romBankCount() const
{
// We report 4 banks (of ROM), even though RAM can overlap the upper 2K
// of cart address space at some times

View File

@ -155,7 +155,7 @@ class CartridgeCM : public Cartridge
/**
Query the number of banks supported by the cartridge.
*/
uInt16 bankCount() const override;
uInt16 romBankCount() const override;
/**
Patch the cartridge ROM.

View File

@ -255,7 +255,7 @@ uInt16 CartridgeCTY::getBank(uInt16) const
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt16 CartridgeCTY::bankCount() const
uInt16 CartridgeCTY::romBankCount() const
{
return 8;
}

View File

@ -153,7 +153,7 @@ class CartridgeCTY : public Cartridge
/**
Query the number of banks supported by the cartridge.
*/
uInt16 bankCount() const override;
uInt16 romBankCount() const override;
/**
Patch the cartridge ROM.

View File

@ -399,7 +399,7 @@ uInt16 CartridgeDPC::getBank(uInt16) const
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt16 CartridgeDPC::bankCount() const
uInt16 CartridgeDPC::romBankCount() const
{
return 2;
}

View File

@ -85,7 +85,7 @@ class CartridgeDPC : public Cartridge
/**
Query the number of banks supported by the cartridge.
*/
uInt16 bankCount() const override;
uInt16 romBankCount() const override;
/**
Patch the cartridge ROM.

View File

@ -619,7 +619,7 @@ uInt16 CartridgeDPCPlus::getBank(uInt16) const
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt16 CartridgeDPCPlus::bankCount() const
uInt16 CartridgeDPCPlus::romBankCount() const
{
return 6;
}

View File

@ -100,7 +100,7 @@ class CartridgeDPCPlus : public Cartridge
/**
Query the number of banks supported by the cartridge.
*/
uInt16 bankCount() const override;
uInt16 romBankCount() const override;
/**
Patch the cartridge ROM.

View File

@ -34,16 +34,19 @@ CartridgeEnhanced::CartridgeEnhanced(const ByteBuffer& image, size_t size,
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CartridgeEnhanced::install(System& system)
{
// Copy the ROM image into my buffer
createRomAccessArrays(mySize);
// limit banked RAM size to the size of one RAM bank
uInt16 ramSize = myRamBankCount ? 1 << (myBankShift - 1) : myRamSize;
// 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)
myWriteOffset = myRamWpHigh ? myRamSize : 0;
myReadOffset = myRamWpHigh ? 0 : myRamSize;
myRomOffset = myRamBankCount ? 0 : myRamSize * 2;
myRamMask = ramSize - 1; // e.g. = 0xFFFF (doesn't matter for RAM size 0)
myWriteOffset = myRamWpHigh ? ramSize : 0;
myReadOffset = myRamWpHigh ? 0 : ramSize;
createRomAccessArrays(mySize + (myRomOffset ? 0 : myRamSize));
// Allocate array for the current bank segments slices
myCurrentSegOffset = make_unique<uInt32[]>(myBankSegs);
@ -51,9 +54,11 @@ void CartridgeEnhanced::install(System& system)
// Allocate array for the RAM area
myRAM = make_unique<uInt8[]>(myRamSize);
// Setup page access
mySystem = &system;
if(myRomOffset)
{
// Setup page access for extended RAM; banked RAM will be setup in bank()
System::PageAccess access(this, System::PageAccessType::READ);
// Set the page accessing method for the RAM writing pages
@ -80,12 +85,13 @@ void CartridgeEnhanced::install(System& system)
access.romPokeCounter = &myRomAccessCounter[myReadOffset + offset + myAccessSize];
mySystem->setPageAccess(addr, access);
}
}
// Install pages for the startup bank (TODO: currently only in first bank segment)
bank(startBank(), 0);
if(mySize >= 4_KB && myBankSegs > 1)
// Setup the last bank segment to always point to the last ROM segment
bank(bankCount() - 1, myBankSegs - 1);
bank(romBankCount() - 1, myBankSegs - 1);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -106,28 +112,67 @@ uInt8 CartridgeEnhanced::peek(uInt16 address)
if (hotspot())
checkSwitchBank(address & 0x0FFF);
if(isRamBank(address))
{
address &= myRamMask;
// This is a read access to a write port!
// Reading from the write port triggers an unwanted write
// The RAM banks follow the ROM banks and are half the size of a ROM bank
return peekRAM(myRAM[((myCurrentSegOffset[(peekAddress & 0xFFF) >> myBankShift] - mySize) >> 1) + address],
peekAddress);
}
else
{
address &= myBankMask;
// Write port is e.g. at 0xF000 - 0xF07F (128 bytes)
if(address < myReadOffset + myRamSize && address >= myReadOffset)
// This is a read access to a write port!
// Reading from the write port triggers an unwanted write
return peekRAM(myRAM[address], peekAddress);
else
return myImage[myCurrentSegOffset[(peekAddress & 0xFFF) >> myBankShift] + address];
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool CartridgeEnhanced::poke(uInt16 address, uInt8 value)
{
uInt16 pokeAddress = address;
// Switch banks if necessary
// Note: (TODO?)
// The checkSwitchBank() call makes no difference between ROM and e.g TIA space
// Writing to e.g. 0xf0xx might triger a bankswitch, is (and was!) this a bug???
if (checkSwitchBank(address & 0x0FFF, value))
return false;
address &= myBankMask;
if(myRamSize)
{
uInt16 pokeAddress = address;
if(isRamBank(address))
{
if(bool(address & (myBankSize >> 1)) == myRamWpHigh)
{
address &= myRamMask;
// The RAM banks follow the ROM banks and are half the size of a ROM bank
pokeRAM(myRAM[((myCurrentSegOffset[(pokeAddress & 0xFFF) >> myBankShift] - mySize) >> 1) + address],
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;
}
}
else
{
//address &= myBankMask;
if(bool(address & myRamSize) == myRamWpHigh)
{
pokeRAM(myRAM[address & myRamMask], pokeAddress, value);
@ -142,27 +187,28 @@ bool CartridgeEnhanced::poke(uInt16 address, uInt8 value)
myRamWriteAccess = pokeAddress;
}
}
}
return false;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool CartridgeEnhanced::bank(uInt16 bank, uInt16 segment, bool isRAM)
bool CartridgeEnhanced::bank(uInt16 bank, uInt16 segment)
{
if(bankLocked()) return false;
uInt16 segmentOffset = segment << myBankShift;
if(!isRAM)
if(!myRamBankCount || bank < romBankCount())
{
// Setup ROM bank
// Remember what bank is in which segment
uInt32 bankOffset = myCurrentSegOffset[segment] = bank << myBankShift;
uInt16 romBank = bank % romBankCount();
// Remember what bank is in this segment
uInt32 bankOffset = myCurrentSegOffset[segment] = romBank << myBankShift;
uInt16 hotspot = this->hotspot();
uInt16 hotSpotAddr;
uInt16 fromAddr = (segmentOffset + 0x1000 + myRamSize * 2) & ~System::PAGE_MASK;
uInt16 fromAddr = (0x1000 + segmentOffset + myRomOffset) & ~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;
uInt16 toAddr = (0x1000 + segmentOffset + (mySize < 4_KB ? 0x1000 : myBankSize)) & ~System::PAGE_MASK;
if(hotspot)
hotSpotAddr = (hotspot & ~System::PAGE_MASK);
@ -185,24 +231,24 @@ bool CartridgeEnhanced::bank(uInt16 bank, uInt16 segment, bool isRAM)
mySystem->setPageAccess(addr, access);
}
}
/*else
else
{
// Setup RAM bank
// TODO: define offsets on init
uInt16 myWriteBankOffset = myBankSize >> 1;
uInt16 myReadBankOffset = 0;
uInt16 ramBank = (bank - romBankCount()) % myRamBankCount;
// The RAM banks follow the ROM banks and are half the size of a ROM bank
uInt32 bankOffset = uInt32(mySize) + (ramBank << (myBankShift - 1));
// Remember what bank is in which segment
uInt32 bankOffset = myCurrentSegOffset[segment] = bank << myBankShift;
// Remember what bank is in this segment
myCurrentSegOffset[segment] = bank << myBankShift;
// Set the page accessing method for the RAM writing pages
uInt16 fromAddr = (segmentOffset + myWriteBankOffset + 0x1000) & ~System::PAGE_MASK;
uInt16 toAddr = (segmentOffset + myWriteBankOffset + 0x1000 + myBankSize >> 1) & ~System::PAGE_MASK;
uInt16 fromAddr = (0x1000 + segmentOffset + myWriteOffset) & ~System::PAGE_MASK;
uInt16 toAddr = (0x1000 + segmentOffset + myWriteOffset + (myBankSize >> 1)) & ~System::PAGE_MASK;
System::PageAccess access(this, System::PageAccessType::WRITE);
for(uInt16 addr = fromAddr; addr < toAddr; addr += System::PAGE_SIZE)
{
uInt32 offset = bankOffset + (addr & myBankMask);
uInt32 offset = bankOffset + (addr & myRamMask);
access.romAccessBase = &myRomAccessBase[offset];
access.romPeekCounter = &myRomAccessCounter[offset];
@ -211,25 +257,23 @@ bool CartridgeEnhanced::bank(uInt16 bank, uInt16 segment, bool isRAM)
}
// Set the page accessing method for the RAM reading pages
fromAddr = (segmentOffset + myReadBankOffset + 0x1000) & ~System::PAGE_MASK;
toAddr = (segmentOffset + myReadBankOffset + 0x1000 + myBankSize >> 1) & ~System::PAGE_MASK;
fromAddr = (0x1000 + segmentOffset + myReadOffset) & ~System::PAGE_MASK;
toAddr = (0x1000 + segmentOffset + myReadOffset + (myBankSize >> 1)) & ~System::PAGE_MASK;
access.type = System::PageAccessType::READ;
for(uInt16 addr = fromAddr; addr < toAddr; addr += System::PAGE_SIZE)
{
uInt32 offset = bankOffset + (addr & myBankMask);
uInt32 offset = bankOffset + (addr & myRamMask);
uInt16 offset = addr & myRamMask;
access.directPeekBase = &myBankRAM[offset];
access.directPeekBase = &myRAM[offset - mySize];
access.romAccessBase = &myRomAccessBase[offset];
access.romPeekCounter = &myRomAccessCounter[offset];
access.romPokeCounter = &myRomAccessCounter[offset + myAccessSize];
mySystem->setPageAccess(addr, access);
}
}*/
}
return myBankChanged = true;
}
@ -246,14 +290,32 @@ uInt16 CartridgeEnhanced::getSegmentBank(uInt16 segment) const
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt16 CartridgeEnhanced::bankCount() const
uInt16 CartridgeEnhanced::romBankCount() const
{
return uInt16(mySize >> myBankShift);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt16 CartridgeEnhanced::ramBankCount() const
{
return myRamBankCount;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool CartridgeEnhanced::isRamBank(uInt16 address) const
{
return myRamBankCount ? getBank(address) >= romBankCount() : false;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool CartridgeEnhanced::patch(uInt16 address, uInt8 value)
{
if(isRamBank(address))
{
myRAM[((myCurrentSegOffset[(address & 0xFFF) >> myBankShift] - mySize) >> 1) + (address & myRamMask)] = value;
}
else
{
if((address & myBankMask) < myRamSize * 2)
{
// Normally, a write to the read port won't do anything
@ -263,6 +325,7 @@ bool CartridgeEnhanced::patch(uInt16 address, uInt8 value)
}
else
myImage[myCurrentSegOffset[(address & 0xFFF) >> myBankShift] + (address & myBankMask)] = value;
}
return myBankChanged = true;
}

View File

@ -62,11 +62,10 @@ class CartridgeEnhanced : public Cartridge
@param bank The bank that should be installed in the system
@param segment The segment the bank should be using
@param isRAM True if the bank is a RAM bank
@return true, if bank has changed
*/
bool bank(uInt16 bank, uInt16 segment, bool isRAM = false);
bool bank(uInt16 bank, uInt16 segment);
/**
Install pages for the specified bank in the system.
@ -94,7 +93,21 @@ class CartridgeEnhanced : public Cartridge
/**
Query the number of banks supported by the cartridge.
*/
uInt16 bankCount() const override;
uInt16 romBankCount() const override;
/**
Query the number of RAM 'banks' supported by the cartridge.
*/
uInt16 ramBankCount() const override;
/**
Check if the segment at that address contains a RAM bank
@param address The address which defines the segment
@return true, if the segment is currently mapped to a RAM bank
*/
bool isRamBank(uInt16 address) const;
/**
Patch the cartridge ROM.
@ -162,9 +175,19 @@ class CartridgeEnhanced : public Cartridge
// The extra RAM size
uInt16 myRamSize{RAM_SIZE}; // default 0
// The number of RAM banks
uInt16 myRamBankCount{RAM_BANKS}; // default 0
// The mask for the extra RAM
uInt16 myRamMask{0}; // RAM_SIZE - 1, but doesn't matter when RAM_SIZE is 0
// The offset into ROM space for reading from ROM
// This is zero for types without RAM and with banked RAM
// - xxSC = 0x0100
// - FA(2) = 0x0200
// - CV = 0x0800
uInt16 myRomOffset{0};
// The offset into ROM space for writing to RAM
// - xxSC = 0x0000
// - FA(2) = 0x0000
@ -202,6 +225,9 @@ class CartridgeEnhanced : public Cartridge
// The size of extra RAM in ROM address space
static constexpr uInt16 RAM_SIZE = 0; // default = none
// The size of extra RAM in ROM address space
static constexpr uInt16 RAM_BANKS = 0;
// Write port for extra RAM is at low address by default
static constexpr bool RAM_HIGH_WP = false;

View File

@ -61,14 +61,14 @@ bool CartridgeFC::poke(uInt16 address, uInt8 value)
case 0x0FF9:
// Set the high bits of target 4k bank
if (value << 2 < bankCount())
if (value << 2 < romBankCount())
{
myTargetBank += value << 2;
myTargetBank %= bankCount();
myTargetBank %= romBankCount();
}
else
// special handling when both values are identical (e.g. 4/4 or 5/5)
myTargetBank = value % bankCount();
myTargetBank = value % romBankCount();
break;
default:

View File

@ -36,7 +36,7 @@ void CartridgeMNetwork::initialize(const ByteBuffer& image, size_t size)
std::copy_n(image.get(), std::min<size_t>(romSize(), size), myImage.get());
createRomAccessArrays(romSize() + myRAM.size());
myRAMSlice = bankCount() - 1;
myRAMSlice = romBankCount() - 1;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -265,7 +265,7 @@ bool CartridgeMNetwork::patch(uInt16 address, uInt8 value)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
const uInt8* CartridgeMNetwork::getImage(size_t& size) const
{
size = bankCount() * BANK_SIZE;
size = romBankCount() * BANK_SIZE;
return myImage.get();
}
@ -310,7 +310,7 @@ bool CartridgeMNetwork::load(Serializer& in)
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt16 CartridgeMNetwork::bankCount() const
uInt16 CartridgeMNetwork::romBankCount() const
{
return uInt16(mySize >> 11);
}
@ -318,5 +318,5 @@ uInt16 CartridgeMNetwork::bankCount() const
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt16 CartridgeMNetwork::romSize() const
{
return bankCount() * BANK_SIZE;
return romBankCount() * BANK_SIZE;
}

View File

@ -108,7 +108,7 @@ class CartridgeMNetwork : public Cartridge
/**
Query the number of banks supported by the cartridge.
*/
uInt16 bankCount() const override;
uInt16 romBankCount() const override;
/**
Patch the cartridge ROM.

View File

@ -64,7 +64,7 @@ bool CartridgeSB::checkSwitchBank(uInt16 address, uInt8)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt8 CartridgeSB::peek(uInt16 address)
{
address &= (0x17FF + bankCount());
address &= (0x17FF + romBankCount());
checkSwitchBank(address);
@ -82,7 +82,7 @@ uInt8 CartridgeSB::peek(uInt16 address)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool CartridgeSB::poke(uInt16 address, uInt8 value)
{
address &= (0x17FF + bankCount());
address &= (0x17FF + romBankCount());
checkSwitchBank(address);

View File

@ -100,7 +100,7 @@ class CartridgeSB : public CartridgeEnhanced
uInt16 hotspot() const override { return 0x0840; }
uInt16 getStartBank() const override { return bankCount() - 1; }
uInt16 getStartBank() const override { return romBankCount() - 1; }
private:
// Previous Device's page access

View File

@ -250,7 +250,7 @@ uInt16 CartridgeWD::getBank(uInt16) const
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt16 CartridgeWD::bankCount() const
uInt16 CartridgeWD::romBankCount() const
{
return 16;
}

View File

@ -101,7 +101,7 @@ class CartridgeWD : public Cartridge
/**
Query the number of banks supported by the cartridge.
*/
uInt16 bankCount() const override;
uInt16 romBankCount() const override;
/**
Patch the cartridge ROM.

View File

@ -445,7 +445,7 @@ void GameInfoDialog::loadEmulationProperties(const Properties& props)
VarList::push_back(items, "Auto", "AUTO");
if(instance().hasConsole())
{
uInt16 numBanks = instance().console().cartridge().bankCount();
uInt16 numBanks = instance().console().cartridge().romBankCount();
for(uInt16 i = 0; i < numBanks; ++i)
VarList::push_back(items, i, i);