1 #include "stdafx.h"
2 #include <thread>
3 #include "../Utilities/FolderUtilities.h"
4 #include "MessageManager.h"
5 #include "Debugger.h"
6 #include "Console.h"
7 #include "BaseMapper.h"
8 #include "Disassembler.h"
9 #include "VideoDecoder.h"
10 #include "APU.h"
11 #include "SoundMixer.h"
12 #include "CodeDataLogger.h"
13 #include "ExpressionEvaluator.h"
14 #include "LabelManager.h"
15 #include "MemoryDumper.h"
16 #include "MemoryAccessCounter.h"
17 #include "Profiler.h"
18 #include "Assembler.h"
19 #include "CodeRunner.h"
20 #include "DisassemblyInfo.h"
21 #include "PPU.h"
22 #include "MemoryManager.h"
23 #include "RewindManager.h"
24 #include "DebugBreakHelper.h"
25 #include "ScriptHost.h"
26 #include "StandardController.h"
27 #include "TraceLogger.h"
28 #include "Breakpoint.h"
29 #include "CodeDataLogger.h"
30 #include "NotificationManager.h"
31 #include "DebugHud.h"
32 #include "DummyCpu.h"
33 #include "PerformanceTracker.h"
34 
35 const int Debugger::BreakpointTypeCount;
36 string Debugger::_disassemblerOutput = "";
37 
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)38 Debugger::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)
39 {
40 	_romName = console->GetRomInfo().RomName;
41 	_console = console;
42 	_cpu = cpu;
43 	_apu = apu;
44 	_memoryManager = memoryManager;
45 	_mapper = mapper;
46 
47 	_dummyCpu.reset(new DummyCpu(console));
48 	_breakOnFirstCycle = false;
49 
50 	_labelManager.reset(new LabelManager(_mapper));
51 	_assembler.reset(new Assembler(_labelManager));
52 	_disassembler.reset(new Disassembler(memoryManager.get(), mapper.get(), this));
53 	_codeDataLogger.reset(new CodeDataLogger(this, mapper->GetMemorySize(DebugMemoryType::PrgRom), mapper->GetMemorySize(DebugMemoryType::ChrRom)));
54 
55 	SetPpu(ppu);
56 
57 	_memoryAccessCounter.reset(new MemoryAccessCounter(this));
58 	_profiler.reset(new Profiler(this));
59 	_performanceTracker.reset(new PerformanceTracker(console));
60 	_traceLogger.reset(new TraceLogger(this, memoryManager, _labelManager));
61 
62 	_bpExpEval.reset(new ExpressionEvaluator(this));
63 	_watchExpEval.reset(new ExpressionEvaluator(this));
64 
65 #if _DEBUG
66 	_bpExpEval->RunTests();
67 #endif
68 
69 	_stepOut = false;
70 	_stepCount = -1;
71 	_stepOverAddr = -1;
72 	_stepCycleCount = -1;
73 	_ppuStepCount = -1;
74 	_breakRequested = false;
75 	_pausedForDebugHelper = false;
76 	_breakOnScanline = -2;
77 	_breakSource = BreakSource::Unspecified;
78 
79 	memset(_hasBreakpoint, 0, sizeof(_hasBreakpoint));
80 	_bpDummyCpuRequired = false;
81 
82 	_preventResume = 0;
83 	_stopFlag = false;
84 	_suspendCount = 0;
85 
86 	_opCodeCycle = 0;
87 	_lastInstruction = 0;
88 
89 	_stepOutReturnAddress = -1;
90 
91 	_currentReadAddr = nullptr;
92 	_currentReadValue = nullptr;
93 	_nextReadAddr = -1;
94 	_returnToAddress = 0;
95 
96 	_ppuScrollX = 0;
97 	_ppuScrollY = 0;
98 
99 	_flags = 0;
100 
101 	_runToCycle = 0;
102 	_prevInstructionCycle = 0;
103 	_curInstructionCycle = 0;
104 	_needRewind = false;
105 
106 	//Only enable break on uninitialized reads when debugger is opened at power on/reset
107 	_enableBreakOnUninitRead = _cpu->GetPC() == 0;
108 
109 	_executionStopped = false;
110 
111 	_disassemblerOutput = "";
112 
113 	memset(_inputOverride, 0, sizeof(_inputOverride));
114 
115 	_frozenAddresses.insert(_frozenAddresses.end(), 0x10000, 0);
116 
117 	if(!LoadCdlFile(FolderUtilities::CombinePath(FolderUtilities::GetDebuggerFolder(), FolderUtilities::GetFilename(_romName, false) + ".cdl"))) {
118 		_disassembler->Reset();
119 	}
120 
121 	_hasScript = false;
122 	_nextScriptId = 0;
123 
124 	_released = false;
125 
126 	UpdatePpuCyclesToProcess();
127 }
128 
~Debugger()129 Debugger::~Debugger()
130 {
131 	if(!_released) {
132 		ReleaseDebugger(true);
133 	}
134 }
135 
ReleaseDebugger(bool needPause)136 void Debugger::ReleaseDebugger(bool needPause)
137 {
138 	auto lock = _releaseLock.AcquireSafe();
139 	if(!_released) {
140 		_codeDataLogger->SaveCdlFile(FolderUtilities::CombinePath(FolderUtilities::GetDebuggerFolder(), FolderUtilities::GetFilename(_romName, false) + ".cdl"));
141 
142 		_stopFlag = true;
143 
144 		if(needPause) {
145 			//ReleaseDebugger is called in the callback for "BeforeEmulationStop"
146 			//calling Pause in this scenario will cause a deadlock, but doing so is
147 			//unnecessary, so we can just skip it.
148 			_console->Pause();
149 		}
150 
151 		{
152 			auto lock = _scriptLock.AcquireSafe();
153 			for(shared_ptr<ScriptHost> script : _scripts) {
154 				//Send a ScriptEnded event to all active scripts
155 				script->ProcessEvent(EventType::ScriptEnded);
156 			}
157 			_scripts.clear();
158 			_hasScript = false;
159 		}
160 
161 		_breakLock.Acquire();
162 		_breakLock.Release();
163 
164 		if(needPause) {
165 			_console->Resume();
166 		}
167 
168 		_released = true;
169 	}
170 }
171 
SetPpu(shared_ptr<PPU> ppu)172 void Debugger::SetPpu(shared_ptr<PPU> ppu)
173 {
174 	_ppu = ppu;
175 	_memoryDumper.reset(new MemoryDumper(_ppu, _memoryManager, _mapper, _codeDataLogger, this, _disassembler));
176 }
177 
GetConsole()178 Console* Debugger::GetConsole()
179 {
180 	return _console.get();
181 }
182 
Suspend()183 void Debugger::Suspend()
184 {
185 	_suspendCount++;
186 	while(_executionStopped) {}
187 }
188 
Resume()189 void Debugger::Resume()
190 {
191 	_suspendCount--;
192 	if(_suspendCount < 0) {
193 		_suspendCount = 0;
194 	}
195 }
196 
SetFlags(uint32_t flags)197 void Debugger::SetFlags(uint32_t flags)
198 {
199 	bool needUpdate = ((flags ^ _flags) & (int)DebuggerFlags::DisplayOpCodesInLowerCase) != 0;
200 	_flags = flags;
201 	_breakOnFirstCycle = CheckFlag(DebuggerFlags::BreakOnFirstCycle);
202 	if(needUpdate) {
203 		_disassembler->BuildOpCodeTables(CheckFlag(DebuggerFlags::DisplayOpCodesInLowerCase));
204 	}
205 }
206 
CheckFlag(DebuggerFlags flag)207 bool Debugger::CheckFlag(DebuggerFlags flag)
208 {
209 	return (_flags & (uint32_t)flag) == (uint32_t)flag;
210 }
211 
LoadCdlFile(string cdlFilepath)212 bool Debugger::LoadCdlFile(string cdlFilepath)
213 {
214 	if(_codeDataLogger->LoadCdlFile(cdlFilepath)) {
215 		//Can't use DebugBreakHelper due to the fact this is called in the constructor
216 		bool isEmulationThread = _console->GetEmulationThreadId() == std::this_thread::get_id();
217 		if(!isEmulationThread) {
218 			_console->Pause();
219 		}
220 		UpdateCdlCache();
221 		if(!isEmulationThread) {
222 			_console->Resume();
223 		}
224 		return true;
225 	}
226 	return false;
227 }
228 
SetCdlData(uint8_t * cdlData,uint32_t length)229 void Debugger::SetCdlData(uint8_t* cdlData, uint32_t length)
230 {
231 	DebugBreakHelper helper(this);
232 	_codeDataLogger->SetCdlData(cdlData, length);
233 	UpdateCdlCache();
234 }
235 
ResetCdl()236 void Debugger::ResetCdl()
237 {
238 	DebugBreakHelper helper(this);
239 	_codeDataLogger->Reset();
240 	UpdateCdlCache();
241 }
242 
UpdateCdlCache()243 void Debugger::UpdateCdlCache()
244 {
245 	DebugBreakHelper helper(this);
246 
247 	_disassembler->Reset();
248 	for(int i = 0, len = _mapper->GetMemorySize(DebugMemoryType::PrgRom); i < len; i++) {
249 		if(_codeDataLogger->IsCode(i)) {
250 			AddressTypeInfo info = { i, AddressType::PrgRom };
251 			i = _disassembler->BuildCache(info, 0, false, false) - 1;
252 		}
253 	}
254 
255 	_functionEntryPoints.clear();
256 	for(int i = 0, len = _mapper->GetMemorySize(DebugMemoryType::PrgRom); i < len; i++) {
257 		if(_codeDataLogger->IsSubEntryPoint(i)) {
258 			_functionEntryPoints.emplace(i);
259 
260 			//After resetting the cache, set the entry point flags in the disassembly cache
261 			AddressTypeInfo info = { i, AddressType::PrgRom };
262 			_disassembler->BuildCache(info, 0, true, false);
263 		}
264 	}
265 }
266 
IsMarkedAsCode(uint16_t relativeAddress)267 bool Debugger::IsMarkedAsCode(uint16_t relativeAddress)
268 {
269 	AddressTypeInfo info;
270 	GetAbsoluteAddressAndType(relativeAddress, &info);
271 	if(info.Address >= 0 && info.Type == AddressType::PrgRom) {
272 		return _codeDataLogger->IsCode(info.Address);
273 	} else {
274 		return false;
275 	}
276 }
277 
GetCodeDataLogger()278 shared_ptr<CodeDataLogger> Debugger::GetCodeDataLogger()
279 {
280 	return _codeDataLogger;
281 }
282 
GetLabelManager()283 shared_ptr<LabelManager> Debugger::GetLabelManager()
284 {
285 	return _labelManager;
286 }
287 
GetProfiler()288 shared_ptr<Profiler> Debugger::GetProfiler()
289 {
290 	return _profiler;
291 }
292 
SetBreakpoints(Breakpoint breakpoints[],uint32_t length)293 void Debugger::SetBreakpoints(Breakpoint breakpoints[], uint32_t length)
294 {
295 	DebugBreakHelper helper(this);
296 
297 	for(int i = 0; i < Debugger::BreakpointTypeCount; i++) {
298 		_breakpoints[i].clear();
299 		_breakpointRpnList[i].clear();
300 		_hasBreakpoint[i] = false;
301 	}
302 
303 	_bpDummyCpuRequired = false;
304 
305 	_bpExpEval.reset(new ExpressionEvaluator(this));
306 	for(uint32_t j = 0; j < length; j++) {
307 		Breakpoint &bp = breakpoints[j];
308 		for(int i = 0; i < Debugger::BreakpointTypeCount; i++) {
309 			bool isEnabled = bp.IsEnabled() && _console->GetSettings()->CheckFlag(EmulationFlags::DebuggerWindowEnabled);
310 			if((bp.IsMarked() || isEnabled) && bp.HasBreakpointType((BreakpointType)i)) {
311 				_breakpoints[i].push_back(bp);
312 
313 				if(bp.HasCondition()) {
314 					bool success = true;
315 					ExpressionData data = _bpExpEval->GetRpnList(bp.GetCondition(), success);
316 					_breakpointRpnList[i].push_back(success ? data : ExpressionData());
317 				} else {
318 					_breakpointRpnList[i].push_back(ExpressionData());
319 				}
320 
321 				if(isEnabled) {
322 					bool isReadWriteBp = i == BreakpointType::ReadVram || i == BreakpointType::ReadRam || i == BreakpointType::WriteVram || i == BreakpointType::WriteRam || i == BreakpointType::DummyReadRam || i == BreakpointType::DummyWriteRam;
323 					_bpDummyCpuRequired |= isReadWriteBp;
324 				}
325 
326 				_hasBreakpoint[i] = true;
327 			}
328 		}
329 	}
330 }
331 
ProcessBreakpoints(BreakpointType type,OperationInfo & operationInfo,bool allowBreak,bool allowMark)332 bool Debugger::ProcessBreakpoints(BreakpointType type, OperationInfo &operationInfo, bool allowBreak, bool allowMark)
333 {
334 	//Disable breakpoints if debugger window is closed
335 	allowBreak &= _console->GetSettings()->CheckFlag(EmulationFlags::DebuggerWindowEnabled);
336 
337 	if(_runToCycle != 0) {
338 		//Disable all breakpoints while stepping backwards
339 		return false;
340 	} else if(!allowBreak && !allowMark) {
341 		//Nothing to be done, skip processing
342 		return false;
343 	}
344 
345 	AddressTypeInfo info { -1, AddressType::InternalRam };
346 	PpuAddressTypeInfo ppuInfo { -1, PpuAddressType::None };
347 	bool isPpuBreakpoint = false;
348 	switch(type) {
349 		case BreakpointType::Global:
350 			break;
351 
352 		case BreakpointType::Execute:
353 		case BreakpointType::ReadRam:
354 		case BreakpointType::WriteRam:
355 		case BreakpointType::DummyReadRam:
356 		case BreakpointType::DummyWriteRam:
357 			GetAbsoluteAddressAndType(operationInfo.Address, &info);
358 			break;
359 
360 		case BreakpointType::ReadVram:
361 		case BreakpointType::WriteVram:
362 			GetPpuAbsoluteAddressAndType(operationInfo.Address, &ppuInfo);
363 			isPpuBreakpoint = true;
364 			break;
365 	}
366 
367 	vector<Breakpoint> &breakpoints = _breakpoints[(int)type];
368 
369 	bool needBreak = false;
370 	bool needMark = false;
371 	bool needState = true;
372 	uint32_t markBreakpointId = 0;
373 	uint32_t breakpointId = 0;
374 	EvalResultType resultType;
375 
376 	auto processBreakpoint = [&needMark, &needBreak, &markBreakpointId, &breakpointId](Breakpoint &bp) {
377 		if(bp.IsMarked()) {
378 			needMark = true;
379 			markBreakpointId = bp.GetId();
380 		}
381 		if(bp.IsEnabled()) {
382 			needBreak = true;
383 			breakpointId = bp.GetId();
384 		}
385 	};
386 
387 	for(size_t i = 0, len = breakpoints.size(); i < len; i++) {
388 		Breakpoint &breakpoint = breakpoints[i];
389 
390 		if(
391 			((breakpoint.IsEnabled() && allowBreak) || (breakpoint.IsMarked() && allowMark)) &&
392 			(type == BreakpointType::Global ||
393 			(!isPpuBreakpoint && breakpoint.Matches(operationInfo.Address, info)) ||
394 			(isPpuBreakpoint && breakpoint.Matches(operationInfo.Address, ppuInfo)))
395 		) {
396 			if(!breakpoint.HasCondition()) {
397 				processBreakpoint(breakpoint);
398 			} else {
399 				if(needState) {
400 					GetState(&_debugState, false);
401 					needState = false;
402 				}
403 				if(_bpExpEval->Evaluate(_breakpointRpnList[(int)type][i], _debugState, resultType, operationInfo) != 0) {
404 					processBreakpoint(breakpoint);
405 				}
406 			}
407 
408 			if((needMark || !allowMark) && (needBreak || !allowBreak)) {
409 				//No need to process remaining breakpoints
410 				break;
411 			}
412 		}
413 	}
414 
415 	if(needMark && allowMark) {
416 		AddDebugEvent(DebugEventType::Breakpoint, operationInfo.Address, (uint8_t)operationInfo.Value, markBreakpointId);
417 	}
418 
419 	if(needBreak && allowBreak) {
420 		//Found a matching breakpoint, stop execution
421 		Step(1);
422 		SleepUntilResume(BreakSource::Breakpoint, breakpointId, type, operationInfo.Address, (uint8_t)operationInfo.Value, operationInfo.OperationType);
423 		return true;
424 	} else {
425 		return false;
426 	}
427 }
428 
ProcessAllBreakpoints(OperationInfo & operationInfo)429 void Debugger::ProcessAllBreakpoints(OperationInfo &operationInfo)
430 {
431 	if(_runToCycle != 0) {
432 		//Disable all breakpoints while stepping backwards
433 		return;
434 	}
435 
436 	if(_hasBreakpoint[BreakpointType::Execute]) {
437 		ProcessBreakpoints(BreakpointType::Execute, operationInfo, true, true);
438 	}
439 
440 	bool checkUninitReads = _enableBreakOnUninitRead && CheckFlag(DebuggerFlags::BreakOnUninitMemoryRead);
441 
442 	if(!checkUninitReads && !_bpDummyCpuRequired) {
443 		//Nothing to do, no read/write breakpoints are active and don't need to check uninit reads
444 		return;
445 	}
446 
447 	_dummyCpu->SetDummyState(_cpu.get());
448 	_dummyCpu->Exec();
449 
450 	DebugState &state = _debugState;
451 	uint32_t readCount = _dummyCpu->GetReadCount();
452 	if(readCount > 0) {
453 		uint16_t addr;
454 		uint8_t value;
455 		bool isDummyRead;
456 		for(uint32_t i = 0; i < readCount; i++) {
457 			_dummyCpu->GetReadAddr(i, addr, value, isDummyRead);
458 
459 			OperationInfo info;
460 
461 			if(addr >= 0x2000 && addr < 0x4000 && (addr & 0x07) == 0x07) {
462 				//Reads to $2007 will trigger a PPU read
463 				if(_hasBreakpoint[BreakpointType::ReadVram]) {
464 					OperationInfo ppuInfo;
465 					ppuInfo.OperationType = MemoryOperationType::Read;
466 					ppuInfo.Address = state.PPU.BusAddress;
467 					ppuInfo.Value = _ppu->PeekRAM(addr);
468 					if(ProcessBreakpoints(BreakpointType::ReadVram, ppuInfo, true, false)) {
469 						return;
470 					}
471 				}
472 
473 				info.Value = state.PPU.MemoryReadBuffer;
474 			} else {
475 				if(!isDummyRead && checkUninitReads) {
476 					//Break on uninit memory read
477 					AddressTypeInfo info;
478 					GetAbsoluteAddressAndType(addr, &info);
479 					if(info.Address >= 0 && _memoryAccessCounter->IsAddressUninitialized(info)) {
480 						Step(1);
481 						SleepUntilResume(BreakSource::BreakOnUninitMemoryRead, 0, BreakpointType::ReadRam, addr, value);
482 						return;
483 					}
484 				}
485 
486 				info.Value = value;
487 			}
488 
489 			info.Address = addr;
490 			if(isDummyRead) {
491 				if(_hasBreakpoint[BreakpointType::DummyReadRam]) {
492 					info.OperationType = MemoryOperationType::DummyRead;
493 					if(ProcessBreakpoints(BreakpointType::DummyReadRam, info, true, false)) {
494 						return;
495 					}
496 				}
497 			} else {
498 				if(_hasBreakpoint[BreakpointType::ReadRam]) {
499 					info.OperationType = MemoryOperationType::Read;
500 					if(ProcessBreakpoints(BreakpointType::ReadRam, info, true, false)) {
501 						return;
502 					}
503 				}
504 			}
505 		}
506 	}
507 
508 	uint32_t writeCount = _dummyCpu->GetWriteCount();
509 	if(writeCount > 0) {
510 		uint16_t addr;
511 		uint8_t value;
512 		bool isDummyWrite;
513 		for(uint32_t i = 0; i < writeCount; i++) {
514 			_dummyCpu->GetWriteAddrValue(i, addr, value, isDummyWrite);
515 
516 			OperationInfo info;
517 			info.Address = addr;
518 			info.Value = value;
519 			if(isDummyWrite) {
520 				if(_hasBreakpoint[BreakpointType::DummyWriteRam]) {
521 					info.OperationType = MemoryOperationType::DummyWrite;
522 					if(ProcessBreakpoints(BreakpointType::DummyWriteRam, info, true, false)) {
523 						return;
524 					}
525 				}
526 			} else {
527 				if(_hasBreakpoint[BreakpointType::WriteRam]) {
528 					info.OperationType = MemoryOperationType::Write;
529 					if(ProcessBreakpoints(BreakpointType::WriteRam, info, true, false)) {
530 						return;
531 					}
532 				}
533 			}
534 
535 			if(_hasBreakpoint[BreakpointType::WriteVram]) {
536 				if(addr >= 0x2000 && addr < 0x4000 && (addr & 0x07) == 0x07) {
537 					//Write to $2007 will trigger a PPU write
538 					OperationInfo ppuInfo;
539 					ppuInfo.Address = state.PPU.BusAddress;
540 					ppuInfo.Value = value;
541 					ppuInfo.OperationType = MemoryOperationType::Write;
542 					if(ProcessBreakpoints(BreakpointType::WriteVram, ppuInfo, true, false)) {
543 						return;
544 					}
545 				}
546 			}
547 		}
548 	}
549 }
550 
EvaluateExpression(string expression,EvalResultType & resultType,bool useCache)551 int32_t Debugger::EvaluateExpression(string expression, EvalResultType &resultType, bool useCache)
552 {
553 	DebugState state;
554 	OperationInfo operationInfo { 0, 0, MemoryOperationType::DummyRead };
555 	GetState(&state);
556 	if(useCache) {
557 		return _watchExpEval->Evaluate(expression, state, resultType, operationInfo);
558 	} else {
559 		ExpressionEvaluator expEval(this);
560 		return expEval.Evaluate(expression, state, resultType, operationInfo);
561 	}
562 }
563 
UpdateCallstack(uint8_t instruction,uint32_t addr)564 void Debugger::UpdateCallstack(uint8_t instruction, uint32_t addr)
565 {
566 	if((instruction == 0x60 || instruction == 0x40) && !_callstack.empty()) {
567 		//RTS & RTI
568 		uint16_t expectedReturnAddress = _callstack[_callstack.size() - 1].JumpSource;
569 
570 		_callstack.pop_back();
571 		_subReturnAddresses.pop_back();
572 
573 		int spOffset = instruction == 0x40 ? 2 : 1; //RTI has an extra byte on the stack (flags)
574 
575 		uint16_t targetAddr = _memoryManager->DebugReadWord(0x100 + ((_debugState.CPU.SP + spOffset) & 0xFF));
576 		if(targetAddr < expectedReturnAddress || targetAddr - expectedReturnAddress > 3) {
577 			//Mismatch, pop that stack frame and add the new one
578 			if(!_callstack.empty()) {
579 				bool foundMatch = false;
580 				for(int i = (int)_callstack.size() - 1; i >= 0; i--) {
581 					if(targetAddr > _callstack[i].JumpSource && targetAddr < _callstack[i].JumpSource + 3) {
582 						//Found a matching stack frame, unstack until that point
583 						foundMatch = true;
584 						for(int j = (int)_callstack.size() - i - 1; j >= 0; j--) {
585 							_callstack.pop_back();
586 							_subReturnAddresses.pop_back();
587 						}
588 						break;
589 					}
590 				}
591 				if(!foundMatch) {
592 					//Couldn't find a matching frame, replace the current one
593 					AddCallstackFrame(expectedReturnAddress, targetAddr, StackFrameFlags::None);
594 					_subReturnAddresses.push_back(expectedReturnAddress + 3);
595 				}
596 			}
597 		}
598 
599 		_profiler->UnstackFunction();
600 	} else if(instruction == 0x20) {
601 		//JSR
602 		uint16_t targetAddr = _memoryManager->DebugRead(addr + 1) | (_memoryManager->DebugRead(addr + 2) << 8);
603 		AddCallstackFrame(addr, targetAddr, StackFrameFlags::None);
604 		_subReturnAddresses.push_back(addr + 3);
605 
606 		_profiler->StackFunction(_mapper->ToAbsoluteAddress(addr), _mapper->ToAbsoluteAddress(targetAddr));
607 	}
608 }
609 
AddCallstackFrame(uint16_t source,uint16_t target,StackFrameFlags flags)610 void Debugger::AddCallstackFrame(uint16_t source, uint16_t target, StackFrameFlags flags)
611 {
612 	if(_callstack.size() >= 511) {
613 		//Ensure callstack stays below 512 entries - games can use various tricks that could keep making the callstack grow
614 		_callstack.pop_front();
615 		_subReturnAddresses.pop_front();
616 	}
617 
618 	StackFrameInfo stackFrame;
619 	stackFrame.JumpSource = source;
620 	stackFrame.JumpSourceAbsolute = _mapper->ToAbsoluteAddress(source);
621 
622 	stackFrame.JumpTarget = target;
623 	stackFrame.JumpTargetAbsolute = _mapper->ToAbsoluteAddress(target);
624 
625 	stackFrame.Flags = flags;
626 
627 	_callstack.push_back(stackFrame);
628 }
629 
ProcessInterrupt(uint16_t cpuAddr,uint16_t destCpuAddr,bool forNmi)630 void Debugger::ProcessInterrupt(uint16_t cpuAddr, uint16_t destCpuAddr, bool forNmi)
631 {
632 	AddCallstackFrame(cpuAddr, destCpuAddr, forNmi ? StackFrameFlags::Nmi : StackFrameFlags::Irq);
633 	_subReturnAddresses.push_back(cpuAddr);
634 
635 	_profiler->StackFunction(-1, _mapper->ToAbsoluteAddress(destCpuAddr));
636 
637 	ProcessEvent(forNmi ? EventType::Nmi : EventType::Irq);
638 }
639 
ProcessStepConditions(uint16_t addr)640 void Debugger::ProcessStepConditions(uint16_t addr)
641 {
642 	if(_stepOut && (_lastInstruction == 0x60 || _lastInstruction == 0x40) && _stepOutReturnAddress == addr) {
643 		//RTS/RTI found, if we're on the expected return address, break immediately
644 		Step(1);
645 	} else if(_stepOverAddr != -1 && addr == (uint32_t)_stepOverAddr) {
646 		Step(1);
647 	}
648 }
649 
IsPpuCycleToProcess()650 bool Debugger::IsPpuCycleToProcess()
651 {
652 	return _proccessPpuCycle[_ppu->GetCurrentCycle()] || _hasBreakpoint[BreakpointType::Global] || _ppuStepCount > 0;
653 }
654 
ProcessPpuCycle()655 void Debugger::ProcessPpuCycle()
656 {
657 	if(_proccessPpuCycle[_ppu->GetCurrentCycle()]) {
658 		int32_t currentCycle = (_ppu->GetCurrentCycle() << 9) + _ppu->GetCurrentScanline();
659 		for(auto updateCycle : _ppuViewerUpdateCycle) {
660 			if(updateCycle.second == currentCycle) {
661 				_console->GetNotificationManager()->SendNotification(ConsoleNotificationType::PpuViewerDisplayFrame, (void*)(uint64_t)updateCycle.first);
662 			}
663 		}
664 
665 		if(_ppu->GetCurrentCycle() == 0) {
666 			if(_breakOnScanline == _ppu->GetCurrentScanline()) {
667 				Step(1);
668 				SleepUntilResume(BreakSource::Pause);
669 			}
670 			if(_ppu->GetCurrentScanline() == 240) {
671 				ProcessEvent(EventType::EndFrame);
672 			} else if(_ppu->GetCurrentScanline() == -1) {
673 				ProcessEvent(EventType::StartFrame);
674 			}
675 		}
676 	}
677 
678 	if(_hasBreakpoint[BreakpointType::Global]) {
679 		OperationInfo operationInfo { 0, 0, MemoryOperationType::DummyRead };
680 		ProcessBreakpoints(BreakpointType::Global, operationInfo);
681 	}
682 
683 	if(_ppuStepCount > 0) {
684 		_ppuStepCount--;
685 		if(_ppuStepCount == 0) {
686 			Step(1);
687 			SleepUntilResume(BreakSource::PpuStep);
688 		}
689 	}
690 }
691 
ProcessRamOperation(MemoryOperationType type,uint16_t & addr,uint8_t & value)692 bool Debugger::ProcessRamOperation(MemoryOperationType type, uint16_t &addr, uint8_t &value)
693 {
694 	OperationInfo operationInfo { addr, (int16_t)value, type };
695 
696 	_memoryOperationType = type;
697 
698 	bool isDmcRead = false;
699 	if(type == MemoryOperationType::DmcRead) {
700 		//Used to flag the data in the CDL file
701 		isDmcRead = true;
702 		type = MemoryOperationType::Read;
703 	}
704 
705 	ProcessCpuOperation(addr, value, type);
706 
707 	if(type == MemoryOperationType::ExecOpCode) {
708 		_cpu->SetDebugPC(addr);
709 
710 		if(_runToCycle == 0) {
711 			_rewindCache.clear();
712 			_rewindPrevInstructionCycleCache.clear();
713 		}
714 
715 		if(_nextReadAddr != -1) {
716 			//SetNextStatement (either from manual action or code runner)
717 			if(addr < 0x3000 || addr >= 0x4000) {
718 				_returnToAddress = addr;
719 			}
720 
721 			addr = _nextReadAddr;
722 			value = _memoryManager->DebugRead(addr, true);
723 			_cpu->SetDebugPC(addr);
724 			_nextReadAddr = -1;
725 		} else if(_needRewind) {
726 			//Step back - Need to load a state, and then alter the current opcode based on the new program counter
727 			if(!_rewindCache.empty()) {
728 				//Restore the state, and the cycle number of the instruction that preceeded that state
729 				//Otherwise, the target cycle number when building the next cache will be incorrect
730 				_console->LoadState(_rewindCache.back());
731 				_curInstructionCycle = _rewindPrevInstructionCycleCache.back();
732 
733 				_rewindCache.pop_back();
734 				_rewindPrevInstructionCycleCache.pop_back();
735 
736 				//This state is for the instruction we want to stop on, break here.
737 				_runToCycle = 0;
738 				Step(1);
739 			} else {
740 				_console->GetRewindManager()->StartRewinding(true);
741 			}
742 			UpdateProgramCounter(addr, value);
743 			_needRewind = false;
744 		}
745 		ProcessScriptSaveState(addr, value);
746 
747 		_currentReadAddr = &addr;
748 		_currentReadValue = &value;
749 	}
750 
751 	//Check if a breakpoint has been hit and freeze execution if one has
752 	bool breakDone = false;
753 	AddressTypeInfo addressInfo;
754 	GetAbsoluteAddressAndType(addr, &addressInfo);
755 	int32_t absoluteAddr = addressInfo.Type == AddressType::PrgRom ? addressInfo.Address : -1;
756 	int32_t absoluteRamAddr = addressInfo.Type == AddressType::WorkRam ? addressInfo.Address : -1;
757 
758 	if(addressInfo.Address >= 0 && type != MemoryOperationType::DummyRead && type != MemoryOperationType::DummyWrite && _runToCycle == 0) {
759 		//Ignore dummy read/writes and do not change counters while using the step back feature
760 		if(type == MemoryOperationType::Write && CheckFlag(DebuggerFlags::IgnoreRedundantWrites)) {
761 			if(_memoryManager->DebugRead(addr) != value) {
762 				_memoryAccessCounter->ProcessMemoryAccess(addressInfo, type, _cpu->GetCycleCount());
763 			}
764 		} else {
765 			if(_memoryAccessCounter->ProcessMemoryAccess(addressInfo, type, _cpu->GetCycleCount())) {
766 				if(!_breakOnFirstCycle && _enableBreakOnUninitRead && CheckFlag(DebuggerFlags::BreakOnUninitMemoryRead)) {
767 					//Break on uninit memory read
768 					Step(1);
769 					breakDone = SleepUntilResume(BreakSource::BreakOnUninitMemoryRead, 0, BreakpointType::Global, operationInfo.Address, (uint8_t)operationInfo.Value, operationInfo.OperationType);
770 				}
771 			}
772 		}
773 	}
774 
775 	if(absoluteAddr >= 0) {
776 		if(type == MemoryOperationType::ExecOperand) {
777 			_codeDataLogger->SetFlag(absoluteAddr, CdlPrgFlags::Code);
778 		} else if(type == MemoryOperationType::Read) {
779 			_codeDataLogger->SetFlag(absoluteAddr, CdlPrgFlags::Data);
780 			if(isDmcRead) {
781 				_codeDataLogger->SetFlag(absoluteAddr, CdlPrgFlags::PcmData);
782 			}
783 		}
784 	} else if(addr < 0x2000 || absoluteRamAddr >= 0) {
785 		if(type == MemoryOperationType::Write) {
786 			_disassembler->InvalidateCache(addressInfo);
787 		}
788 	}
789 
790 	if(type == MemoryOperationType::ExecOpCode) {
791 		_opCodeCycle = 0;
792 		_prevInstructionCycle = _curInstructionCycle;
793 		_curInstructionCycle = _cpu->GetCycleCount();
794 
795 		_disassembler->BuildCache(addressInfo, addr, false, true);
796 
797 		if(absoluteAddr >= 0) {
798 			_codeDataLogger->SetFlag(absoluteAddr, CdlPrgFlags::Code);
799 		}
800 
801 		if(_disassembler->IsJump(value)) {
802 			uint16_t targetPc = _disassembler->GetDisassemblyInfo(addressInfo).GetJumpDestination(_cpu->GetPC(), _memoryManager.get());
803 			AddressTypeInfo addressInfo;
804 			GetAbsoluteAddressAndType(targetPc, &addressInfo);
805 			if(addressInfo.Address >= 0 && addressInfo.Type == AddressType::PrgRom) {
806 				if(value == 0x20) {
807 					//JSR, mark target as a sub entry point
808 					_disassembler->BuildCache(addressInfo, targetPc, true, false);
809 					_functionEntryPoints.emplace(addressInfo.Address);
810 					_codeDataLogger->SetFlag(addressInfo.Address, CdlPrgFlags::SubEntryPoint);
811 				} else {
812 					//Only mark as jump target if not marked as sub entry point
813 					_codeDataLogger->SetFlag(addressInfo.Address, CdlPrgFlags::JumpTarget);
814 				}
815 			}
816 		}
817 
818 		ProcessStepConditions(addr);
819 
820 		_performanceTracker->ProcessCpuExec(addressInfo);
821 		_profiler->ProcessInstructionStart(absoluteAddr);
822 
823 		BreakSource breakSource = BreakSource::Unspecified;
824 		if(value == 0 && CheckFlag(DebuggerFlags::BreakOnBrk)) {
825 			Step(1);
826 			breakSource = BreakSource::BreakOnBrk;
827 		} else if(CheckFlag(DebuggerFlags::BreakOnUnofficialOpCode) && _disassembler->IsUnofficialOpCode(value)) {
828 			Step(1);
829 			breakSource = BreakSource::BreakOnUnofficialOpCode;
830 		}
831 
832 		if(_runToCycle != 0) {
833 			if(_cpu->GetCycleCount() >= _runToCycle) {
834 				//Step back operation is done, revert RewindManager's state & break debugger
835 				_console->GetRewindManager()->StopRewinding(true);
836 				_runToCycle = 0;
837 				Step(1);
838 			} else if(_runToCycle - _cpu->GetCycleCount() < 500) {
839 				_rewindCache.push_back(stringstream());
840 				_console->SaveState(_rewindCache.back());
841 				_rewindPrevInstructionCycleCache.push_back(_prevInstructionCycle);
842 			}
843 		}
844 
845 		_lastInstruction = value;
846 		breakDone = SleepUntilResume(breakSource);
847 
848 		if(_codeRunner && !_codeRunner->IsRunning()) {
849 			_codeRunner.reset();
850 		}
851 
852 		GetState(&_debugState, false);
853 
854 		DisassemblyInfo disassemblyInfo;
855 		if(_codeRunner && _codeRunner->IsRunning() && addr >= 0x3000 && addr < 0x4000) {
856 			disassemblyInfo = _codeRunner->GetDisassemblyInfo(addr);
857 		} else {
858 			disassemblyInfo = _disassembler->GetDisassemblyInfo(addressInfo);
859 		}
860 		_traceLogger->Log(_debugState, disassemblyInfo, operationInfo);
861 	} else {
862 		_opCodeCycle++;
863 		_traceLogger->LogNonExec(operationInfo);
864 		_profiler->ProcessCycle();
865 	}
866 
867 	if(!breakDone && _stepCycleCount > 0) {
868 		_stepCycleCount--;
869 		if(_stepCycleCount == 0) {
870 			Step(1);
871 			breakDone = SleepUntilResume(BreakSource::CpuStep);
872 		}
873 	}
874 
875 	BreakpointType breakpointType;
876 	switch(type) {
877 		default: breakpointType = BreakpointType::Execute; break;
878 
879 		case MemoryOperationType::DummyRead:
880 		case MemoryOperationType::Read: breakpointType = BreakpointType::ReadRam; break;
881 
882 		case MemoryOperationType::DummyWrite:
883 		case MemoryOperationType::Write: breakpointType = BreakpointType::WriteRam; break;
884 	}
885 
886 	//For DMC reads, always break when it happens, rather than at the start (because we can't predict it easily)
887 	if(_breakOnFirstCycle && !isDmcRead) {
888 		if(type == MemoryOperationType::ExecOpCode && !breakDone) {
889 			ProcessAllBreakpoints(operationInfo);
890 		} else if(_hasBreakpoint[breakpointType]) {
891 			//Process marked breakpoints
892 			ProcessBreakpoints(breakpointType, operationInfo, false, true);
893 		}
894 	} else {
895 		if(_hasBreakpoint[breakpointType]) {
896 			ProcessBreakpoints(breakpointType, operationInfo, !breakDone, true);
897 		}
898 	}
899 
900 	_currentReadAddr = nullptr;
901 	_currentReadValue = nullptr;
902 
903 	if(type == MemoryOperationType::Write) {
904 		if(addr >= 0x2000 && addr <= 0x3FFF) {
905 			if((addr & 0x07) == 5 || (addr & 0x07) == 6) {
906 				GetState(&_debugState, false);
907 				AddDebugEvent(DebugEventType::PpuRegisterWrite, addr, value, -1, _debugState.PPU.State.WriteToggle ? 1 : 0);
908 			} else {
909 				AddDebugEvent(DebugEventType::PpuRegisterWrite, addr, value);
910 			}
911 		} else if(addr >= 0x4018 && _mapper->IsWriteRegister(addr)) {
912 			AddDebugEvent(DebugEventType::MapperRegisterWrite, addr, value);
913 		}
914 
915 		if(_frozenAddresses[addr]) {
916 			return false;
917 		}
918 	} else if(type == MemoryOperationType::Read) {
919 		if(addr >= 0x2000 && addr <= 0x3FFF) {
920 			AddDebugEvent(DebugEventType::PpuRegisterRead, addr, value);
921 		} else if(addr >= 0x4018 && _mapper->IsReadRegister(addr)) {
922 			AddDebugEvent(DebugEventType::MapperRegisterRead, addr, value);
923 		}
924 	} else if(type == MemoryOperationType::ExecOpCode) {
925 		UpdateCallstack(_lastInstruction, addr);
926 	}
927 
928 	return true;
929 }
930 
SleepUntilResume(BreakSource source,uint32_t breakpointId,BreakpointType bpType,uint16_t bpAddress,uint8_t bpValue,MemoryOperationType bpMemOpType)931 bool Debugger::SleepUntilResume(BreakSource source, uint32_t breakpointId, BreakpointType bpType, uint16_t bpAddress, uint8_t bpValue, MemoryOperationType bpMemOpType)
932 {
933 	int32_t stepCount = _stepCount.load();
934 	if(stepCount > 0) {
935 		_stepCount--;
936 		stepCount = _stepCount.load();
937 	} else if(stepCount == 0) {
938 		//If stepCount was already 0 when we enter the function, it means
939 		//Debugger::Suspend() and Debugger::Resume() were called by another thread
940 		source = BreakSource::BreakAfterSuspend;
941 	}
942 
943 	//Read both values here since they might change while executing the code below
944 	int32_t preventResume = _preventResume;
945 	bool breakRequested = _breakRequested;
946 
947 	if((stepCount == 0 || breakRequested) && !_stopFlag && _suspendCount == 0) {
948 		//Break
949 		auto lock = _breakLock.AcquireSafe();
950 
951 		if(preventResume == 0) {
952 			_console->GetSoundMixer()->StopAudio();
953 			if(source == BreakSource::Unspecified) {
954 				source = _breakSource;
955 			}
956 			_breakSource = BreakSource::Unspecified;
957 
958 			uint64_t param = (
959 				((uint64_t)breakpointId << 40) |
960 				((uint64_t)bpValue << 32) |
961 				((uint64_t)(bpAddress & 0xFFFF) << 16) |
962 				((uint64_t)((int)bpMemOpType & 0x0F) << 12) |
963 				((uint64_t)(bpType & 0x0F) << 8) |
964 				((uint64_t)source & 0xFF)
965 			);
966 
967 			_console->GetNotificationManager()->SendNotification(ConsoleNotificationType::CodeBreak, (void*)(uint64_t)param);
968 
969 			ProcessEvent(EventType::CodeBreak);
970 			_stepOverAddr = -1;
971 			if(CheckFlag(DebuggerFlags::PpuPartialDraw)) {
972 				_ppu->DebugSendFrame();
973 			}
974 		}
975 
976 		_executionStopped = true;
977 		_pausedForDebugHelper = breakRequested;
978 		while((((stepCount == 0 || _breakRequested) && _suspendCount == 0) || _preventResume > 0) && !_stopFlag) {
979 			std::this_thread::sleep_for(std::chrono::duration<int, std::milli>(10));
980 			if(stepCount == 0) {
981 				_console->ResetRunTimers();
982 			}
983 			stepCount = _stepCount.load();
984 		}
985 		_pausedForDebugHelper = false;
986 		_executionStopped = false;
987 		return true;
988 	}
989 	return false;
990 }
991 
ProcessVramReadOperation(MemoryOperationType type,uint16_t addr,uint8_t & value)992 void Debugger::ProcessVramReadOperation(MemoryOperationType type, uint16_t addr, uint8_t &value)
993 {
994 	PpuAddressTypeInfo addressInfo;
995 	_mapper->GetPpuAbsoluteAddressAndType(addr, &addressInfo);
996 	_codeDataLogger->SetFlag(addressInfo.Address, type == MemoryOperationType::Read ? CdlChrFlags::Read : CdlChrFlags::Drawn);
997 
998 	if(_hasBreakpoint[BreakpointType::ReadVram]) {
999 		OperationInfo operationInfo{ addr, value, type };
1000 		ProcessBreakpoints(BreakpointType::ReadVram, operationInfo, !_breakOnFirstCycle, true);
1001 	}
1002 	_memoryAccessCounter->ProcessPpuMemoryAccess(addressInfo, type, _cpu->GetCycleCount());
1003 	ProcessPpuOperation(addr, value, MemoryOperationType::Read);
1004 }
1005 
ProcessVramWriteOperation(uint16_t addr,uint8_t & value)1006 void Debugger::ProcessVramWriteOperation(uint16_t addr, uint8_t &value)
1007 {
1008 	PpuAddressTypeInfo addressInfo;
1009 	_mapper->GetPpuAbsoluteAddressAndType(addr, &addressInfo);
1010 
1011 	if(_hasBreakpoint[BreakpointType::WriteVram]) {
1012 		OperationInfo operationInfo{ addr, value, MemoryOperationType::Write };
1013 		ProcessBreakpoints(BreakpointType::WriteVram, operationInfo, !_breakOnFirstCycle, true);
1014 	}
1015 	_memoryAccessCounter->ProcessPpuMemoryAccess(addressInfo, MemoryOperationType::Write, _cpu->GetCycleCount());
1016 	ProcessPpuOperation(addr, value, MemoryOperationType::Write);
1017 }
1018 
GetInstructionProgress(InstructionProgress & state)1019 void Debugger::GetInstructionProgress(InstructionProgress &state)
1020 {
1021 	state.OpCode = _lastInstruction;
1022 	state.OpCycle = _opCodeCycle;
1023 	state.OpMemoryOperationType = _memoryOperationType;
1024 }
1025 
GetApuState(ApuState * state)1026 void Debugger::GetApuState(ApuState *state)
1027 {
1028 	//Pause the emulation
1029 	DebugBreakHelper helper(this);
1030 
1031 	//Force APU to catch up before we retrieve its state
1032 	_apu->Run();
1033 
1034 	*state = _apu->GetState();
1035 }
1036 
GetState(DebugState * state,bool includeMapperInfo)1037 void Debugger::GetState(DebugState *state, bool includeMapperInfo)
1038 {
1039 	state->Model = _console->GetModel();
1040 	state->ClockRate = _cpu->GetClockRate(_console->GetModel());
1041 	_cpu->GetState(state->CPU);
1042 	_ppu->GetState(state->PPU);
1043 	if(includeMapperInfo) {
1044 		state->Cartridge = _mapper->GetState();
1045 		state->APU = _apu->GetState();
1046 	}
1047 }
1048 
SetState(DebugState state)1049 void Debugger::SetState(DebugState state)
1050 {
1051 	_cpu->SetState(state.CPU);
1052 	_ppu->SetState(state.PPU);
1053 	if(state.CPU.PC != _cpu->GetPC()) {
1054 		SetNextStatement(state.CPU.PC);
1055 	}
1056 }
1057 
Break()1058 void Debugger::Break()
1059 {
1060 	_breakRequested = true;
1061 }
1062 
ResumeFromBreak()1063 void Debugger::ResumeFromBreak()
1064 {
1065 	_breakRequested = false;
1066 }
1067 
ResetStepState()1068 void Debugger::ResetStepState()
1069 {
1070 	_ppuStepCount = -1;
1071 	_stepOverAddr = -1;
1072 	_stepCycleCount = -1;
1073 	_stepCount = -1;
1074 	_breakOnScanline = -2;
1075 	_stepOut = false;
1076 }
1077 
PpuStep(uint32_t count)1078 void Debugger::PpuStep(uint32_t count)
1079 {
1080 	ResetStepState();
1081 	_ppuStepCount = count;
1082 	_breakSource = BreakSource::PpuStep;
1083 }
1084 
Step(uint32_t count,BreakSource source)1085 void Debugger::Step(uint32_t count, BreakSource source)
1086 {
1087 	//Run CPU for [count] INSTRUCTIONS before breaking again
1088 	ResetStepState();
1089 	_stepCount = count;
1090 	_breakSource = source;
1091 }
1092 
StepCycles(uint32_t count)1093 void Debugger::StepCycles(uint32_t count)
1094 {
1095 	//Run CPU for [count] CYCLES before breaking again
1096 	ResetStepState();
1097 	_stepCycleCount = count;
1098 	_breakSource = BreakSource::CpuStep;
1099 }
1100 
StepOut()1101 void Debugger::StepOut()
1102 {
1103 	if(_subReturnAddresses.empty()) {
1104 		return;
1105 	}
1106 
1107 	ResetStepState();
1108 	_stepOut = true;
1109 	_stepOutReturnAddress = _subReturnAddresses.back();
1110 }
1111 
StepOver()1112 void Debugger::StepOver()
1113 {
1114 	if(_lastInstruction == 0x20 || _lastInstruction == 0x00) {
1115 		//We are on a JSR/BRK instruction, need to continue until the following instruction
1116 		_stepOverAddr = _cpu->GetPC() + (_lastInstruction == 0x20 ? 3 : 1);
1117 		Run();
1118 	} else {
1119 		//Except for JSR & BRK, StepOver behaves the same as StepTnto
1120 		Step(1);
1121 	}
1122 }
1123 
StepBack()1124 void Debugger::StepBack()
1125 {
1126 	if(_runToCycle == 0) {
1127 		_runToCycle = _prevInstructionCycle;
1128 		_needRewind = true;
1129 		Run();
1130 	}
1131 }
1132 
Run()1133 void Debugger::Run()
1134 {
1135 	//Resume execution after a breakpoint has been hit
1136 	_ppuStepCount = -1;
1137 	_stepCount = -1;
1138 	_breakOnScanline = -2;
1139 	_stepCycleCount = -1;
1140 	_stepOut = false;
1141 }
1142 
BreakImmediately(BreakSource source)1143 void Debugger::BreakImmediately(BreakSource source)
1144 {
1145 	Step(1);
1146 	SleepUntilResume(source);
1147 }
1148 
BreakOnScanline(int16_t scanline)1149 void Debugger::BreakOnScanline(int16_t scanline)
1150 {
1151 	Run();
1152 	_breakOnScanline = scanline;
1153 }
1154 
GenerateCodeOutput()1155 void Debugger::GenerateCodeOutput()
1156 {
1157 	State cpuState;
1158 	_cpu->GetState(cpuState);
1159 
1160 	_disassemblerOutput.clear();
1161 	_disassemblerOutput.reserve(10000);
1162 
1163 	for(uint32_t i = 0; i < 0x10000; i += 0x100) {
1164 		//Merge all sequential ranges into 1 chunk
1165 		AddressTypeInfo startInfo, currentInfo, endInfo;
1166 		GetAbsoluteAddressAndType(i, &startInfo);
1167 		currentInfo = startInfo;
1168 		GetAbsoluteAddressAndType(i+0x100, &endInfo);
1169 
1170 		uint32_t startMemoryAddr = i;
1171 		int32_t startAddr, endAddr;
1172 
1173 		if(startInfo.Address >= 0) {
1174 			startAddr = startInfo.Address;
1175 			endAddr = startAddr + 0xFF;
1176 			while(currentInfo.Type == endInfo.Type && currentInfo.Address + 0x100 == endInfo.Address && i < 0x10000) {
1177 				endAddr += 0x100;
1178 				currentInfo = endInfo;
1179 				i+=0x100;
1180 				GetAbsoluteAddressAndType(i + 0x100, &endInfo);
1181 			}
1182 			_disassemblerOutput += _disassembler->GetCode(startInfo, endAddr, startMemoryAddr, cpuState, _memoryManager, _labelManager);
1183 		}
1184 	}
1185 }
1186 
GetCode(uint32_t & length)1187 const char* Debugger::GetCode(uint32_t &length)
1188 {
1189 	string previousCode = _disassemblerOutput;
1190 	GenerateCodeOutput();
1191 	bool forceRefresh = length == (uint32_t)-1;
1192 	length = (uint32_t)_disassemblerOutput.size();
1193 	if(!forceRefresh && previousCode.compare(_disassemblerOutput) == 0) {
1194 		//Return null pointer if the code is identical to last call
1195 		//This avois the UTF8->UTF16 conversion that the UI needs to do
1196 		//before comparing the strings
1197 		return nullptr;
1198 	} else {
1199 		return _disassemblerOutput.c_str();
1200 	}
1201 }
1202 
GetRelativeAddress(uint32_t addr,AddressType type)1203 int32_t Debugger::GetRelativeAddress(uint32_t addr, AddressType type)
1204 {
1205 	switch(type) {
1206 		case AddressType::InternalRam:
1207 		case AddressType::Register:
1208 			return addr;
1209 
1210 		case AddressType::PrgRom:
1211 		case AddressType::WorkRam:
1212 		case AddressType::SaveRam:
1213 			return _mapper->FromAbsoluteAddress(addr, type);
1214 	}
1215 
1216 	return -1;
1217 }
1218 
GetRelativePpuAddress(uint32_t addr,PpuAddressType type)1219 int32_t Debugger::GetRelativePpuAddress(uint32_t addr, PpuAddressType type)
1220 {
1221 	if(type == PpuAddressType::PaletteRam) {
1222 		return 0x3F00 | (addr & 0x1F);
1223 	}
1224 	return _mapper->FromAbsolutePpuAddress(addr, type);
1225 }
1226 
GetAbsoluteAddress(uint32_t addr)1227 int32_t Debugger::GetAbsoluteAddress(uint32_t addr)
1228 {
1229 	return _mapper->ToAbsoluteAddress(addr);
1230 }
1231 
GetAbsoluteChrAddress(uint32_t addr)1232 int32_t Debugger::GetAbsoluteChrAddress(uint32_t addr)
1233 {
1234 	return _mapper->ToAbsoluteChrAddress(addr);
1235 }
1236 
SetNextStatement(uint16_t addr)1237 void Debugger::SetNextStatement(uint16_t addr)
1238 {
1239 	if(_currentReadAddr) {
1240 		_cpu->SetDebugPC(addr);
1241 		*_currentReadAddr = addr;
1242 		*_currentReadValue = _memoryManager->DebugRead(addr, false);
1243 	} else {
1244 		//Can't change the address right away (CPU is in the middle of an instruction)
1245 		//Address will change after current instruction is done executing
1246 		_nextReadAddr = addr;
1247 
1248 		//Force the current instruction to finish
1249 		Step(1);
1250 	}
1251 }
1252 
GetCallstack(StackFrameInfo * callstackArray,uint32_t & callstackSize)1253 void Debugger::GetCallstack(StackFrameInfo* callstackArray, uint32_t &callstackSize)
1254 {
1255 	DebugBreakHelper helper(this);
1256 	int i = 0;
1257 	for(StackFrameInfo &info : _callstack) {
1258 		callstackArray[i] = info;
1259 		i++;
1260 	}
1261 	callstackSize = i;
1262 }
1263 
GetFunctionEntryPointCount()1264 int32_t Debugger::GetFunctionEntryPointCount()
1265 {
1266 	DebugBreakHelper helper(this);
1267 	return (int32_t)_functionEntryPoints.size();
1268 }
1269 
GetFunctionEntryPoints(int32_t * entryPoints,int32_t maxCount)1270 void Debugger::GetFunctionEntryPoints(int32_t* entryPoints, int32_t maxCount)
1271 {
1272 	DebugBreakHelper helper(this);
1273 	int32_t i = 0;
1274 	for(auto itt = _functionEntryPoints.begin(); itt != _functionEntryPoints.end(); itt++) {
1275 		entryPoints[i] = *itt;
1276 		i++;
1277 		if(i == maxCount - 1) {
1278 			break;
1279 		}
1280 	}
1281 	entryPoints[i] = -1;
1282 }
1283 
GetAssembler()1284 shared_ptr<Assembler> Debugger::GetAssembler()
1285 {
1286 	return _assembler;
1287 }
1288 
GetTraceLogger()1289 shared_ptr<TraceLogger> Debugger::GetTraceLogger()
1290 {
1291 	return _traceLogger;
1292 }
1293 
GetMemoryDumper()1294 shared_ptr<MemoryDumper> Debugger::GetMemoryDumper()
1295 {
1296 	return _memoryDumper;
1297 }
1298 
GetMemoryAccessCounter()1299 shared_ptr<MemoryAccessCounter> Debugger::GetMemoryAccessCounter()
1300 {
1301 	return _memoryAccessCounter;
1302 }
1303 
GetPerformanceTracker()1304 shared_ptr<PerformanceTracker> Debugger::GetPerformanceTracker()
1305 {
1306 	return _performanceTracker;
1307 }
1308 
IsExecutionStopped()1309 bool Debugger::IsExecutionStopped()
1310 {
1311 	return _executionStopped || _console->IsExecutionStopped();
1312 }
1313 
IsPauseIconShown()1314 bool Debugger::IsPauseIconShown()
1315 {
1316 	return (_executionStopped || _console->IsPaused()) && !CheckFlag(DebuggerFlags::HidePauseIcon) && _preventResume == 0 && !_pausedForDebugHelper;
1317 }
1318 
PreventResume()1319 void Debugger::PreventResume()
1320 {
1321 	_preventResume++;
1322 }
1323 
AllowResume()1324 void Debugger::AllowResume()
1325 {
1326 	_preventResume--;
1327 }
1328 
GetAbsoluteAddressAndType(uint32_t relativeAddr,AddressTypeInfo * info)1329 void Debugger::GetAbsoluteAddressAndType(uint32_t relativeAddr, AddressTypeInfo* info)
1330 {
1331 	return _mapper->GetAbsoluteAddressAndType(relativeAddr, info);
1332 }
1333 
GetPpuAbsoluteAddressAndType(uint32_t relativeAddr,PpuAddressTypeInfo * info)1334 void Debugger::GetPpuAbsoluteAddressAndType(uint32_t relativeAddr, PpuAddressTypeInfo* info)
1335 {
1336 	return _mapper->GetPpuAbsoluteAddressAndType(relativeAddr, info);
1337 }
1338 
UpdatePpuCyclesToProcess()1339 void Debugger::UpdatePpuCyclesToProcess()
1340 {
1341 	memset(_proccessPpuCycle, 0, sizeof(_proccessPpuCycle));
1342 	for(auto updateCycle : _ppuViewerUpdateCycle) {
1343 		int16_t cycle = updateCycle.second >> 9;
1344 		if(cycle < 341) {
1345 			_proccessPpuCycle[cycle] = true;
1346 		}
1347 	}
1348 	_proccessPpuCycle[0] = true;
1349 }
1350 
SetPpuViewerScanlineCycle(int32_t ppuViewerId,int32_t scanline,int32_t cycle)1351 void Debugger::SetPpuViewerScanlineCycle(int32_t ppuViewerId, int32_t scanline, int32_t cycle)
1352 {
1353 	DebugBreakHelper helper(this);
1354 	_ppuViewerUpdateCycle[ppuViewerId] = (cycle << 9) + scanline;
1355 	UpdatePpuCyclesToProcess();
1356 }
1357 
ClearPpuViewerSettings(int32_t ppuViewer)1358 void Debugger::ClearPpuViewerSettings(int32_t ppuViewer)
1359 {
1360 	DebugBreakHelper helper(this);
1361 	_ppuViewerUpdateCycle.erase(ppuViewer);
1362 	UpdatePpuCyclesToProcess();
1363 }
1364 
SetLastFramePpuScroll(uint16_t addr,uint8_t xScroll,bool updateHorizontalScrollOnly)1365 void Debugger::SetLastFramePpuScroll(uint16_t addr, uint8_t xScroll, bool updateHorizontalScrollOnly)
1366 {
1367 	_ppuScrollX = ((addr & 0x1F) << 3) | xScroll | ((addr & 0x400) ? 0x100 : 0);
1368 	if(!updateHorizontalScrollOnly) {
1369 		_ppuScrollY = (((addr & 0x3E0) >> 2) | ((addr & 0x7000) >> 12)) + ((addr & 0x800) ? 240 : 0);
1370 	}
1371 }
1372 
GetPpuScroll()1373 uint32_t Debugger::GetPpuScroll()
1374 {
1375 	return (_ppuScrollY << 16) | _ppuScrollX;
1376 }
1377 
SetFreezeState(uint16_t address,bool frozen)1378 void Debugger::SetFreezeState(uint16_t address, bool frozen)
1379 {
1380 	_frozenAddresses[address] = frozen ? 1 : 0;
1381 }
1382 
GetFreezeState(uint16_t startAddress,uint16_t length,bool * freezeState)1383 void Debugger::GetFreezeState(uint16_t startAddress, uint16_t length, bool* freezeState)
1384 {
1385 	for(uint16_t i = 0; i < length; i++) {
1386 		freezeState[i] = _frozenAddresses[startAddress + i] ? true : false;
1387 	}
1388 }
1389 
StartCodeRunner(uint8_t * byteCode,uint32_t codeLength)1390 void Debugger::StartCodeRunner(uint8_t *byteCode, uint32_t codeLength)
1391 {
1392 	_codeRunner.reset(new CodeRunner(vector<uint8_t>(byteCode, byteCode + codeLength), this));
1393 	_memoryManager->RegisterIODevice(_codeRunner.get());
1394 	_returnToAddress = _cpu->GetDebugPC();
1395 	SetNextStatement(CodeRunner::BaseAddress);
1396 }
1397 
StopCodeRunner()1398 void Debugger::StopCodeRunner()
1399 {
1400 	_memoryManager->UnregisterIODevice(_codeRunner.get());
1401 	_memoryManager->RegisterIODevice(_ppu.get());
1402 
1403 	//Break debugger when code has finished executing
1404 	SetNextStatement(_returnToAddress);
1405 
1406 	if(_console->GetSettings()->CheckFlag(EmulationFlags::DebuggerWindowEnabled)) {
1407 		Step(1);
1408 	} else {
1409 		Run();
1410 	}
1411 }
1412 
GetNesHeader(uint8_t * header)1413 void Debugger::GetNesHeader(uint8_t* header)
1414 {
1415 	NESHeader nesHeader = _mapper->GetRomInfo().NesHeader;
1416 	memcpy(header, &nesHeader, sizeof(NESHeader));
1417 }
1418 
SaveRomToDisk(string filename,bool saveAsIps,uint8_t * header,CdlStripFlag cdlStripflag)1419 void Debugger::SaveRomToDisk(string filename, bool saveAsIps, uint8_t* header, CdlStripFlag cdlStripflag)
1420 {
1421 	vector<uint8_t> fileData;
1422 	_mapper->GetRomFileData(fileData, saveAsIps, header);
1423 
1424 	_codeDataLogger->StripData(fileData.data() + sizeof(NESHeader), cdlStripflag);
1425 
1426 	ofstream file(filename, ios::out | ios::binary);
1427 	if(file.good()) {
1428 		file.write((char*)fileData.data(), fileData.size());
1429 		file.close();
1430 	}
1431 }
1432 
RevertPrgChrChanges()1433 void Debugger::RevertPrgChrChanges()
1434 {
1435 	DebugBreakHelper helper(this);
1436 	_mapper->RevertPrgChrChanges();
1437 	_disassembler->Reset();
1438 	UpdateCdlCache();
1439 }
1440 
HasPrgChrChanges()1441 bool Debugger::HasPrgChrChanges()
1442 {
1443 	return _mapper->HasPrgChrChanges();
1444 }
1445 
FindSubEntryPoint(uint16_t relativeAddress)1446 int32_t Debugger::FindSubEntryPoint(uint16_t relativeAddress)
1447 {
1448 	AddressTypeInfo info;
1449 	int32_t address = relativeAddress;
1450 	do {
1451 		GetAbsoluteAddressAndType(address, &info);
1452 		if(info.Address < 0 || info.Type != AddressType::PrgRom || _codeDataLogger->IsData(info.Address)) {
1453 			break;
1454 		}
1455 		address--;
1456 		if(_codeDataLogger->IsSubEntryPoint(info.Address)) {
1457 			break;
1458 		}
1459 	} while(address >= 0);
1460 
1461 	return address > relativeAddress ? relativeAddress : (address + 1);
1462 }
1463 
SetInputOverride(uint8_t port,uint32_t state)1464 void Debugger::SetInputOverride(uint8_t port, uint32_t state)
1465 {
1466 	_inputOverride[port] = state;
1467 }
1468 
LoadScript(string name,string content,int32_t scriptId)1469 int Debugger::LoadScript(string name, string content, int32_t scriptId)
1470 {
1471 	DebugBreakHelper helper(this);
1472 	auto lock = _scriptLock.AcquireSafe();
1473 
1474 	if(scriptId < 0) {
1475 		shared_ptr<ScriptHost> script(new ScriptHost(_nextScriptId++));
1476 		script->LoadScript(name, content, this);
1477 		_scripts.push_back(script);
1478 		_hasScript = true;
1479 		return script->GetScriptId();
1480 	} else {
1481 		auto result = std::find_if(_scripts.begin(), _scripts.end(), [=](shared_ptr<ScriptHost> &script) {
1482 			return script->GetScriptId() == scriptId;
1483 		});
1484 		if(result != _scripts.end()) {
1485 			//Send a ScriptEnded event before reloading the code
1486 			(*result)->ProcessEvent(EventType::ScriptEnded);
1487 
1488 			(*result)->LoadScript(name, content, this);
1489 			return scriptId;
1490 		}
1491 	}
1492 
1493 	return -1;
1494 }
1495 
RemoveScript(int32_t scriptId)1496 void Debugger::RemoveScript(int32_t scriptId)
1497 {
1498 	DebugBreakHelper helper(this);
1499 	auto lock = _scriptLock.AcquireSafe();
1500 	_scripts.erase(std::remove_if(_scripts.begin(), _scripts.end(), [=](const shared_ptr<ScriptHost>& script) {
1501 		if(script->GetScriptId() == scriptId) {
1502 			//Send a ScriptEnded event before unloading the script
1503 			script->ProcessEvent(EventType::ScriptEnded);
1504 			_console->GetDebugHud()->ClearScreen();
1505 			return true;
1506 		}
1507 		return false;
1508 	}), _scripts.end());
1509 	_hasScript = _scripts.size() > 0;
1510 }
1511 
GetScriptLog(int32_t scriptId)1512 const char* Debugger::GetScriptLog(int32_t scriptId)
1513 {
1514 	auto lock = _scriptLock.AcquireSafe();
1515 	for(shared_ptr<ScriptHost> &script : _scripts) {
1516 		if(script->GetScriptId() == scriptId) {
1517 			return script->GetLog();
1518 		}
1519 	}
1520 	return "";
1521 }
1522 
ResetCounters()1523 void Debugger::ResetCounters()
1524 {
1525 	//This is called when loading a state (among other things)
1526 	//Prevent counter reset when using step back (_runToCycle != 0), because step back will load a state
1527 	if(_runToCycle == 0) {
1528 		_memoryAccessCounter->ResetCounts();
1529 	}
1530 	_profiler->Reset();
1531 }
1532 
UpdateProgramCounter(uint16_t & addr,uint8_t & value)1533 void Debugger::UpdateProgramCounter(uint16_t &addr, uint8_t &value)
1534 {
1535 	addr = _cpu->GetPC();
1536 	value = _memoryManager->DebugRead(addr, true);
1537 	_cpu->SetDebugPC(addr);
1538 }
1539 
ProcessScriptSaveState(uint16_t & addr,uint8_t & value)1540 void Debugger::ProcessScriptSaveState(uint16_t &addr, uint8_t &value)
1541 {
1542 	if(_hasScript) {
1543 		for(shared_ptr<ScriptHost> &script : _scripts) {
1544 			if(script->ProcessSavestate()) {
1545 				//Adjust PC and current addr/value if a state was loaded due to a call to loadSavestateAsync
1546 				UpdateProgramCounter(addr, value);
1547 			}
1548 		}
1549 	}
1550 }
1551 
ProcessCpuOperation(uint16_t & addr,uint8_t & value,MemoryOperationType type)1552 void Debugger::ProcessCpuOperation(uint16_t &addr, uint8_t &value, MemoryOperationType type)
1553 {
1554 	if(_hasScript) {
1555 		for(shared_ptr<ScriptHost> &script : _scripts) {
1556 			script->ProcessCpuOperation(addr, value, type);
1557 			if(type == MemoryOperationType::ExecOpCode && script->CheckStateLoadedFlag()) {
1558 				//Adjust PC and current addr/value when a state was loaded during a CpuExec callback
1559 				UpdateProgramCounter(addr, value);
1560 			}
1561 		}
1562 	}
1563 }
1564 
ProcessPpuOperation(uint16_t addr,uint8_t & value,MemoryOperationType type)1565 void Debugger::ProcessPpuOperation(uint16_t addr, uint8_t &value, MemoryOperationType type)
1566 {
1567 	if(_hasScript) {
1568 		for(shared_ptr<ScriptHost> &script : _scripts) {
1569 			script->ProcessPpuOperation(addr, value, type);
1570 		}
1571 	}
1572 }
1573 
ProcessEvent(EventType type)1574 void Debugger::ProcessEvent(EventType type)
1575 {
1576 	if(_hasScript) {
1577 		for(shared_ptr<ScriptHost> &script : _scripts) {
1578 			script->ProcessEvent(type);
1579 		}
1580 	}
1581 
1582 	if(type == EventType::InputPolled) {
1583 		for(int i = 0; i < 4; i++) {
1584 			if(_inputOverride[i] != 0) {
1585 				shared_ptr<StandardController> controller = std::dynamic_pointer_cast<StandardController>(_console->GetControlManager()->GetControlDevice(i));
1586 				if(controller) {
1587 					controller->SetBitValue(StandardController::Buttons::A, (_inputOverride[i] & 0x01) != 0);
1588 					controller->SetBitValue(StandardController::Buttons::B, (_inputOverride[i] & 0x02) != 0);
1589 					controller->SetBitValue(StandardController::Buttons::Select, (_inputOverride[i] & 0x04) != 0);
1590 					controller->SetBitValue(StandardController::Buttons::Start, (_inputOverride[i] & 0x08) != 0);
1591 					controller->SetBitValue(StandardController::Buttons::Up, (_inputOverride[i] & 0x10) != 0);
1592 					controller->SetBitValue(StandardController::Buttons::Down, (_inputOverride[i] & 0x20) != 0);
1593 					controller->SetBitValue(StandardController::Buttons::Left, (_inputOverride[i] & 0x40) != 0);
1594 					controller->SetBitValue(StandardController::Buttons::Right, (_inputOverride[i] & 0x80) != 0);
1595 				}
1596 			}
1597 		}
1598 	} else if(type == EventType::EndFrame) {
1599 		_performanceTracker->ProcessEndOfFrame();
1600 		_memoryDumper->GatherChrPaletteInfo();
1601 	} else if(type == EventType::StartFrame) {
1602 		//Update the event viewer
1603 		_console->GetNotificationManager()->SendNotification(ConsoleNotificationType::EventViewerDisplayFrame);
1604 
1605 		//Clear the current frame/event log
1606 		if(CheckFlag(DebuggerFlags::PpuPartialDraw)) {
1607 			_ppu->DebugUpdateFrameBuffer(CheckFlag(DebuggerFlags::PpuShowPreviousFrame));
1608 		}
1609 		_prevDebugEvents = _debugEvents;
1610 		_debugEvents.clear();
1611 	} else if(type == EventType::Nmi) {
1612 		AddDebugEvent(DebugEventType::Nmi);
1613 	} else if(type == EventType::Irq) {
1614 		AddDebugEvent(DebugEventType::Irq);
1615 	} else if(type == EventType::SpriteZeroHit) {
1616 		AddDebugEvent(DebugEventType::SpriteZeroHit);
1617 	} else if(type == EventType::Reset) {
1618 		_enableBreakOnUninitRead = true;
1619 	}
1620 }
1621 
AddDebugEvent(DebugEventType type,uint16_t address,uint8_t value,int16_t breakpointId,int8_t ppuLatch)1622 void Debugger::AddDebugEvent(DebugEventType type, uint16_t address, uint8_t value, int16_t breakpointId, int8_t ppuLatch)
1623 {
1624 	_debugEvents.push_back({
1625 		(uint16_t)_ppu->GetCurrentCycle(),
1626 		(int16_t)_ppu->GetCurrentScanline(),
1627 		_cpu->GetDebugPC(),
1628 		address,
1629 		breakpointId,
1630 		type,
1631 		value,
1632 		ppuLatch,
1633 	});
1634 }
1635 
GetDebugEvents(uint32_t * pictureBuffer,DebugEventInfo * infoArray,uint32_t & maxEventCount,bool returnPreviousFrameData)1636 void Debugger::GetDebugEvents(uint32_t* pictureBuffer, DebugEventInfo *infoArray, uint32_t &maxEventCount, bool returnPreviousFrameData)
1637 {
1638 	DebugBreakHelper helper(this);
1639 
1640 	uint16_t *ppuBuffer = new uint16_t[PPU::PixelCount];
1641 	uint32_t *palette = _console->GetSettings()->GetRgbPalette();
1642 	_ppu->DebugCopyOutputBuffer(ppuBuffer);
1643 
1644 	for(int i = 0; i < PPU::PixelCount; i++) {
1645 		pictureBuffer[i] = palette[ppuBuffer[i] & 0x3F];
1646 	}
1647 
1648 	delete[] ppuBuffer;
1649 
1650 	vector<DebugEventInfo> &events = returnPreviousFrameData ? _prevDebugEvents : _debugEvents;
1651 	uint32_t eventCount = std::min(maxEventCount, (uint32_t)events.size());
1652 	memcpy(infoArray, events.data(), eventCount * sizeof(DebugEventInfo));
1653 	maxEventCount = eventCount;
1654 }
1655 
GetDebugEventCount(bool returnPreviousFrameData)1656 uint32_t Debugger::GetDebugEventCount(bool returnPreviousFrameData)
1657 {
1658 	DebugBreakHelper helper(this);
1659 	return (uint32_t)(returnPreviousFrameData ? _prevDebugEvents.size() : _debugEvents.size());
1660 }
1661 
GetScreenPixel(uint8_t x,uint8_t y)1662 uint32_t Debugger::GetScreenPixel(uint8_t x, uint8_t y)
1663 {
1664 	return _ppu->GetPixel(x, y);
1665 }
1666 
AddTrace(const char * log)1667 void Debugger::AddTrace(const char* log)
1668 {
1669 	_traceLogger->LogExtraInfo(log, _cpu->GetCycleCount());
1670 }