#pragma once #include "stdafx.h" #include #include #include using std::atomic; using std::deque; using std::unordered_set; #include "../Utilities/SimpleLock.h" #include "DebuggerTypes.h" class CPU; class APU; class PPU; class MemoryManager; class Console; class Assembler; class Disassembler; class LabelManager; class MemoryDumper; class MemoryAccessCounter; class Profiler; class CodeRunner; class BaseMapper; class ScriptHost; class TraceLogger; class PerformanceTracker; class Breakpoint; class CodeDataLogger; class ExpressionEvaluator; class DummyCpu; class EventManager; struct ExpressionData; enum EvalResultType : int32_t; enum class CdlStripFlag; class Debugger { private: static constexpr int BreakpointTypeCount = 8; //Must be static to be thread-safe when switching game static string _disassemblerOutput; shared_ptr _disassembler; shared_ptr _assembler; shared_ptr _memoryDumper; shared_ptr _codeDataLogger; shared_ptr _memoryAccessCounter; shared_ptr _labelManager; shared_ptr _traceLogger; shared_ptr _profiler; shared_ptr _performanceTracker; shared_ptr _eventManager; unique_ptr _codeRunner; shared_ptr _console; shared_ptr _cpu; shared_ptr _ppu; shared_ptr _apu; shared_ptr _memoryManager; shared_ptr _mapper; shared_ptr _dummyCpu; bool _bpDummyCpuRequired; bool _breakOnFirstCycle; bool _hasScript; SimpleLock _scriptLock; int _nextScriptId; vector> _scripts; atomic _preventResume; atomic _stopFlag; atomic _executionStopped; atomic _suspendCount; vector _breakpoints[BreakpointTypeCount]; vector _breakpointRpnList[BreakpointTypeCount]; bool _hasBreakpoint[BreakpointTypeCount] = {}; vector _frozenAddresses; uint32_t _opCodeCycle; MemoryOperationType _memoryOperationType; deque _callstack; deque _subReturnAddresses; int32_t _stepOutReturnAddress; unordered_set _functionEntryPoints; unique_ptr _watchExpEval; unique_ptr _bpExpEval; DebugState _debugState; SimpleLock _breakLock; //Used to alter the executing address via "Set Next Statement" uint16_t *_currentReadAddr; uint8_t *_currentReadValue; int32_t _nextReadAddr; uint16_t _returnToAddress; uint32_t _flags; string _romName; atomic _stepCount; atomic _ppuStepCount; atomic _stepCycleCount; atomic _lastInstruction; atomic _stepOut; atomic _stepOverAddr; BreakSource _breakSource; atomic _released; SimpleLock _releaseLock; bool _enableBreakOnUninitRead; atomic _breakRequested; bool _pausedForDebugHelper; atomic _breakOnScanline; bool _proccessPpuCycle[341]; std::unordered_map _ppuViewerUpdateCycle; uint16_t _ppuScrollX; uint16_t _ppuScrollY; int64_t _prevInstructionCycle; int64_t _curInstructionCycle; int64_t _runToCycle; bool _needRewind; vector _rewindCache; vector _rewindPrevInstructionCycleCache; uint32_t _inputOverride[4]; private: bool ProcessBreakpoints(BreakpointType type, OperationInfo &operationInfo, bool allowBreak = true, bool allowMark = true); void ProcessAllBreakpoints(OperationInfo &operationInfo); void AddCallstackFrame(uint16_t source, uint16_t target, StackFrameFlags flags); void UpdateCallstack(uint8_t currentInstruction, uint32_t addr); void ProcessStepConditions(uint16_t addr); bool SleepUntilResume(BreakSource source, uint32_t breakpointId = 0, BreakpointType bpType = BreakpointType::Global, uint16_t bpAddress = 0, uint8_t bpValue = 0, MemoryOperationType bpMemOpType = MemoryOperationType::Read); void UpdatePpuCyclesToProcess(); void ResetStepState(); public: Debugger(shared_ptr console, shared_ptr cpu, shared_ptr ppu, shared_ptr apu, shared_ptr memoryManager, shared_ptr mapper); ~Debugger(); void ReleaseDebugger(bool needPause); void SetPpu(shared_ptr ppu); Console* GetConsole(); void SetFlags(uint32_t flags); bool CheckFlag(DebuggerFlags flag); void SetBreakpoints(Breakpoint breakpoints[], uint32_t length); shared_ptr GetLabelManager(); void GetFunctionEntryPoints(int32_t* entryPoints, int32_t maxCount); int32_t GetFunctionEntryPointCount(); void GetCallstack(StackFrameInfo* callstackArray, uint32_t &callstackSize); void GetInstructionProgress(InstructionProgress &state); void GetApuState(ApuState *state); void GetState(DebugState *state, bool includeMapperInfo = true); void SetState(DebugState state); void Suspend(); void Resume(); void Break(); void ResumeFromBreak(); void PpuStep(uint32_t count = 1); void Step(uint32_t count = 1, BreakSource source = BreakSource::CpuStep); void StepCycles(uint32_t cycleCount = 1); void StepOver(); void StepOut(); void StepBack(); void Run(); void BreakImmediately(BreakSource source); void BreakOnScanline(int16_t scanline); bool LoadCdlFile(string cdlFilepath); void SetCdlData(uint8_t* cdlData, uint32_t length); void ResetCdl(); void UpdateCdlCache(); bool IsMarkedAsCode(uint16_t relativeAddress); shared_ptr GetCodeDataLogger(); void SetNextStatement(uint16_t addr); void SetPpuViewerScanlineCycle(int32_t ppuViewerId, int32_t scanline, int32_t cycle); void ClearPpuViewerSettings(int32_t ppuViewer); bool IsExecutionStopped(); bool IsPauseIconShown(); void PreventResume(); void AllowResume(); void GenerateCodeOutput(); const char* GetCode(uint32_t &length); int32_t GetRelativeAddress(uint32_t addr, AddressType type); int32_t GetRelativePpuAddress(uint32_t addr, PpuAddressType type); int32_t GetAbsoluteAddress(uint32_t addr); int32_t GetAbsoluteChrAddress(uint32_t addr); void GetAbsoluteAddressAndType(uint32_t relativeAddr, AddressTypeInfo* info); void GetPpuAbsoluteAddressAndType(uint32_t relativeAddr, PpuAddressTypeInfo* info); shared_ptr GetProfiler(); shared_ptr GetAssembler(); shared_ptr GetTraceLogger(); shared_ptr GetMemoryDumper(); shared_ptr GetMemoryAccessCounter(); shared_ptr GetPerformanceTracker(); shared_ptr GetEventManager(); int32_t EvaluateExpression(string expression, EvalResultType &resultType, bool useCache); bool IsPpuCycleToProcess(); void ProcessPpuCycle(); bool ProcessRamOperation(MemoryOperationType type, uint16_t &addr, uint8_t &value); void ProcessVramReadOperation(MemoryOperationType type, uint16_t addr, uint8_t &value); void ProcessVramWriteOperation(uint16_t addr, uint8_t &value); void SetLastFramePpuScroll(uint16_t addr, uint8_t xScroll, bool updateHorizontalScrollOnly); uint32_t GetPpuScroll(); void ProcessInterrupt(uint16_t cpuAddr, uint16_t destCpuAddr, bool forNmi); void AddTrace(const char *log); void SetFreezeState(uint16_t address, bool frozen); void GetFreezeState(uint16_t startAddress, uint16_t length, bool* freezeState); void StartCodeRunner(uint8_t *byteCode, uint32_t codeLength); void StopCodeRunner(); void GetNesHeader(uint8_t* header); void SaveRomToDisk(string filename, bool saveAsIps, uint8_t* header, CdlStripFlag cdlStripflag); void RevertPrgChrChanges(); bool HasPrgChrChanges(); int32_t FindSubEntryPoint(uint16_t relativeAddress); void SetInputOverride(uint8_t port, uint32_t state); int32_t LoadScript(string name, string content, int32_t scriptId); void RemoveScript(int32_t scriptId); const char* GetScriptLog(int32_t scriptId); void ResetCounters(); void UpdateProgramCounter(uint16_t &addr, uint8_t &value); void ProcessScriptSaveState(uint16_t &addr, uint8_t &value); void ProcessCpuOperation(uint16_t &addr, uint8_t &value, MemoryOperationType type); void ProcessPpuOperation(uint16_t addr, uint8_t &value, MemoryOperationType type); void ProcessEvent(EventType type); uint32_t GetScreenPixel(uint8_t x, uint8_t y); };