first shot at #586 (Heat Map) (TODO: differentiate cartridge read/write access)

add Cartridge::bankSize method (TODO: varying bank sizes)
add Cartridge::bankOrigin detection method (TODO: banks smaller 4K)
This commit is contained in:
thrust26 2020-04-01 11:06:03 +02:00
parent a6ac378554
commit 96131e2f7f
55 changed files with 446 additions and 84 deletions

View File

@ -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<size_t>(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)
{

View File

@ -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).

View File

@ -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::Command, 99> DebuggerParser::commands = { {
std::array<DebuggerParser::Command, 100> DebuggerParser::commands = { {
{
"a",
"Set Accumulator to <value>",
@ -2998,6 +3004,16 @@ std::array<DebuggerParser::Command, 99> 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)",

View File

@ -98,7 +98,7 @@ class DebuggerParser
std::array<Parameters, 10> parms;
std::function<void (DebuggerParser*)> executor;
};
static std::array<Command, 99> commands;
static std::array<Command, 100> commands;
struct Trap
{
@ -215,6 +215,7 @@ class DebuggerParser
void executeRunToPc();
void executeS();
void executeSave();
void executeSaveAccess();
void executeSaveallstates();
void executeSaveconfig();
void executeSavedisassembly();

View File

@ -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<Device::AccessFlags[]>(size);
std::fill_n(myRomAccessBase.get(), size, Device::ROW);
myRomAccessCounter = make_unique<Device::AccessCounter[]>(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<uInt16, 8> 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
{

View File

@ -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<Device::AccessFlags[]> myRomAccessBase;
// The array containing information about every byte of ROM indicating
// how often it is accessed.
std::unique_ptr<Device::AccessCounter[]> myRomAccessCounter;
// Contains address of illegal RAM write access or 0
uInt16 myRamWriteAccess{0};

View File

@ -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());
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

View File

@ -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

View File

@ -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());
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

View File

@ -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());
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

View File

@ -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);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

View File

@ -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());
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

View File

@ -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);
}
}

View File

@ -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());
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

View File

@ -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);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

View File

@ -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());
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

View File

@ -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());
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

View File

@ -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

View File

@ -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

View File

@ -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());
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

View File

@ -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);

View File

@ -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());
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

View File

@ -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());
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

View File

@ -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());
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

View File

@ -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());
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

View File

@ -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());
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

View File

@ -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();

View File

@ -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;

View File

@ -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());
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

View File

@ -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());
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

View File

@ -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());
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

View File

@ -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());
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

View File

@ -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());
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

View File

@ -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());
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

View File

@ -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());
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

View File

@ -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());
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

View File

@ -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());
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

View File

@ -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());
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

View File

@ -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());
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

View File

@ -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);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

View File

@ -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());
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

View File

@ -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());
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

View File

@ -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);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

View File

@ -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<size_t>(romSize(), size), myImage.get());
createRomAccessBase(romSize() + myRAM.size());
createRomAccessArrays(romSize() + myRAM.size());
myRAMSlice = bankCount() - 1;
}

View File

@ -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);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

View File

@ -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());
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

View File

@ -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);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

View File

@ -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());
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

View File

@ -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};

View File

@ -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

View File

@ -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<Device::AccessFlags, RAM_SIZE> myRAMAccessBase;
std::array<Device::AccessFlags, STACK_SIZE> myStackAccessBase;
std::array<Device::AccessFlags, IO_SIZE> myIOAccessBase;
// The arrays containing information about every byte of RIOT
// indicating how often it is accessed.
std::array<Device::AccessCounter, RAM_SIZE * 2> myRAMAccessCounter;
std::array<Device::AccessCounter, STACK_SIZE * 2> myStackAccessCounter;
std::array<Device::AccessCounter, IO_SIZE * 2> myIOAccessCounter;
// The array used to skip the first ZP access tracking
std::array<uInt8, RAM_SIZE> myZPAccessDelay;
#endif // DEBUGGER_SUPPORT

View File

@ -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
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

View File

@ -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.

View File

@ -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

View File

@ -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<Device::AccessFlags, TIA_SIZE> myAccessBase;
// The arrays containing information about every byte of TIA
// indicating how often it is accessed (read and write).
std::array<Device::AccessCounter, TIA_SIZE + TIA_READ_SIZE> myAccessCounter;
// The array used to skip the first two TIA access trackings
std::array<uInt8, TIA_SIZE> myAccessDelay;