1 #pragma once
2 
3 #include "stdafx.h"
4 #include <atomic>
5 #include <deque>
6 #include <unordered_set>
7 using std::atomic;
8 using std::deque;
9 using std::unordered_set;
10 
11 #include "../Utilities/SimpleLock.h"
12 #include "DebuggerTypes.h"
13 
14 class CPU;
15 class APU;
16 class PPU;
17 class MemoryManager;
18 class Console;
19 class Assembler;
20 class Disassembler;
21 class LabelManager;
22 class MemoryDumper;
23 class MemoryAccessCounter;
24 class Profiler;
25 class CodeRunner;
26 class BaseMapper;
27 class ScriptHost;
28 class TraceLogger;
29 class PerformanceTracker;
30 class Breakpoint;
31 class CodeDataLogger;
32 class ExpressionEvaluator;
33 class DummyCpu;
34 struct ExpressionData;
35 
36 enum EvalResultType : int32_t;
37 enum class CdlStripFlag;
38 
39 class Debugger
40 {
41 private:
42 	static constexpr int BreakpointTypeCount = 8;
43 
44 	//Must be static to be thread-safe when switching game
45 	static string _disassemblerOutput;
46 
47 	shared_ptr<Disassembler> _disassembler;
48 	shared_ptr<Assembler> _assembler;
49 	shared_ptr<MemoryDumper> _memoryDumper;
50 	shared_ptr<CodeDataLogger> _codeDataLogger;
51 	shared_ptr<MemoryAccessCounter> _memoryAccessCounter;
52 	shared_ptr<LabelManager> _labelManager;
53 	shared_ptr<TraceLogger> _traceLogger;
54 	shared_ptr<Profiler> _profiler;
55 	shared_ptr<PerformanceTracker> _performanceTracker;
56 	unique_ptr<CodeRunner> _codeRunner;
57 
58 	shared_ptr<Console> _console;
59 	shared_ptr<CPU> _cpu;
60 	shared_ptr<PPU> _ppu;
61 	shared_ptr<APU> _apu;
62 	shared_ptr<MemoryManager> _memoryManager;
63 	shared_ptr<BaseMapper> _mapper;
64 
65 	shared_ptr<DummyCpu> _dummyCpu;
66 	bool _bpDummyCpuRequired;
67 	bool _breakOnFirstCycle;
68 
69 	bool _hasScript;
70 	SimpleLock _scriptLock;
71 	int _nextScriptId;
72 	vector<shared_ptr<ScriptHost>> _scripts;
73 
74 	atomic<int32_t> _preventResume;
75 	atomic<bool> _stopFlag;
76 	atomic<bool> _executionStopped;
77 	atomic<int32_t> _suspendCount;
78 	vector<Breakpoint> _breakpoints[BreakpointTypeCount];
79 	vector<ExpressionData> _breakpointRpnList[BreakpointTypeCount];
80 	bool _hasBreakpoint[BreakpointTypeCount] = {};
81 
82 	vector<uint8_t> _frozenAddresses;
83 
84 	uint32_t _opCodeCycle;
85 	MemoryOperationType _memoryOperationType;
86 
87 	deque<StackFrameInfo> _callstack;
88 	deque<int32_t> _subReturnAddresses;
89 
90 	int32_t _stepOutReturnAddress;
91 
92 	unordered_set<uint32_t> _functionEntryPoints;
93 
94 	unique_ptr<ExpressionEvaluator> _watchExpEval;
95 	unique_ptr<ExpressionEvaluator> _bpExpEval;
96 	DebugState _debugState;
97 
98 	SimpleLock _breakLock;
99 
100 	//Used to alter the executing address via "Set Next Statement"
101 	uint16_t *_currentReadAddr;
102 	uint8_t *_currentReadValue;
103 	int32_t _nextReadAddr;
104 	uint16_t _returnToAddress;
105 
106 	uint32_t _flags;
107 
108 	string _romName;
109 	atomic<int32_t> _stepCount;
110 	atomic<int32_t> _ppuStepCount;
111 	atomic<int32_t> _stepCycleCount;
112 	atomic<uint8_t> _lastInstruction;
113 	atomic<bool> _stepOut;
114 	atomic<int32_t> _stepOverAddr;
115 	BreakSource _breakSource;
116 
117 	atomic<bool> _released;
118 	SimpleLock _releaseLock;
119 
120 	bool _enableBreakOnUninitRead;
121 
122 	atomic<bool> _breakRequested;
123 	bool _pausedForDebugHelper;
124 
125 	atomic<int32_t> _breakOnScanline;
126 
127 	bool _proccessPpuCycle[341];
128 	std::unordered_map<int, int> _ppuViewerUpdateCycle;
129 
130 	uint16_t _ppuScrollX;
131 	uint16_t _ppuScrollY;
132 
133 	uint64_t _prevInstructionCycle;
134 	uint64_t _curInstructionCycle;
135 	uint64_t _runToCycle;
136 	bool _needRewind;
137 
138 	vector<stringstream> _rewindCache;
139 	vector<uint64_t> _rewindPrevInstructionCycleCache;
140 
141 	uint32_t _inputOverride[4];
142 
143 	vector<DebugEventInfo> _prevDebugEvents;
144 	vector<DebugEventInfo> _debugEvents;
145 
146 private:
147 	bool ProcessBreakpoints(BreakpointType type, OperationInfo &operationInfo, bool allowBreak = true, bool allowMark = true);
148 	void ProcessAllBreakpoints(OperationInfo &operationInfo);
149 
150 	void AddCallstackFrame(uint16_t source, uint16_t target, StackFrameFlags flags);
151 	void UpdateCallstack(uint8_t currentInstruction, uint32_t addr);
152 
153 	void ProcessStepConditions(uint16_t addr);
154 	bool SleepUntilResume(BreakSource source, uint32_t breakpointId = 0, BreakpointType bpType = BreakpointType::Global, uint16_t bpAddress = 0, uint8_t bpValue = 0, MemoryOperationType bpMemOpType = MemoryOperationType::Read);
155 
156 	void AddDebugEvent(DebugEventType type, uint16_t address = -1, uint8_t value = 0, int16_t breakpointId = -1, int8_t ppuLatch = -1);
157 
158 	void UpdatePpuCyclesToProcess();
159 	void ResetStepState();
160 
161 public:
162 	Debugger(shared_ptr<Console> console, shared_ptr<CPU> cpu, shared_ptr<PPU> ppu, shared_ptr<APU> apu, shared_ptr<MemoryManager> memoryManager, shared_ptr<BaseMapper> mapper);
163 	~Debugger();
164 
165 	void ReleaseDebugger(bool needPause);
166 
167 	void SetPpu(shared_ptr<PPU> ppu);
168 	Console* GetConsole();
169 
170 	void SetFlags(uint32_t flags);
171 	bool CheckFlag(DebuggerFlags flag);
172 
173 	void SetBreakpoints(Breakpoint breakpoints[], uint32_t length);
174 
175 	shared_ptr<LabelManager> GetLabelManager();
176 
177 	void GetFunctionEntryPoints(int32_t* entryPoints, int32_t maxCount);
178 	int32_t GetFunctionEntryPointCount();
179 
180 	void GetCallstack(StackFrameInfo* callstackArray, uint32_t &callstackSize);
181 
182 	void GetInstructionProgress(InstructionProgress &state);
183 	void GetApuState(ApuState *state);
184 	__forceinline void GetState(DebugState *state, bool includeMapperInfo = true);
185 	void SetState(DebugState state);
186 
187 	void Suspend();
188 	void Resume();
189 
190 	void Break();
191 	void ResumeFromBreak();
192 
193 	void PpuStep(uint32_t count = 1);
194 	void Step(uint32_t count = 1, BreakSource source = BreakSource::CpuStep);
195 	void StepCycles(uint32_t cycleCount = 1);
196 	void StepOver();
197 	void StepOut();
198 	void StepBack();
199 	void Run();
200 
201 	void BreakImmediately(BreakSource source);
202 	void BreakOnScanline(int16_t scanline);
203 
204 	bool LoadCdlFile(string cdlFilepath);
205 	void SetCdlData(uint8_t* cdlData, uint32_t length);
206 	void ResetCdl();
207 	void UpdateCdlCache();
208 	bool IsMarkedAsCode(uint16_t relativeAddress);
209 	shared_ptr<CodeDataLogger> GetCodeDataLogger();
210 
211 	void SetNextStatement(uint16_t addr);
212 
213 	void SetPpuViewerScanlineCycle(int32_t ppuViewerId, int32_t scanline, int32_t cycle);
214 	void ClearPpuViewerSettings(int32_t ppuViewer);
215 
216 	bool IsExecutionStopped();
217 
218 	bool IsPauseIconShown();
219 	void PreventResume();
220 	void AllowResume();
221 
222 	void GenerateCodeOutput();
223 	const char* GetCode(uint32_t &length);
224 
225 	int32_t GetRelativeAddress(uint32_t addr, AddressType type);
226 	int32_t GetRelativePpuAddress(uint32_t addr, PpuAddressType type);
227 	int32_t GetAbsoluteAddress(uint32_t addr);
228 	int32_t GetAbsoluteChrAddress(uint32_t addr);
229 
230 	void GetAbsoluteAddressAndType(uint32_t relativeAddr, AddressTypeInfo* info);
231 	void GetPpuAbsoluteAddressAndType(uint32_t relativeAddr, PpuAddressTypeInfo* info);
232 
233 	shared_ptr<Profiler> GetProfiler();
234 	shared_ptr<Assembler> GetAssembler();
235 	shared_ptr<TraceLogger> GetTraceLogger();
236 	shared_ptr<MemoryDumper> GetMemoryDumper();
237 	shared_ptr<MemoryAccessCounter> GetMemoryAccessCounter();
238 	shared_ptr<PerformanceTracker> GetPerformanceTracker();
239 
240 	int32_t EvaluateExpression(string expression, EvalResultType &resultType, bool useCache);
241 
242 	bool IsPpuCycleToProcess();
243 	void ProcessPpuCycle();
244 	bool ProcessRamOperation(MemoryOperationType type, uint16_t &addr, uint8_t &value);
245 	void ProcessVramReadOperation(MemoryOperationType type, uint16_t addr, uint8_t &value);
246 	void ProcessVramWriteOperation(uint16_t addr, uint8_t &value);
247 
248 	void SetLastFramePpuScroll(uint16_t addr, uint8_t xScroll, bool updateHorizontalScrollOnly);
249 	uint32_t GetPpuScroll();
250 
251 	void ProcessInterrupt(uint16_t cpuAddr, uint16_t destCpuAddr, bool forNmi);
252 
253 	void AddTrace(const char *log);
254 
255 	void SetFreezeState(uint16_t address, bool frozen);
256 	void GetFreezeState(uint16_t startAddress, uint16_t length, bool* freezeState);
257 
258 	void StartCodeRunner(uint8_t *byteCode, uint32_t codeLength);
259 	void StopCodeRunner();
260 
261 	void GetNesHeader(uint8_t* header);
262 	void SaveRomToDisk(string filename, bool saveAsIps, uint8_t* header, CdlStripFlag cdlStripflag);
263 	void RevertPrgChrChanges();
264 	bool HasPrgChrChanges();
265 
266 	int32_t FindSubEntryPoint(uint16_t relativeAddress);
267 
268 	void SetInputOverride(uint8_t port, uint32_t state);
269 
270 	int32_t LoadScript(string name, string content, int32_t scriptId);
271 	void RemoveScript(int32_t scriptId);
272 	const char* GetScriptLog(int32_t scriptId);
273 
274 	void ResetCounters();
275 
276 	void UpdateProgramCounter(uint16_t &addr, uint8_t &value);
277 
278 	void ProcessScriptSaveState(uint16_t &addr, uint8_t &value);
279 	void ProcessCpuOperation(uint16_t &addr, uint8_t &value, MemoryOperationType type);
280 	void ProcessPpuOperation(uint16_t addr, uint8_t &value, MemoryOperationType type);
281 	void ProcessEvent(EventType type);
282 
283 	void GetDebugEvents(uint32_t* pictureBuffer, DebugEventInfo *infoArray, uint32_t &maxEventCount, bool returnPreviousFrameData);
284 	uint32_t GetDebugEventCount(bool returnPreviousFrameData);
285 
286 	uint32_t GetScreenPixel(uint8_t x, uint8_t y);
287 };