Debugger: Added access counters for CHR ROM/RAM and nametable memory

+Added read/write highlighting, etc. for memory viewer tabs
+Improved show tile/attribute updates in PPU viewer
This commit is contained in:
Sour 2019-01-13 18:32:27 -05:00
parent a00a36256a
commit 76f64b19ef
18 changed files with 490 additions and 157 deletions

View File

@ -931,6 +931,7 @@ uint32_t BaseMapper::GetMemorySize(DebugMemoryType type)
default: return 0;
case DebugMemoryType::ChrRom: return _onlyChrRam ? 0 : _chrRomSize;
case DebugMemoryType::ChrRam: return _chrRamSize;
case DebugMemoryType::NametableRam: return _nametableCount * BaseMapper::NametableSize;
case DebugMemoryType::SaveRam: return _saveRamSize;
case DebugMemoryType::PrgRom: return _prgSize;
case DebugMemoryType::WorkRam: return _workRamSize;
@ -1035,6 +1036,29 @@ int32_t BaseMapper::ToAbsoluteSaveRamAddress(uint16_t addr)
return -1;
}
void BaseMapper::GetPpuAbsoluteAddressAndType(uint32_t relativeAddr, PpuAddressTypeInfo* info)
{
if(relativeAddr >= 0x3F00) {
info->Address = relativeAddr & 0x1F;
info->Type = PpuAddressType::PaletteRam;
} else {
uint8_t *addr = _chrPages[relativeAddr >> 8] + (uint8_t)relativeAddr;
if(addr >= _chrRom && addr < _chrRom + _chrRomSize) {
info->Address = (uint32_t)(addr - _chrRom);
info->Type = PpuAddressType::ChrRom;
} else if(addr >= _chrRam && addr < _chrRam + _chrRamSize) {
info->Address = (uint32_t)(addr - _chrRam);
info->Type = PpuAddressType::ChrRam;
} else if(addr >= _nametableRam && addr < _nametableRam + BaseMapper::NametableSize * BaseMapper::NametableCount) {
info->Address = (uint32_t)(addr - _nametableRam);
info->Type = PpuAddressType::NametableRam;
} else {
info->Address = -1;
info->Type = PpuAddressType::None;
}
}
}
int32_t BaseMapper::ToAbsoluteChrAddress(uint16_t addr)
{
uint8_t *chrAddr = _chrPages[addr >> 8] + (uint8_t)addr;

View File

@ -51,9 +51,6 @@ private:
vector<uint8_t> _originalChrRom;
protected:
static constexpr uint32_t NametableCount = 0x10;
static constexpr uint32_t NametableSize = 0x400;
RomInfo _romInfo;
shared_ptr<BaseControlDevice> _mapperControlDevice;
@ -152,6 +149,9 @@ protected:
MirroringType GetMirroringType();
public:
static constexpr uint32_t NametableCount = 0x10;
static constexpr uint32_t NametableSize = 0x400;
void Initialize(RomData &romData);
virtual ~BaseMapper();
@ -217,6 +217,7 @@ public:
void WriteMemory(DebugMemoryType type, uint8_t* buffer);
void GetAbsoluteAddressAndType(uint32_t relativeAddr, AddressTypeInfo *info);
void GetPpuAbsoluteAddressAndType(uint32_t relativeAddr, PpuAddressTypeInfo *info);
int32_t ToAbsoluteAddress(uint16_t addr);
int32_t ToAbsoluteSaveRamAddress(uint16_t addr);
int32_t ToAbsoluteWorkRamAddress(uint16_t addr);

View File

@ -749,7 +749,7 @@ bool Debugger::ProcessRamOperation(MemoryOperationType type, uint16_t &addr, uin
if(!_breakOnFirstCycle && _enableBreakOnUninitRead && CheckFlag(DebuggerFlags::BreakOnUninitMemoryRead)) {
//Break on uninit memory read
Step(1);
breakDone = SleepUntilResume(BreakSource::BreakOnUninitMemoryRead, 0, BreakpointType::Global, operationInfo.Address, operationInfo.Value, operationInfo.OperationType);
breakDone = SleepUntilResume(BreakSource::BreakOnUninitMemoryRead, 0, BreakpointType::Global, operationInfo.Address, (uint8_t)operationInfo.Value, operationInfo.OperationType);
}
}
}
@ -956,24 +956,28 @@ bool Debugger::SleepUntilResume(BreakSource source, uint32_t breakpointId, Break
void Debugger::ProcessVramReadOperation(MemoryOperationType type, uint16_t addr, uint8_t &value)
{
int32_t absoluteAddr = _mapper->ToAbsoluteChrAddress(addr);
_codeDataLogger->SetFlag(absoluteAddr, type == MemoryOperationType::Read ? CdlChrFlags::Read : CdlChrFlags::Drawn);
PpuAddressTypeInfo addressInfo;
_mapper->GetPpuAbsoluteAddressAndType(addr, &addressInfo);
_codeDataLogger->SetFlag(addressInfo.Address, type == MemoryOperationType::Read ? CdlChrFlags::Read : CdlChrFlags::Drawn);
if(_hasBreakpoint[BreakpointType::ReadVram]) {
OperationInfo operationInfo{ addr, value, type };
ProcessBreakpoints(BreakpointType::ReadVram, operationInfo, !_breakOnFirstCycle, true);
}
_memoryAccessCounter->ProcessPpuMemoryAccess(addressInfo, type, _cpu->GetCycleCount());
ProcessPpuOperation(addr, value, MemoryOperationType::Read);
}
void Debugger::ProcessVramWriteOperation(uint16_t addr, uint8_t &value)
{
PpuAddressTypeInfo addressInfo;
_mapper->GetPpuAbsoluteAddressAndType(addr, &addressInfo);
if(_hasBreakpoint[BreakpointType::WriteVram]) {
OperationInfo operationInfo{ addr, value, MemoryOperationType::Write };
ProcessBreakpoints(BreakpointType::WriteVram, operationInfo, !_breakOnFirstCycle, true);
}
_memoryAccessCounter->ProcessPpuMemoryAccess(addressInfo, MemoryOperationType::Write, _cpu->GetCycleCount());
ProcessPpuOperation(addr, value, MemoryOperationType::Write);
}
@ -1283,28 +1287,7 @@ void Debugger::GetAbsoluteAddressAndType(uint32_t relativeAddr, AddressTypeInfo*
void Debugger::GetPpuAbsoluteAddressAndType(uint32_t relativeAddr, PpuAddressTypeInfo* info)
{
if(relativeAddr >= 0x3F00) {
info->Address = relativeAddr & 0x1F;
info->Type = PpuAddressType::PaletteRam;
return;
}
int32_t addr = _mapper->ToAbsoluteChrRomAddress(relativeAddr);
if(addr >= 0) {
info->Address = addr;
info->Type = PpuAddressType::ChrRom;
return;
}
addr = _mapper->ToAbsoluteChrRamAddress(relativeAddr);
if(addr >= 0) {
info->Address = addr;
info->Type = PpuAddressType::ChrRam;
return;
}
info->Address = -1;
info->Type = PpuAddressType::None;
return _mapper->GetPpuAbsoluteAddressAndType(relativeAddr, info);
}
void Debugger::UpdatePpuCyclesToProcess()

View File

@ -70,10 +70,11 @@ enum class AddressType
enum class PpuAddressType
{
None = 0,
ChrRom = 1,
ChrRam = 2,
PaletteRam = 3
None = -1,
ChrRom = 0,
ChrRam = 1,
PaletteRam = 2,
NametableRam = 3
};
struct AddressTypeInfo
@ -100,7 +101,8 @@ enum class DebugMemoryType
ChrRam = 7,
WorkRam = 8,
SaveRam = 9,
InternalRam = 10
InternalRam = 10,
NametableRam = 11,
};
enum class CdlHighlightType

View File

@ -760,18 +760,34 @@ int LuaApi::GetAccessCounters(lua_State *lua)
errorCond(memoryType >= AddressType::Register, "Invalid memory type");
checkparams();
DebugMemoryType debugMemoryType;
uint32_t size = 0;
switch(memoryType) {
case AddressType::Register: error("Invalid memory type"); break;
case AddressType::InternalRam: size = 0x2000; break;
case AddressType::PrgRom: size = _memoryDumper->GetMemorySize(DebugMemoryType::PrgRom); break;
case AddressType::WorkRam: size = _memoryDumper->GetMemorySize(DebugMemoryType::WorkRam); break;
case AddressType::SaveRam: size = _memoryDumper->GetMemorySize(DebugMemoryType::SaveRam); break;
case AddressType::InternalRam:
debugMemoryType = DebugMemoryType::InternalRam;
size = 0x2000;
break;
case AddressType::PrgRom:
debugMemoryType = DebugMemoryType::PrgRom;
size = _memoryDumper->GetMemorySize(DebugMemoryType::PrgRom);
break;
case AddressType::WorkRam:
debugMemoryType = DebugMemoryType::WorkRam;
size = _memoryDumper->GetMemorySize(DebugMemoryType::WorkRam);
break;
case AddressType::SaveRam:
debugMemoryType = DebugMemoryType::SaveRam;
size = _memoryDumper->GetMemorySize(DebugMemoryType::SaveRam);
break;
}
vector<uint32_t> counts;
vector<int32_t> counts;
counts.resize(size, 0);
_debugger->GetMemoryAccessCounter()->GetAccessCounts(memoryType, operationType, counts.data(), false);
_debugger->GetMemoryAccessCounter()->GetAccessCounts(0, size, debugMemoryType, operationType, counts.data());
lua_newtable(lua);
for(uint32_t i = 0; i < size; i++) {

View File

@ -1,18 +1,20 @@
#include "stdafx.h"
#include "MemoryAccessCounter.h"
#include "Console.h"
#include "CPU.h"
#include "DebugBreakHelper.h"
#include "Debugger.h"
#include "MemoryDumper.h"
#include "BaseMapper.h"
MemoryAccessCounter::MemoryAccessCounter(Debugger* debugger)
{
_debugger = debugger;
uint32_t memorySizes[4] = {
0x2000,
_debugger->GetMemoryDumper()->GetMemorySize(DebugMemoryType::PrgRom),
_debugger->GetMemoryDumper()->GetMemorySize(DebugMemoryType::WorkRam),
uint32_t memorySizes[4] = {
0x2000,
_debugger->GetMemoryDumper()->GetMemorySize(DebugMemoryType::PrgRom),
_debugger->GetMemoryDumper()->GetMemorySize(DebugMemoryType::WorkRam),
_debugger->GetMemoryDumper()->GetMemorySize(DebugMemoryType::SaveRam)
};
@ -27,20 +29,56 @@ MemoryAccessCounter::MemoryAccessCounter(Debugger* debugger)
_uninitReads[i].insert(_uninitReads[i].end(), memorySizes[i], 0);
}
uint32_t ppuMemorySizes[4] = {
_debugger->GetMemoryDumper()->GetMemorySize(DebugMemoryType::ChrRom),
_debugger->GetMemoryDumper()->GetMemorySize(DebugMemoryType::ChrRam),
_debugger->GetMemoryDumper()->GetMemorySize(DebugMemoryType::PaletteMemory),
BaseMapper::NametableSize * BaseMapper::NametableCount,
};
for(int i = 0; i < 4; i++) {
_ppuReadCounts[i].insert(_ppuReadCounts[i].end(), ppuMemorySizes[i], 0);
_ppuWriteCounts[i].insert(_ppuWriteCounts[i].end(), ppuMemorySizes[i], 0);
_ppuReadStamps[i].insert(_ppuReadStamps[i].end(), ppuMemorySizes[i], 0);
_ppuWriteStamps[i].insert(_ppuWriteStamps[i].end(), ppuMemorySizes[i], 0);
}
}
vector<int32_t>& MemoryAccessCounter::GetArray(MemoryOperationType operationType, AddressType addressType, bool stampArray)
vector<int32_t>& MemoryAccessCounter::GetCountArray(MemoryOperationType operationType, AddressType addressType)
{
switch(operationType) {
case MemoryOperationType::Read: return stampArray ? _readStamps[(int)addressType] : _readCounts[(int)addressType];
case MemoryOperationType::Write: return stampArray ? _writeStamps[(int)addressType] : _writeCounts[(int)addressType];
case MemoryOperationType::Read: return _readCounts[(int)addressType];
case MemoryOperationType::Write: return _writeCounts[(int)addressType];
default:
case MemoryOperationType::ExecOpCode:
case MemoryOperationType::ExecOperand: return stampArray ? _execStamps[(int)addressType] : _execCounts[(int)addressType];
case MemoryOperationType::ExecOperand: return _execCounts[(int)addressType];
}
}
vector<int32_t>& MemoryAccessCounter::GetStampArray(MemoryOperationType operationType, AddressType addressType)
{
switch(operationType) {
case MemoryOperationType::Read: return _readStamps[(int)addressType];
case MemoryOperationType::Write: return _writeStamps[(int)addressType];
default:
case MemoryOperationType::ExecOpCode:
case MemoryOperationType::ExecOperand: return _execStamps[(int)addressType];
}
}
vector<int32_t>& MemoryAccessCounter::GetPpuCountArray(MemoryOperationType operationType, PpuAddressType addressType)
{
return operationType == MemoryOperationType::Write ? _ppuWriteCounts[(int)addressType] : _ppuReadCounts[(int)addressType];
}
vector<int32_t>& MemoryAccessCounter::GetPpuStampArray(MemoryOperationType operationType, PpuAddressType addressType)
{
return operationType == MemoryOperationType::Write ? _ppuWriteStamps[(int)addressType] : _ppuReadStamps[(int)addressType];
}
bool MemoryAccessCounter::IsAddressUninitialized(AddressTypeInfo &addressInfo)
{
if(addressInfo.Type == AddressType::InternalRam || addressInfo.Type == AddressType::WorkRam) {
@ -50,18 +88,26 @@ bool MemoryAccessCounter::IsAddressUninitialized(AddressTypeInfo &addressInfo)
return false;
}
bool MemoryAccessCounter::ProcessMemoryAccess(AddressTypeInfo &addressInfo, MemoryOperationType operation, int32_t cpuCycle)
void MemoryAccessCounter::ProcessPpuMemoryAccess(PpuAddressTypeInfo &addressInfo, MemoryOperationType operation, int32_t cpuCycle)
{
int index = (int)addressInfo.Type;
vector<int> &counts = GetArray(operation, addressInfo.Type, false);
vector<int> &counts = GetPpuCountArray(operation, addressInfo.Type);
counts.data()[addressInfo.Address]++;
vector<int> &stamps = GetArray(operation, addressInfo.Type, true);
vector<int> &stamps = GetPpuStampArray(operation, addressInfo.Type);
stamps.data()[addressInfo.Address] = cpuCycle;
}
bool MemoryAccessCounter::ProcessMemoryAccess(AddressTypeInfo &addressInfo, MemoryOperationType operation, int32_t cpuCycle)
{
vector<int> &counts = GetCountArray(operation, addressInfo.Type);
counts.data()[addressInfo.Address]++;
vector<int> &stamps = GetStampArray(operation, addressInfo.Type);
stamps.data()[addressInfo.Address] = cpuCycle;
if(operation == MemoryOperationType::Read && (addressInfo.Type == AddressType::InternalRam || addressInfo.Type == AddressType::WorkRam) && !_writeCounts[index][addressInfo.Address]) {
if(operation == MemoryOperationType::Read && (addressInfo.Type == AddressType::InternalRam || addressInfo.Type == AddressType::WorkRam) && !_writeCounts[(int)addressInfo.Type][addressInfo.Address]) {
//Mark address as read before being written to (if trying to read/execute)
_uninitReads[index][addressInfo.Address] = true;
_uninitReads[(int)addressInfo.Type][addressInfo.Address] = true;
return true;
}
@ -79,17 +125,11 @@ void MemoryAccessCounter::ResetCounts()
memset(_readStamps[i].data(), 0, _readStamps[i].size() * sizeof(uint32_t));
memset(_writeStamps[i].data(), 0, _writeStamps[i].size() * sizeof(uint32_t));
memset(_execStamps[i].data(), 0, _execStamps[i].size() * sizeof(uint32_t));
}
}
void MemoryAccessCounter::GetAccessCounts(AddressType memoryType, MemoryOperationType operationType, uint32_t counts[], bool forUninitReads)
{
if(forUninitReads) {
for(size_t i = 0, len = _uninitReads[(int)memoryType].size(); i < len; i++) {
counts[i] = _uninitReads[(int)memoryType][i];
}
} else {
memcpy(counts, GetArray(operationType, memoryType, false).data(), GetArray(operationType, memoryType, false).size() * sizeof(uint32_t));
memset(_ppuReadCounts[i].data(), 0, _ppuReadCounts[i].size() * sizeof(uint32_t));
memset(_ppuWriteCounts[i].data(), 0, _ppuWriteCounts[i].size() * sizeof(uint32_t));
memset(_ppuReadStamps[i].data(), 0, _ppuReadStamps[i].size() * sizeof(uint32_t));
memset(_ppuWriteStamps[i].data(), 0, _ppuWriteStamps[i].size() * sizeof(uint32_t));
}
}
@ -99,57 +139,136 @@ void MemoryAccessCounter::GetAccessStamps(uint32_t offset, uint32_t length, Debu
default: break;
case DebugMemoryType::InternalRam:
memcpy(stamps, GetArray(operationType, AddressType::InternalRam, true).data() + offset, length * sizeof(uint32_t));
memcpy(stamps, GetStampArray(operationType, AddressType::InternalRam).data() + offset, length * sizeof(uint32_t));
break;
case DebugMemoryType::WorkRam:
memcpy(stamps, GetArray(operationType, AddressType::WorkRam, true).data() + offset, length * sizeof(uint32_t));
memcpy(stamps, GetStampArray(operationType, AddressType::WorkRam).data() + offset, length * sizeof(uint32_t));
break;
case DebugMemoryType::SaveRam:
memcpy(stamps, GetArray(operationType, AddressType::SaveRam, true).data() + offset, length * sizeof(uint32_t));
memcpy(stamps, GetStampArray(operationType, AddressType::SaveRam).data() + offset, length * sizeof(uint32_t));
break;
case DebugMemoryType::PrgRom:
memcpy(stamps, GetArray(operationType, AddressType::PrgRom, true).data() + offset, length * sizeof(uint32_t));
memcpy(stamps, GetStampArray(operationType, AddressType::PrgRom).data() + offset, length * sizeof(uint32_t));
break;
case DebugMemoryType::ChrRom:
memcpy(stamps, GetPpuStampArray(operationType, PpuAddressType::ChrRom).data() + offset, length * sizeof(uint32_t));
break;
case DebugMemoryType::ChrRam:
memcpy(stamps, GetPpuStampArray(operationType, PpuAddressType::ChrRam).data() + offset, length * sizeof(uint32_t));
break;
case DebugMemoryType::NametableRam:
memcpy(stamps, GetPpuStampArray(operationType, PpuAddressType::NametableRam).data() + offset, length * sizeof(uint32_t));
break;
case DebugMemoryType::PaletteMemory:
memcpy(stamps, GetPpuStampArray(operationType, PpuAddressType::PaletteRam).data() + offset, length * sizeof(uint32_t));
break;
case DebugMemoryType::CpuMemory:
for(uint32_t i = 0; i < length; i++) {
AddressTypeInfo info;
_debugger->GetAbsoluteAddressAndType(offset + i, &info);
stamps[i] = GetArray(operationType, info.Type, true).data()[info.Address];
stamps[i] = GetStampArray(operationType, info.Type).data()[info.Address];
}
break;
case DebugMemoryType::PpuMemory:
for(uint32_t i = 0; i < length; i++) {
PpuAddressTypeInfo info;
_debugger->GetPpuAbsoluteAddressAndType(offset + i, &info);
stamps[i] = GetPpuStampArray(operationType, info.Type).data()[info.Address];
}
break;
}
}
void MemoryAccessCounter::GetAccessCountsEx(uint32_t offset, uint32_t length, DebugMemoryType memoryType, MemoryOperationType operationType, int32_t counts[])
void MemoryAccessCounter::GetNametableChangedData(bool ntChangedData[])
{
PpuAddressTypeInfo addressInfo;
int32_t cpuCycle = _debugger->GetConsole()->GetCpu()->GetCycleCount();
int32_t cyclesPerFrame = _debugger->GetConsole()->GetCpu()->GetClockRate(_debugger->GetConsole()->GetModel()) / 60;
for(int i = 0; i < 0x1000; i++) {
_debugger->GetPpuAbsoluteAddressAndType(0x2000+i, &addressInfo);
if(addressInfo.Type != PpuAddressType::None) {
ntChangedData[i] = (cpuCycle - _ppuWriteStamps[(int)addressInfo.Type][addressInfo.Address]) < cyclesPerFrame;
} else {
ntChangedData[i] = false;
}
}
}
void MemoryAccessCounter::GetUninitMemoryReads(DebugMemoryType memoryType, int32_t counts[])
{
AddressType addressType;
switch(memoryType) {
default: return;
case DebugMemoryType::InternalRam: addressType = AddressType::InternalRam; break;
case DebugMemoryType::WorkRam: addressType = AddressType::WorkRam; break;
case DebugMemoryType::SaveRam: addressType = AddressType::SaveRam; break;
case DebugMemoryType::PrgRom: addressType = AddressType::PrgRom; break;
}
for(size_t i = 0, len = _uninitReads[(int)addressType].size(); i < len; i++) {
counts[i] = _uninitReads[(int)addressType][i];
}
}
void MemoryAccessCounter::GetAccessCounts(uint32_t offset, uint32_t length, DebugMemoryType memoryType, MemoryOperationType operationType, int32_t counts[])
{
switch(memoryType) {
default: break;
case DebugMemoryType::InternalRam:
memcpy(counts, GetArray(operationType, AddressType::InternalRam, false).data() + offset, length * sizeof(uint32_t));
memcpy(counts, GetCountArray(operationType, AddressType::InternalRam).data() + offset, length * sizeof(uint32_t));
break;
case DebugMemoryType::WorkRam:
memcpy(counts, GetArray(operationType, AddressType::WorkRam, false).data() + offset, length * sizeof(uint32_t));
memcpy(counts, GetCountArray(operationType, AddressType::WorkRam).data() + offset, length * sizeof(uint32_t));
break;
case DebugMemoryType::SaveRam:
memcpy(counts, GetArray(operationType, AddressType::SaveRam, false).data() + offset, length * sizeof(uint32_t));
memcpy(counts, GetCountArray(operationType, AddressType::SaveRam).data() + offset, length * sizeof(uint32_t));
break;
case DebugMemoryType::PrgRom:
memcpy(counts, GetArray(operationType, AddressType::PrgRom, false).data() + offset, length * sizeof(uint32_t));
memcpy(counts, GetCountArray(operationType, AddressType::PrgRom).data() + offset, length * sizeof(uint32_t));
break;
case DebugMemoryType::ChrRom:
memcpy(counts, GetPpuCountArray(operationType, PpuAddressType::ChrRom).data() + offset, length * sizeof(uint32_t));
break;
case DebugMemoryType::ChrRam:
memcpy(counts, GetPpuCountArray(operationType, PpuAddressType::ChrRam).data() + offset, length * sizeof(uint32_t));
break;
case DebugMemoryType::NametableRam:
memcpy(counts, GetPpuCountArray(operationType, PpuAddressType::NametableRam).data() + offset, length * sizeof(uint32_t));
break;
case DebugMemoryType::PaletteMemory:
memcpy(counts, GetPpuCountArray(operationType, PpuAddressType::PaletteRam).data() + offset, length * sizeof(uint32_t));
break;
case DebugMemoryType::CpuMemory:
for(uint32_t i = 0; i < length; i++) {
AddressTypeInfo info;
_debugger->GetAbsoluteAddressAndType(offset + i, &info);
counts[i] = GetArray(operationType, info.Type, false).data()[info.Address];
counts[i] = GetCountArray(operationType, info.Type).data()[info.Address];
}
break;
case DebugMemoryType::PpuMemory:
for(uint32_t i = 0; i < length; i++) {
PpuAddressTypeInfo info;
_debugger->GetPpuAbsoluteAddressAndType(offset + i, &info);
counts[i] = GetPpuCountArray(operationType, info.Type).data()[info.Address];
}
break;
}

View File

@ -19,17 +19,28 @@ private:
vector<uint8_t> _uninitReads[4];
vector<int32_t>& GetArray(MemoryOperationType operationType, AddressType addressType, bool stampArray);
vector<int32_t> _ppuReadCounts[4];
vector<int32_t> _ppuWriteCounts[4];
vector<int32_t> _ppuReadStamps[4];
vector<int32_t> _ppuWriteStamps[4];
vector<int32_t>& GetCountArray(MemoryOperationType operationType, AddressType addressType);
vector<int32_t>& GetStampArray(MemoryOperationType operationType, AddressType addressType);
vector<int32_t>& GetPpuCountArray(MemoryOperationType operationType, PpuAddressType addressType);
vector<int32_t>& GetPpuStampArray(MemoryOperationType operationType, PpuAddressType addressType);
public:
MemoryAccessCounter(Debugger* debugger);
void ProcessPpuMemoryAccess(PpuAddressTypeInfo &addressInfo, MemoryOperationType operation, int32_t cpuCycle);
bool ProcessMemoryAccess(AddressTypeInfo &addressInfo, MemoryOperationType operation, int32_t cpuCycle);
void ResetCounts();
bool IsAddressUninitialized(AddressTypeInfo &addressInfo);
void GetAccessCounts(AddressType memoryType, MemoryOperationType operationType, uint32_t counts[], bool forUninitReads);
void GetAccessCountsEx(uint32_t offset, uint32_t length, DebugMemoryType memoryType, MemoryOperationType operationType, int32_t counts[]);
void GetUninitMemoryReads(DebugMemoryType memoryType, int32_t counts[]);
void GetNametableChangedData(bool ntChangedData[]);
void GetAccessCounts(uint32_t offset, uint32_t length, DebugMemoryType memoryType, MemoryOperationType operationType, int32_t counts[]);
void GetAccessStamps(uint32_t offset, uint32_t length, DebugMemoryType memoryType, MemoryOperationType operationType, uint32_t stamps[]);
};

View File

@ -88,6 +88,7 @@ uint32_t MemoryDumper::GetMemorySize(DebugMemoryType type)
case DebugMemoryType::SpriteMemory: return 0x100;
case DebugMemoryType::SecondarySpriteMemory: return 0x20;
case DebugMemoryType::InternalRam: return 0x800;
case DebugMemoryType::NametableRam:
case DebugMemoryType::PrgRom:
case DebugMemoryType::ChrRom:
case DebugMemoryType::ChrRam:

View File

@ -194,6 +194,7 @@ namespace Mesen.GUI.Config
public bool NtViewerUseGrayscalePalette = false;
public bool NtViewerHighlightTileUpdates = false;
public bool NtViewerHighlightAttributeUpdates = false;
public bool NtViewerIgnoreRedundantWrites = false;
public int ChrViewerSelectedPalette = 0;
public CdlHighlightType ChrViewerHighlightType = CdlHighlightType.None;

View File

@ -81,9 +81,9 @@ namespace Mesen.GUI.Debugger
_freezeState = InteropEmu.DebugGetFreezeState((UInt16)firstByteIndex, (UInt16)visibleByteCount);
}
_readCounts = InteropEmu.DebugGetMemoryAccessCountsEx((UInt32)firstByteIndex, (UInt32)visibleByteCount, _memoryType, MemoryOperationType.Read);
_writeCounts = InteropEmu.DebugGetMemoryAccessCountsEx((UInt32)firstByteIndex, (UInt32)visibleByteCount, _memoryType, MemoryOperationType.Write);
_execCounts = InteropEmu.DebugGetMemoryAccessCountsEx((UInt32)firstByteIndex, (UInt32)visibleByteCount, _memoryType, MemoryOperationType.Exec);
_readCounts = InteropEmu.DebugGetMemoryAccessCounts((UInt32)firstByteIndex, (UInt32)visibleByteCount, _memoryType, MemoryOperationType.Read);
_writeCounts = InteropEmu.DebugGetMemoryAccessCounts((UInt32)firstByteIndex, (UInt32)visibleByteCount, _memoryType, MemoryOperationType.Write);
_execCounts = InteropEmu.DebugGetMemoryAccessCounts((UInt32)firstByteIndex, (UInt32)visibleByteCount, _memoryType, MemoryOperationType.Exec);
_cdlData = null;
if(_highlightDmcDataBytes || _highlightDataBytes || _highlightCodeBytes) {
@ -116,7 +116,7 @@ namespace Mesen.GUI.Debugger
InteropEmu.DebugGetState(ref _state);
}
public Color DarkerColor(Color input, double brightnessPercentage)
public static Color DarkerColor(Color input, double brightnessPercentage)
{
if(double.IsInfinity(brightnessPercentage)) {
brightnessPercentage = 1.0;

View File

@ -9,6 +9,17 @@ namespace Mesen.GUI.Debugger
public class ChrByteColorProvider : IByteColorProvider
{
DebugMemoryType _memoryType;
Int32[] _readStamps;
Int32[] _writeStamps;
Int32[] _readCounts;
Int32[] _writeCounts;
DebugState _state = new DebugState();
bool _showWrite;
bool _showRead;
int _framesToFade;
bool _hideUnusedBytes;
bool _hideReadBytes;
bool _hideWrittenBytes;
bool _highlightDrawnBytes;
bool _highlightReadBytes;
bool _highlightBreakpoints;
@ -16,9 +27,15 @@ namespace Mesen.GUI.Debugger
ByteColors _colors = new ByteColors();
BreakpointType[] _breakpointTypes;
public ChrByteColorProvider(DebugMemoryType memoryType, bool highlightDrawnBytes, bool highlightReadBytes, bool highlightBreakpoints)
public ChrByteColorProvider(DebugMemoryType memoryType, bool showWrite, bool showRead, int framesToFade, bool hideUnusedBytes, bool hideReadBytes, bool hideWrittenBytes, bool highlightDrawnBytes, bool highlightReadBytes, bool highlightBreakpoints)
{
_memoryType = memoryType;
_showWrite = showWrite;
_showRead = showRead;
_framesToFade = framesToFade;
_hideUnusedBytes = hideUnusedBytes;
_hideReadBytes = hideReadBytes;
_hideWrittenBytes = hideWrittenBytes;
_highlightDrawnBytes = highlightDrawnBytes;
_highlightReadBytes = highlightReadBytes;
_highlightBreakpoints = highlightBreakpoints;
@ -46,7 +63,14 @@ namespace Mesen.GUI.Debugger
_breakpointTypes = null;
}
if(_memoryType == DebugMemoryType.ChrRam && (_highlightDrawnBytes || _highlightReadBytes)) {
InteropEmu.DebugGetState(ref _state);
_readStamps = InteropEmu.DebugGetMemoryAccessStamps((UInt32)firstByteIndex, (UInt32)visibleByteCount, _memoryType, MemoryOperationType.Read);
_writeStamps = InteropEmu.DebugGetMemoryAccessStamps((UInt32)firstByteIndex, (UInt32)visibleByteCount, _memoryType, MemoryOperationType.Write);
_readCounts = InteropEmu.DebugGetMemoryAccessCounts((UInt32)firstByteIndex, (UInt32)visibleByteCount, _memoryType, MemoryOperationType.Read);
_writeCounts = InteropEmu.DebugGetMemoryAccessCounts((UInt32)firstByteIndex, (UInt32)visibleByteCount, _memoryType, MemoryOperationType.Write);
if(_memoryType == DebugMemoryType.ChrRom && (_highlightDrawnBytes || _highlightReadBytes)) {
_cdlData = InteropEmu.DebugGetCdlData((UInt32)firstByteIndex, (UInt32)visibleByteCount, _memoryType);
} else {
_cdlData = null;
@ -55,7 +79,22 @@ namespace Mesen.GUI.Debugger
public ByteColors GetByteColor(long firstByteIndex, long byteIndex)
{
const int CyclesPerFrame = 29780;
long index = byteIndex - firstByteIndex;
double framesSinceWrite = (double)(_state.CPU.CycleCount - _writeStamps[index]) / CyclesPerFrame;
double framesSinceRead = (double)(_state.CPU.CycleCount - _readStamps[index]) / CyclesPerFrame;
bool isRead = _readCounts[index] > 0;
bool isWritten = _writeCounts[index] > 0;
bool isUnused = !isRead && !isWritten;
int alpha = 0;
if(isRead && _hideReadBytes || isWritten && _hideWrittenBytes || isUnused && _hideUnusedBytes) {
alpha = 128;
}
if(isRead && !_hideReadBytes || isWritten && !_hideWrittenBytes || isUnused && !_hideUnusedBytes) {
alpha = 255;
}
_colors.BackColor = Color.Transparent;
if(_cdlData != null) {
@ -76,6 +115,14 @@ namespace Mesen.GUI.Debugger
}
}
if(_showWrite && _writeStamps[index] != 0 && framesSinceWrite >= 0 && (framesSinceWrite < _framesToFade || _framesToFade == 0)) {
_colors.ForeColor = Color.FromArgb(alpha, ByteColorProvider.DarkerColor(ConfigManager.Config.DebugInfo.RamWriteColor, (_framesToFade - framesSinceWrite) / _framesToFade));
} else if(_showRead && _readStamps[index] != 0 && framesSinceRead >= 0 && (framesSinceRead < _framesToFade || _framesToFade == 0)) {
_colors.ForeColor = Color.FromArgb(alpha, ByteColorProvider.DarkerColor(ConfigManager.Config.DebugInfo.RamReadColor, (_framesToFade - framesSinceRead) / _framesToFade));
} else {
_colors.ForeColor = Color.FromArgb(alpha, Color.Black);
}
return _colors;
}
}

View File

@ -16,7 +16,7 @@ namespace Mesen.GUI.Debugger.Controls
public partial class ctrlMemoryAccessCounters : BaseControl
{
private MemoryCountData[] _data;
private AddressType _memoryType = AddressType.InternalRam;
private DebugMemoryType _memoryType = DebugMemoryType.InternalRam;
private SortType _sortType = SortType.Address;
public ctrlMemoryAccessCounters()
@ -46,22 +46,31 @@ namespace Mesen.GUI.Debugger.Controls
{
cboMemoryType.SelectedIndexChanged -= cboMemoryType_SelectedIndexChanged;
AddressType originalValue = cboMemoryType.GetEnumValue<AddressType>();
DebugMemoryType originalValue = cboMemoryType.GetEnumValue<DebugMemoryType>();
cboMemoryType.BeginUpdate();
cboMemoryType.Items.Clear();
cboMemoryType.Items.Add(ResourceHelper.GetEnumText(AddressType.InternalRam));
cboMemoryType.Items.Add(ResourceHelper.GetEnumText(DebugMemoryType.InternalRam));
if(InteropEmu.DebugGetMemorySize(DebugMemoryType.PrgRom) > 0) {
cboMemoryType.Items.Add(ResourceHelper.GetEnumText(AddressType.PrgRom));
cboMemoryType.Items.Add(ResourceHelper.GetEnumText(DebugMemoryType.PrgRom));
}
if(InteropEmu.DebugGetMemorySize(DebugMemoryType.WorkRam) > 0) {
cboMemoryType.Items.Add(ResourceHelper.GetEnumText(AddressType.WorkRam));
cboMemoryType.Items.Add(ResourceHelper.GetEnumText(DebugMemoryType.WorkRam));
}
if(InteropEmu.DebugGetMemorySize(DebugMemoryType.SaveRam) > 0) {
cboMemoryType.Items.Add(ResourceHelper.GetEnumText(AddressType.SaveRam));
cboMemoryType.Items.Add(ResourceHelper.GetEnumText(DebugMemoryType.SaveRam));
}
if(InteropEmu.DebugGetMemorySize(DebugMemoryType.ChrRom) > 0) {
cboMemoryType.Items.Add(ResourceHelper.GetEnumText(DebugMemoryType.ChrRom));
}
if(InteropEmu.DebugGetMemorySize(DebugMemoryType.ChrRam) > 0) {
cboMemoryType.Items.Add(ResourceHelper.GetEnumText(DebugMemoryType.ChrRam));
}
cboMemoryType.Items.Add(ResourceHelper.GetEnumText(DebugMemoryType.PaletteMemory));
cboMemoryType.Items.Add(ResourceHelper.GetEnumText(DebugMemoryType.NametableRam));
cboMemoryType.SelectedIndex = 0;
cboMemoryType.SetEnumValue(originalValue);
cboMemoryType.SelectedIndexChanged += cboMemoryType_SelectedIndexChanged;
@ -75,11 +84,18 @@ namespace Mesen.GUI.Debugger.Controls
public void RefreshData()
{
int[] readCounts = InteropEmu.DebugGetMemoryAccessCounts(_memoryType, MemoryOperationType.Read, false);
int[] writeCounts = InteropEmu.DebugGetMemoryAccessCounts(_memoryType, MemoryOperationType.Write, false);
int[] execCounts = InteropEmu.DebugGetMemoryAccessCounts(_memoryType, MemoryOperationType.Exec, false);
bool isPpu = (
_memoryType == DebugMemoryType.ChrRom ||
_memoryType == DebugMemoryType.ChrRam ||
_memoryType == DebugMemoryType.PaletteMemory ||
_memoryType == DebugMemoryType.NametableRam
);
int[] uninitReads = InteropEmu.DebugGetMemoryAccessCounts(_memoryType, MemoryOperationType.Read, true);
int[] readCounts = InteropEmu.DebugGetMemoryAccessCounts(_memoryType, MemoryOperationType.Read);
int[] writeCounts = InteropEmu.DebugGetMemoryAccessCounts(_memoryType, MemoryOperationType.Write);
int[] execCounts = isPpu ? new int[readCounts.Length] : InteropEmu.DebugGetMemoryAccessCounts(_memoryType, MemoryOperationType.Exec);
int[] uninitReads = isPpu ? new int[readCounts.Length] : InteropEmu.DebugGetUninitMemoryReads(_memoryType);
List<int> addresses = new List<int>(readCounts.Length);
List<string> content = new List<string>(readCounts.Length);
@ -97,6 +113,7 @@ namespace Mesen.GUI.Debugger.Controls
_data[i].WriteCount = writeCounts[i];
_data[i].ExecCount = execCounts[i];
_data[i].UninitRead = uninitReads[i] > 0;
_data[i].IsPpu = isPpu;
}
MemoryCountData[] data = new MemoryCountData[readCounts.Length];
@ -123,7 +140,11 @@ namespace Mesen.GUI.Debugger.Controls
} else {
ctrlScrollableTextbox.StyleProvider = null;
}
ctrlScrollableTextbox.Header = " " + "Read".PadRight(12) + "Write".PadRight(12) + "Execute";
if(isPpu) {
ctrlScrollableTextbox.Header = " " + "Read".PadRight(12) + "Write";
} else {
ctrlScrollableTextbox.Header = " " + "Read".PadRight(12) + "Write".PadRight(12) + "Execute";
}
ctrlScrollableTextbox.LineNumbers = addresses.ToArray();
ctrlScrollableTextbox.TextLines = content.ToArray();
}
@ -158,7 +179,7 @@ namespace Mesen.GUI.Debugger.Controls
private void UpdateMemoryType()
{
_memoryType = cboMemoryType.GetEnumValue<AddressType>();
_memoryType = cboMemoryType.GetEnumValue<DebugMemoryType>();
RefreshData();
}
@ -248,7 +269,7 @@ namespace Mesen.GUI.Debugger.Controls
if(this._needRecalc) {
_content = " " + (_readCount == 0 ? "0" : _readCount.ToString()).PadRight(12) +
(_writeCount == 0 ? "0" : _writeCount.ToString()).PadRight(12) +
(_execCount == 0 ? "0" : _execCount.ToString());
(IsPpu ? "" : (_execCount == 0 ? "0" : _execCount.ToString()));
_needRecalc = false;
}
return _content;
@ -256,6 +277,7 @@ namespace Mesen.GUI.Debugger.Controls
}
public bool UninitRead { get; set; }
public bool IsPpu { get; set; }
}
private void mnuCopy_Click(object sender, EventArgs e)

View File

@ -32,7 +32,7 @@ namespace Mesen.GUI.Debugger.Controls
this.components = new System.ComponentModel.Container();
this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel();
this.picNametable = new System.Windows.Forms.PictureBox();
this.ctxMenu = new ctrlMesenContextMenuStrip(this.components);
this.ctxMenu = new Mesen.GUI.Controls.ctrlMesenContextMenuStrip(this.components);
this.mnuEditInMemoryViewer = new System.Windows.Forms.ToolStripMenuItem();
this.mnuShowInChrViewer = new System.Windows.Forms.ToolStripMenuItem();
this.toolStripMenuItem1 = new System.Windows.Forms.ToolStripSeparator();
@ -67,12 +67,14 @@ namespace Mesen.GUI.Debugger.Controls
this.chkShowTileGrid = new System.Windows.Forms.CheckBox();
this.chkShowAttributeGrid = new System.Windows.Forms.CheckBox();
this.chkUseGrayscalePalette = new System.Windows.Forms.CheckBox();
this.chkHighlightTileUpdates = new System.Windows.Forms.CheckBox();
this.chkHighlightAttributeUpdates = new System.Windows.Forms.CheckBox();
this.chkHighlightChrTile = new System.Windows.Forms.CheckBox();
this.tableLayoutPanel3 = new System.Windows.Forms.TableLayoutPanel();
this.lblMirroring = new System.Windows.Forms.Label();
this.lblMirroringType = new System.Windows.Forms.Label();
this.chkHighlightTileUpdates = new System.Windows.Forms.CheckBox();
this.chkHighlightAttributeUpdates = new System.Windows.Forms.CheckBox();
this.lblHighlight = new System.Windows.Forms.Label();
this.chkIgnoreRedundantWrites = new System.Windows.Forms.CheckBox();
this.tableLayoutPanel1.SuspendLayout();
((System.ComponentModel.ISupportInitialize)(this.picNametable)).BeginInit();
this.ctxMenu.SuspendLayout();
@ -92,6 +94,7 @@ namespace Mesen.GUI.Debugger.Controls
this.tableLayoutPanel1.Controls.Add(this.grpTileInfo, 1, 0);
this.tableLayoutPanel1.Controls.Add(this.flowLayoutPanel1, 1, 1);
this.tableLayoutPanel1.Controls.Add(this.tableLayoutPanel3, 0, 2);
this.tableLayoutPanel1.Controls.Add(this.chkIgnoreRedundantWrites, 0, 3);
this.tableLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Fill;
this.tableLayoutPanel1.Location = new System.Drawing.Point(0, 0);
this.tableLayoutPanel1.Name = "tableLayoutPanel1";
@ -108,7 +111,7 @@ namespace Mesen.GUI.Debugger.Controls
this.picNametable.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
this.picNametable.ContextMenuStrip = this.ctxMenu;
this.picNametable.Location = new System.Drawing.Point(4, 4);
this.picNametable.Margin = new System.Windows.Forms.Padding(4);
this.picNametable.Margin = new System.Windows.Forms.Padding(4, 4, 4, 0);
this.picNametable.Name = "picNametable";
this.tableLayoutPanel1.SetRowSpan(this.picNametable, 2);
this.picNametable.Size = new System.Drawing.Size(514, 482);
@ -438,8 +441,6 @@ namespace Mesen.GUI.Debugger.Controls
this.flowLayoutPanel1.Controls.Add(this.chkShowTileGrid);
this.flowLayoutPanel1.Controls.Add(this.chkShowAttributeGrid);
this.flowLayoutPanel1.Controls.Add(this.chkUseGrayscalePalette);
this.flowLayoutPanel1.Controls.Add(this.chkHighlightTileUpdates);
this.flowLayoutPanel1.Controls.Add(this.chkHighlightAttributeUpdates);
this.flowLayoutPanel1.Controls.Add(this.chkHighlightChrTile);
this.flowLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Fill;
this.flowLayoutPanel1.Location = new System.Drawing.Point(522, 351);
@ -493,32 +494,10 @@ namespace Mesen.GUI.Debugger.Controls
this.chkUseGrayscalePalette.UseVisualStyleBackColor = true;
this.chkUseGrayscalePalette.Click += new System.EventHandler(this.chkUseGrayscalePalette_Click);
//
// chkHighlightTileUpdates
//
this.chkHighlightTileUpdates.AutoSize = true;
this.chkHighlightTileUpdates.Location = new System.Drawing.Point(3, 95);
this.chkHighlightTileUpdates.Name = "chkHighlightTileUpdates";
this.chkHighlightTileUpdates.Size = new System.Drawing.Size(130, 17);
this.chkHighlightTileUpdates.TabIndex = 6;
this.chkHighlightTileUpdates.Text = "Highlight Tile Updates";
this.chkHighlightTileUpdates.UseVisualStyleBackColor = true;
this.chkHighlightTileUpdates.Click += new System.EventHandler(this.chkHighlightTileUpdates_Click);
//
// chkHighlightAttributeUpdates
//
this.chkHighlightAttributeUpdates.AutoSize = true;
this.chkHighlightAttributeUpdates.Location = new System.Drawing.Point(3, 118);
this.chkHighlightAttributeUpdates.Name = "chkHighlightAttributeUpdates";
this.chkHighlightAttributeUpdates.Size = new System.Drawing.Size(152, 17);
this.chkHighlightAttributeUpdates.TabIndex = 7;
this.chkHighlightAttributeUpdates.Text = "Highlight Attribute Updates";
this.chkHighlightAttributeUpdates.UseVisualStyleBackColor = true;
this.chkHighlightAttributeUpdates.Click += new System.EventHandler(this.chkHighlightAttributeUpdates_Click);
//
// chkHighlightChrTile
//
this.chkHighlightChrTile.CheckAlign = System.Drawing.ContentAlignment.TopLeft;
this.chkHighlightChrTile.Location = new System.Drawing.Point(3, 141);
this.chkHighlightChrTile.Location = new System.Drawing.Point(3, 95);
this.chkHighlightChrTile.Name = "chkHighlightChrTile";
this.chkHighlightChrTile.Size = new System.Drawing.Size(150, 31);
this.chkHighlightChrTile.TabIndex = 4;
@ -528,25 +507,32 @@ namespace Mesen.GUI.Debugger.Controls
//
// tableLayoutPanel3
//
this.tableLayoutPanel3.ColumnCount = 3;
this.tableLayoutPanel3.ColumnCount = 6;
this.tableLayoutPanel3.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
this.tableLayoutPanel3.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
this.tableLayoutPanel3.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F));
this.tableLayoutPanel3.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
this.tableLayoutPanel3.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
this.tableLayoutPanel3.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
this.tableLayoutPanel3.Controls.Add(this.lblMirroring, 0, 0);
this.tableLayoutPanel3.Controls.Add(this.lblMirroringType, 1, 0);
this.tableLayoutPanel3.Controls.Add(this.chkHighlightTileUpdates, 4, 0);
this.tableLayoutPanel3.Controls.Add(this.chkHighlightAttributeUpdates, 5, 0);
this.tableLayoutPanel3.Controls.Add(this.lblHighlight, 3, 0);
this.tableLayoutPanel3.Dock = System.Windows.Forms.DockStyle.Fill;
this.tableLayoutPanel3.Location = new System.Drawing.Point(0, 490);
this.tableLayoutPanel3.Location = new System.Drawing.Point(0, 486);
this.tableLayoutPanel3.Margin = new System.Windows.Forms.Padding(0);
this.tableLayoutPanel3.Name = "tableLayoutPanel3";
this.tableLayoutPanel3.RowCount = 1;
this.tableLayoutPanel3.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F));
this.tableLayoutPanel3.Size = new System.Drawing.Size(522, 16);
this.tableLayoutPanel3.Size = new System.Drawing.Size(522, 20);
this.tableLayoutPanel3.TabIndex = 6;
//
// lblMirroring
//
this.lblMirroring.Anchor = System.Windows.Forms.AnchorStyles.Left;
this.lblMirroring.AutoSize = true;
this.lblMirroring.Location = new System.Drawing.Point(3, 0);
this.lblMirroring.Location = new System.Drawing.Point(3, 3);
this.lblMirroring.Name = "lblMirroring";
this.lblMirroring.Size = new System.Drawing.Size(80, 13);
this.lblMirroring.TabIndex = 0;
@ -554,14 +540,64 @@ namespace Mesen.GUI.Debugger.Controls
//
// lblMirroringType
//
this.lblMirroringType.Anchor = System.Windows.Forms.AnchorStyles.Left;
this.lblMirroringType.AutoSize = true;
this.lblMirroringType.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.lblMirroringType.Location = new System.Drawing.Point(89, 0);
this.lblMirroringType.Location = new System.Drawing.Point(89, 3);
this.lblMirroringType.Name = "lblMirroringType";
this.lblMirroringType.Size = new System.Drawing.Size(64, 13);
this.lblMirroringType.TabIndex = 1;
this.lblMirroringType.Text = "Horizontal";
//
// chkHighlightTileUpdates
//
this.chkHighlightTileUpdates.Anchor = System.Windows.Forms.AnchorStyles.Left;
this.chkHighlightTileUpdates.AutoSize = true;
this.chkHighlightTileUpdates.Location = new System.Drawing.Point(319, 3);
this.chkHighlightTileUpdates.Margin = new System.Windows.Forms.Padding(3, 3, 3, 0);
this.chkHighlightTileUpdates.Name = "chkHighlightTileUpdates";
this.chkHighlightTileUpdates.Size = new System.Drawing.Size(86, 17);
this.chkHighlightTileUpdates.TabIndex = 6;
this.chkHighlightTileUpdates.Text = "Tile Updates";
this.chkHighlightTileUpdates.UseVisualStyleBackColor = true;
this.chkHighlightTileUpdates.Click += new System.EventHandler(this.chkHighlightTileUpdates_Click);
//
// chkHighlightAttributeUpdates
//
this.chkHighlightAttributeUpdates.Anchor = System.Windows.Forms.AnchorStyles.Left;
this.chkHighlightAttributeUpdates.AutoSize = true;
this.chkHighlightAttributeUpdates.Location = new System.Drawing.Point(411, 3);
this.chkHighlightAttributeUpdates.Margin = new System.Windows.Forms.Padding(3, 3, 3, 0);
this.chkHighlightAttributeUpdates.Name = "chkHighlightAttributeUpdates";
this.chkHighlightAttributeUpdates.Size = new System.Drawing.Size(108, 17);
this.chkHighlightAttributeUpdates.TabIndex = 7;
this.chkHighlightAttributeUpdates.Text = "Attribute Updates";
this.chkHighlightAttributeUpdates.UseVisualStyleBackColor = true;
this.chkHighlightAttributeUpdates.Click += new System.EventHandler(this.chkHighlightAttributeUpdates_Click);
//
// lblHighlight
//
this.lblHighlight.Anchor = System.Windows.Forms.AnchorStyles.Left;
this.lblHighlight.AutoSize = true;
this.lblHighlight.Location = new System.Drawing.Point(262, 3);
this.lblHighlight.Name = "lblHighlight";
this.lblHighlight.Size = new System.Drawing.Size(51, 13);
this.lblHighlight.TabIndex = 2;
this.lblHighlight.Text = "Highlight:";
//
// chkIgnoreRedundantWrites
//
this.chkIgnoreRedundantWrites.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
this.chkIgnoreRedundantWrites.AutoSize = true;
this.chkIgnoreRedundantWrites.Location = new System.Drawing.Point(332, 507);
this.chkIgnoreRedundantWrites.Margin = new System.Windows.Forms.Padding(3, 1, 3, 0);
this.chkIgnoreRedundantWrites.Name = "chkIgnoreRedundantWrites";
this.chkIgnoreRedundantWrites.Size = new System.Drawing.Size(187, 17);
this.chkIgnoreRedundantWrites.TabIndex = 7;
this.chkIgnoreRedundantWrites.Text = "Ignore writes that do not alter data";
this.chkIgnoreRedundantWrites.UseVisualStyleBackColor = true;
this.chkIgnoreRedundantWrites.Click += new System.EventHandler(this.chkIgnoreRedundantWrites_Click);
//
// ctrlNametableViewer
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
@ -631,5 +667,7 @@ namespace Mesen.GUI.Debugger.Controls
private System.Windows.Forms.ToolStripSeparator toolStripMenuItem2;
private System.Windows.Forms.ToolStripMenuItem mnuExportToPng;
private System.Windows.Forms.ToolStripMenuItem mnuEditInMemoryViewer;
private System.Windows.Forms.Label lblHighlight;
private System.Windows.Forms.CheckBox chkIgnoreRedundantWrites;
}
}

View File

@ -37,6 +37,7 @@ namespace Mesen.GUI.Debugger.Controls
private DebugState _state = new DebugState();
private HdPackCopyHelper _hdCopyHelper = new HdPackCopyHelper();
private bool _firstDraw = true;
private bool[] _ntChanged = null;
public ctrlNametableViewer()
{
@ -51,6 +52,9 @@ namespace Mesen.GUI.Debugger.Controls
chkUseGrayscalePalette.Checked = ConfigManager.Config.DebugInfo.NtViewerUseGrayscalePalette;
chkHighlightTileUpdates.Checked = ConfigManager.Config.DebugInfo.NtViewerHighlightTileUpdates;
chkHighlightAttributeUpdates.Checked = ConfigManager.Config.DebugInfo.NtViewerHighlightAttributeUpdates;
chkIgnoreRedundantWrites.Checked = ConfigManager.Config.DebugInfo.NtViewerIgnoreRedundantWrites;
UpdateIgnoreWriteCheckbox();
}
}
@ -81,6 +85,8 @@ namespace Mesen.GUI.Debugger.Controls
InteropEmu.DebugGetPpuScroll(out _xScroll, out _yScroll);
InteropEmu.DebugGetState(ref _state);
_ntChanged = InteropEmu.DebugGetNametableChangedData();
//Keep a copy of the previous frame to highlight modifications
for(int i = 0; i < 4; i++) {
_prevTileData[i] = _tileData[i] != null ? (byte[])_tileData[i].Clone() : null;
@ -168,30 +174,45 @@ namespace Mesen.GUI.Debugger.Controls
private void DrawEditHighlights(Graphics g)
{
bool ignoreRedundantWrites = chkIgnoreRedundantWrites.Checked;
using(Brush redBrush = new SolidBrush(Color.FromArgb(128, Color.Red))) {
using(Brush yellowBrush = new SolidBrush(Color.FromArgb(128, Color.Yellow))) {
for(int nt = 0; nt < 4; nt++) {
if(_prevTileData[nt] == null || _prevAttributeData[nt] == null) {
if(_prevTileData[nt] == null || _prevAttributeData[nt] == null || _ntChanged == null) {
continue;
}
int ntBaseAddress = nt * 0x400;
for(int y = 0; y < 30; y++) {
for(int x = 0; x < 32; x++) {
int tileX = ((nt % 2 == 1) ? x + 32 : x) * 8;
int tileY = ((nt >= 2) ? y + 30 : y) * 8;
if(chkHighlightTileUpdates.Checked && _prevTileData[nt][y * 32 + x] != _tileData[nt][y * 32 + x]) {
bool tileChanged = false;
bool attrChanged = false;
if(ignoreRedundantWrites) {
tileChanged = _prevTileData[nt][y * 32 + x] != _tileData[nt][y * 32 + x];
int shift = (x & 0x02) | ((y & 0x02) << 1);
int attribute = (_attributeData[nt][y * 32 + x] >> shift) & 0x03;
int prevAttribute = (_prevAttributeData[nt][y * 32 + x] >> shift) & 0x03;
attrChanged = attribute != prevAttribute;
} else {
int tileAddress = ntBaseAddress + y * 32 + x;
int attrAddress = ntBaseAddress + 32 * 30 + ((y & 0xFC) << 1) + (x >> 2);
tileChanged = _ntChanged[tileAddress];
attrChanged = _ntChanged[attrAddress];
}
if(chkHighlightTileUpdates.Checked && tileChanged) {
g.FillRectangle(redBrush, tileX, tileY, 8, 8);
g.DrawRectangle(Pens.Red, tileX, tileY, 8, 8);
}
if(chkHighlightAttributeUpdates.Checked) {
int shift = (x & 0x02) | ((y & 0x02) << 1);
int attribute = (_attributeData[nt][y * 32 + x] >> shift) & 0x03;
int prevAttribute = (_prevAttributeData[nt][y * 32 + x] >> shift) & 0x03;
if(prevAttribute != attribute) {
g.FillRectangle(yellowBrush, tileX, tileY, 8, 8);
g.DrawRectangle(Pens.Yellow, tileX, tileY, 8, 8);
}
if(chkHighlightAttributeUpdates.Checked && attrChanged) {
g.FillRectangle(yellowBrush, tileX, tileY, 8, 8);
g.DrawRectangle(Pens.Yellow, tileX, tileY, 8, 8);
}
}
}
@ -368,6 +389,7 @@ namespace Mesen.GUI.Debugger.Controls
ConfigManager.Config.DebugInfo.NtViewerHighlightTileUpdates = chkHighlightTileUpdates.Checked;
ConfigManager.ApplyChanges();
this.RefreshViewer();
UpdateIgnoreWriteCheckbox();
}
private void chkHighlightAttributeUpdates_Click(object sender, EventArgs e)
@ -375,6 +397,19 @@ namespace Mesen.GUI.Debugger.Controls
ConfigManager.Config.DebugInfo.NtViewerHighlightAttributeUpdates = chkHighlightAttributeUpdates.Checked;
ConfigManager.ApplyChanges();
this.RefreshViewer();
UpdateIgnoreWriteCheckbox();
}
private void chkIgnoreRedundantWrites_Click(object sender, EventArgs e)
{
ConfigManager.Config.DebugInfo.NtViewerIgnoreRedundantWrites = chkIgnoreRedundantWrites.Checked;
ConfigManager.ApplyChanges();
this.RefreshViewer();
}
private void UpdateIgnoreWriteCheckbox()
{
chkIgnoreRedundantWrites.Enabled = chkHighlightAttributeUpdates.Checked || chkHighlightTileUpdates.Checked;
}
string _copyData;

View File

@ -333,6 +333,12 @@ namespace Mesen.GUI.Debugger
case DebugMemoryType.PaletteMemory:
this.ctrlHexViewer.ByteColorProvider = new ChrByteColorProvider(
this._memoryType,
mnuHighlightWrites.Checked,
mnuHightlightReads.Checked,
ConfigManager.Config.DebugInfo.RamFadeSpeed,
mnuHideUnusedBytes.Checked,
mnuHideReadBytes.Checked,
mnuHideWrittenBytes.Checked,
mnuHighlightChrDrawnBytes.Checked,
mnuHighlightChrReadBytes.Checked,
mnuHighlightBreakpoints.Checked

View File

@ -1105,6 +1105,7 @@
<Value ID="WorkRam">Work RAM</Value>
<Value ID="SaveRam">Save RAM</Value>
<Value ID="InternalRam">NES RAM (2 KB)</Value>
<Value ID="NametableRam">Nametable RAM</Value>
</Enum>
<Enum ID="AddrMode">
<Value ID="None">None</Value>

View File

@ -511,15 +511,24 @@ namespace Mesen.GUI
return profileData;
}
[DllImport(DLLPath, EntryPoint = "DebugGetMemoryAccessCounts")] private static extern void DebugGetMemoryAccessCountsWrapper(AddressType type, MemoryOperationType operationType, IntPtr counts, [MarshalAs(UnmanagedType.I1)]bool forUninitReads);
public static Int32[] DebugGetMemoryAccessCounts(AddressType type, MemoryOperationType operationType, bool forUninitReads)
public static Int32[] DebugGetMemoryAccessCounts(DebugMemoryType type, MemoryOperationType operationType)
{
int size = 0;
switch(type) {
case AddressType.InternalRam: size = 0x2000; break;
case AddressType.PrgRom: size = InteropEmu.DebugGetMemorySize(DebugMemoryType.PrgRom); break;
case AddressType.WorkRam: size = InteropEmu.DebugGetMemorySize(DebugMemoryType.WorkRam); break;
case AddressType.SaveRam: size = InteropEmu.DebugGetMemorySize(DebugMemoryType.SaveRam); break;
int size = InteropEmu.DebugGetMemorySize(type);
return InteropEmu.DebugGetMemoryAccessCounts(0, (uint)size, type, operationType);
}
public static Int32[] DebugGetMemoryAccessStamps(DebugMemoryType type, MemoryOperationType operationType)
{
int size = InteropEmu.DebugGetMemorySize(type);
return InteropEmu.DebugGetMemoryAccessStamps(0, (uint)size, type, operationType);
}
[DllImport(DLLPath, EntryPoint = "DebugGetUninitMemoryReads")] private static extern void DebugGetUninitMemoryReadsWrapper(DebugMemoryType type, IntPtr counts);
public static Int32[] DebugGetUninitMemoryReads(DebugMemoryType type)
{
int size = InteropEmu.DebugGetMemorySize(type);
if(type == DebugMemoryType.InternalRam) {
size = 0x2000;
}
Int32[] counts = new Int32[size];
@ -527,7 +536,7 @@ namespace Mesen.GUI
if(size > 0) {
GCHandle hCounts = GCHandle.Alloc(counts, GCHandleType.Pinned);
try {
InteropEmu.DebugGetMemoryAccessCountsWrapper(type, operationType, hCounts.AddrOfPinnedObject(), forUninitReads);
InteropEmu.DebugGetUninitMemoryReadsWrapper(type, hCounts.AddrOfPinnedObject());
} finally {
hCounts.Free();
}
@ -551,20 +560,35 @@ namespace Mesen.GUI
return stamps;
}
[DllImport(DLLPath, EntryPoint = "DebugGetMemoryAccessCountsEx")] private static extern void DebugGetMemoryAccessCountsExWrapper(UInt32 offset, UInt32 length, DebugMemoryType type, MemoryOperationType operationType, IntPtr counts);
public static Int32[] DebugGetMemoryAccessCountsEx(UInt32 offset, UInt32 length, DebugMemoryType type, MemoryOperationType operationType)
[DllImport(DLLPath, EntryPoint = "DebugGetMemoryAccessCounts")] private static extern void DebugGetMemoryAccessCountsWrapper(UInt32 offset, UInt32 length, DebugMemoryType type, MemoryOperationType operationType, IntPtr counts);
public static Int32[] DebugGetMemoryAccessCounts(UInt32 offset, UInt32 length, DebugMemoryType type, MemoryOperationType operationType)
{
Int32[] counts = new Int32[length];
GCHandle hResult = GCHandle.Alloc(counts, GCHandleType.Pinned);
try {
InteropEmu.DebugGetMemoryAccessCountsExWrapper(offset, length, type, operationType, hResult.AddrOfPinnedObject());
InteropEmu.DebugGetMemoryAccessCountsWrapper(offset, length, type, operationType, hResult.AddrOfPinnedObject());
} finally {
hResult.Free();
}
return counts;
}
[DllImport(DLLPath, EntryPoint = "DebugGetNametableChangedData")] private static extern void DebugGetNametableChangedDataWrapper(IntPtr ntChangedData);
public static bool[] DebugGetNametableChangedData()
{
bool[] ntChangedData = new bool[0x1000];
GCHandle hNtChangedData = GCHandle.Alloc(ntChangedData, GCHandleType.Pinned);
try {
InteropEmu.DebugGetNametableChangedDataWrapper(hNtChangedData.AddrOfPinnedObject());
} finally {
hNtChangedData.Free();
}
return ntChangedData;
}
[DllImport(DLLPath, EntryPoint = "DebugGetFreezeState")] private static extern void DebugGetFreezeStateWrapper(UInt16 startAddress, UInt16 length, IntPtr freezeState);
public static bool[] DebugGetFreezeState(UInt16 startAddress, UInt16 length)
@ -2285,7 +2309,8 @@ namespace Mesen.GUI
ChrRam = 7,
WorkRam = 8,
SaveRam = 9,
InternalRam = 10
InternalRam = 10,
NametableRam = 11
}
public enum BreakSource

View File

@ -109,10 +109,11 @@ extern "C"
DllExport void __stdcall DebugSetMemoryValue(DebugMemoryType type, uint32_t address, uint8_t value) { return GetDebugger()->GetMemoryDumper()->SetMemoryValue(type, address, value); }
DllExport void __stdcall DebugSetMemoryValues(DebugMemoryType type, uint32_t address, uint8_t* data, int32_t length) { return GetDebugger()->GetMemoryDumper()->SetMemoryValues(type, address, data, length); }
DllExport void __stdcall DebugGetMemoryAccessCounts(AddressType memoryType, MemoryOperationType operationType, uint32_t* counts, bool forUninitReads) { GetDebugger()->GetMemoryAccessCounter()->GetAccessCounts(memoryType, operationType, counts, forUninitReads); }
DllExport void __stdcall DebugResetMemoryAccessCounts() { GetDebugger()->GetMemoryAccessCounter()->ResetCounts(); }
DllExport void __stdcall DebugGetMemoryAccessStamps(uint32_t offset, uint32_t length, DebugMemoryType memoryType, MemoryOperationType operationType, uint32_t* stamps) { GetDebugger()->GetMemoryAccessCounter()->GetAccessStamps(offset, length, memoryType, operationType, stamps); }
DllExport void __stdcall DebugGetMemoryAccessCountsEx(uint32_t offset, uint32_t length, DebugMemoryType memoryType, MemoryOperationType operationType, int32_t* counts) { GetDebugger()->GetMemoryAccessCounter()->GetAccessCountsEx(offset, length, memoryType, operationType, counts); }
DllExport void __stdcall DebugGetMemoryAccessCounts(uint32_t offset, uint32_t length, DebugMemoryType memoryType, MemoryOperationType operationType, int32_t* counts) { GetDebugger()->GetMemoryAccessCounter()->GetAccessCounts(offset, length, memoryType, operationType, counts); }
DllExport void __stdcall DebugGetUninitMemoryReads(DebugMemoryType memoryType, int32_t* counts) { GetDebugger()->GetMemoryAccessCounter()->GetUninitMemoryReads(memoryType, counts); }
DllExport void __stdcall DebugGetNametableChangedData(bool* ntChangedData) { GetDebugger()->GetMemoryAccessCounter()->GetNametableChangedData(ntChangedData); }
DllExport void __stdcall DebugGetProfilerData(int64_t* profilerData, ProfilerDataType dataType) { GetDebugger()->GetProfiler()->GetProfilerData(profilerData, dataType); }
DllExport void __stdcall DebugResetProfiler() { GetDebugger()->GetProfiler()->Reset(); }