#include "stdafx.h" #include "MemoryAccessCounter.h" #include "Console.h" #include "CPU.h" #include "DebugBreakHelper.h" #include "Debugger.h" #include "MemoryDumper.h" #include "PPU.h" #include "BaseMapper.h" MemoryAccessCounter::MemoryAccessCounter(Debugger* debugger) { _debugger = debugger; uint32_t memorySizes[4] = { _debugger->GetMemoryDumper()->GetMemorySize(DebugMemoryType::InternalRam), _debugger->GetMemoryDumper()->GetMemorySize(DebugMemoryType::PrgRom), _debugger->GetMemoryDumper()->GetMemorySize(DebugMemoryType::WorkRam), _debugger->GetMemoryDumper()->GetMemorySize(DebugMemoryType::SaveRam) }; for(int i = 0; i < 4; i++) { _counters[i].reserve(memorySizes[i]); for(uint32_t j = 0; j < memorySizes[i]; j++) { _counters[i].push_back({ (uint32_t)j }); } } 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++) { _ppuCounters[i].reserve(ppuMemorySizes[i]); for(uint32_t j = 0; j < ppuMemorySizes[i]; j++) { _ppuCounters[i].push_back({ (uint32_t)j }); } } } bool MemoryAccessCounter::IsAddressUninitialized(AddressTypeInfo &addressInfo) { if(addressInfo.Type == AddressType::InternalRam || addressInfo.Type == AddressType::WorkRam) { return _counters[(int)addressInfo.Type][addressInfo.Address].WriteCount == 0; } return false; } void MemoryAccessCounter::ProcessPpuMemoryRead(PpuAddressTypeInfo &addressInfo, uint64_t cpuCycle) { if(addressInfo.Address < 0) { return; } AddressCounters& counts = _ppuCounters[(int)addressInfo.Type][addressInfo.Address]; counts.ReadCount++; counts.ReadStamp = cpuCycle; } void MemoryAccessCounter::ProcessPpuMemoryWrite(PpuAddressTypeInfo& addressInfo, uint64_t cpuCycle) { if(addressInfo.Address < 0) { return; } AddressCounters& counts = _ppuCounters[(int)addressInfo.Type][addressInfo.Address]; counts.WriteCount++; counts.WriteStamp = cpuCycle; } bool MemoryAccessCounter::ProcessMemoryRead(AddressTypeInfo &addressInfo, uint64_t cpuCycle) { if(addressInfo.Address < 0) { return false; } AddressCounters& counts = _counters[(int)addressInfo.Type][addressInfo.Address]; counts.ReadCount++; counts.ReadStamp = cpuCycle; if(counts.WriteCount == 0 && (addressInfo.Type == AddressType::InternalRam || addressInfo.Type == AddressType::WorkRam)) { //Mark address as read before being written to (if trying to read/execute) counts.UninitRead = true; return true; } return false; } void MemoryAccessCounter::ProcessMemoryWrite(AddressTypeInfo& addressInfo, uint64_t cpuCycle) { if(addressInfo.Address < 0) { return; } AddressCounters& counts = _counters[(int)addressInfo.Type][addressInfo.Address]; counts.WriteCount++; counts.WriteStamp = cpuCycle; } void MemoryAccessCounter::ProcessMemoryExec(AddressTypeInfo& addressInfo, uint64_t cpuCycle) { if(addressInfo.Address < 0) { return; } AddressCounters& counts = _counters[(int)addressInfo.Type][addressInfo.Address]; counts.ExecCount++; counts.ExecStamp = cpuCycle; } void MemoryAccessCounter::ResetCounts() { DebugBreakHelper helper(_debugger); for(int i = 0; i < 4; i++) { for(int j = 0; j < _counters[i].size(); j++) { _counters[i][j] = { (uint32_t)j }; } for(int j = 0; j < _ppuCounters[i].size(); j++) { _ppuCounters[i][j] = { (uint32_t)j }; } } } void MemoryAccessCounter::GetNametableChangedData(bool ntChangedData[]) { PpuAddressTypeInfo addressInfo; uint64_t cpuCycle = _debugger->GetConsole()->GetCpu()->GetCycleCount(); NesModel model = _debugger->GetConsole()->GetModel(); double frameRate = model == NesModel::NTSC ? 60.1 : 50.01; double overclockRate = _debugger->GetConsole()->GetPpu()->GetOverclockRate() * 100; uint32_t cyclesPerFrame = (uint32_t)(_debugger->GetConsole()->GetCpu()->GetClockRate(model) / frameRate * overclockRate); for(int i = 0; i < 0x1000; i++) { _debugger->GetPpuAbsoluteAddressAndType(0x2000+i, &addressInfo); if(addressInfo.Type != PpuAddressType::None) { ntChangedData[i] = (cpuCycle - _ppuCounters[(int)addressInfo.Type][addressInfo.Address].WriteStamp) < cyclesPerFrame; } else { ntChangedData[i] = false; } } } void MemoryAccessCounter::GetAccessCounts(uint32_t offset, uint32_t length, DebugMemoryType memoryType, AddressCounters counts[]) { switch(memoryType) { default: break; case DebugMemoryType::PrgRom: memcpy(counts, _counters[(int)AddressType::PrgRom].data() + offset, length * sizeof(AddressCounters)); break; case DebugMemoryType::WorkRam: memcpy(counts, _counters[(int)AddressType::WorkRam].data() + offset, length * sizeof(AddressCounters)); break; case DebugMemoryType::SaveRam: memcpy(counts, _counters[(int)AddressType::SaveRam].data() + offset, length * sizeof(AddressCounters)); break; case DebugMemoryType::InternalRam: memcpy(counts, _counters[(int)AddressType::InternalRam].data() + offset, length * sizeof(AddressCounters)); break; case DebugMemoryType::ChrRom: memcpy(counts, _ppuCounters[(int)PpuAddressType::ChrRom].data() + offset, length * sizeof(AddressCounters)); break; case DebugMemoryType::ChrRam: memcpy(counts, _ppuCounters[(int)PpuAddressType::ChrRam].data() + offset, length * sizeof(AddressCounters)); break; case DebugMemoryType::NametableRam: memcpy(counts, _ppuCounters[(int)PpuAddressType::NametableRam].data() + offset, length * sizeof(AddressCounters)); break; case DebugMemoryType::PaletteMemory: memcpy(counts, _ppuCounters[(int)PpuAddressType::PaletteRam].data() + offset, length * sizeof(AddressCounters)); break; case DebugMemoryType::CpuMemory: for(uint32_t i = 0; i < length; i++) { AddressTypeInfo info; _debugger->GetAbsoluteAddressAndType(offset + i, &info); if(info.Address >= 0) { counts[i] = _counters[(int)info.Type][info.Address]; } else { counts[i] = {}; } } break; case DebugMemoryType::PpuMemory: for(uint32_t i = 0; i < length; i++) { PpuAddressTypeInfo info; _debugger->GetPpuAbsoluteAddressAndType(offset + i, &info); if(info.Address >= 0) { counts[i] = _ppuCounters[(int)info.Type][info.Address]; } else { counts[i] = {}; } } break; } }