From 00e67f1a51dcd94dc14ef81316c7dd3156d43ca5 Mon Sep 17 00:00:00 2001 From: thrust26 Date: Wed, 15 Apr 2020 14:53:05 +0200 Subject: [PATCH] add RAM bank support to CartEnhanced refactor Cart3E differentiate between ROM and RAM banks (TODO: check debugger) --- src/debugger/CartDebug.cxx | 45 ++-- src/debugger/CartDebug.hxx | 4 +- src/debugger/DebuggerParser.cxx | 14 +- src/debugger/gui/Cart3EWidget.cxx | 24 +-- src/debugger/gui/Cart3FWidget.cxx | 2 +- src/debugger/gui/CartFA2Widget.cxx | 4 +- src/debugger/gui/CartFCWidget.cxx | 4 +- src/debugger/gui/CartMDMWidget.cxx | 2 +- src/debugger/gui/CartMNetworkWidget.cxx | 4 +- src/debugger/gui/CartSBWidget.cxx | 4 +- src/debugger/gui/RomWidget.cxx | 2 +- src/emucore/Cart.cxx | 14 +- src/emucore/Cart.hxx | 12 +- src/emucore/Cart3E.cxx | 263 +++--------------------- src/emucore/Cart3E.hxx | 108 ++-------- src/emucore/Cart3EPlus.cxx | 2 +- src/emucore/Cart3EPlus.hxx | 2 +- src/emucore/Cart3F.cxx | 2 +- src/emucore/CartAR.cxx | 2 +- src/emucore/CartAR.hxx | 2 +- src/emucore/CartBUS.cxx | 2 +- src/emucore/CartBUS.hxx | 2 +- src/emucore/CartCDF.cxx | 2 +- src/emucore/CartCDF.hxx | 2 +- src/emucore/CartCM.cxx | 2 +- src/emucore/CartCM.hxx | 2 +- src/emucore/CartCTY.cxx | 2 +- src/emucore/CartCTY.hxx | 2 +- src/emucore/CartDPC.cxx | 2 +- src/emucore/CartDPC.hxx | 2 +- src/emucore/CartDPCPlus.cxx | 2 +- src/emucore/CartDPCPlus.hxx | 2 +- src/emucore/CartEnhanced.cxx | 217 ++++++++++++------- src/emucore/CartEnhanced.hxx | 32 ++- src/emucore/CartFC.cxx | 6 +- src/emucore/CartMNetwork.cxx | 8 +- src/emucore/CartMNetwork.hxx | 2 +- src/emucore/CartSB.cxx | 4 +- src/emucore/CartSB.hxx | 2 +- src/emucore/CartWD.cxx | 2 +- src/emucore/CartWD.hxx | 2 +- src/gui/GameInfoDialog.cxx | 2 +- 42 files changed, 313 insertions(+), 504 deletions(-) diff --git a/src/debugger/CartDebug.cxx b/src/debugger/CartDebug.cxx index a52732cfe..ef6924187 100644 --- a/src/debugger/CartDebug.cxx +++ b/src/debugger/CartDebug.cxx @@ -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; diff --git a/src/debugger/CartDebug.hxx b/src/debugger/CartDebug.hxx index c2bd03cae..486eedd79 100644 --- a/src/debugger/CartDebug.hxx +++ b/src/debugger/CartDebug.hxx @@ -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. diff --git a/src/debugger/DebuggerParser.cxx b/src/debugger/DebuggerParser.cxx index 4f50be800..da3b0bc5f 100644 --- a/src/debugger/DebuggerParser.cxx +++ b/src/debugger/DebuggerParser.cxx @@ -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; diff --git a/src/debugger/gui/Cart3EWidget.cxx b/src/debugger/gui/Cart3EWidget.cxx index 3880f2026..e91b268ab 100644 --- a/src/debugger/gui/Cart3EWidget.cxx +++ b/src/debugger/gui/Cart3EWidget.cxx @@ -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; diff --git a/src/debugger/gui/Cart3FWidget.cxx b/src/debugger/gui/Cart3FWidget.cxx index 86d43177b..13cd851bd 100644 --- a/src/debugger/gui/Cart3FWidget.cxx +++ b/src/debugger/gui/Cart3FWidget.cxx @@ -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; diff --git a/src/debugger/gui/CartFA2Widget.cxx b/src/debugger/gui/CartFA2Widget.cxx index eb2bf4d07..9a24eb5a7 100644 --- a/src/debugger/gui/CartFA2Widget.cxx +++ b/src/debugger/gui/CartFA2Widget.cxx @@ -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 = diff --git a/src/debugger/gui/CartFCWidget.cxx b/src/debugger/gui/CartFCWidget.cxx index ce1bf9403..a034b56e3 100644 --- a/src/debugger/gui/CartFCWidget.cxx +++ b/src/debugger/gui/CartFCWidget.cxx @@ -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() +")"); diff --git a/src/debugger/gui/CartMDMWidget.cxx b/src/debugger/gui/CartMDMWidget.cxx index 2ba603168..48afbaf77 100644 --- a/src/debugger/gui/CartMDMWidget.cxx +++ b/src/debugger/gui/CartMDMWidget.cxx @@ -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 << ")"; diff --git a/src/debugger/gui/CartMNetworkWidget.cxx b/src/debugger/gui/CartMNetworkWidget.cxx index cdc1f9bce..37d382a7e 100644 --- a/src/debugger/gui/CartMNetworkWidget.cxx +++ b/src/debugger/gui/CartMNetworkWidget.cxx @@ -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)); diff --git a/src/debugger/gui/CartSBWidget.cxx b/src/debugger/gui/CartSBWidget.cxx index 78d352879..7a82ba8e0 100644 --- a/src/debugger/gui/CartSBWidget.cxx +++ b/src/debugger/gui/CartSBWidget.cxx @@ -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]; diff --git a/src/debugger/gui/RomWidget.cxx b/src/debugger/gui/RomWidget.cxx index 18c8b0b78..e62fe0a17 100644 --- a/src/debugger/gui/RomWidget.cxx +++ b/src/debugger/gui/RomWidget.cxx @@ -68,7 +68,7 @@ void RomWidget::loadConfig() const CartState& oldstate = static_cast(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()); diff --git a/src/emucore/Cart.cxx b/src/emucore/Cart.cxx index f85850ba2..7639101ff 100644 --- a/src/emucore/Cart.cxx +++ b/src/emucore/Cart.cxx @@ -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); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/emucore/Cart.hxx b/src/emucore/Cart.hxx index ce7d66a8b..a7488f551 100644 --- a/src/emucore/Cart.hxx +++ b/src/emucore/Cart.hxx @@ -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. diff --git a/src/emucore/Cart3E.cxx b/src/emucore/Cart3E.cxx index f1ccd2957..a927ddd2d 100644 --- a/src/emucore/Cart3E.cxx +++ b/src/emucore/Cart3E.cxx @@ -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(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); } diff --git a/src/emucore/Cart3E.hxx b/src/emucore/Cart3E.hxx index d78cb3bb0..4871c67a6 100644 --- a/src/emucore/Cart3E.hxx +++ b/src/emucore/Cart3E.hxx @@ -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 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 diff --git a/src/emucore/Cart3EPlus.cxx b/src/emucore/Cart3EPlus.cxx index 27eb94986..1fe28a022 100644 --- a/src/emucore/Cart3EPlus.cxx +++ b/src/emucore/Cart3EPlus.cxx @@ -85,7 +85,7 @@ uInt16 Cartridge3EPlus::getBank(uInt16 address) const } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt16 Cartridge3EPlus::bankCount() const +uInt16 Cartridge3EPlus::romBankCount() const { return uInt16(mySize >> 10); // 1K slices } diff --git a/src/emucore/Cart3EPlus.hxx b/src/emucore/Cart3EPlus.hxx index 76919b9ae..70309d308 100644 --- a/src/emucore/Cart3EPlus.hxx +++ b/src/emucore/Cart3EPlus.hxx @@ -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. diff --git a/src/emucore/Cart3F.cxx b/src/emucore/Cart3F.cxx index 7c3701c16..21b21b9c7 100644 --- a/src/emucore/Cart3F.cxx +++ b/src/emucore/Cart3F.cxx @@ -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; diff --git a/src/emucore/CartAR.cxx b/src/emucore/CartAR.cxx index 5201a14df..2d8b204b6 100644 --- a/src/emucore/CartAR.cxx +++ b/src/emucore/CartAR.cxx @@ -406,7 +406,7 @@ uInt16 CartridgeAR::getBank(uInt16) const } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt16 CartridgeAR::bankCount() const +uInt16 CartridgeAR::romBankCount() const { return 32; } diff --git a/src/emucore/CartAR.hxx b/src/emucore/CartAR.hxx index 6fda35f38..0bc74a291 100644 --- a/src/emucore/CartAR.hxx +++ b/src/emucore/CartAR.hxx @@ -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. diff --git a/src/emucore/CartBUS.cxx b/src/emucore/CartBUS.cxx index 2c2cd803a..bd6d227c2 100644 --- a/src/emucore/CartBUS.cxx +++ b/src/emucore/CartBUS.cxx @@ -457,7 +457,7 @@ uInt16 CartridgeBUS::getBank(uInt16) const } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt16 CartridgeBUS::bankCount() const +uInt16 CartridgeBUS::romBankCount() const { return 7; } diff --git a/src/emucore/CartBUS.hxx b/src/emucore/CartBUS.hxx index d00e90133..5567f1196 100644 --- a/src/emucore/CartBUS.hxx +++ b/src/emucore/CartBUS.hxx @@ -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. diff --git a/src/emucore/CartCDF.cxx b/src/emucore/CartCDF.cxx index b182634a3..2758a9825 100644 --- a/src/emucore/CartCDF.cxx +++ b/src/emucore/CartCDF.cxx @@ -430,7 +430,7 @@ uInt16 CartridgeCDF::getBank(uInt16) const } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt16 CartridgeCDF::bankCount() const +uInt16 CartridgeCDF::romBankCount() const { return 7; } diff --git a/src/emucore/CartCDF.hxx b/src/emucore/CartCDF.hxx index 5e65bc4d4..7c5295f7a 100644 --- a/src/emucore/CartCDF.hxx +++ b/src/emucore/CartCDF.hxx @@ -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. diff --git a/src/emucore/CartCM.cxx b/src/emucore/CartCM.cxx index 5fa6dff3d..40ec603e5 100644 --- a/src/emucore/CartCM.cxx +++ b/src/emucore/CartCM.cxx @@ -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 diff --git a/src/emucore/CartCM.hxx b/src/emucore/CartCM.hxx index 2c0cf54d2..bf8b2586e 100644 --- a/src/emucore/CartCM.hxx +++ b/src/emucore/CartCM.hxx @@ -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. diff --git a/src/emucore/CartCTY.cxx b/src/emucore/CartCTY.cxx index 1536b64e0..822473081 100644 --- a/src/emucore/CartCTY.cxx +++ b/src/emucore/CartCTY.cxx @@ -255,7 +255,7 @@ uInt16 CartridgeCTY::getBank(uInt16) const } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt16 CartridgeCTY::bankCount() const +uInt16 CartridgeCTY::romBankCount() const { return 8; } diff --git a/src/emucore/CartCTY.hxx b/src/emucore/CartCTY.hxx index 5626013a1..fdd6c1e19 100644 --- a/src/emucore/CartCTY.hxx +++ b/src/emucore/CartCTY.hxx @@ -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. diff --git a/src/emucore/CartDPC.cxx b/src/emucore/CartDPC.cxx index 808e658d4..c8a038c25 100644 --- a/src/emucore/CartDPC.cxx +++ b/src/emucore/CartDPC.cxx @@ -399,7 +399,7 @@ uInt16 CartridgeDPC::getBank(uInt16) const } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt16 CartridgeDPC::bankCount() const +uInt16 CartridgeDPC::romBankCount() const { return 2; } diff --git a/src/emucore/CartDPC.hxx b/src/emucore/CartDPC.hxx index 330a0086a..6c186bfdb 100644 --- a/src/emucore/CartDPC.hxx +++ b/src/emucore/CartDPC.hxx @@ -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. diff --git a/src/emucore/CartDPCPlus.cxx b/src/emucore/CartDPCPlus.cxx index 0761eeb19..b71f5a8c0 100644 --- a/src/emucore/CartDPCPlus.cxx +++ b/src/emucore/CartDPCPlus.cxx @@ -619,7 +619,7 @@ uInt16 CartridgeDPCPlus::getBank(uInt16) const } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt16 CartridgeDPCPlus::bankCount() const +uInt16 CartridgeDPCPlus::romBankCount() const { return 6; } diff --git a/src/emucore/CartDPCPlus.hxx b/src/emucore/CartDPCPlus.hxx index 46b18af99..9617d6545 100644 --- a/src/emucore/CartDPCPlus.hxx +++ b/src/emucore/CartDPCPlus.hxx @@ -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. diff --git a/src/emucore/CartEnhanced.cxx b/src/emucore/CartEnhanced.cxx index 1a446a9a8..b8c1cde13 100644 --- a/src/emucore/CartEnhanced.cxx +++ b/src/emucore/CartEnhanced.cxx @@ -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(myBankSegs); @@ -51,41 +54,44 @@ void CartridgeEnhanced::install(System& system) // Allocate array for the RAM area myRAM = make_unique(myRamSize); - // Setup page access 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 + myWriteOffset; addr < 0x1000 + myWriteOffset + myRamSize; addr += System::PAGE_SIZE) + if(myRomOffset) { - uInt16 offset = addr & myRamMask; - access.romAccessBase = &myRomAccessBase[myWriteOffset + offset]; - access.romPeekCounter = &myRomAccessCounter[myWriteOffset + offset]; - access.romPokeCounter = &myRomAccessCounter[myWriteOffset + offset + myAccessSize]; - mySystem->setPageAccess(addr, access); - } + // 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 reading pages - access.type = System::PageAccessType::READ; - for(uInt16 addr = 0x1000 + myReadOffset; addr < 0x1000 + myReadOffset + myRamSize; addr += System::PAGE_SIZE) - { - uInt16 offset = addr & myRamMask; - access.directPeekBase = &myRAM[offset]; - access.romAccessBase = &myRomAccessBase[myReadOffset + offset]; - access.romPeekCounter = &myRomAccessCounter[myReadOffset + offset]; - access.romPokeCounter = &myRomAccessCounter[myReadOffset + offset + myAccessSize]; - mySystem->setPageAccess(addr, access); + // 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 + myWriteOffset; addr < 0x1000 + myWriteOffset + myRamSize; addr += System::PAGE_SIZE) + { + uInt16 offset = addr & myRamMask; + access.romAccessBase = &myRomAccessBase[myWriteOffset + offset]; + access.romPeekCounter = &myRomAccessCounter[myWriteOffset + offset]; + access.romPokeCounter = &myRomAccessCounter[myWriteOffset + offset + myAccessSize]; + mySystem->setPageAccess(addr, access); + } + + // Set the page accessing method for the RAM reading pages + access.type = System::PageAccessType::READ; + for(uInt16 addr = 0x1000 + myReadOffset; addr < 0x1000 + myReadOffset + myRamSize; addr += System::PAGE_SIZE) + { + uInt16 offset = addr & myRamMask; + access.directPeekBase = &myRAM[offset]; + access.romAccessBase = &myRomAccessBase[myReadOffset + offset]; + access.romPeekCounter = &myRomAccessCounter[myReadOffset + offset]; + 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,63 +112,103 @@ uInt8 CartridgeEnhanced::peek(uInt16 address) if (hotspot()) checkSwitchBank(address & 0x0FFF); - address &= myBankMask; - // Write port is e.g. at 0xF000 - 0xF07F (128 bytes) - if(address < myReadOffset + myRamSize && address >= myReadOffset) + if(isRamBank(address)) + { + address &= myRamMask; + // This is a read access to a write port! - return peekRAM(myRAM[address], peekAddress); + // 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 - return myImage[myCurrentSegOffset[(peekAddress & 0xFFF) >> myBankShift] + address]; + { + 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) { - if(bool(address & myRamSize) == myRamWpHigh) + uInt16 pokeAddress = address; + + if(isRamBank(address)) { - pokeRAM(myRAM[address & myRamMask], pokeAddress, value); - return true; + 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 { - // Writing to the read port should be ignored, but trigger a break if option enabled - uInt8 dummy; + //address &= myBankMask; + if(bool(address & myRamSize) == myRamWpHigh) + { + pokeRAM(myRAM[address & myRamMask], 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; + pokeRAM(dummy, pokeAddress, 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,23 +290,42 @@ 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((address & myBankMask) < myRamSize * 2) + if(isRamBank(address)) { - // 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 & myRamMask] = value; + myRAM[((myCurrentSegOffset[(address & 0xFFF) >> myBankShift] - mySize) >> 1) + (address & myRamMask)] = value; } else - myImage[myCurrentSegOffset[(address & 0xFFF) >> myBankShift] + (address & myBankMask)] = value; + { + if((address & myBankMask) < myRamSize * 2) + { + // 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 & myRamMask] = value; + } + else + myImage[myCurrentSegOffset[(address & 0xFFF) >> myBankShift] + (address & myBankMask)] = value; + } return myBankChanged = true; } diff --git a/src/emucore/CartEnhanced.hxx b/src/emucore/CartEnhanced.hxx index 29046f0ea..3b68101cc 100644 --- a/src/emucore/CartEnhanced.hxx +++ b/src/emucore/CartEnhanced.hxx @@ -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; diff --git a/src/emucore/CartFC.cxx b/src/emucore/CartFC.cxx index 741935c06..925718d50 100644 --- a/src/emucore/CartFC.cxx +++ b/src/emucore/CartFC.cxx @@ -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: diff --git a/src/emucore/CartMNetwork.cxx b/src/emucore/CartMNetwork.cxx index c5ff0cfab..984769b17 100644 --- a/src/emucore/CartMNetwork.cxx +++ b/src/emucore/CartMNetwork.cxx @@ -36,7 +36,7 @@ void CartridgeMNetwork::initialize(const ByteBuffer& image, size_t size) std::copy_n(image.get(), std::min(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; } diff --git a/src/emucore/CartMNetwork.hxx b/src/emucore/CartMNetwork.hxx index ef06aae57..dd9443390 100644 --- a/src/emucore/CartMNetwork.hxx +++ b/src/emucore/CartMNetwork.hxx @@ -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. diff --git a/src/emucore/CartSB.cxx b/src/emucore/CartSB.cxx index 58dd94522..56973392c 100644 --- a/src/emucore/CartSB.cxx +++ b/src/emucore/CartSB.cxx @@ -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); diff --git a/src/emucore/CartSB.hxx b/src/emucore/CartSB.hxx index 3682dbb04..1e8a363a9 100644 --- a/src/emucore/CartSB.hxx +++ b/src/emucore/CartSB.hxx @@ -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 diff --git a/src/emucore/CartWD.cxx b/src/emucore/CartWD.cxx index c6373fa05..9a14be24a 100644 --- a/src/emucore/CartWD.cxx +++ b/src/emucore/CartWD.cxx @@ -250,7 +250,7 @@ uInt16 CartridgeWD::getBank(uInt16) const } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt16 CartridgeWD::bankCount() const +uInt16 CartridgeWD::romBankCount() const { return 16; } diff --git a/src/emucore/CartWD.hxx b/src/emucore/CartWD.hxx index 0e2aad45c..88c59e469 100644 --- a/src/emucore/CartWD.hxx +++ b/src/emucore/CartWD.hxx @@ -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. diff --git a/src/gui/GameInfoDialog.cxx b/src/gui/GameInfoDialog.cxx index 49ec158b0..bd5d87402 100644 --- a/src/gui/GameInfoDialog.cxx +++ b/src/gui/GameInfoDialog.cxx @@ -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);