2019-03-28 17:47:43 -04:00
|
|
|
#include "stdafx.h"
|
|
|
|
#include "MemoryAccessCounter.h"
|
|
|
|
#include "MemoryManager.h"
|
|
|
|
#include "DebugBreakHelper.h"
|
|
|
|
#include "Debugger.h"
|
|
|
|
#include "MemoryDumper.h"
|
2019-04-07 14:38:22 -04:00
|
|
|
#include "Spc.h"
|
2019-07-25 22:22:09 -04:00
|
|
|
#include "Sa1.h"
|
2019-07-30 22:34:52 -04:00
|
|
|
#include "Gsu.h"
|
2020-02-24 22:00:52 -05:00
|
|
|
#include "Cx4.h"
|
2020-05-18 16:10:53 -04:00
|
|
|
#include "Gameboy.h"
|
2019-07-25 22:22:09 -04:00
|
|
|
#include "BaseCartridge.h"
|
2019-03-28 17:47:43 -04:00
|
|
|
|
2020-12-19 23:30:09 +03:00
|
|
|
MemoryAccessCounter::MemoryAccessCounter(Debugger* debugger, Console* console)
|
2019-03-28 17:47:43 -04:00
|
|
|
{
|
|
|
|
_debugger = debugger;
|
2019-07-25 22:22:09 -04:00
|
|
|
_memoryManager = console->GetMemoryManager().get();
|
|
|
|
_spc = console->GetSpc().get();
|
|
|
|
_sa1 = console->GetCartridge()->GetSa1();
|
2019-07-30 22:34:52 -04:00
|
|
|
_gsu = console->GetCartridge()->GetGsu();
|
2020-02-24 22:00:52 -05:00
|
|
|
_cx4 = console->GetCartridge()->GetCx4();
|
2020-05-18 16:10:53 -04:00
|
|
|
_gameboy = console->GetCartridge()->GetGameboy();
|
2019-03-28 17:47:43 -04:00
|
|
|
|
2020-12-19 23:30:09 +03:00
|
|
|
for (int i = (int)SnesMemoryType::PrgRom; i < (int)SnesMemoryType::Register; i++)
|
|
|
|
{
|
2019-03-28 17:47:43 -04:00
|
|
|
uint32_t memSize = _debugger->GetMemoryDumper()->GetMemorySize((SnesMemoryType)i);
|
2020-02-15 10:49:11 -05:00
|
|
|
_counters[i].reserve(memSize);
|
2020-12-19 23:30:09 +03:00
|
|
|
for (uint32_t j = 0; j < memSize; j++)
|
|
|
|
{
|
|
|
|
_counters[i].push_back({j});
|
2020-02-15 10:49:11 -05:00
|
|
|
}
|
2019-03-28 17:47:43 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-06-23 18:34:03 -04:00
|
|
|
bool MemoryAccessCounter::IsAddressUninitialized(AddressInfo& addressInfo)
|
2019-03-28 17:47:43 -04:00
|
|
|
{
|
2020-12-19 23:30:09 +03:00
|
|
|
if (!DebugUtilities::IsRomMemory(addressInfo.Type))
|
|
|
|
{
|
2020-02-12 21:26:50 -05:00
|
|
|
return _counters[(int)addressInfo.Type][addressInfo.Address].WriteCount == 0;
|
2019-03-28 17:47:43 -04:00
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2020-06-23 18:34:03 -04:00
|
|
|
uint64_t MemoryAccessCounter::GetReadCount(AddressInfo& addressInfo)
|
|
|
|
{
|
|
|
|
return _counters[(int)addressInfo.Type][addressInfo.Address].ReadCount;
|
|
|
|
}
|
|
|
|
|
2020-12-19 23:30:09 +03:00
|
|
|
bool MemoryAccessCounter::ProcessMemoryRead(AddressInfo& addressInfo, uint64_t masterClock)
|
2019-03-28 17:47:43 -04:00
|
|
|
{
|
2020-12-19 23:30:09 +03:00
|
|
|
if (addressInfo.Address < 0)
|
|
|
|
{
|
2019-03-28 17:47:43 -04:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2020-02-12 21:26:50 -05:00
|
|
|
AddressCounters& counts = _counters[(int)addressInfo.Type][addressInfo.Address];
|
|
|
|
counts.ReadCount++;
|
|
|
|
counts.ReadStamp = masterClock;
|
2020-12-19 23:30:09 +03:00
|
|
|
if (counts.WriteCount == 0 && IsAddressUninitialized(addressInfo))
|
|
|
|
{
|
2019-03-28 17:47:43 -04:00
|
|
|
//Mark address as read before being written to (if trying to read/execute)
|
2020-02-12 21:26:50 -05:00
|
|
|
counts.UninitRead = true;
|
2019-03-28 17:47:43 -04:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2020-02-12 21:26:50 -05:00
|
|
|
void MemoryAccessCounter::ProcessMemoryWrite(AddressInfo& addressInfo, uint64_t masterClock)
|
2019-03-28 17:47:43 -04:00
|
|
|
{
|
2020-12-19 23:30:09 +03:00
|
|
|
if (addressInfo.Address < 0)
|
|
|
|
{
|
2020-02-12 21:26:50 -05:00
|
|
|
return;
|
2019-03-28 17:47:43 -04:00
|
|
|
}
|
2020-02-12 21:26:50 -05:00
|
|
|
|
|
|
|
AddressCounters& counts = _counters[(int)addressInfo.Type][addressInfo.Address];
|
|
|
|
counts.WriteCount++;
|
|
|
|
counts.WriteStamp = masterClock;
|
2019-03-28 17:47:43 -04:00
|
|
|
}
|
|
|
|
|
2020-02-12 21:26:50 -05:00
|
|
|
void MemoryAccessCounter::ProcessMemoryExec(AddressInfo& addressInfo, uint64_t masterClock)
|
2019-03-28 17:47:43 -04:00
|
|
|
{
|
2020-12-19 23:30:09 +03:00
|
|
|
if (addressInfo.Address < 0)
|
|
|
|
{
|
2020-02-12 21:26:50 -05:00
|
|
|
return;
|
|
|
|
}
|
2019-07-25 22:22:09 -04:00
|
|
|
|
2020-02-12 21:26:50 -05:00
|
|
|
AddressCounters& counts = _counters[(int)addressInfo.Type][addressInfo.Address];
|
|
|
|
counts.ExecCount++;
|
|
|
|
counts.ExecStamp = masterClock;
|
|
|
|
}
|
2019-07-30 22:34:52 -04:00
|
|
|
|
2020-02-12 21:26:50 -05:00
|
|
|
void MemoryAccessCounter::ResetCounts()
|
|
|
|
{
|
|
|
|
DebugBreakHelper helper(_debugger);
|
2020-12-19 23:30:09 +03:00
|
|
|
for (int i = 0; i < (int)SnesMemoryType::Register; i++)
|
|
|
|
{
|
|
|
|
for (uint32_t j = 0; j < _counters[i].size(); j++)
|
|
|
|
{
|
|
|
|
_counters[i][j] = {j};
|
2020-02-15 10:49:11 -05:00
|
|
|
}
|
2019-03-28 17:47:43 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-12-19 23:30:09 +03:00
|
|
|
void MemoryAccessCounter::GetAccessCounts(uint32_t offset, uint32_t length, SnesMemoryType memoryType,
|
|
|
|
AddressCounters counts[])
|
2019-03-28 17:47:43 -04:00
|
|
|
{
|
2020-12-19 23:30:09 +03:00
|
|
|
switch (memoryType)
|
|
|
|
{
|
|
|
|
case SnesMemoryType::CpuMemory:
|
|
|
|
for (uint32_t i = 0; i < length; i++)
|
|
|
|
{
|
|
|
|
AddressInfo info = _memoryManager->GetMemoryMappings()->GetAbsoluteAddress(offset + i);
|
|
|
|
if (info.Address >= 0)
|
|
|
|
{
|
|
|
|
counts[i] = _counters[(int)info.Type][info.Address];
|
2019-03-28 17:47:43 -04:00
|
|
|
}
|
2020-12-19 23:30:09 +03:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SnesMemoryType::SpcMemory:
|
|
|
|
for (uint32_t i = 0; i < length; i++)
|
|
|
|
{
|
|
|
|
AddressInfo info = _spc->GetAbsoluteAddress(offset + i);
|
|
|
|
if (info.Address >= 0)
|
|
|
|
{
|
|
|
|
counts[i] = _counters[(int)info.Type][info.Address];
|
2019-04-07 14:38:22 -04:00
|
|
|
}
|
2020-12-19 23:30:09 +03:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SnesMemoryType::Sa1Memory:
|
|
|
|
if (_sa1)
|
|
|
|
{
|
|
|
|
for (uint32_t i = 0; i < length; i++)
|
|
|
|
{
|
|
|
|
AddressInfo info = _sa1->GetMemoryMappings()->GetAbsoluteAddress(offset + i);
|
|
|
|
if (info.Address >= 0)
|
|
|
|
{
|
|
|
|
counts[i] = _counters[(int)info.Type][info.Address];
|
2019-07-25 22:22:09 -04:00
|
|
|
}
|
|
|
|
}
|
2020-12-19 23:30:09 +03:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SnesMemoryType::GsuMemory:
|
|
|
|
if (_gsu)
|
|
|
|
{
|
|
|
|
for (uint32_t i = 0; i < length; i++)
|
|
|
|
{
|
|
|
|
AddressInfo info = _gsu->GetMemoryMappings()->GetAbsoluteAddress(offset + i);
|
|
|
|
if (info.Address >= 0)
|
|
|
|
{
|
|
|
|
counts[i] = _counters[(int)info.Type][info.Address];
|
2019-07-30 22:34:52 -04:00
|
|
|
}
|
|
|
|
}
|
2020-12-19 23:30:09 +03:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SnesMemoryType::Cx4Memory:
|
|
|
|
if (_cx4)
|
|
|
|
{
|
|
|
|
for (uint32_t i = 0; i < length; i++)
|
|
|
|
{
|
|
|
|
AddressInfo info = _cx4->GetMemoryMappings()->GetAbsoluteAddress(offset + i);
|
|
|
|
if (info.Address >= 0)
|
|
|
|
{
|
|
|
|
counts[i] = _counters[(int)info.Type][info.Address];
|
2020-05-18 16:10:53 -04:00
|
|
|
}
|
|
|
|
}
|
2020-12-19 23:30:09 +03:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SnesMemoryType::GameboyMemory:
|
|
|
|
if (_gameboy)
|
|
|
|
{
|
|
|
|
for (uint32_t i = 0; i < length; i++)
|
|
|
|
{
|
|
|
|
AddressInfo info = _gameboy->GetAbsoluteAddress(offset + i);
|
|
|
|
if (info.Address >= 0)
|
|
|
|
{
|
|
|
|
counts[i] = _counters[(int)info.Type][info.Address];
|
2020-02-24 22:00:52 -05:00
|
|
|
}
|
|
|
|
}
|
2020-12-19 23:30:09 +03:00
|
|
|
}
|
|
|
|
break;
|
2020-02-24 22:00:52 -05:00
|
|
|
|
2020-12-19 23:30:09 +03:00
|
|
|
default:
|
|
|
|
memcpy(counts, _counters[(int)memoryType].data() + offset, length * sizeof(AddressCounters));
|
|
|
|
break;
|
2019-03-28 17:47:43 -04:00
|
|
|
}
|
|
|
|
}
|