1 #include "stdafx.h"
2 #include "MemoryAccessCounter.h"
3 #include "Console.h"
4 #include "CPU.h"
5 #include "DebugBreakHelper.h"
6 #include "Debugger.h"
7 #include "MemoryDumper.h"
8 #include "PPU.h"
9 #include "BaseMapper.h"
10 
MemoryAccessCounter(Debugger * debugger)11 MemoryAccessCounter::MemoryAccessCounter(Debugger* debugger)
12 {
13 	_debugger = debugger;
14 
15 	uint32_t memorySizes[4] = {
16 		0x2000,
17 		_debugger->GetMemoryDumper()->GetMemorySize(DebugMemoryType::PrgRom),
18 		_debugger->GetMemoryDumper()->GetMemorySize(DebugMemoryType::WorkRam),
19 		_debugger->GetMemoryDumper()->GetMemorySize(DebugMemoryType::SaveRam)
20 	};
21 
22 	for(int i = 0; i < 4; i++) {
23 		_readCounts[i].insert(_readCounts[i].end(), memorySizes[i], 0);
24 		_writeCounts[i].insert(_writeCounts[i].end(), memorySizes[i], 0);
25 		_execCounts[i].insert(_execCounts[i].end(), memorySizes[i], 0);
26 
27 		_readStamps[i].insert(_readStamps[i].end(), memorySizes[i], 0);
28 		_writeStamps[i].insert(_writeStamps[i].end(), memorySizes[i], 0);
29 		_execStamps[i].insert(_execStamps[i].end(), memorySizes[i], 0);
30 
31 		_uninitReads[i].insert(_uninitReads[i].end(), memorySizes[i], 0);
32 	}
33 
34 	uint32_t ppuMemorySizes[4] = {
35 		_debugger->GetMemoryDumper()->GetMemorySize(DebugMemoryType::ChrRom),
36 		_debugger->GetMemoryDumper()->GetMemorySize(DebugMemoryType::ChrRam),
37 		_debugger->GetMemoryDumper()->GetMemorySize(DebugMemoryType::PaletteMemory),
38 		BaseMapper::NametableSize * BaseMapper::NametableCount,
39 	};
40 
41 	for(int i = 0; i < 4; i++) {
42 		_ppuReadCounts[i].insert(_ppuReadCounts[i].end(), ppuMemorySizes[i], 0);
43 		_ppuWriteCounts[i].insert(_ppuWriteCounts[i].end(), ppuMemorySizes[i], 0);
44 		_ppuReadStamps[i].insert(_ppuReadStamps[i].end(), ppuMemorySizes[i], 0);
45 		_ppuWriteStamps[i].insert(_ppuWriteStamps[i].end(), ppuMemorySizes[i], 0);
46 	}
47 }
48 
GetCountArray(MemoryOperationType operationType,AddressType addressType)49 vector<int32_t>& MemoryAccessCounter::GetCountArray(MemoryOperationType operationType, AddressType addressType)
50 {
51 	switch(operationType) {
52 		case MemoryOperationType::Read: return _readCounts[(int)addressType];
53 		case MemoryOperationType::Write: return _writeCounts[(int)addressType];
54 
55 		default:
56 		case MemoryOperationType::ExecOpCode:
57 		case MemoryOperationType::ExecOperand: return _execCounts[(int)addressType];
58 	}
59 }
60 
GetStampArray(MemoryOperationType operationType,AddressType addressType)61 vector<uint64_t>& MemoryAccessCounter::GetStampArray(MemoryOperationType operationType, AddressType addressType)
62 {
63 	switch(operationType) {
64 		case MemoryOperationType::Read: return _readStamps[(int)addressType];
65 		case MemoryOperationType::Write: return _writeStamps[(int)addressType];
66 
67 		default:
68 		case MemoryOperationType::ExecOpCode:
69 		case MemoryOperationType::ExecOperand: return _execStamps[(int)addressType];
70 	}
71 }
72 
GetPpuCountArray(MemoryOperationType operationType,PpuAddressType addressType)73 vector<int32_t>& MemoryAccessCounter::GetPpuCountArray(MemoryOperationType operationType, PpuAddressType addressType)
74 {
75 	return operationType == MemoryOperationType::Write ? _ppuWriteCounts[(int)addressType] : _ppuReadCounts[(int)addressType];
76 }
77 
GetPpuStampArray(MemoryOperationType operationType,PpuAddressType addressType)78 vector<uint64_t>& MemoryAccessCounter::GetPpuStampArray(MemoryOperationType operationType, PpuAddressType addressType)
79 {
80 	return operationType == MemoryOperationType::Write ? _ppuWriteStamps[(int)addressType] : _ppuReadStamps[(int)addressType];
81 }
82 
IsAddressUninitialized(AddressTypeInfo & addressInfo)83 bool MemoryAccessCounter::IsAddressUninitialized(AddressTypeInfo &addressInfo)
84 {
85 	if(addressInfo.Type == AddressType::InternalRam || addressInfo.Type == AddressType::WorkRam) {
86 		int index = (int)addressInfo.Type;
87 		return _writeCounts[index][addressInfo.Address] == 0;
88 	}
89 	return false;
90 }
91 
ProcessPpuMemoryAccess(PpuAddressTypeInfo & addressInfo,MemoryOperationType operation,uint64_t cpuCycle)92 void MemoryAccessCounter::ProcessPpuMemoryAccess(PpuAddressTypeInfo &addressInfo, MemoryOperationType operation, uint64_t cpuCycle)
93 {
94 	if(addressInfo.Address >= 0) {
95 		vector<int> &counts = GetPpuCountArray(operation, addressInfo.Type);
96 		counts.data()[addressInfo.Address]++;
97 
98 		vector<uint64_t> &stamps = GetPpuStampArray(operation, addressInfo.Type);
99 		stamps.data()[addressInfo.Address] = cpuCycle;
100 	}
101 }
102 
ProcessMemoryAccess(AddressTypeInfo & addressInfo,MemoryOperationType operation,uint64_t cpuCycle)103 bool MemoryAccessCounter::ProcessMemoryAccess(AddressTypeInfo &addressInfo, MemoryOperationType operation, uint64_t cpuCycle)
104 {
105 	vector<int> &counts = GetCountArray(operation, addressInfo.Type);
106 	counts.data()[addressInfo.Address]++;
107 
108 	vector<uint64_t> &stamps = GetStampArray(operation, addressInfo.Type);
109 	stamps.data()[addressInfo.Address] = cpuCycle;
110 
111 	if(operation == MemoryOperationType::Read && (addressInfo.Type == AddressType::InternalRam || addressInfo.Type == AddressType::WorkRam) && !_writeCounts[(int)addressInfo.Type][addressInfo.Address]) {
112 		//Mark address as read before being written to (if trying to read/execute)
113 		_uninitReads[(int)addressInfo.Type][addressInfo.Address] = true;
114 		return true;
115 	}
116 
117 	return false;
118 }
119 
ResetCounts()120 void MemoryAccessCounter::ResetCounts()
121 {
122 	DebugBreakHelper helper(_debugger);
123 	for(int i = 0; i < 4; i++) {
124 		memset(_readCounts[i].data(), 0, _readCounts[i].size() * sizeof(uint32_t));
125 		memset(_writeCounts[i].data(), 0, _writeCounts[i].size() * sizeof(uint32_t));
126 		memset(_execCounts[i].data(), 0, _execCounts[i].size() * sizeof(uint32_t));
127 
128 		memset(_readStamps[i].data(), 0, _readStamps[i].size() * sizeof(uint64_t));
129 		memset(_writeStamps[i].data(), 0, _writeStamps[i].size() * sizeof(uint64_t));
130 		memset(_execStamps[i].data(), 0, _execStamps[i].size() * sizeof(uint64_t));
131 
132 		memset(_ppuReadCounts[i].data(), 0, _ppuReadCounts[i].size() * sizeof(uint32_t));
133 		memset(_ppuWriteCounts[i].data(), 0, _ppuWriteCounts[i].size() * sizeof(uint32_t));
134 		memset(_ppuReadStamps[i].data(), 0, _ppuReadStamps[i].size() * sizeof(uint32_t));
135 		memset(_ppuWriteStamps[i].data(), 0, _ppuWriteStamps[i].size() * sizeof(uint32_t));
136 	}
137 }
138 
GetAccessStamps(uint32_t offset,uint32_t length,DebugMemoryType memoryType,MemoryOperationType operationType,uint64_t stamps[])139 void MemoryAccessCounter::GetAccessStamps(uint32_t offset, uint32_t length, DebugMemoryType memoryType, MemoryOperationType operationType, uint64_t stamps[])
140 {
141 	switch(memoryType) {
142 		default: break;
143 
144 		case DebugMemoryType::InternalRam:
145 			memcpy(stamps, GetStampArray(operationType, AddressType::InternalRam).data() + offset, length * sizeof(uint64_t));
146 			break;
147 
148 		case DebugMemoryType::WorkRam:
149 			memcpy(stamps, GetStampArray(operationType, AddressType::WorkRam).data() + offset, length * sizeof(uint64_t));
150 			break;
151 
152 		case DebugMemoryType::SaveRam:
153 			memcpy(stamps, GetStampArray(operationType, AddressType::SaveRam).data() + offset, length * sizeof(uint64_t));
154 			break;
155 
156 		case DebugMemoryType::PrgRom:
157 			memcpy(stamps, GetStampArray(operationType, AddressType::PrgRom).data() + offset, length * sizeof(uint64_t));
158 			break;
159 
160 		case DebugMemoryType::ChrRom:
161 			memcpy(stamps, GetPpuStampArray(operationType, PpuAddressType::ChrRom).data() + offset, length * sizeof(uint64_t));
162 			break;
163 
164 		case DebugMemoryType::ChrRam:
165 			memcpy(stamps, GetPpuStampArray(operationType, PpuAddressType::ChrRam).data() + offset, length * sizeof(uint64_t));
166 			break;
167 
168 		case DebugMemoryType::NametableRam:
169 			memcpy(stamps, GetPpuStampArray(operationType, PpuAddressType::NametableRam).data() + offset, length * sizeof(uint64_t));
170 			break;
171 
172 		case DebugMemoryType::PaletteMemory:
173 			memcpy(stamps, GetPpuStampArray(operationType, PpuAddressType::PaletteRam).data() + offset, length * sizeof(uint64_t));
174 			break;
175 
176 		case DebugMemoryType::CpuMemory:
177 			for(uint32_t i = 0; i < length; i++) {
178 				AddressTypeInfo info;
179 				_debugger->GetAbsoluteAddressAndType(offset + i, &info);
180 				stamps[i] = GetStampArray(operationType, info.Type).data()[info.Address];
181 			}
182 			break;
183 
184 		case DebugMemoryType::PpuMemory:
185 			for(uint32_t i = 0; i < length; i++) {
186 				PpuAddressTypeInfo info;
187 				_debugger->GetPpuAbsoluteAddressAndType(offset + i, &info);
188 				stamps[i] = GetPpuStampArray(operationType, info.Type).data()[info.Address];
189 			}
190 			break;
191 	}
192 }
193 
GetNametableChangedData(bool ntChangedData[])194 void MemoryAccessCounter::GetNametableChangedData(bool ntChangedData[])
195 {
196 	PpuAddressTypeInfo addressInfo;
197 	uint64_t cpuCycle = _debugger->GetConsole()->GetCpu()->GetCycleCount();
198 	NesModel model = _debugger->GetConsole()->GetModel();
199 	double frameRate = model == NesModel::NTSC ? 60.1 : 50.01;
200 	double overclockRate = _debugger->GetConsole()->GetPpu()->GetOverclockRate() * (_debugger->GetConsole()->GetSettings()->GetOverclockRate() / 100);
201 	int32_t cyclesPerFrame = (int32_t)(_debugger->GetConsole()->GetCpu()->GetClockRate(model) / frameRate * overclockRate);
202 
203 	for(int i = 0; i < 0x1000; i++) {
204 		_debugger->GetPpuAbsoluteAddressAndType(0x2000+i, &addressInfo);
205 		if(addressInfo.Type != PpuAddressType::None) {
206 			ntChangedData[i] = (cpuCycle - _ppuWriteStamps[(int)addressInfo.Type][addressInfo.Address]) < cyclesPerFrame;
207 		} else {
208 			ntChangedData[i] = false;
209 		}
210 	}
211 }
212 
GetUninitMemoryReads(DebugMemoryType memoryType,int32_t counts[])213 void MemoryAccessCounter::GetUninitMemoryReads(DebugMemoryType memoryType, int32_t counts[])
214 {
215 	AddressType addressType;
216 	switch(memoryType) {
217 		default: return;
218 		case DebugMemoryType::InternalRam: addressType = AddressType::InternalRam; break;
219 		case DebugMemoryType::WorkRam: addressType = AddressType::WorkRam; break;
220 		case DebugMemoryType::SaveRam: addressType = AddressType::SaveRam; break;
221 		case DebugMemoryType::PrgRom: addressType = AddressType::PrgRom; break;
222 	}
223 
224 	for(size_t i = 0, len = _uninitReads[(int)addressType].size(); i < len; i++) {
225 		counts[i] = _uninitReads[(int)addressType][i];
226 	}
227 }
228 
GetAccessCounts(uint32_t offset,uint32_t length,DebugMemoryType memoryType,MemoryOperationType operationType,int32_t counts[])229 void MemoryAccessCounter::GetAccessCounts(uint32_t offset, uint32_t length, DebugMemoryType memoryType, MemoryOperationType operationType, int32_t counts[])
230 {
231 	switch(memoryType) {
232 		default: break;
233 
234 		case DebugMemoryType::InternalRam:
235 			memcpy(counts, GetCountArray(operationType, AddressType::InternalRam).data() + offset, length * sizeof(uint32_t));
236 			break;
237 
238 		case DebugMemoryType::WorkRam:
239 			memcpy(counts, GetCountArray(operationType, AddressType::WorkRam).data() + offset, length * sizeof(uint32_t));
240 			break;
241 
242 		case DebugMemoryType::SaveRam:
243 			memcpy(counts, GetCountArray(operationType, AddressType::SaveRam).data() + offset, length * sizeof(uint32_t));
244 			break;
245 
246 		case DebugMemoryType::PrgRom:
247 			memcpy(counts, GetCountArray(operationType, AddressType::PrgRom).data() + offset, length * sizeof(uint32_t));
248 			break;
249 
250 		case DebugMemoryType::ChrRom:
251 			memcpy(counts, GetPpuCountArray(operationType, PpuAddressType::ChrRom).data() + offset, length * sizeof(uint32_t));
252 			break;
253 
254 		case DebugMemoryType::ChrRam:
255 			memcpy(counts, GetPpuCountArray(operationType, PpuAddressType::ChrRam).data() + offset, length * sizeof(uint32_t));
256 			break;
257 
258 		case DebugMemoryType::NametableRam:
259 			memcpy(counts, GetPpuCountArray(operationType, PpuAddressType::NametableRam).data() + offset, length * sizeof(uint32_t));
260 			break;
261 
262 		case DebugMemoryType::PaletteMemory:
263 			memcpy(counts, GetPpuCountArray(operationType, PpuAddressType::PaletteRam).data() + offset, length * sizeof(uint32_t));
264 			break;
265 
266 		case DebugMemoryType::CpuMemory:
267 			for(uint32_t i = 0; i < length; i++) {
268 				AddressTypeInfo info;
269 				_debugger->GetAbsoluteAddressAndType(offset + i, &info);
270 				counts[i] = GetCountArray(operationType, info.Type).data()[info.Address];
271 			}
272 			break;
273 
274 		case DebugMemoryType::PpuMemory:
275 			for(uint32_t i = 0; i < length; i++) {
276 				PpuAddressTypeInfo info;
277 				_debugger->GetPpuAbsoluteAddressAndType(offset + i, &info);
278 				counts[i] = GetPpuCountArray(operationType, info.Type).data()[info.Address];
279 			}
280 			break;
281 	}
282 }