diff --git a/Core/BaseMapper.cpp b/Core/BaseMapper.cpp index 0ca02b9f..b059710c 100644 --- a/Core/BaseMapper.cpp +++ b/Core/BaseMapper.cpp @@ -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; diff --git a/Core/BaseMapper.h b/Core/BaseMapper.h index 5ba2d4ca..49f45fbe 100644 --- a/Core/BaseMapper.h +++ b/Core/BaseMapper.h @@ -51,9 +51,6 @@ private: vector _originalChrRom; protected: - static constexpr uint32_t NametableCount = 0x10; - static constexpr uint32_t NametableSize = 0x400; - RomInfo _romInfo; shared_ptr _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); diff --git a/Core/Debugger.cpp b/Core/Debugger.cpp index e8814a81..0cec8bf7 100644 --- a/Core/Debugger.cpp +++ b/Core/Debugger.cpp @@ -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() diff --git a/Core/DebuggerTypes.h b/Core/DebuggerTypes.h index 262ed973..f9ac7d95 100644 --- a/Core/DebuggerTypes.h +++ b/Core/DebuggerTypes.h @@ -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 diff --git a/Core/LuaApi.cpp b/Core/LuaApi.cpp index 64711590..d57335f5 100644 --- a/Core/LuaApi.cpp +++ b/Core/LuaApi.cpp @@ -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 counts; + vector 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++) { diff --git a/Core/MemoryAccessCounter.cpp b/Core/MemoryAccessCounter.cpp index 5378fd14..ad7d92e3 100644 --- a/Core/MemoryAccessCounter.cpp +++ b/Core/MemoryAccessCounter.cpp @@ -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& MemoryAccessCounter::GetArray(MemoryOperationType operationType, AddressType addressType, bool stampArray) +vector& 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& 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& MemoryAccessCounter::GetPpuCountArray(MemoryOperationType operationType, PpuAddressType addressType) +{ + return operationType == MemoryOperationType::Write ? _ppuWriteCounts[(int)addressType] : _ppuReadCounts[(int)addressType]; +} + +vector& 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 &counts = GetArray(operation, addressInfo.Type, false); + vector &counts = GetPpuCountArray(operation, addressInfo.Type); counts.data()[addressInfo.Address]++; - vector &stamps = GetArray(operation, addressInfo.Type, true); + vector &stamps = GetPpuStampArray(operation, addressInfo.Type); + stamps.data()[addressInfo.Address] = cpuCycle; +} + +bool MemoryAccessCounter::ProcessMemoryAccess(AddressTypeInfo &addressInfo, MemoryOperationType operation, int32_t cpuCycle) +{ + vector &counts = GetCountArray(operation, addressInfo.Type); + counts.data()[addressInfo.Address]++; + + vector &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; } diff --git a/Core/MemoryAccessCounter.h b/Core/MemoryAccessCounter.h index 1164b84e..9e6aae9a 100644 --- a/Core/MemoryAccessCounter.h +++ b/Core/MemoryAccessCounter.h @@ -19,17 +19,28 @@ private: vector _uninitReads[4]; - vector& GetArray(MemoryOperationType operationType, AddressType addressType, bool stampArray); + vector _ppuReadCounts[4]; + vector _ppuWriteCounts[4]; + vector _ppuReadStamps[4]; + vector _ppuWriteStamps[4]; + + vector& GetCountArray(MemoryOperationType operationType, AddressType addressType); + vector& GetStampArray(MemoryOperationType operationType, AddressType addressType); + + vector& GetPpuCountArray(MemoryOperationType operationType, PpuAddressType addressType); + vector& 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[]); }; \ No newline at end of file diff --git a/Core/MemoryDumper.cpp b/Core/MemoryDumper.cpp index 747c14fa..e1bb4dc6 100644 --- a/Core/MemoryDumper.cpp +++ b/Core/MemoryDumper.cpp @@ -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: diff --git a/GUI.NET/Config/DebugInfo.cs b/GUI.NET/Config/DebugInfo.cs index 8c8dcfc8..98d7a3b7 100644 --- a/GUI.NET/Config/DebugInfo.cs +++ b/GUI.NET/Config/DebugInfo.cs @@ -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; diff --git a/GUI.NET/Debugger/ByteColorProvider.cs b/GUI.NET/Debugger/ByteColorProvider.cs index 0902eb8e..d0aa3711 100644 --- a/GUI.NET/Debugger/ByteColorProvider.cs +++ b/GUI.NET/Debugger/ByteColorProvider.cs @@ -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; diff --git a/GUI.NET/Debugger/ChrByteColorProvider.cs b/GUI.NET/Debugger/ChrByteColorProvider.cs index 3f65631d..af1b1ed8 100644 --- a/GUI.NET/Debugger/ChrByteColorProvider.cs +++ b/GUI.NET/Debugger/ChrByteColorProvider.cs @@ -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; } } diff --git a/GUI.NET/Debugger/Controls/ctrlMemoryAccessCounters.cs b/GUI.NET/Debugger/Controls/ctrlMemoryAccessCounters.cs index f799fe17..693e2651 100644 --- a/GUI.NET/Debugger/Controls/ctrlMemoryAccessCounters.cs +++ b/GUI.NET/Debugger/Controls/ctrlMemoryAccessCounters.cs @@ -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(); + DebugMemoryType originalValue = cboMemoryType.GetEnumValue(); 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 addresses = new List(readCounts.Length); List content = new List(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(); + _memoryType = cboMemoryType.GetEnumValue(); 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) diff --git a/GUI.NET/Debugger/Controls/ctrlNametableViewer.Designer.cs b/GUI.NET/Debugger/Controls/ctrlNametableViewer.Designer.cs index 2cd3d71d..52087f14 100644 --- a/GUI.NET/Debugger/Controls/ctrlNametableViewer.Designer.cs +++ b/GUI.NET/Debugger/Controls/ctrlNametableViewer.Designer.cs @@ -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; } } diff --git a/GUI.NET/Debugger/Controls/ctrlNametableViewer.cs b/GUI.NET/Debugger/Controls/ctrlNametableViewer.cs index 12b1a0e4..4ff735f1 100644 --- a/GUI.NET/Debugger/Controls/ctrlNametableViewer.cs +++ b/GUI.NET/Debugger/Controls/ctrlNametableViewer.cs @@ -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; diff --git a/GUI.NET/Debugger/frmMemoryViewer.cs b/GUI.NET/Debugger/frmMemoryViewer.cs index d4d44fba..7d9a806a 100644 --- a/GUI.NET/Debugger/frmMemoryViewer.cs +++ b/GUI.NET/Debugger/frmMemoryViewer.cs @@ -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 diff --git a/GUI.NET/Dependencies/resources.en.xml b/GUI.NET/Dependencies/resources.en.xml index 4b630852..66c97c1a 100644 --- a/GUI.NET/Dependencies/resources.en.xml +++ b/GUI.NET/Dependencies/resources.en.xml @@ -1105,6 +1105,7 @@ Work RAM Save RAM NES RAM (2 KB) + Nametable RAM None diff --git a/GUI.NET/InteropEmu.cs b/GUI.NET/InteropEmu.cs index 98af9707..1a691305 100644 --- a/GUI.NET/InteropEmu.cs +++ b/GUI.NET/InteropEmu.cs @@ -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 diff --git a/InteropDLL/DebugWrapper.cpp b/InteropDLL/DebugWrapper.cpp index 3e15ae4c..519181ee 100644 --- a/InteropDLL/DebugWrapper.cpp +++ b/InteropDLL/DebugWrapper.cpp @@ -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(); }