diff --git a/src/debugger/CartDebug.cxx b/src/debugger/CartDebug.cxx index 7e76d2dc1..e6dd39c0e 100644 --- a/src/debugger/CartDebug.cxx +++ b/src/debugger/CartDebug.cxx @@ -34,6 +34,8 @@ #include "Base.hxx" #include "Device.hxx" #include "exception/EmulationWarning.hxx" +#include "TIA.hxx" +#include "M6532.hxx" using Common::Base; using std::hex; @@ -69,16 +71,12 @@ CartDebug::CartDebug(Debugger& dbg, Console& console, const OSystem& osystem) } // Create bank information for each potential bank, and an extra one for ZP RAM - // Banksizes greater than 4096 indicate multi-bank ROMs, but we handle only - // 4K pieces at a time - // Banksizes less than 4K use the actual value - size_t banksize = 0; - myConsole.cartridge().getImage(banksize); - BankInfo info; - info.size = std::min(banksize, 4_KB); for(uInt32 i = 0; i < myConsole.cartridge().bankCount(); ++i) + { + info.size = myConsole.cartridge().bankSize(i); myBankInfo.push_back(info); + } info.size = 128; // ZP RAM myBankInfo.push_back(info); @@ -248,31 +246,9 @@ bool CartDebug::disassemble(bool force) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartDebug::disassembleBank(int bank) { - // isolate the high 3 address bits, count them and - // select the most frequent to define the bank offset BankInfo& info = myBankInfo[bank]; - uInt16 count[8]; - for(int i = 0; i < 8; ++i) - count[i] = 0; - - for(uInt32 addr = 0x1000; addr < 0x1000 + info.size; ++addr) - { - Device::AccessFlags flags = mySystem.getAccessFlags(addr); - // only count really accessed addresses - if (flags & ~Device::ROW) - count[(flags & Device::HADDR) >> 13]++; - } - uInt16 max = 0, maxIdx = 0; - for(int idx = 0; idx < 8; ++idx) - { - if(count[idx] > max) - { - max = count[idx]; - maxIdx = idx; - } - } - info.offset = maxIdx << 13 | 0x1000; + info.offset = myConsole.cartridge().bankOrigin(bank); return disassemble(bank, info.offset, true); } @@ -1368,6 +1344,24 @@ string CartDebug::saveRom() return DebuggerParser::red("failed to save ROM"); } +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +string CartDebug::saveAccessFile() +{ + const string& rom = myConsole.properties().get(PropType::Cart_Name) + ".cvs"; + FilesystemNode node(myOSystem.defaultSaveDir() + rom); + ofstream out(node.getPath()); + + if(out) + { + out << myConsole.tia().getAccessCounters(); + out << myConsole.riot().getAccessCounters(); + out << myConsole.cartridge().getAccessCounters(); + return "saved access counters as " + node.getShortPath(); + } + else + return DebuggerParser::red("failed to save access counters file"); +} + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string CartDebug::listConfig(int bank) { diff --git a/src/debugger/CartDebug.hxx b/src/debugger/CartDebug.hxx index f0b4b49fe..7fff9c8a6 100644 --- a/src/debugger/CartDebug.hxx +++ b/src/debugger/CartDebug.hxx @@ -209,6 +209,11 @@ class CartDebug : public DebuggerSystem string saveDisassembly(); string saveRom(); + /** + Save access counters file + */ + string saveAccessFile(); + /** Show Distella directives (both set by the user and determined by Distella) for the given bank (or all banks, if no bank is specified). diff --git a/src/debugger/DebuggerParser.cxx b/src/debugger/DebuggerParser.cxx index fb905e8a5..4f50be800 100644 --- a/src/debugger/DebuggerParser.cxx +++ b/src/debugger/DebuggerParser.cxx @@ -678,7 +678,6 @@ string DebuggerParser::saveScriptFile(string file) return "saved " + node.getShortPath() + " OK"; } - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void DebuggerParser::executeDirective(Device::AccessType type) { @@ -1810,6 +1809,13 @@ void DebuggerParser::executeSave() commandResult << saveScriptFile(argStrings[0]); } +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +// "saveaccess" +void DebuggerParser::executeSaveAccess() +{ + commandResult << debugger.cartDebug().saveAccessFile(); +} + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // "saveconfig" void DebuggerParser::executeSaveconfig() @@ -2277,7 +2283,7 @@ void DebuggerParser::executeZ() // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // List of all commands available to the parser -std::array DebuggerParser::commands = { { +std::array DebuggerParser::commands = { { { "a", "Set Accumulator to ", @@ -2998,6 +3004,16 @@ std::array DebuggerParser::commands = { { std::mem_fn(&DebuggerParser::executeSave) }, + { + "saveaccess", + "Save the access counters to CSV file", + "Example: saveaccess (no parameters)", + false, + false, + { Parameters::ARG_END_ARGS }, + std::mem_fn(&DebuggerParser::executeSaveAccess) + }, + { "saveconfig", "Save Distella config file (with default name)", diff --git a/src/debugger/DebuggerParser.hxx b/src/debugger/DebuggerParser.hxx index 9de21b3e9..44445b307 100644 --- a/src/debugger/DebuggerParser.hxx +++ b/src/debugger/DebuggerParser.hxx @@ -98,7 +98,7 @@ class DebuggerParser std::array parms; std::function executor; }; - static std::array commands; + static std::array commands; struct Trap { @@ -215,6 +215,7 @@ class DebuggerParser void executeRunToPc(); void executeS(); void executeSave(); + void executeSaveAccess(); void executeSaveallstates(); void executeSaveconfig(); void executeSavedisassembly(); diff --git a/src/emucore/Cart.cxx b/src/emucore/Cart.cxx index c5c13e34c..f6a787f48 100644 --- a/src/emucore/Cart.cxx +++ b/src/emucore/Cart.cxx @@ -20,6 +20,7 @@ #include "MD5.hxx" #ifdef DEBUGGER_SUPPORT #include "Debugger.hxx" + #include "Base.hxx" #endif #include "Cart.hxx" @@ -75,6 +76,16 @@ bool Cartridge::bankChanged() return changed; } +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +uInt16 Cartridge::bankSize(uInt16 bank) const +{ + size_t size; + + getImage(size); + + return std::min(uInt32(size) / bankCount(), 4_KB); // assuming that each bank has the same size +} + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 Cartridge::peekRAM(uInt8& dest, uInt16 address) { @@ -113,16 +124,72 @@ void Cartridge::pokeRAM(uInt8& dest, uInt16 address, uInt8 value) } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void Cartridge::createRomAccessBase(size_t size) +void Cartridge::createRomAccessArrays(size_t size) { #ifdef DEBUGGER_SUPPORT myRomAccessBase = make_unique(size); std::fill_n(myRomAccessBase.get(), size, Device::ROW); + myRomAccessCounter = make_unique(size * 2); + std::fill_n(myRomAccessCounter.get(), size * 2, 0); #else myRomAccessBase = nullptr; + myRomAccessCounter = nullptr; #endif } +#ifdef DEBUGGER_SUPPORT +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +string Cartridge::getAccessCounters() const +{ + ostringstream out; + + for(uInt16 bank = 0; bank < bankCount(); ++bank) + { + uInt32 offset = bank * bankSize(); + uInt16 origin = bankOrigin(bank); + + out << "Bank " << bank << " / 0.." << bankCount() - 1 << ":\n"; + for(uInt16 addr = 0; addr < bankSize(); ++addr) + { + out << Common::Base::HEX4 << (addr | origin) << "," + << Common::Base::toString(myRomAccessBase[offset + addr], Common::Base::Fmt::_10_8) << ", "; + } + out << "\n"; + } + + return out.str(); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +uInt16 Cartridge::bankOrigin(uInt16 bank) const +{ + // isolate the high 3 address bits, count them and + // select the most frequent to define the bank origin + std::array count; + uInt32 offset = bank * bankSize(); + + count.fill(0); + + for(uInt16 addr = 0x0000; addr < bankSize(bank); ++addr) + { + Device::AccessFlags flags = myRomAccessBase[offset + addr]; + // only count really accessed addresses + if (flags & ~Device::ROW) + count[(flags & Device::HADDR) >> 13]++; + } + uInt16 max = 0, maxIdx = 0; + for(int idx = 0; idx < 8; ++idx) + { + if(count[idx] > max) + { + max = count[idx]; + maxIdx = idx; + } + } + return maxIdx << 13 | 0x1000; +} +#endif + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Cartridge::initializeRAM(uInt8* arr, size_t size, uInt8 val) const { diff --git a/src/emucore/Cart.hxx b/src/emucore/Cart.hxx index 8a5124219..34e575a6c 100644 --- a/src/emucore/Cart.hxx +++ b/src/emucore/Cart.hxx @@ -136,6 +136,22 @@ class Cartridge : public Device @return Address of illegal access if one occurred, else 0 */ uInt16 getIllegalRAMWriteAccess() const { return myRamWriteAccess; } + + + /** + Query the access counters + + @return The access counters as comma separated string + */ + string getAccessCounters() const override; + + /** + Determine the bank's origin + + @param The bank to query + @return The origin of the bank + */ + uInt16 bankOrigin(uInt16 bank) const; #endif public: @@ -178,6 +194,14 @@ class Cartridge : public Device */ virtual uInt16 bankCount() const { return 1; } + /** + 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. @@ -274,7 +298,7 @@ class Cartridge : public Device @param size The size of the code-access array to create */ - void createRomAccessBase(size_t size); + void createRomAccessArrays(size_t size); /** Fill the given RAM array with (possibly random) data. @@ -325,6 +349,11 @@ class Cartridge : public Device // whether it is used as code, data, graphics etc. std::unique_ptr myRomAccessBase; + // The array containing information about every byte of ROM indicating + // how often it is accessed. + std::unique_ptr myRomAccessCounter; + + // Contains address of illegal RAM write access or 0 uInt16 myRamWriteAccess{0}; diff --git a/src/emucore/Cart0840.cxx b/src/emucore/Cart0840.cxx index 21e0f35fd..f10dbb7b2 100644 --- a/src/emucore/Cart0840.cxx +++ b/src/emucore/Cart0840.cxx @@ -25,7 +25,7 @@ Cartridge0840::Cartridge0840(const ByteBuffer& image, size_t size, { // Copy the ROM image into my buffer std::copy_n(image.get(), std::min(myImage.size(), size), myImage.begin()); - createRomAccessBase(myImage.size()); + createRomAccessArrays(myImage.size()); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/emucore/Cart2K.cxx b/src/emucore/Cart2K.cxx index 5a6ffec5d..ed7820b1b 100644 --- a/src/emucore/Cart2K.cxx +++ b/src/emucore/Cart2K.cxx @@ -51,7 +51,7 @@ Cartridge2K::Cartridge2K(const ByteBuffer& image, size_t size, mySize = System::PAGE_SIZE; } - createRomAccessBase(mySize); + createRomAccessArrays(mySize); // Set mask for accessing the image buffer // This is guaranteed to work, as mySize is a power of two diff --git a/src/emucore/Cart3E.cxx b/src/emucore/Cart3E.cxx index 7df89d58c..a4683762b 100644 --- a/src/emucore/Cart3E.cxx +++ b/src/emucore/Cart3E.cxx @@ -30,7 +30,7 @@ Cartridge3E::Cartridge3E(const ByteBuffer& image, size_t size, // Copy the ROM image into my buffer std::copy_n(image.get(), mySize, myImage.get()); - createRomAccessBase(mySize + myRAM.size()); + createRomAccessArrays(mySize + myRAM.size()); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/emucore/Cart3EPlus.cxx b/src/emucore/Cart3EPlus.cxx index 1ca18f7d9..27eb94986 100644 --- a/src/emucore/Cart3EPlus.cxx +++ b/src/emucore/Cart3EPlus.cxx @@ -30,7 +30,7 @@ Cartridge3EPlus::Cartridge3EPlus(const ByteBuffer& image, size_t size, // Copy the ROM image into my buffer std::copy_n(image.get(), mySize, myImage.get()); - createRomAccessBase(mySize + myRAM.size()); + createRomAccessArrays(mySize + myRAM.size()); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/emucore/Cart3F.cxx b/src/emucore/Cart3F.cxx index 8be902554..47b5c4dcd 100644 --- a/src/emucore/Cart3F.cxx +++ b/src/emucore/Cart3F.cxx @@ -30,7 +30,7 @@ Cartridge3F::Cartridge3F(const ByteBuffer& image, size_t size, // Copy the ROM image into my buffer std::copy_n(image.get(), mySize, myImage.get()); - createRomAccessBase(mySize); + createRomAccessArrays(mySize); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/emucore/Cart4A50.cxx b/src/emucore/Cart4A50.cxx index 373684481..845229bc4 100644 --- a/src/emucore/Cart4A50.cxx +++ b/src/emucore/Cart4A50.cxx @@ -41,7 +41,7 @@ Cartridge4A50::Cartridge4A50(const ByteBuffer& image, size_t size, // // Instead, access will be through the getAccessFlags and setAccessFlags // methods below - createRomAccessBase(myImage.size() + myRAM.size()); + createRomAccessArrays(myImage.size() + myRAM.size()); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/emucore/Cart4K.cxx b/src/emucore/Cart4K.cxx index 763bc35f0..417afccc8 100644 --- a/src/emucore/Cart4K.cxx +++ b/src/emucore/Cart4K.cxx @@ -25,7 +25,7 @@ Cartridge4K::Cartridge4K(const ByteBuffer& image, size_t size, { // Copy the ROM image into my buffer std::copy_n(image.get(), std::min(myImage.size(), size), myImage.begin()); - createRomAccessBase(myImage.size()); + createRomAccessArrays(myImage.size()); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -47,6 +47,7 @@ void Cartridge4K::install(System& system) { access.directPeekBase = &myImage[addr & 0x0FFF]; access.romAccessBase = &myRomAccessBase[addr & 0x0FFF]; + access.romAccessCounter = &myRomAccessCounter[addr & 0x0FFF]; mySystem->setPageAccess(addr, access); } } diff --git a/src/emucore/Cart4KSC.cxx b/src/emucore/Cart4KSC.cxx index e65955735..09e043c94 100644 --- a/src/emucore/Cart4KSC.cxx +++ b/src/emucore/Cart4KSC.cxx @@ -25,7 +25,7 @@ Cartridge4KSC::Cartridge4KSC(const ByteBuffer& image, size_t size, { // Copy the ROM image into my buffer std::copy_n(image.get(), std::min(myImage.size(), size), myImage.begin()); - createRomAccessBase(myImage.size()); + createRomAccessArrays(myImage.size()); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/emucore/CartAR.cxx b/src/emucore/CartAR.cxx index f4edb41ba..5201a14df 100644 --- a/src/emucore/CartAR.cxx +++ b/src/emucore/CartAR.cxx @@ -41,7 +41,7 @@ CartridgeAR::CartridgeAR(const ByteBuffer& image, size_t size, // // Instead, access will be through the getAccessFlags and setAccessFlags // methods below - createRomAccessBase(mySize); + createRomAccessArrays(mySize); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/emucore/CartBF.cxx b/src/emucore/CartBF.cxx index df773d805..91d13cbb7 100644 --- a/src/emucore/CartBF.cxx +++ b/src/emucore/CartBF.cxx @@ -25,7 +25,7 @@ CartridgeBF::CartridgeBF(const ByteBuffer& image, size_t size, { // Copy the ROM image into my buffer std::copy_n(image.get(), std::min(myImage.size(), size), myImage.begin()); - createRomAccessBase(myImage.size()); + createRomAccessArrays(myImage.size()); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/emucore/CartBFSC.cxx b/src/emucore/CartBFSC.cxx index fdfac6f95..d0d33c79f 100644 --- a/src/emucore/CartBFSC.cxx +++ b/src/emucore/CartBFSC.cxx @@ -25,7 +25,7 @@ CartridgeBFSC::CartridgeBFSC(const ByteBuffer& image, size_t size, { // Copy the ROM image into my buffer std::copy_n(image.get(), std::min(myImage.size(), size), myImage.begin()); - createRomAccessBase(myImage.size()); + createRomAccessArrays(myImage.size()); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/emucore/CartBUS.cxx b/src/emucore/CartBUS.cxx index 1dc991563..cb0be831f 100644 --- a/src/emucore/CartBUS.cxx +++ b/src/emucore/CartBUS.cxx @@ -49,7 +49,7 @@ CartridgeBUS::CartridgeBUS(const ByteBuffer& image, size_t size, std::copy_n(image.get(), std::min(myImage.size(), size), myImage.begin()); // Even though the ROM is 32K, only 28K is accessible to the 6507 - createRomAccessBase(28_KB); + createRomAccessArrays(28_KB); // Pointer to the program ROM (28K @ 0 byte offset) // which starts after the 2K BUS Driver and 2K C Code diff --git a/src/emucore/CartCDF.cxx b/src/emucore/CartCDF.cxx index 48f3d3d0f..3289b2e04 100644 --- a/src/emucore/CartCDF.cxx +++ b/src/emucore/CartCDF.cxx @@ -65,7 +65,7 @@ CartridgeCDF::CartridgeCDF(const ByteBuffer& image, size_t size, std::copy_n(image.get(), std::min(myImage.size(), size), myImage.begin()); // even though the ROM is 32K, only 28K is accessible to the 6507 - createRomAccessBase(28_KB); + createRomAccessArrays(28_KB); // Pointer to the program ROM (28K @ 0 byte offset) // which starts after the 2K CDF Driver and 2K C Code diff --git a/src/emucore/CartCM.cxx b/src/emucore/CartCM.cxx index 6bead1b33..7ce27bea4 100644 --- a/src/emucore/CartCM.cxx +++ b/src/emucore/CartCM.cxx @@ -27,7 +27,7 @@ CartridgeCM::CartridgeCM(const ByteBuffer& image, size_t size, { // Copy the ROM image into my buffer std::copy_n(image.get(), std::min(myImage.size(), size), myImage.begin()); - createRomAccessBase(myImage.size()); + createRomAccessArrays(myImage.size()); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/emucore/CartCTY.cxx b/src/emucore/CartCTY.cxx index 40cae5597..9133ca891 100644 --- a/src/emucore/CartCTY.cxx +++ b/src/emucore/CartCTY.cxx @@ -28,7 +28,7 @@ CartridgeCTY::CartridgeCTY(const ByteBuffer& image, size_t size, { // Copy the ROM image into my buffer std::copy_n(image.get(), std::min(myImage.size(), size), myImage.begin()); - createRomAccessBase(myImage.size()); + createRomAccessArrays(myImage.size()); // Default to no tune data in case user is utilizing an old ROM myTuneData.fill(0); diff --git a/src/emucore/CartCV.cxx b/src/emucore/CartCV.cxx index bea42e759..cb77d7790 100644 --- a/src/emucore/CartCV.cxx +++ b/src/emucore/CartCV.cxx @@ -40,7 +40,7 @@ CartridgeCV::CartridgeCV(const ByteBuffer& image, size_t size, // Copy the RAM image into a buffer for use in reset() std::copy_n(image.get(), myInitialRAM.size(), myInitialRAM.begin()); } - createRomAccessBase(myImage.size() + myRAM.size()); + createRomAccessArrays(myImage.size() + myRAM.size()); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/emucore/CartCVPlus.cxx b/src/emucore/CartCVPlus.cxx index c0d9b01d2..86fb25d8b 100644 --- a/src/emucore/CartCVPlus.cxx +++ b/src/emucore/CartCVPlus.cxx @@ -30,7 +30,7 @@ CartridgeCVPlus::CartridgeCVPlus(const ByteBuffer& image, size_t size, // Copy the ROM image into my buffer std::copy_n(image.get(), mySize, myImage.get()); - createRomAccessBase(mySize + myRAM.size()); + createRomAccessArrays(mySize + myRAM.size()); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/emucore/CartDASH.cxx b/src/emucore/CartDASH.cxx index e893b6f07..6e187d76a 100644 --- a/src/emucore/CartDASH.cxx +++ b/src/emucore/CartDASH.cxx @@ -30,7 +30,7 @@ CartridgeDASH::CartridgeDASH(const ByteBuffer& image, size_t size, // Copy the ROM image into my buffer std::copy_n(image.get(), mySize, myImage.get()); - createRomAccessBase(mySize + myRAM.size()); + createRomAccessArrays(mySize + myRAM.size()); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/emucore/CartDF.cxx b/src/emucore/CartDF.cxx index 7e4ed9c2c..556d51bf6 100644 --- a/src/emucore/CartDF.cxx +++ b/src/emucore/CartDF.cxx @@ -25,7 +25,7 @@ CartridgeDF::CartridgeDF(const ByteBuffer& image, size_t size, { // Copy the ROM image into my buffer std::copy_n(image.get(), std::min(myImage.size(), size), myImage.begin()); - createRomAccessBase(myImage.size()); + createRomAccessArrays(myImage.size()); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/emucore/CartDFSC.cxx b/src/emucore/CartDFSC.cxx index 530ef811c..993bbf226 100644 --- a/src/emucore/CartDFSC.cxx +++ b/src/emucore/CartDFSC.cxx @@ -25,7 +25,7 @@ CartridgeDFSC::CartridgeDFSC(const ByteBuffer& image, size_t size, { // Copy the ROM image into my buffer std::copy_n(image.get(), std::min(myImage.size(), size), myImage.begin()); - createRomAccessBase(myImage.size()); + createRomAccessArrays(myImage.size()); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/emucore/CartDPC.cxx b/src/emucore/CartDPC.cxx index 2ac559a57..43d15dc7e 100644 --- a/src/emucore/CartDPC.cxx +++ b/src/emucore/CartDPC.cxx @@ -27,7 +27,7 @@ CartridgeDPC::CartridgeDPC(const ByteBuffer& image, size_t size, { // Make a copy of the entire image std::copy_n(image.get(), std::min(myImage.size(), size), myImage.begin()); - createRomAccessBase(8_KB); + createRomAccessArrays(8_KB); // Pointer to the program ROM (8K @ 0 byte offset) myProgramImage = myImage.data(); diff --git a/src/emucore/CartDPCPlus.cxx b/src/emucore/CartDPCPlus.cxx index 5e92ec2a1..c9392fdc8 100644 --- a/src/emucore/CartDPCPlus.cxx +++ b/src/emucore/CartDPCPlus.cxx @@ -36,7 +36,7 @@ CartridgeDPCPlus::CartridgeDPCPlus(const ByteBuffer& image, size_t size, if(mySize < myImage.size()) myImage.fill(0); std::copy_n(image.get(), size, myImage.begin() + (myImage.size() - mySize)); - createRomAccessBase(24_KB); + createRomAccessArrays(24_KB); // Pointer to the program ROM (24K @ 3K offset; ignore first 3K) myProgramImage = myImage.data() + 3_KB; diff --git a/src/emucore/CartE0.cxx b/src/emucore/CartE0.cxx index 96029f903..9102788f2 100644 --- a/src/emucore/CartE0.cxx +++ b/src/emucore/CartE0.cxx @@ -25,7 +25,7 @@ CartridgeE0::CartridgeE0(const ByteBuffer& image, size_t size, { // Copy the ROM image into my buffer std::copy_n(image.get(), std::min(myImage.size(), size), myImage.begin()); - createRomAccessBase(myImage.size()); + createRomAccessArrays(myImage.size()); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/emucore/CartEF.cxx b/src/emucore/CartEF.cxx index 96c5cf0da..1de837bf7 100644 --- a/src/emucore/CartEF.cxx +++ b/src/emucore/CartEF.cxx @@ -25,7 +25,7 @@ CartridgeEF::CartridgeEF(const ByteBuffer& image, size_t size, { // Copy the ROM image into my buffer std::copy_n(image.get(), std::min(myImage.size(), size), myImage.begin()); - createRomAccessBase(myImage.size()); + createRomAccessArrays(myImage.size()); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/emucore/CartEFSC.cxx b/src/emucore/CartEFSC.cxx index 8c9cdbb3c..4cb481547 100644 --- a/src/emucore/CartEFSC.cxx +++ b/src/emucore/CartEFSC.cxx @@ -25,7 +25,7 @@ CartridgeEFSC::CartridgeEFSC(const ByteBuffer& image, size_t size, { // Copy the ROM image into my buffer std::copy_n(image.get(), std::min(myImage.size(), size), myImage.begin()); - createRomAccessBase(myImage.size()); + createRomAccessArrays(myImage.size()); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/emucore/CartF0.cxx b/src/emucore/CartF0.cxx index bb10ccd43..44f967327 100644 --- a/src/emucore/CartF0.cxx +++ b/src/emucore/CartF0.cxx @@ -25,7 +25,7 @@ CartridgeF0::CartridgeF0(const ByteBuffer& image, size_t size, { // Copy the ROM image into my buffer std::copy_n(image.get(), std::min(myImage.size(), size), myImage.begin()); - createRomAccessBase(myImage.size()); + createRomAccessArrays(myImage.size()); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/emucore/CartF4.cxx b/src/emucore/CartF4.cxx index 81e53a238..5576f5fd3 100644 --- a/src/emucore/CartF4.cxx +++ b/src/emucore/CartF4.cxx @@ -26,7 +26,7 @@ CartridgeF4::CartridgeF4(const ByteBuffer& image, size_t size, { // Copy the ROM image into my buffer std::copy_n(image.get(), std::min(myImage.size(), size), myImage.begin()); - createRomAccessBase(myImage.size()); + createRomAccessArrays(myImage.size()); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/emucore/CartF4SC.cxx b/src/emucore/CartF4SC.cxx index 79e34e854..98d9f675c 100644 --- a/src/emucore/CartF4SC.cxx +++ b/src/emucore/CartF4SC.cxx @@ -25,7 +25,7 @@ CartridgeF4SC::CartridgeF4SC(const ByteBuffer& image, size_t size, { // Copy the ROM image into my buffer std::copy_n(image.get(), std::min(myImage.size(), size), myImage.begin()); - createRomAccessBase(myImage.size()); + createRomAccessArrays(myImage.size()); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/emucore/CartF6.cxx b/src/emucore/CartF6.cxx index 8bf672695..43ae4abe7 100644 --- a/src/emucore/CartF6.cxx +++ b/src/emucore/CartF6.cxx @@ -25,7 +25,7 @@ CartridgeF6::CartridgeF6(const ByteBuffer& image, size_t size, { // Copy the ROM image into my buffer std::copy_n(image.get(), std::min(myImage.size(), size), myImage.begin()); - createRomAccessBase(myImage.size()); + createRomAccessArrays(myImage.size()); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/emucore/CartF6SC.cxx b/src/emucore/CartF6SC.cxx index dbcd4c340..5ee84ee8a 100644 --- a/src/emucore/CartF6SC.cxx +++ b/src/emucore/CartF6SC.cxx @@ -25,7 +25,7 @@ CartridgeF6SC::CartridgeF6SC(const ByteBuffer& image, size_t size, { // Copy the ROM image into my buffer std::copy_n(image.get(), std::min(myImage.size(), size), myImage.begin()); - createRomAccessBase(myImage.size()); + createRomAccessArrays(myImage.size()); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/emucore/CartF8.cxx b/src/emucore/CartF8.cxx index cde6d47f0..bb06d9414 100644 --- a/src/emucore/CartF8.cxx +++ b/src/emucore/CartF8.cxx @@ -25,7 +25,7 @@ CartridgeF8::CartridgeF8(const ByteBuffer& image, size_t size, { // Copy the ROM image into my buffer std::copy_n(image.get(), std::min(myImage.size(), size), myImage.begin()); - createRomAccessBase(myImage.size()); + createRomAccessArrays(myImage.size()); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/emucore/CartF8SC.cxx b/src/emucore/CartF8SC.cxx index 549fbea35..e45298779 100644 --- a/src/emucore/CartF8SC.cxx +++ b/src/emucore/CartF8SC.cxx @@ -25,7 +25,7 @@ CartridgeF8SC::CartridgeF8SC(const ByteBuffer& image, size_t size, { // Copy the ROM image into my buffer std::copy_n(image.get(), std::min(myImage.size(), size), myImage.begin()); - createRomAccessBase(myImage.size()); + createRomAccessArrays(myImage.size()); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/emucore/CartFA.cxx b/src/emucore/CartFA.cxx index e06b869b6..c91ea3b8e 100644 --- a/src/emucore/CartFA.cxx +++ b/src/emucore/CartFA.cxx @@ -25,7 +25,7 @@ CartridgeFA::CartridgeFA(const ByteBuffer& image, size_t size, { // Copy the ROM image into my buffer std::copy_n(image.get(), std::min(myImage.size(), size), myImage.begin()); - createRomAccessBase(myImage.size()); + createRomAccessArrays(myImage.size()); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/emucore/CartFA2.cxx b/src/emucore/CartFA2.cxx index e6325e9ac..57fb118bb 100644 --- a/src/emucore/CartFA2.cxx +++ b/src/emucore/CartFA2.cxx @@ -35,7 +35,7 @@ CartridgeFA2::CartridgeFA2(const ByteBuffer& image, size_t size, // Copy the ROM image into my buffer std::copy_n(img_ptr, mySize, myImage.begin()); - createRomAccessBase(mySize); + createRomAccessArrays(mySize); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/emucore/CartFC.cxx b/src/emucore/CartFC.cxx index 5195e499e..a35b531ca 100644 --- a/src/emucore/CartFC.cxx +++ b/src/emucore/CartFC.cxx @@ -26,7 +26,7 @@ CartridgeFC::CartridgeFC(const ByteBuffer& image, size_t size, { // Copy the ROM image into my buffer std::copy_n(image.get(), std::min(myImage.size(), size), myImage.begin()); - createRomAccessBase(myImage.size()); + createRomAccessArrays(myImage.size()); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/emucore/CartFE.cxx b/src/emucore/CartFE.cxx index de5c088e9..c827906f9 100644 --- a/src/emucore/CartFE.cxx +++ b/src/emucore/CartFE.cxx @@ -26,7 +26,7 @@ CartridgeFE::CartridgeFE(const ByteBuffer& image, size_t size, { // Copy the ROM image into my buffer std::copy_n(image.get(), std::min(myImage.size(), size), myImage.begin()); - createRomAccessBase(myImage.size()); + createRomAccessArrays(myImage.size()); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/emucore/CartMDM.cxx b/src/emucore/CartMDM.cxx index 6eaacee0b..a3b0a0a6c 100644 --- a/src/emucore/CartMDM.cxx +++ b/src/emucore/CartMDM.cxx @@ -29,7 +29,7 @@ CartridgeMDM::CartridgeMDM(const ByteBuffer& image, size_t size, // Copy the ROM image into my buffer std::copy_n(image.get(), mySize, myImage.get()); - createRomAccessBase(mySize); + createRomAccessArrays(mySize); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/emucore/CartMNetwork.cxx b/src/emucore/CartMNetwork.cxx index 9c3213292..e9a3a5e45 100644 --- a/src/emucore/CartMNetwork.cxx +++ b/src/emucore/CartMNetwork.cxx @@ -34,7 +34,7 @@ void CartridgeMNetwork::initialize(const ByteBuffer& image, size_t size) // Copy the ROM image into my buffer std::copy_n(image.get(), std::min(romSize(), size), myImage.get()); - createRomAccessBase(romSize() + myRAM.size()); + createRomAccessArrays(romSize() + myRAM.size()); myRAMSlice = bankCount() - 1; } diff --git a/src/emucore/CartSB.cxx b/src/emucore/CartSB.cxx index db8d4a051..34db0cca1 100644 --- a/src/emucore/CartSB.cxx +++ b/src/emucore/CartSB.cxx @@ -29,7 +29,7 @@ CartridgeSB::CartridgeSB(const ByteBuffer& image, size_t size, // Copy the ROM image into my buffer std::copy_n(image.get(), mySize, myImage.get()); - createRomAccessBase(mySize); + createRomAccessArrays(mySize); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/emucore/CartUA.cxx b/src/emucore/CartUA.cxx index b0643cf97..b4729c38e 100644 --- a/src/emucore/CartUA.cxx +++ b/src/emucore/CartUA.cxx @@ -27,7 +27,7 @@ CartridgeUA::CartridgeUA(const ByteBuffer& image, size_t size, { // Copy the ROM image into my buffer std::copy_n(image.get(), std::min(myImage.size(), size), myImage.begin()); - createRomAccessBase(myImage.size()); + createRomAccessArrays(myImage.size()); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/emucore/CartWD.cxx b/src/emucore/CartWD.cxx index 2a6ea653a..254c78aa4 100644 --- a/src/emucore/CartWD.cxx +++ b/src/emucore/CartWD.cxx @@ -37,7 +37,7 @@ CartridgeWD::CartridgeWD(const ByteBuffer& image, size_t size, } else std::copy_n(image.get(), mySize, myImage.begin()); - createRomAccessBase(8_KB); + createRomAccessArrays(8_KB); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/emucore/CartX07.cxx b/src/emucore/CartX07.cxx index a58b97abb..fc58b0df5 100644 --- a/src/emucore/CartX07.cxx +++ b/src/emucore/CartX07.cxx @@ -27,7 +27,7 @@ CartridgeX07::CartridgeX07(const ByteBuffer& image, size_t size, { // Copy the ROM image into my buffer std::copy_n(image.get(), std::min(myImage.size(), size), myImage.begin()); - createRomAccessBase(myImage.size()); + createRomAccessArrays(myImage.size()); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/emucore/Device.hxx b/src/emucore/Device.hxx index ecb857e21..496306ae2 100644 --- a/src/emucore/Device.hxx +++ b/src/emucore/Device.hxx @@ -63,6 +63,8 @@ class Device : public Serializable }; using AccessFlags = uInt16; + using AccessCounter = uInt32; + public: Device() = default; virtual ~Device() = default; @@ -128,6 +130,7 @@ class Device : public Serializable */ virtual bool poke(uInt16 address, uInt8 value) { return false; } + #ifdef DEBUGGER_SUPPORT /** Query the given address for its access flags @@ -143,6 +146,28 @@ class Device : public Serializable */ virtual void setAccessFlags(uInt16 address, AccessFlags flags) { } + /** + Query the given address for its access counter + + @param address The address to query for + */ + virtual AccessCounter getAccessCounter(uInt16 address) const { return 0; } + + /** + Increase the given address's access counter + + @param address The address to modify + */ + virtual void increaseAccessCounter(uInt16 address, bool isWrite = false) { } + + /** + Query the access counters + + @return The access counters as comma separated string + */ + virtual string getAccessCounters() const { return ""; }; + #endif + protected: /// Pointer to the system the device is installed in or the null pointer System* mySystem{nullptr}; diff --git a/src/emucore/M6532.cxx b/src/emucore/M6532.cxx index 645a4a332..8165b5294 100644 --- a/src/emucore/M6532.cxx +++ b/src/emucore/M6532.cxx @@ -21,6 +21,7 @@ #include "Settings.hxx" #include "Switches.hxx" #include "System.hxx" +#include "Base.hxx" #include "M6532.hxx" @@ -460,6 +461,9 @@ void M6532::createAccessBases() myRAMAccessBase.fill(Device::NONE); myStackAccessBase.fill(Device::NONE); myIOAccessBase.fill(Device::NONE); + myRAMAccessCounter.fill(0); + myStackAccessCounter.fill(0); + myIOAccessCounter.fill(0); myZPAccessDelay.fill(ZP_DELAY); } @@ -492,4 +496,74 @@ void M6532::setAccessFlags(uInt16 address, Device::AccessFlags flags) } } } + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Device::AccessCounter M6532::getAccessCounter(uInt16 address) const +{ + if (address & IO_BIT) + return myIOAccessCounter[address & IO_MASK]; + else if (address & STACK_BIT) + return myStackAccessCounter[address & STACK_MASK]; + else + return myRAMAccessCounter[address & RAM_MASK]; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void M6532::increaseAccessCounter(uInt16 address, bool isWrite) +{ + if (address & IO_BIT) + myIOAccessCounter[isWrite ? 0 : IO_SIZE + (address & IO_MASK)]++; + else { + // the first access, either by direct RAM or stack access is assumed as initialization + if (myZPAccessDelay[address & RAM_MASK]) + myZPAccessDelay[address & RAM_MASK]--; + else if (address & STACK_BIT) + myStackAccessCounter[isWrite ? 0 : STACK_SIZE + (address & STACK_MASK)]++; + else + myRAMAccessCounter[isWrite ? 0 : RAM_SIZE + (address & RAM_MASK)]++; + } +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +string M6532::getAccessCounters() const +{ + ostringstream out; + + out << "RAM reads:\n"; + for(uInt16 addr = 0x00; addr < RAM_SIZE; ++addr) + out << Common::Base::HEX4 << (addr | 0x80) << "," + << Common::Base::toString(myRAMAccessCounter[addr], Common::Base::Fmt::_10_8) << ", "; + out << "\n"; + out << "RAM writes:\n"; + for(uInt16 addr = 0x00; addr < RAM_SIZE; ++addr) + out << Common::Base::HEX4 << (addr | 0x80) << "," + << Common::Base::toString(myRAMAccessCounter[RAM_SIZE + addr], Common::Base::Fmt::_10_8) << ", "; + out << "\n"; + + + out << "Stack reads:\n"; + for(uInt16 addr = 0x00; addr < STACK_SIZE; ++addr) + out << Common::Base::HEX4 << (addr | 0x180) << "," + << Common::Base::toString(myStackAccessCounter[addr], Common::Base::Fmt::_10_8) << ", "; + out << "\n"; + out << "Stack writes:\n"; + for(uInt16 addr = 0x00; addr < STACK_SIZE; ++addr) + out << Common::Base::HEX4 << (addr | 0x180) << "," + << Common::Base::toString(myStackAccessCounter[STACK_SIZE + addr], Common::Base::Fmt::_10_8) << ", "; + out << "\n"; + + out << "IO reads:\n"; + for(uInt16 addr = 0x00; addr < IO_SIZE; ++addr) + out << Common::Base::HEX4 << (addr | 0x280) << "," + << Common::Base::toString(myIOAccessCounter[addr], Common::Base::Fmt::_10_8) << ", "; + out << "\n"; + out << "IO writes:\n"; + for(uInt16 addr = 0x00; addr < IO_SIZE; ++addr) + out << Common::Base::HEX4 << (addr | 0x280) << "," + << Common::Base::toString(myIOAccessCounter[IO_SIZE + addr], Common::Base::Fmt::_10_8) << ", "; + out << "\n"; + + return out.str(); +} + #endif // DEBUGGER_SUPPORT diff --git a/src/emucore/M6532.hxx b/src/emucore/M6532.hxx index 4f543b8a8..d4cb695c9 100644 --- a/src/emucore/M6532.hxx +++ b/src/emucore/M6532.hxx @@ -130,12 +130,21 @@ class M6532 : public Device */ const uInt8* getRAM() const { return myRAM.data(); } + #ifdef DEBUGGER_SUPPORT + /** + Query the access counters + + @return The access counters as comma separated string + */ + string getAccessCounters() const override; + #endif + private: void setTimerRegister(uInt8 data, uInt8 interval); void setPinState(bool shcha); -#ifdef DEBUGGER_SUPPORT + #ifdef DEBUGGER_SUPPORT // The following are used by the debugger to read INTIM/TIMINT // We need separate methods to do this, so the state of the system // isn't changed @@ -159,7 +168,21 @@ class M6532 : public Device @param flags A bitfield of AccessType directives for the given address */ void setAccessFlags(uInt16 address, Device::AccessFlags flags) override; -#endif // DEBUGGER_SUPPORT + + /** + Query the given address for its access counter + + @param address The address to query for + */ + Device::AccessCounter getAccessCounter(uInt16 address) const override; + + /** + Increase the given address's access counter + + @param address The address to modify + */ + void increaseAccessCounter(uInt16 address, bool isWrite) override; + #endif // DEBUGGER_SUPPORT private: // Reference to the console @@ -221,13 +244,18 @@ class M6532 : public Device RAM_SIZE = 0x80, RAM_MASK = RAM_SIZE - 1, STACK_SIZE = RAM_SIZE, STACK_MASK = RAM_MASK, STACK_BIT = 0x100, IO_SIZE = 0x20, IO_MASK = IO_SIZE - 1, IO_BIT = 0x200, - ZP_DELAY = 1; + ZP_DELAY = 1 * 2; // The arrays containing information about every byte of RIOT // indicating whether and how (RW) it is used. std::array myRAMAccessBase; std::array myStackAccessBase; std::array myIOAccessBase; + // The arrays containing information about every byte of RIOT + // indicating how often it is accessed. + std::array myRAMAccessCounter; + std::array myStackAccessCounter; + std::array myIOAccessCounter; // The array used to skip the first ZP access tracking std::array myZPAccessDelay; #endif // DEBUGGER_SUPPORT diff --git a/src/emucore/System.cxx b/src/emucore/System.cxx index c94f465fd..b1f0c538a 100644 --- a/src/emucore/System.cxx +++ b/src/emucore/System.cxx @@ -109,6 +109,11 @@ uInt8 System::peek(uInt16 addr, Device::AccessFlags flags) *(access.romAccessBase + (addr & PAGE_MASK)) |= (flags | (addr & Device::HADDR)); else access.device->setAccessFlags(addr, flags); + // Increase access counter + if(access.romAccessCounter) + *(access.romAccessCounter + (addr & PAGE_MASK)) += 1; + else + access.device->increaseAccessCounter(addr); #endif // See if this page uses direct accessing or not @@ -138,6 +143,11 @@ void System::poke(uInt16 addr, uInt8 value, Device::AccessFlags flags) *(access.romAccessBase + (addr & PAGE_MASK)) |= (flags | (addr & Device::HADDR)); else access.device->setAccessFlags(addr, flags); + // Increase access counter + if(access.romAccessCounter) + *(access.romAccessCounter + (addr & PAGE_MASK)) += 1; + else + access.device->increaseAccessCounter(addr, true); #endif // See if this page uses direct accessing or not @@ -181,6 +191,29 @@ void System::setAccessFlags(uInt16 addr, Device::AccessFlags flags) else access.device->setAccessFlags(addr, flags); } + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Device::AccessCounter System::getAccessCounter(uInt16 addr) const +{ + const PageAccess& access = getPageAccess(addr); + + if(access.romAccessCounter) + return *(access.romAccessCounter + (addr & PAGE_MASK)); + else + return access.device->getAccessCounter(addr); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void System::increaseAccessCounter(uInt16 addr, bool isWrite) +{ + const PageAccess& access = getPageAccess(addr); + + if(access.romAccessCounter) + *(access.romAccessCounter + (addr & PAGE_MASK)) += 1; + else + access.device->increaseAccessCounter(addr, isWrite); +} + #endif // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/emucore/System.hxx b/src/emucore/System.hxx index b400b1cdb..6c5547d7f 100644 --- a/src/emucore/System.hxx +++ b/src/emucore/System.hxx @@ -239,6 +239,20 @@ class System : public Serializable */ Device::AccessFlags getAccessFlags(uInt16 address) const; void setAccessFlags(uInt16 address, Device::AccessFlags flags); + + /** + Query the given address for its access counter + + @param address The address to query for + */ + Device::AccessCounter getAccessCounter(uInt16 address) const; + + /** + Increase the given address's access counter + + @param address The address to modify + */ + void increaseAccessCounter(uInt16 address, bool isWrite); #endif public: @@ -285,6 +299,11 @@ class System : public Serializable */ Device::AccessFlags* romAccessBase{nullptr}; + /** + TODO + */ + Device::AccessCounter* romAccessCounter{nullptr}; + /** Pointer to the device associated with this page or to the system's null device if the page hasn't been mapped to a device. diff --git a/src/emucore/tia/TIA.cxx b/src/emucore/tia/TIA.cxx index c5896c3aa..57192b436 100644 --- a/src/emucore/tia/TIA.cxx +++ b/src/emucore/tia/TIA.cxx @@ -24,6 +24,7 @@ #include "frame-manager/FrameManager.hxx" #include "AudioQueue.hxx" #include "DispatchResult.hxx" +#include "Base.hxx" enum CollisionMask: uInt32 { player0 = 0b0111110000000000, @@ -183,7 +184,7 @@ void TIA::initialize() enableFixedColors(mySettings.getBool(devSettings ? "dev.debugcolors" : "plr.debugcolors")); #ifdef DEBUGGER_SUPPORT - createAccessBase(); + createAccessArrays(); #endif // DEBUGGER_SUPPORT } @@ -1950,9 +1951,10 @@ void TIA::toggleCollBLPF() #ifdef DEBUGGER_SUPPORT // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void TIA::createAccessBase() +void TIA::createAccessArrays() { myAccessBase.fill(Device::NONE); + myAccessCounter.fill(0); myAccessDelay.fill(TIA_DELAY); } @@ -1977,4 +1979,44 @@ void TIA::setAccessFlags(uInt16 address, Device::AccessFlags flags) myAccessBase[address & TIA_READ_MASK] |= flags; } } + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Device::AccessCounter TIA::getAccessCounter(uInt16 address) const +{ + return myAccessCounter[address & TIA_MASK]; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void TIA::increaseAccessCounter(uInt16 address, bool isWrite) +{ + if(isWrite) + { + // the first two write accesses are assumed as initialization + if(myAccessDelay[address & TIA_MASK]) + myAccessDelay[address & TIA_MASK]--; + else + myAccessCounter[address & TIA_MASK]++; + } + else + myAccessCounter[TIA_SIZE + (address & TIA_READ_MASK)]++; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +string TIA::getAccessCounters() const +{ + ostringstream out; + + out << "TIA reads:\n"; + for(uInt16 addr = 0x00; addr < TIA_READ_SIZE; ++addr) + out << Common::Base::HEX4 << addr << "," + << Common::Base::toString(myAccessCounter[TIA_SIZE + addr], Common::Base::Fmt::_10_8) << ", "; + out << "\n"; + out << "TIA writes:\n"; + for(uInt16 addr = 0x00; addr < TIA_SIZE; ++addr) + out << Common::Base::HEX4 << addr << "," + << Common::Base::toString(myAccessCounter[addr], Common::Base::Fmt::_10_8) << ", "; + out << "\n"; + + return out.str(); +} #endif // DEBUGGER_SUPPORT diff --git a/src/emucore/tia/TIA.hxx b/src/emucore/tia/TIA.hxx index 30c3d04f5..28481dfc6 100644 --- a/src/emucore/tia/TIA.hxx +++ b/src/emucore/tia/TIA.hxx @@ -530,6 +530,15 @@ class TIA : public Device */ void updateEmulation(); + #ifdef DEBUGGER_SUPPORT + /** + Query the access counters + + @return The access counters as comma separated string + */ + string getAccessCounters() const; + #endif + private: /** * During each line, the TIA cycles through these two states. @@ -678,7 +687,7 @@ class TIA : public Device void applyDeveloperSettings(); #ifdef DEBUGGER_SUPPORT - void createAccessBase(); + void createAccessArrays(); /** * Query the given address type for the associated access flags. @@ -693,6 +702,20 @@ class TIA : public Device * @param flags A bitfield of AccessType directives for the given address */ void setAccessFlags(uInt16 address, Device::AccessFlags flags) override; + + /** + Query the given address for its access counter + + @param address The address to query for + */ + Device::AccessCounter getAccessCounter(uInt16 address) const override; + + /** + Increase the given address's access counter + + @param address The address to modify + */ + void increaseAccessCounter(uInt16 address, bool isWrite) override; #endif // DEBUGGER_SUPPORT private: @@ -896,12 +919,17 @@ class TIA : public Device uInt8 myJitterFactor{0}; static constexpr uInt16 - TIA_SIZE = 0x40, TIA_MASK = TIA_SIZE - 1, TIA_READ_MASK = 0x0f, TIA_BIT = 0x080, TIA_DELAY = 2; + TIA_SIZE = 0x40, TIA_MASK = TIA_SIZE - 1, + TIA_READ_SIZE = 0x10, TIA_READ_MASK = TIA_READ_SIZE - 1, + TIA_BIT = 0x080, TIA_DELAY = 2 * 2; #ifdef DEBUGGER_SUPPORT // The arrays containing information about every byte of TIA // indicating whether and how (RW) it is used. std::array myAccessBase; + // The arrays containing information about every byte of TIA + // indicating how often it is accessed (read and write). + std::array myAccessCounter; // The array used to skip the first two TIA access trackings std::array myAccessDelay;