diff --git a/src/emucore/Cart3EPlus.cxx b/src/emucore/Cart3EPlus.cxx index 274e1f9db..5803f2136 100644 --- a/src/emucore/Cart3EPlus.cxx +++ b/src/emucore/Cart3EPlus.cxx @@ -29,44 +29,17 @@ Cartridge3EPlus::Cartridge3EPlus(const ByteBuffer& image, size_t size, myRamSize = RAM_SIZE; myRamBankCount = RAM_BANKS; myRamWpHigh = RAM_HIGH_WP; - - //// 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 Cartridge3EPlus::reset() -//{ -// initializeRAM(myRAM.data(), myRAM.size()); -// -// // Remember startup bank (0 per spec, rather than last per 3E scheme). -// // Set this to go to 3rd 1K Bank. -// initializeStartBank(0); -// -// // Initialise bank values for all ROM/RAM access -// // This is used to reverse-lookup from address to bank location -// for(auto& b: bankInUse) -// b = BANK_UNDEFINED; // bank is undefined and inaccessible! -// -// initializeBankState(); -// -// // We'll map the startup banks 0 and 3 from the image into the third 1K bank upon reset -// bankROM((0 << BANK_BITS) | 0); -// bankROM((3 << BANK_BITS) | 0); -//} - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Cartridge3EPlus::reset() { CartridgeEnhanced::reset(); + // 1st segment in mapped to start bank in CartridgeEnhanced bank(mySystem->randGenerator().next() % romBankCount(), 1); bank(mySystem->randGenerator().next() % romBankCount(), 2); - bank(startBank(), 3); // Stella reads the PC vector always from here (TODO?) + bank(startBank(), 3); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/emucore/CartEnhanced.cxx b/src/emucore/CartEnhanced.cxx index 5816181f2..d75c77ac8 100644 --- a/src/emucore/CartEnhanced.cxx +++ b/src/emucore/CartEnhanced.cxx @@ -68,6 +68,8 @@ void CartridgeEnhanced::install(System& system) for(uInt16 addr = ROM_OFFSET + myWriteOffset; addr < ROM_OFFSET + myWriteOffset + myRamSize; addr += System::PAGE_SIZE) { uInt16 offset = addr & myRamMask; + + access.directPokeBase = &myRAM[offset]; access.romAccessBase = &myRomAccessBase[myWriteOffset + offset]; access.romPeekCounter = &myRomAccessCounter[myWriteOffset + offset]; access.romPokeCounter = &myRomAccessCounter[myWriteOffset + offset + myAccessSize]; @@ -76,6 +78,7 @@ void CartridgeEnhanced::install(System& system) // Set the page accessing method for the RAM reading pages access.type = System::PageAccessType::READ; + access.directPokeBase = nullptr; for(uInt16 addr = ROM_OFFSET + myReadOffset; addr < ROM_OFFSET + myReadOffset + myRamSize; addr += System::PAGE_SIZE) { uInt16 offset = addr & myRamMask; @@ -125,7 +128,7 @@ uInt8 CartridgeEnhanced::peek(uInt16 address) } else { - address &= myBankMask; + address &= ROM_MASK; // Write port is e.g. at 0xF000 - 0xF07F (128 bytes) if(address < myReadOffset + myRamSize && address >= myReadOffset) @@ -133,7 +136,8 @@ uInt8 CartridgeEnhanced::peek(uInt16 address) // Reading from the write port triggers an unwanted write return peekRAM(myRAM[address], peekAddress); else - return myImage[myCurrentSegOffset[(peekAddress & ROM_MASK) >> myBankShift] + address]; + return myImage[myCurrentSegOffset[(peekAddress & ROM_MASK) >> myBankShift] + + (peekAddress & myBankMask)]; } } @@ -206,7 +210,8 @@ bool CartridgeEnhanced::bank(uInt16 bank, uInt16 segment) uInt32 bankOffset = myCurrentSegOffset[segment] = romBank << myBankShift; uInt16 hotspot = this->hotspot(); uInt16 hotSpotAddr; - uInt16 fromAddr = (ROM_OFFSET + segmentOffset + myRomOffset) & ~System::PAGE_MASK; + // Skip extra RAM; if existing it is only mapped into first segment + uInt16 fromAddr = (ROM_OFFSET + segmentOffset + (segment == 0 ? myRomOffset : 0)) & ~System::PAGE_MASK; // for ROMs < 4_KB, the whole address space will be mapped. uInt16 toAddr = (ROM_OFFSET + segmentOffset + (mySize < 4_KB ? 4_KB : myBankSize)) & ~System::PAGE_MASK; diff --git a/src/emucore/CartEnhanced.hxx b/src/emucore/CartEnhanced.hxx index a45e4796e..10dbfb0d6 100644 --- a/src/emucore/CartEnhanced.hxx +++ b/src/emucore/CartEnhanced.hxx @@ -65,7 +65,7 @@ class CartridgeEnhanced : public Cartridge @return true, if bank has changed */ - bool bank(uInt16 bank, uInt16 segment); + virtual bool bank(uInt16 bank, uInt16 segment); /** Install pages for the specified bank in the system. diff --git a/src/emucore/CartWD.cxx b/src/emucore/CartWD.cxx index 9a14be24a..ff72a2b38 100644 --- a/src/emucore/CartWD.cxx +++ b/src/emucore/CartWD.cxx @@ -23,70 +23,46 @@ // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeWD::CartridgeWD(const ByteBuffer& image, size_t size, const string& md5, const Settings& settings) - : Cartridge(settings, md5), - mySize(std::min(8_KB + 3, size)) + : CartridgeEnhanced(image, size, md5, settings) { // Copy the ROM image into my buffer if (mySize == 8_KB + 3) { - // swap slices 2 & 3 - std::copy_n(image.get(), 1_KB * 2, myImage.begin()); - std::copy_n(image.get() + 1_KB * 3, 1_KB * 1, myImage.begin() + 1_KB * 2); - std::copy_n(image.get() + 1_KB * 2, 1_KB * 1, myImage.begin() + 1_KB * 3); - std::copy_n(image.get() + 1_KB * 4, 1_KB * 4, myImage.begin() + 1_KB * 4); + // swap slices 2 & 3 of bad dump and correct size + std::copy_n(image.get() + 1_KB * 3, 1_KB * 1, myImage.get() + 1_KB * 2); + std::copy_n(image.get() + 1_KB * 2, 1_KB * 1, myImage.get() + 1_KB * 3); + mySize = 8_KB; } - else - std::copy_n(image.get(), mySize, myImage.begin()); - createRomAccessArrays(8_KB); + myDirectPeek = false; + + myBankShift = BANK_SHIFT; + myRamSize = RAM_SIZE; + myRamWpHigh = RAM_HIGH_WP; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeWD::reset() { - initializeRAM(myRAM.data(), myRAM.size()); - initializeStartBank(0); + CartridgeEnhanced::reset(); myCyclesAtBankswitchInit = 0; myPendingBank = 0xF0; // one more than the allowable bank # - - // Setup segments to some default slices - bank(startBank()); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeWD::install(System& system) { - mySystem = &system; + CartridgeEnhanced::install(system); - // Set the page accessing method for the RAM reading pages - System::PageAccess read(this, System::PageAccessType::READ); - for(uInt16 addr = 0x1000; addr < 0x1040; addr += System::PAGE_SIZE) - { - read.directPeekBase = &myRAM[addr & 0x003F]; - read.romAccessBase = &myRomAccessBase[addr & 0x003F]; - read.romPeekCounter = &myRomAccessCounter[addr & 0x003F]; - read.romPokeCounter = &myRomAccessCounter[(addr & 0x003F) + 8_KB]; - mySystem->setPageAccess(addr, read); - } + 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 - System::PageAccess write(this, System::PageAccessType::WRITE); - for(uInt16 addr = 0x1040; addr < 0x1080; addr += System::PAGE_SIZE) - { - write.romAccessBase = &myRomAccessBase[addr & 0x003F]; - write.romPeekCounter = &myRomAccessCounter[addr & 0x003F]; - write.romPokeCounter = &myRomAccessCounter[(addr & 0x003F) + 8_KB]; - mySystem->setPageAccess(addr, write); - } + // The hotspots are in TIA address space, so we claim it here + for(uInt16 addr = 0x00; addr < 0x40; addr += System::PAGE_SIZE) + mySystem->setPageAccess(addr, access); // Mirror all access in TIA; by doing so we're taking responsibility // for that address space in peek and poke below. - mySystem->tia().installDelegate(system, *this); - - // Setup segments to some default slices - bank(startBank()); + //mySystem->tia().installDelegate(system, *this); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -113,134 +89,31 @@ uInt8 CartridgeWD::peek(uInt16 address) return mySystem->tia().peek(address); } else - { - uInt16 peekAddress = address; - address &= 0x0FFF; - - if(address < 0x0040) // RAM read port - return myRAM[address]; - else if(address < 0x0080) // RAM write port - // Reading from the write port @ $1040 - $107F triggers an unwanted write - return peekRAM(myRAM[address & 0x003F], peekAddress); - else if(address < 0x0400) - return myImage[myOffset[0] + (address & 0x03FF)]; - else if(address < 0x0800) - return myImage[myOffset[1] + (address & 0x03FF)]; - else if(address < 0x0C00) - return myImage[myOffset[2] + (address & 0x03FF)]; - else - return mySegment3[address & 0x03FF]; - } + return CartridgeEnhanced::peek(address); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeWD::poke(uInt16 address, uInt8 value) { - if(!(address & 0x1000)) // TIA addresses + if(address < 0x40) return mySystem->tia().poke(address, value); - else - { - if(address & 0x040) - { - pokeRAM(myRAM[address & 0x003F], address, value); - return true; - } - else - { - // Writing to the read port should be ignored, but trigger a break if option enabled - uInt8 dummy; - pokeRAM(dummy, address, value); - myRamWriteAccess = address; - return false; - } - } + return CartridgeEnhanced::poke(address, value); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool CartridgeWD::bank(uInt16 bank) +bool CartridgeWD::bank(uInt16 bank, uInt16) { - if(bankLocked() || bank > 15) return false; + if(bankLocked()) return false; - myCurrentBank = bank; + myCurrentBank = bank % romBankCount(); - segmentZero(ourBankOrg[bank & 0x7].zero); - segmentOne(ourBankOrg[bank & 0x7].one); - segmentTwo(ourBankOrg[bank & 0x7].two); - segmentThree(ourBankOrg[bank & 0x7].three); + CartridgeEnhanced::bank(ourBankOrg[myCurrentBank].zero, 0); + CartridgeEnhanced::bank(ourBankOrg[myCurrentBank].one, 1); + CartridgeEnhanced::bank(ourBankOrg[myCurrentBank].two, 2); + CartridgeEnhanced::bank(ourBankOrg[myCurrentBank].three, 3); - return myBankChanged = true; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void CartridgeWD::segmentZero(uInt8 slice) -{ - uInt16 offset = slice << 10; - System::PageAccess access(this, System::PageAccessType::READ); - - // Skip first 128 bytes; it is always RAM - for(uInt16 addr = 0x1080; addr < 0x1400; addr += System::PAGE_SIZE) - { - access.romAccessBase = &myRomAccessBase[offset + (addr & 0x03FF)]; - access.romPeekCounter = &myRomAccessCounter[offset + (addr & 0x03FF)]; - access.romPokeCounter = &myRomAccessCounter[offset + (addr & 0x03FF) + 8_KB]; - mySystem->setPageAccess(addr, access); - } - myOffset[0] = offset; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void CartridgeWD::segmentOne(uInt8 slice) -{ - uInt16 offset = slice << 10; - System::PageAccess access(this, System::PageAccessType::READ); - - for(uInt16 addr = 0x1400; addr < 0x1800; addr += System::PAGE_SIZE) - { - access.romAccessBase = &myRomAccessBase[offset + (addr & 0x03FF)]; - access.romPeekCounter = &myRomAccessCounter[offset + (addr & 0x03FF)]; - access.romPokeCounter = &myRomAccessCounter[offset + (addr & 0x03FF) + 8_KB]; - mySystem->setPageAccess(addr, access); - } - myOffset[1] = offset; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void CartridgeWD::segmentTwo(uInt8 slice) -{ - uInt16 offset = slice << 10; - System::PageAccess access(this, System::PageAccessType::READ); - - for(uInt16 addr = 0x1800; addr < 0x1C00; addr += System::PAGE_SIZE) - { - access.romAccessBase = &myRomAccessBase[offset + (addr & 0x03FF)]; - access.romPeekCounter = &myRomAccessCounter[offset + (addr & 0x03FF)]; - access.romPokeCounter = &myRomAccessCounter[offset + (addr & 0x03FF) + 8_KB]; - mySystem->setPageAccess(addr, access); - } - myOffset[2] = offset; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void CartridgeWD::segmentThree(uInt8 slice) -{ - uInt16 offset = slice << 10; - - // Make a copy of the address space pointed to by the slice - // Then overwrite one byte with 0 - std::copy_n(myImage.begin()+offset, mySegment3.size(), mySegment3.begin()); - mySegment3[0x3FC] = 0; - - System::PageAccess access(this, System::PageAccessType::READ); - - for(uInt16 addr = 0x1C00; addr < 0x2000; addr += System::PAGE_SIZE) - { - access.romAccessBase = &myRomAccessBase[offset + (addr & 0x03FF)]; - access.romPeekCounter = &myRomAccessCounter[offset + (addr & 0x03FF)]; - access.romPokeCounter = &myRomAccessCounter[offset + (addr & 0x03FF) + 8_KB]; - mySystem->setPageAccess(addr, access); - } - myOffset[3] = offset; + return true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -249,41 +122,13 @@ uInt16 CartridgeWD::getBank(uInt16) const return myCurrentBank; } -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt16 CartridgeWD::romBankCount() const -{ - return 16; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool CartridgeWD::patch(uInt16 address, uInt8 value) -{ - address &= 0x0FFF; - - uInt16 idx = address >> 10; - myImage[myOffset[idx] + (address & 0x03FF)] = value; - - // The upper segment is mirrored, so we need to patch its buffer too - if(idx == 3) - mySegment3[(address & 0x03FF)] = value; - - return true; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -const uInt8* CartridgeWD::getImage(size_t& size) const -{ - size = mySize; - return myImage.data(); -} - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeWD::save(Serializer& out) const { + CartridgeEnhanced::save(out); try { out.putShort(myCurrentBank); - out.putByteArray(myRAM.data(), myRAM.size()); out.putLong(myCyclesAtBankswitchInit); out.putShort(myPendingBank); } @@ -299,10 +144,10 @@ bool CartridgeWD::save(Serializer& out) const // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeWD::load(Serializer& in) { + CartridgeEnhanced::load(in); try { myCurrentBank = in.getShort(); - in.getByteArray(myRAM.data(), myRAM.size()); myCyclesAtBankswitchInit = in.getLong(); myPendingBank = in.getShort(); @@ -319,9 +164,9 @@ bool CartridgeWD::load(Serializer& in) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const std::array CartridgeWD::ourBankOrg = {{ - // 0 1 2 3 4 5 6 7 - { 0, 0, 1, 3 }, // Bank 0, 8 2 1 - 1 - - - - - { 0, 1, 2, 3 }, // Bank 1, 9 1 1 1 1 - - - - + // 0 1 2 3 4 5 6 7 + { 0, 0, 1, 3 }, // Bank 0, 8 2 1 - 1 - - - - + { 0, 1, 2, 3 }, // Bank 1, 9 1 1 1 1 - - - - { 4, 5, 6, 7 }, // Bank 2, 10 - - - - 1 1 1 1 { 7, 4, 2, 3 }, // Bank 3, 11 - - 1 1 1 - - 1 { 0, 0, 6, 7 }, // Bank 4, 12 2 - - - - - 1 1 diff --git a/src/emucore/CartWD.hxx b/src/emucore/CartWD.hxx index 88c59e469..9623cfa96 100644 --- a/src/emucore/CartWD.hxx +++ b/src/emucore/CartWD.hxx @@ -21,7 +21,7 @@ class System; #include "bspf.hxx" -#include "Cart.hxx" +#include "CartEnhanced.hxx" #ifdef DEBUGGER_SUPPORT #include "CartWDWidget.hxx" #endif @@ -45,15 +45,15 @@ class System; $0037, $003F: 6,0,5,1 - In the uppermost (third) segment, the byte at $3FC is overwritten by 0. + (Removed: In the uppermost (third) segment, the byte at $3FC is overwritten by 0.) The 64 bytes of RAM are accessible at $1000 - $103F (read port) and $1040 - $107F (write port). Because the RAM takes 128 bytes of address space, the range $1000 - $107F of segment 0 ROM will never be available. - @author Stephen Anthony + @author Stephen Anthony, Thomas Jentzsch */ -class CartridgeWD : public Cartridge +class CartridgeWD : public CartridgeEnhanced { friend class CartridgeWDWidget; @@ -89,7 +89,7 @@ class CartridgeWD : public Cartridge @param bank The bank that should be installed in the system */ - bool bank(uInt16 bank) override; + bool bank(uInt16 bank, uInt16 = 0) override; /** Get the current bank. @@ -98,28 +98,6 @@ class CartridgeWD : public Cartridge */ uInt16 getBank(uInt16 address = 0) const override; - /** - Query the number of banks supported by the cartridge. - */ - uInt16 romBankCount() const override; - - /** - Patch the cartridge ROM. - - @param address The ROM address to patch - @param value The value to place into the address - @return Success or failure of the patch operation - */ - bool patch(uInt16 address, uInt8 value) override; - - /** - Access the internal ROM image for this cartridge. - - @param size Set to the size of the internal ROM image data - @return A pointer to the internal ROM image data - */ - const uInt8* getImage(size_t& size) const override; - /** Save the current state of this cart to the given Serializer. @@ -173,51 +151,9 @@ class CartridgeWD : public Cartridge bool poke(uInt16 address, uInt8 value) override; private: - /** - Install the specified slice for segment zero. - - @param slice The slice to map into the segment - */ - void segmentZero(uInt8 slice); - - /** - Install the specified slice for segment one. - - @param slice The slice to map into the segment - */ - void segmentOne(uInt8 slice); - - /** - Install the specified slice for segment two. - - @param slice The slice to map into the segment - */ - void segmentTwo(uInt8 slice); - - /** - Install the specified slice for segment three. - Note that this method also takes care of setting one byte to 0. - - @param slice The slice to map into the segment - */ - void segmentThree(uInt8 slice); + bool checkSwitchBank(uInt16, uInt8 = 0) override { return false; }; private: - // The 8K ROM image of the cartridge - std::array myImage; - - // Indicates the actual size of the ROM image (either 8K or 8K + 3) - size_t mySize{0}; - - // The 64 bytes RAM of the cartridge - std::array myRAM; - - // The 1K ROM mirror of segment 3 (sometimes contains extra 3 bytes) - std::array mySegment3; - - // Indicates the offset for each of the four segments - std::array myOffset; - // Indicates the cycle at which a bankswitch was initiated uInt64 myCyclesAtBankswitchInit{0}; @@ -233,6 +169,16 @@ class CartridgeWD : public Cartridge }; static const std::array ourBankOrg; + private: + // log(ROM bank segment size) / log(2) + static constexpr uInt16 BANK_SHIFT = 10; // = 1K = 0x0400 + + // RAM size + static constexpr uInt16 RAM_SIZE = 0x40; + + // Write port for extra RAM is at low address by default + static constexpr bool RAM_HIGH_WP = true; + private: // Following constructors and assignment operators not supported CartridgeWD() = delete;