From 937a90626de34c1b56ac83d7d8c217364db9725f Mon Sep 17 00:00:00 2001 From: Sour Date: Mon, 24 Dec 2018 15:21:21 -0500 Subject: [PATCH] Debugger: Added option to evaluate all breakpoints on the first cycle of an instruction --- Core/CPU.cpp | 43 ++++++- Core/CPU.h | 87 ++++++++++--- Core/Core.vcxproj | 1 + Core/Core.vcxproj.filters | 3 + Core/Debugger.cpp | 149 +++++++++++++++++++++-- Core/Debugger.h | 9 +- Core/DebuggerTypes.h | 4 + Core/DummyCpu.h | 10 ++ Core/MemoryAccessCounter.cpp | 9 ++ Core/MemoryAccessCounter.h | 4 +- Core/PPU.cpp | 2 + Core/Types.h | 15 +++ GUI.NET/Config/DebugInfo.cs | 1 + GUI.NET/Debugger/frmDebugger.Designer.cs | 97 +++++++++------ GUI.NET/Debugger/frmDebugger.cs | 19 ++- GUI.NET/InteropEmu.cs | 4 + 16 files changed, 378 insertions(+), 79 deletions(-) create mode 100644 Core/DummyCpu.h diff --git a/Core/CPU.cpp b/Core/CPU.cpp index e86a7527..5db653ff 100644 --- a/Core/CPU.cpp +++ b/Core/CPU.cpp @@ -10,6 +10,7 @@ CPU::CPU(shared_ptr console) { _console = console; + _memoryManager = _console->GetMemoryManager(); Func opTable[] = { // 0 1 2 3 4 5 6 7 8 9 A B C D E F @@ -64,7 +65,7 @@ CPU::CPU(shared_ptr console) _dmcCounter = 0; _dmcDmaRunning = false; _cpuWrite = false; - _writeAddr = false; + _writeAddr = 0; _irqMask = 0; _state = {}; _prevRunIrq = false; @@ -73,7 +74,6 @@ CPU::CPU(shared_ptr console) void CPU::Reset(bool softReset, NesModel model) { - _memoryManager = _console->GetMemoryManager(); _state.NMIFlag = false; _state.IRQFlag = 0; _cycleCount = -1; @@ -140,15 +140,19 @@ void CPU::IRQ() SetPC(MemoryReadWord(CPU::NMIVector)); _state.NMIFlag = false; + #ifndef DUMMYCPU _console->DebugAddTrace("NMI"); _console->DebugProcessInterrupt(originalPc, _state.PC, true); + #endif } else { Push((uint8_t)(PS() | PSFlags::Reserved)); SetFlags(PSFlags::Interrupt); SetPC(MemoryReadWord(CPU::IRQVector)); + #ifndef DUMMYCPU _console->DebugAddTrace("IRQ"); _console->DebugProcessInterrupt(originalPc, _state.PC, false); + #endif } } @@ -162,14 +166,18 @@ void CPU::BRK() { SetPC(MemoryReadWord(CPU::NMIVector)); + #ifndef DUMMYCPU _console->DebugAddTrace("NMI"); + #endif } else { Push((uint8_t)flags); SetFlags(PSFlags::Interrupt); SetPC(MemoryReadWord(CPU::IRQVector)); + #ifndef DUMMYCPU _console->DebugAddTrace("IRQ"); + #endif } //Since we just set the flag to prevent interrupts, do not run one right away after this (fixes nmi_and_brk & nmi_and_irq tests) @@ -184,7 +192,17 @@ void CPU::MemoryWrite(uint16_t addr, uint8_t value, MemoryOperationType operatio while(_dmcDmaRunning) { IncCycleCount(); } + +#ifdef DUMMYCPU + if(operationType == MemoryOperationType::Write || operationType == MemoryOperationType::DummyWrite) { + _writeAddresses[_writeCounter] = addr; + _isDummyWrite[_writeCounter] = operationType == MemoryOperationType::DummyWrite; + _writeValue[_writeCounter] = value; + _writeCounter++; + } +#else _memoryManager->Write(addr, value, operationType); +#endif //DMA DMC might have started after a write to $4015, stall CPU if needed while(_dmcDmaRunning) { @@ -202,16 +220,31 @@ uint8_t CPU::MemoryRead(uint16_t addr, MemoryOperationType operationType) { //Reads are only performed every other cycle? This fixes "dma_2007_read" test //This behavior causes the $4016/7 data corruption when a DMC is running. //When reading $4016/7, only the last read counts (because this only occurs to low-to-high transitions, i.e once in this case) + #ifdef DUMMYCPU + _memoryManager->DebugRead(addr); + #else _memoryManager->Read(addr); + #endif } IncCycleCount(); } + +#ifdef DUMMYCPU + if(operationType == MemoryOperationType::Read || operationType == MemoryOperationType::DummyRead) { + _readAddresses[_readCounter] = addr; + _isDummyRead[_readCounter] = operationType == MemoryOperationType::DummyRead; + _readCounter++; + } + + return _memoryManager->DebugRead(addr); +#else if(operationType == MemoryOperationType::ExecOpCode) { _state.DebugPC = _state.PC; } uint8_t value = _memoryManager->Read(addr, operationType); return value; +#endif } uint16_t CPU::FetchOperand() @@ -236,7 +269,7 @@ uint16_t CPU::FetchOperand() default: break; } -#ifndef LIBRETRO +#if !defined(LIBRETRO) && !defined(DUMMYCPU) if(_warnOnCrash && _console->GetSettings()->CheckFlag(EmulationFlags::DeveloperMode)) { MessageManager::DisplayMessage("Error", "GameCrash", "Invalid OP code - CPU crashed."); _warnOnCrash = false; @@ -270,12 +303,16 @@ void CPU::IncCycleCount() if(_dmcCounter == 0) { //Update the DMC buffer when the stall period is completed _dmcDmaRunning = false; + #ifndef DUMMYCPU _console->GetApu()->FillDmcReadBuffer(); _console->DebugAddTrace("DMC DMA End"); + #endif } } + #ifndef DUMMYCPU _console->ProcessCpuClock(); + #endif if(!_spriteDmaTransfer && !_dmcDmaRunning) { //IRQ flags are ignored during Sprite DMA - fixes irq_and_dma diff --git a/Core/CPU.h b/Core/CPU.h index bbb3ae21..b6aa3f38 100644 --- a/Core/CPU.h +++ b/Core/CPU.h @@ -1,4 +1,9 @@ -#pragma once +#if (defined(DUMMYCPU) && !defined(__DUMMYCPU__H)) || (!defined(DUMMYCPU) && !defined(__CPU__H)) +#ifdef DUMMYCPU +#define __DUMMYCPU__H +#else +#define __CPU__H +#endif #include "stdafx.h" #include "Snapshotable.h" @@ -7,24 +12,12 @@ enum class NesModel; class Console; class MemoryManager; - -namespace PSFlags -{ - enum PSFlags : uint8_t - { - Carry = 0x01, - Zero = 0x02, - Interrupt = 0x04, - Decimal = 0x08, - Break = 0x10, - Reserved = 0x20, - Overflow = 0x40, - Negative = 0x80 - }; -} +class DummyCpu; class CPU : public Snapshotable { + friend DummyCpu; + public: static constexpr uint16_t NMIVector = 0xFFFA; static constexpr uint16_t ResetVector = 0xFFFC; @@ -62,6 +55,17 @@ private: bool _warnOnCrash = true; +#ifdef DUMMYCPU + uint32_t _writeCounter = 0; + uint16_t _writeAddresses[10]; + uint8_t _writeValue[10]; + bool _isDummyWrite[10]; + + uint32_t _readCounter = 0; + uint16_t _readAddresses[10]; + bool _isDummyRead[10]; +#endif + void IncCycleCount(); uint16_t FetchOperand(); void IRQ(); @@ -818,4 +822,53 @@ public: state.PC = originalPc; state.DebugPC = originalDebugPc; } -}; \ No newline at end of file + +#ifdef DUMMYCPU +#undef CPU + void SetDummyState(CPU *c) + { +#define CPU DummyCpu + _writeCounter = 0; + _readCounter = 0; + + _state = c->_state; + + _cycleCount = c->_cycleCount; + _operand = c->_operand; + _spriteDmaCounter = c->_spriteDmaCounter; + _spriteDmaTransfer = c->_spriteDmaTransfer; + _dmcCounter = c->_dmcCounter; + _dmcDmaRunning = c->_dmcDmaRunning; + _cpuWrite = c->_cpuWrite; + _irqMask = c->_irqMask; + _prevRunIrq = c->_prevRunIrq; + _runIrq = c->_runIrq; + _cycleCount = c->_cycleCount; + } + + uint32_t GetWriteCount() + { + return _writeCounter; + } + + uint32_t GetReadCount() + { + return _readCounter; + } + + void GetWriteAddrValue(uint32_t index, uint16_t &addr, uint8_t &value, bool &isDummyWrite) + { + addr = _writeAddresses[index]; + value = _writeValue[index]; + isDummyWrite = _isDummyWrite[index]; + } + + void GetReadAddr(uint32_t index, uint16_t &addr, bool &isDummyRead) + { + addr = _readAddresses[index]; + isDummyRead = _isDummyRead[index]; + } +#endif +}; + +#endif \ No newline at end of file diff --git a/Core/Core.vcxproj b/Core/Core.vcxproj index ac47d34a..4e3346f4 100644 --- a/Core/Core.vcxproj +++ b/Core/Core.vcxproj @@ -533,6 +533,7 @@ + diff --git a/Core/Core.vcxproj.filters b/Core/Core.vcxproj.filters index 61ff0a0f..4076cc9e 100644 --- a/Core/Core.vcxproj.filters +++ b/Core/Core.vcxproj.filters @@ -1471,6 +1471,9 @@ Misc + + Debugger + diff --git a/Core/Debugger.cpp b/Core/Debugger.cpp index ace2d834..87b5f8ab 100644 --- a/Core/Debugger.cpp +++ b/Core/Debugger.cpp @@ -29,6 +29,7 @@ #include "CodeDataLogger.h" #include "NotificationManager.h" #include "DebugHud.h" +#include "DummyCpu.h" const int Debugger::BreakpointTypeCount; string Debugger::_disassemblerOutput = ""; @@ -42,6 +43,9 @@ Debugger::Debugger(shared_ptr console, shared_ptr cpu, shared_ptr< _memoryManager = memoryManager; _mapper = mapper; + _dummyCpu.reset(new DummyCpu(console)); + _breakOnFirstCycle = false; + _labelManager.reset(new LabelManager(_mapper)); _assembler.reset(new Assembler(_labelManager)); _disassembler.reset(new Disassembler(memoryManager.get(), mapper.get(), this)); @@ -177,6 +181,7 @@ void Debugger::SetFlags(uint32_t flags) { bool needUpdate = ((flags ^ _flags) & (int)DebuggerFlags::DisplayOpCodesInLowerCase) != 0; _flags = flags; + _breakOnFirstCycle = CheckFlag(DebuggerFlags::BreakOnFirstCycle); if(needUpdate) { _disassembler->BuildOpCodeTables(CheckFlag(DebuggerFlags::DisplayOpCodesInLowerCase)); } @@ -298,11 +303,11 @@ void Debugger::SetBreakpoints(Breakpoint breakpoints[], uint32_t length) } } -void Debugger::ProcessBreakpoints(BreakpointType type, OperationInfo &operationInfo, bool allowBreak) +bool Debugger::ProcessBreakpoints(BreakpointType type, OperationInfo &operationInfo, bool allowBreak, bool allowMark) { if(_runToCycle != 0) { //Disable all breakpoints while stepping backwards - return; + return false; } AddressTypeInfo info { -1, AddressType::InternalRam }; @@ -347,6 +352,11 @@ void Debugger::ProcessBreakpoints(BreakpointType type, OperationInfo &operationI for(size_t i = 0, len = breakpoints.size(); i < len; i++) { Breakpoint &breakpoint = breakpoints[i]; + if(!((breakpoint.IsEnabled() && allowBreak) || (breakpoint.IsMarked() && allowMark))) { + //Skip breakpoints we don't need to process + continue; + } + if( type == BreakpointType::Global || (!isPpuBreakpoint && breakpoint.Matches(operationInfo.Address, info, operationInfo.OperationType)) || @@ -365,20 +375,117 @@ void Debugger::ProcessBreakpoints(BreakpointType type, OperationInfo &operationI } } - if(needMark && needBreak) { + if((needMark || !allowMark) && (needBreak || !allowBreak)) { //No need to process remaining breakpoints break; } } - if(needMark) { + if(needMark && allowMark) { AddDebugEvent(DebugEventType::Breakpoint, operationInfo.Address, (uint8_t)operationInfo.Value, markBreakpointId); } if(needBreak && allowBreak) { //Found a matching breakpoint, stop execution Step(1); - SleepUntilResume(BreakSource::Breakpoint, breakpointId, type, operationInfo.Address); + SleepUntilResume(BreakSource::Breakpoint, breakpointId, type, operationInfo.Address, operationInfo.OperationType); + return true; + } else { + return false; + } +} + +void Debugger::ProcessAllBreakpoints(OperationInfo &operationInfo, AddressTypeInfo &addressInfo) +{ + if(_hasBreakpoint[BreakpointType::Execute]) { + ProcessBreakpoints(BreakpointType::Execute, operationInfo, true, true); + } + + _dummyCpu->SetDummyState(_cpu.get()); + _dummyCpu->Exec(); + + DebugState &state = _debugState; + uint32_t readCount = _dummyCpu->GetReadCount(); + if(readCount > 0) { + uint16_t addr; + bool isDummyRead; + for(uint32_t i = 0; i < readCount; i++) { + _dummyCpu->GetReadAddr(i, addr, isDummyRead); + + OperationInfo info; + + if(addr >= 0x2000 && addr < 0x4000 && (addr & 0x07) == 0x07) { + //Reads to $2007 will trigger a PPU read + if(_hasBreakpoint[BreakpointType::ReadVram]) { + OperationInfo ppuInfo; + ppuInfo.OperationType = MemoryOperationType::Read; + if((state.PPU.State.VideoRamAddr & 0x3FFF) >= 0x3F00) { + ppuInfo.Address = state.PPU.State.VideoRamAddr; + ppuInfo.Value = _ppu->ReadPaletteRAM(ppuInfo.Address); + } else { + ppuInfo.Address = state.PPU.BusAddress; + ppuInfo.Value = _mapper->DebugReadVRAM(ppuInfo.Address); + } + if(ProcessBreakpoints(BreakpointType::ReadVram, ppuInfo, true, false)) { + return; + } + } + + info.Value = state.PPU.MemoryReadBuffer; + } else { + if(_enableBreakOnUninitRead && CheckFlag(DebuggerFlags::BreakOnUninitMemoryRead)) { + //Break on uninit memory read + if(_memoryAccessCounter->IsAddressUninitialized(addressInfo)) { + Step(1); + SleepUntilResume(BreakSource::BreakOnUninitMemoryRead, 0, BreakpointType::ReadRam, addr); + return; + } + } + + info.Value = _memoryManager->DebugRead(addr); + } + + if(_hasBreakpoint[BreakpointType::ReadRam]) { + info.Address = addr; + info.OperationType = isDummyRead ? MemoryOperationType::DummyRead : MemoryOperationType::Read; + if(ProcessBreakpoints(BreakpointType::ReadRam, info, true, false)) { + return; + } + } + } + } + + uint32_t writeCount = _dummyCpu->GetWriteCount(); + if(writeCount > 0 && (_hasBreakpoint[BreakpointType::WriteRam] || _hasBreakpoint[BreakpointType::WriteVram])) { + uint16_t addr; + uint8_t value; + bool isDummyWrite; + for(uint32_t i = 0; i < writeCount; i++) { + _dummyCpu->GetWriteAddrValue(i, addr, value, isDummyWrite); + + if(_hasBreakpoint[BreakpointType::WriteRam]) { + OperationInfo info; + info.Address = addr; + info.Value = value; + info.OperationType = isDummyWrite ? MemoryOperationType::DummyWrite : MemoryOperationType::Write; + if(ProcessBreakpoints(BreakpointType::WriteRam, info, true, false)) { + return; + } + } + + if(_hasBreakpoint[BreakpointType::WriteVram]) { + if(addr >= 0x2000 && addr < 0x4000 && (addr & 0x07) == 0x07) { + //Write to $2007 will trigger a PPU write + OperationInfo ppuInfo; + ppuInfo.Address = state.PPU.BusAddress; + ppuInfo.Value = value; + ppuInfo.OperationType = MemoryOperationType::Write; + if(ProcessBreakpoints(BreakpointType::WriteVram, ppuInfo, true, false)) { + return; + } + } + } + } } } @@ -592,7 +699,7 @@ bool Debugger::ProcessRamOperation(MemoryOperationType type, uint16_t &addr, uin } } else { if(_memoryAccessCounter->ProcessMemoryAccess(addressInfo, type, _cpu->GetCycleCount())) { - if(_enableBreakOnUninitRead && CheckFlag(DebuggerFlags::BreakOnUninitMemoryRead)) { + if(!_breakOnFirstCycle && _enableBreakOnUninitRead && CheckFlag(DebuggerFlags::BreakOnUninitMemoryRead)) { //Break on uninit memory read Step(1); breakDone = SleepUntilResume(BreakSource::BreakOnUninitMemoryRead); @@ -683,7 +790,7 @@ bool Debugger::ProcessRamOperation(MemoryOperationType type, uint16_t &addr, uin BreakpointType breakpointType; switch(type) { default: breakpointType = BreakpointType::Execute; break; - + case MemoryOperationType::DummyRead: case MemoryOperationType::Read: breakpointType = BreakpointType::ReadRam; break; @@ -691,8 +798,17 @@ bool Debugger::ProcessRamOperation(MemoryOperationType type, uint16_t &addr, uin case MemoryOperationType::Write: breakpointType = BreakpointType::WriteRam; break; } - if(_hasBreakpoint[breakpointType]) { - ProcessBreakpoints(breakpointType, operationInfo, !breakDone); + if(_breakOnFirstCycle) { + if(type == MemoryOperationType::ExecOpCode && !breakDone) { + ProcessAllBreakpoints(operationInfo, addressInfo); + } + + //Process marked breakpoints + ProcessBreakpoints(breakpointType, operationInfo, false, true); + } else { + if(_hasBreakpoint[breakpointType]) { + ProcessBreakpoints(breakpointType, operationInfo, !breakDone, true); + } } _currentReadAddr = nullptr; @@ -726,7 +842,7 @@ bool Debugger::ProcessRamOperation(MemoryOperationType type, uint16_t &addr, uin return true; } -bool Debugger::SleepUntilResume(BreakSource source, uint32_t breakpointId, BreakpointType bpType, uint16_t bpAddress) +bool Debugger::SleepUntilResume(BreakSource source, uint32_t breakpointId, BreakpointType bpType, uint16_t bpAddress, MemoryOperationType bpMemOpType) { int32_t stepCount = _stepCount.load(); if(stepCount > 0) { @@ -753,7 +869,14 @@ bool Debugger::SleepUntilResume(BreakSource source, uint32_t breakpointId, Break } _breakSource = BreakSource::Unspecified; - uint64_t param = ((uint64_t)breakpointId << 32) | ((uint64_t)(bpAddress & 0xFFFF) << 16) | ((uint64_t)(bpType & 0xFF) << 8) | ((uint64_t)source & 0xFF); + uint64_t param = ( + ((uint64_t)breakpointId << 32) | + ((uint64_t)(bpAddress & 0xFFFF) << 16) | + ((uint64_t)((int)bpMemOpType & 0x0F) << 12) | + ((uint64_t)(bpType & 0x0F) << 8) | + ((uint64_t)source & 0xFF) + ); + _console->GetNotificationManager()->SendNotification(ConsoleNotificationType::CodeBreak, (void*)(uint64_t)param); ProcessEvent(EventType::CodeBreak); @@ -784,7 +907,7 @@ void Debugger::ProcessVramReadOperation(MemoryOperationType type, uint16_t addr, int32_t absoluteAddr = _mapper->ToAbsoluteChrAddress(addr); _codeDataLogger->SetFlag(absoluteAddr, type == MemoryOperationType::Read ? CdlChrFlags::Read : CdlChrFlags::Drawn); - if(_hasBreakpoint[BreakpointType::ReadVram]) { + if(!_breakOnFirstCycle && _hasBreakpoint[BreakpointType::ReadVram]) { OperationInfo operationInfo{ addr, value, type }; ProcessBreakpoints(BreakpointType::ReadVram, operationInfo); } @@ -794,7 +917,7 @@ void Debugger::ProcessVramReadOperation(MemoryOperationType type, uint16_t addr, void Debugger::ProcessVramWriteOperation(uint16_t addr, uint8_t &value) { - if(_hasBreakpoint[BreakpointType::WriteVram]) { + if(!_breakOnFirstCycle && _hasBreakpoint[BreakpointType::WriteVram]) { OperationInfo operationInfo{ addr, value, MemoryOperationType::Write }; ProcessBreakpoints(BreakpointType::WriteVram, operationInfo); } diff --git a/Core/Debugger.h b/Core/Debugger.h index b0fcfb0b..8d519cdf 100644 --- a/Core/Debugger.h +++ b/Core/Debugger.h @@ -29,6 +29,7 @@ class TraceLogger; class Breakpoint; class CodeDataLogger; class ExpressionEvaluator; +class DummyCpu; struct ExpressionData; enum EvalResultType : int32_t; @@ -58,6 +59,9 @@ private: shared_ptr _apu; shared_ptr _memoryManager; shared_ptr _mapper; + + shared_ptr _dummyCpu; + bool _breakOnFirstCycle; bool _hasScript; SimpleLock _scriptLock; @@ -138,13 +142,14 @@ private: vector> _debugEventMarkerRpn; private: - void ProcessBreakpoints(BreakpointType type, OperationInfo &operationInfo, bool allowBreak = true); + bool ProcessBreakpoints(BreakpointType type, OperationInfo &operationInfo, bool allowBreak = true, bool allowMark = true); + void ProcessAllBreakpoints(OperationInfo &operationInfo, AddressTypeInfo &addressInfo); 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); + bool SleepUntilResume(BreakSource source, uint32_t breakpointId = 0, BreakpointType bpType = BreakpointType::Global, uint16_t bpAddress = 0, MemoryOperationType bpMemOpType = MemoryOperationType::Read); void AddDebugEvent(DebugEventType type, uint16_t address = -1, uint8_t value = 0, int16_t breakpointId = -1, int8_t ppuLatch = -1); diff --git a/Core/DebuggerTypes.h b/Core/DebuggerTypes.h index 6b204d69..d3caaf1e 100644 --- a/Core/DebuggerTypes.h +++ b/Core/DebuggerTypes.h @@ -36,6 +36,8 @@ enum class DebuggerFlags BreakOnDecayedOamRead = 0x2000, BreakOnInit = 0x4000, BreakOnPlay = 0x8000, + + BreakOnFirstCycle = 0x10000, }; enum class BreakSource @@ -117,6 +119,8 @@ struct PPUDebugState uint32_t NmiScanline; uint32_t ScanlineCount; uint32_t SafeOamScanline; + uint16_t BusAddress; + uint8_t MemoryReadBuffer; }; struct DebugState diff --git a/Core/DummyCpu.h b/Core/DummyCpu.h new file mode 100644 index 00000000..931a2a49 --- /dev/null +++ b/Core/DummyCpu.h @@ -0,0 +1,10 @@ +#pragma once + +#include "stdafx.h" + +#define DUMMYCPU +#define CPU DummyCpu +#include "CPU.h" +#include "CPU.cpp" +#undef CPU +#undef DUMMYCPU diff --git a/Core/MemoryAccessCounter.cpp b/Core/MemoryAccessCounter.cpp index 84d03ec7..3741bacd 100644 --- a/Core/MemoryAccessCounter.cpp +++ b/Core/MemoryAccessCounter.cpp @@ -42,6 +42,15 @@ vector& MemoryAccessCounter::GetArray(MemoryOperationType operationType } } +bool MemoryAccessCounter::IsAddressUninitialized(AddressTypeInfo &addressInfo) +{ + if(addressInfo.Type == AddressType::InternalRam || addressInfo.Type == AddressType::WorkRam) { + int index = (int)addressInfo.Type; + return !_initWrites[index][addressInfo.Address]; + } + return false; +} + bool MemoryAccessCounter::ProcessMemoryAccess(AddressTypeInfo &addressInfo, MemoryOperationType operation, int32_t cpuCycle) { int index = (int)addressInfo.Type; diff --git a/Core/MemoryAccessCounter.h b/Core/MemoryAccessCounter.h index f5c2835c..17d11dc6 100644 --- a/Core/MemoryAccessCounter.h +++ b/Core/MemoryAccessCounter.h @@ -21,12 +21,14 @@ private: vector _uninitReads[4]; vector& GetArray(MemoryOperationType operationType, AddressType addressType, bool stampArray); - + public: MemoryAccessCounter(Debugger* debugger); bool ProcessMemoryAccess(AddressTypeInfo &addressInfo, MemoryOperationType operation, int32_t cpuCycle); void ResetCounts(); + + bool IsAddressUninitialized(AddressTypeInfo &addressInfo); void GetAccessCounts(AddressType memoryType, MemoryOperationType operationType, uint32_t counts[], bool forUninitReads); void GetAccessCountsEx(uint32_t offset, uint32_t length, DebugMemoryType memoryType, MemoryOperationType operationType, int32_t counts[]); diff --git a/Core/PPU.cpp b/Core/PPU.cpp index 0fdd3cc7..afc17e4f 100644 --- a/Core/PPU.cpp +++ b/Core/PPU.cpp @@ -150,6 +150,8 @@ void PPU::GetState(PPUDebugState &state) state.NmiScanline = _nmiScanline; state.ScanlineCount = _vblankEnd + 2; state.SafeOamScanline = _nesModel == NesModel::NTSC ? _nmiScanline + 19 : _palSpriteEvalScanline; + state.BusAddress = _ppuBusAddress; + state.MemoryReadBuffer = _memoryReadBuffer; } void PPU::SetState(PPUDebugState &state) diff --git a/Core/Types.h b/Core/Types.h index 38ed4dbf..321edfab 100644 --- a/Core/Types.h +++ b/Core/Types.h @@ -1,6 +1,21 @@ #pragma once #include "stdafx.h" +namespace PSFlags +{ + enum PSFlags : uint8_t + { + Carry = 0x01, + Zero = 0x02, + Interrupt = 0x04, + Decimal = 0x08, + Break = 0x10, + Reserved = 0x20, + Overflow = 0x40, + Negative = 0x80 + }; +} + enum class AddrMode { None, Acc, Imp, Imm, Rel, diff --git a/GUI.NET/Config/DebugInfo.cs b/GUI.NET/Config/DebugInfo.cs index 87689d14..dc029ca4 100644 --- a/GUI.NET/Config/DebugInfo.cs +++ b/GUI.NET/Config/DebugInfo.cs @@ -301,6 +301,7 @@ namespace Mesen.GUI.Config public bool BreakOnUninitMemoryRead = false; public bool BreakOnInit = true; public bool BreakOnPlay = false; + public bool BreakOnFirstCycle = true; public bool BringToFrontOnPause = false; public bool BringToFrontOnBreak = true; diff --git a/GUI.NET/Debugger/frmDebugger.Designer.cs b/GUI.NET/Debugger/frmDebugger.Designer.cs index 306fec81..f1c8bf48 100644 --- a/GUI.NET/Debugger/frmDebugger.Designer.cs +++ b/GUI.NET/Debugger/frmDebugger.Designer.cs @@ -140,6 +140,7 @@ namespace Mesen.GUI.Debugger this.toolStripMenuItem20 = new System.Windows.Forms.ToolStripSeparator(); this.mnuBringToFrontOnBreak = new System.Windows.Forms.ToolStripMenuItem(); this.mnuBringToFrontOnPause = new System.Windows.Forms.ToolStripMenuItem(); + this.mnuEnableSubInstructionBreakpoints = new System.Windows.Forms.ToolStripMenuItem(); this.toolStripMenuItem12 = new System.Windows.Forms.ToolStripSeparator(); this.mnuShowOptions = new System.Windows.Forms.ToolStripMenuItem(); this.mnuShowToolbar = new System.Windows.Forms.ToolStripMenuItem(); @@ -174,6 +175,8 @@ namespace Mesen.GUI.Debugger this.mnuPpuShowPreviousFrame = new System.Windows.Forms.ToolStripMenuItem(); this.toolStripMenuItem19 = new System.Windows.Forms.ToolStripSeparator(); this.mnuShowBreakNotifications = new System.Windows.Forms.ToolStripMenuItem(); + this.mnuShowInstructionProgression = new System.Windows.Forms.ToolStripMenuItem(); + this.toolStripMenuItem27 = new System.Windows.Forms.ToolStripSeparator(); this.mnuAlwaysScrollToCenter = new System.Windows.Forms.ToolStripMenuItem(); this.mnuRefreshWhileRunning = new System.Windows.Forms.ToolStripMenuItem(); this.toolStripMenuItem6 = new System.Windows.Forms.ToolStripSeparator(); @@ -211,8 +214,7 @@ namespace Mesen.GUI.Debugger this.ctrlPpuMemoryMapping = new Mesen.GUI.Debugger.Controls.ctrlMemoryMapping(); this.ctrlCpuMemoryMapping = new Mesen.GUI.Debugger.Controls.ctrlMemoryMapping(); this.tsToolbar = new Mesen.GUI.Controls.ctrlMesenToolStrip(); - this.mnuShowInstructionProgression = new System.Windows.Forms.ToolStripMenuItem(); - this.toolStripMenuItem27 = new System.Windows.Forms.ToolStripSeparator(); + this.toolStripMenuItem28 = new System.Windows.Forms.ToolStripSeparator(); ((System.ComponentModel.ISupportInitialize)(this.splitContainer)).BeginInit(); this.splitContainer.Panel1.SuspendLayout(); this.splitContainer.Panel2.SuspendLayout(); @@ -257,7 +259,7 @@ namespace Mesen.GUI.Debugger this.splitContainer.Panel2.Controls.Add(this.tableLayoutPanel10); this.splitContainer.Panel2MinSize = 100; this.splitContainer.Size = new System.Drawing.Size(1075, 570); - this.splitContainer.SplitterDistance = 416; + this.splitContainer.SplitterDistance = 410; this.splitContainer.SplitterWidth = 7; this.splitContainer.TabIndex = 1; this.splitContainer.TabStop = false; @@ -281,7 +283,7 @@ namespace Mesen.GUI.Debugger // this.ctrlSplitContainerTop.Panel2.Controls.Add(this.tlpFunctionLabelLists); this.ctrlSplitContainerTop.Panel2MinSize = 150; - this.ctrlSplitContainerTop.Size = new System.Drawing.Size(1075, 416); + this.ctrlSplitContainerTop.Size = new System.Drawing.Size(1075, 410); this.ctrlSplitContainerTop.SplitterDistance = 750; this.ctrlSplitContainerTop.SplitterWidth = 7; this.ctrlSplitContainerTop.TabIndex = 3; @@ -302,8 +304,8 @@ namespace Mesen.GUI.Debugger this.tlpTop.Name = "tlpTop"; this.tlpTop.RowCount = 1; this.tlpTop.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F)); - this.tlpTop.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 416F)); - this.tlpTop.Size = new System.Drawing.Size(750, 416); + this.tlpTop.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 410F)); + this.tlpTop.Size = new System.Drawing.Size(750, 410); this.tlpTop.TabIndex = 2; // // panel1 @@ -314,7 +316,7 @@ namespace Mesen.GUI.Debugger this.panel1.Location = new System.Drawing.Point(3, 0); this.panel1.Margin = new System.Windows.Forms.Padding(3, 0, 3, 0); this.panel1.Name = "panel1"; - this.panel1.Size = new System.Drawing.Size(286, 416); + this.panel1.Size = new System.Drawing.Size(286, 410); this.panel1.TabIndex = 5; // // ctrlSourceViewer @@ -323,7 +325,7 @@ namespace Mesen.GUI.Debugger this.ctrlSourceViewer.Dock = System.Windows.Forms.DockStyle.Fill; this.ctrlSourceViewer.Location = new System.Drawing.Point(0, 0); this.ctrlSourceViewer.Name = "ctrlSourceViewer"; - this.ctrlSourceViewer.Size = new System.Drawing.Size(286, 416); + this.ctrlSourceViewer.Size = new System.Drawing.Size(286, 410); this.ctrlSourceViewer.SymbolProvider = null; this.ctrlSourceViewer.TabIndex = 7; this.ctrlSourceViewer.Visible = false; @@ -336,7 +338,7 @@ namespace Mesen.GUI.Debugger this.ctrlDebuggerCode.Location = new System.Drawing.Point(0, 0); this.ctrlDebuggerCode.Name = "ctrlDebuggerCode"; this.ctrlDebuggerCode.ShowMemoryValues = false; - this.ctrlDebuggerCode.Size = new System.Drawing.Size(286, 416); + this.ctrlDebuggerCode.Size = new System.Drawing.Size(286, 410); this.ctrlDebuggerCode.SymbolProvider = null; this.ctrlDebuggerCode.TabIndex = 2; this.ctrlDebuggerCode.OnEditCode += new Mesen.GUI.Debugger.ctrlDebuggerCode.AssemblerEventHandler(this.ctrlDebuggerCode_OnEditCode); @@ -350,7 +352,7 @@ namespace Mesen.GUI.Debugger this.panel2.Location = new System.Drawing.Point(292, 0); this.panel2.Margin = new System.Windows.Forms.Padding(0, 0, 3, 0); this.panel2.Name = "panel2"; - this.panel2.Size = new System.Drawing.Size(1, 416); + this.panel2.Size = new System.Drawing.Size(1, 410); this.panel2.TabIndex = 6; // // ctrlSourceViewerSplit @@ -359,7 +361,7 @@ namespace Mesen.GUI.Debugger this.ctrlSourceViewerSplit.Dock = System.Windows.Forms.DockStyle.Fill; this.ctrlSourceViewerSplit.Location = new System.Drawing.Point(0, 0); this.ctrlSourceViewerSplit.Name = "ctrlSourceViewerSplit"; - this.ctrlSourceViewerSplit.Size = new System.Drawing.Size(1, 416); + this.ctrlSourceViewerSplit.Size = new System.Drawing.Size(1, 410); this.ctrlSourceViewerSplit.SymbolProvider = null; this.ctrlSourceViewerSplit.TabIndex = 8; this.ctrlSourceViewerSplit.Visible = false; @@ -372,7 +374,7 @@ namespace Mesen.GUI.Debugger this.ctrlDebuggerCodeSplit.Location = new System.Drawing.Point(0, 0); this.ctrlDebuggerCodeSplit.Name = "ctrlDebuggerCodeSplit"; this.ctrlDebuggerCodeSplit.ShowMemoryValues = false; - this.ctrlDebuggerCodeSplit.Size = new System.Drawing.Size(1, 416); + this.ctrlDebuggerCodeSplit.Size = new System.Drawing.Size(1, 410); this.ctrlDebuggerCodeSplit.SymbolProvider = null; this.ctrlDebuggerCodeSplit.TabIndex = 4; this.ctrlDebuggerCodeSplit.Visible = false; @@ -392,7 +394,7 @@ namespace Mesen.GUI.Debugger this.tableLayoutPanel1.RowCount = 2; this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle()); this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F)); - this.tableLayoutPanel1.Size = new System.Drawing.Size(458, 416); + this.tableLayoutPanel1.Size = new System.Drawing.Size(458, 410); this.tableLayoutPanel1.TabIndex = 7; // // ctrlConsoleStatus @@ -416,7 +418,7 @@ namespace Mesen.GUI.Debugger this.tlpVerticalLayout.Name = "tlpVerticalLayout"; this.tlpVerticalLayout.RowCount = 1; this.tlpVerticalLayout.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 50F)); - this.tlpVerticalLayout.Size = new System.Drawing.Size(458, 16); + this.tlpVerticalLayout.Size = new System.Drawing.Size(458, 10); this.tlpVerticalLayout.TabIndex = 4; // // tlpFunctionLabelLists @@ -432,16 +434,16 @@ namespace Mesen.GUI.Debugger this.tlpFunctionLabelLists.RowCount = 2; this.tlpFunctionLabelLists.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 50F)); this.tlpFunctionLabelLists.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 50F)); - this.tlpFunctionLabelLists.Size = new System.Drawing.Size(318, 416); + this.tlpFunctionLabelLists.Size = new System.Drawing.Size(318, 410); this.tlpFunctionLabelLists.TabIndex = 5; // // grpLabels // this.grpLabels.Controls.Add(this.ctrlLabelList); this.grpLabels.Dock = System.Windows.Forms.DockStyle.Fill; - this.grpLabels.Location = new System.Drawing.Point(3, 211); + this.grpLabels.Location = new System.Drawing.Point(3, 208); this.grpLabels.Name = "grpLabels"; - this.grpLabels.Size = new System.Drawing.Size(312, 202); + this.grpLabels.Size = new System.Drawing.Size(312, 199); this.grpLabels.TabIndex = 6; this.grpLabels.TabStop = false; this.grpLabels.Text = "Labels"; @@ -451,7 +453,7 @@ namespace Mesen.GUI.Debugger this.ctrlLabelList.Dock = System.Windows.Forms.DockStyle.Fill; this.ctrlLabelList.Location = new System.Drawing.Point(3, 16); this.ctrlLabelList.Name = "ctrlLabelList"; - this.ctrlLabelList.Size = new System.Drawing.Size(306, 183); + this.ctrlLabelList.Size = new System.Drawing.Size(306, 180); this.ctrlLabelList.TabIndex = 0; this.ctrlLabelList.OnFindOccurrence += new System.EventHandler(this.ctrlLabelList_OnFindOccurrence); this.ctrlLabelList.OnLabelSelected += new System.EventHandler(this.ctrlLabelList_OnLabelSelected); @@ -462,7 +464,7 @@ namespace Mesen.GUI.Debugger this.grpFunctions.Dock = System.Windows.Forms.DockStyle.Fill; this.grpFunctions.Location = new System.Drawing.Point(3, 3); this.grpFunctions.Name = "grpFunctions"; - this.grpFunctions.Size = new System.Drawing.Size(312, 202); + this.grpFunctions.Size = new System.Drawing.Size(312, 199); this.grpFunctions.TabIndex = 5; this.grpFunctions.TabStop = false; this.grpFunctions.Text = "Functions"; @@ -472,7 +474,7 @@ namespace Mesen.GUI.Debugger this.ctrlFunctionList.Dock = System.Windows.Forms.DockStyle.Fill; this.ctrlFunctionList.Location = new System.Drawing.Point(3, 16); this.ctrlFunctionList.Name = "ctrlFunctionList"; - this.ctrlFunctionList.Size = new System.Drawing.Size(306, 183); + this.ctrlFunctionList.Size = new System.Drawing.Size(306, 180); this.ctrlFunctionList.TabIndex = 0; this.ctrlFunctionList.OnFindOccurrence += new System.EventHandler(this.ctrlFunctionList_OnFindOccurrence); this.ctrlFunctionList.OnFunctionSelected += new System.EventHandler(this.ctrlFunctionList_OnFunctionSelected); @@ -503,7 +505,7 @@ namespace Mesen.GUI.Debugger this.tableLayoutPanel10.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F)); this.tableLayoutPanel10.RowStyles.Add(new System.Windows.Forms.RowStyle()); this.tableLayoutPanel10.RowStyles.Add(new System.Windows.Forms.RowStyle()); - this.tableLayoutPanel10.Size = new System.Drawing.Size(1075, 147); + this.tableLayoutPanel10.Size = new System.Drawing.Size(1075, 153); this.tableLayoutPanel10.TabIndex = 0; // // grpWatch @@ -512,7 +514,7 @@ namespace Mesen.GUI.Debugger this.grpWatch.Dock = System.Windows.Forms.DockStyle.Fill; this.grpWatch.Location = new System.Drawing.Point(3, 3); this.grpWatch.Name = "grpWatch"; - this.grpWatch.Size = new System.Drawing.Size(352, 141); + this.grpWatch.Size = new System.Drawing.Size(352, 147); this.grpWatch.TabIndex = 2; this.grpWatch.TabStop = false; this.grpWatch.Text = "Watch"; @@ -522,7 +524,7 @@ namespace Mesen.GUI.Debugger this.ctrlWatch.Dock = System.Windows.Forms.DockStyle.Fill; this.ctrlWatch.Location = new System.Drawing.Point(3, 16); this.ctrlWatch.Name = "ctrlWatch"; - this.ctrlWatch.Size = new System.Drawing.Size(346, 122); + this.ctrlWatch.Size = new System.Drawing.Size(346, 128); this.ctrlWatch.TabIndex = 0; // // grpBreakpoints @@ -531,7 +533,7 @@ namespace Mesen.GUI.Debugger this.grpBreakpoints.Dock = System.Windows.Forms.DockStyle.Fill; this.grpBreakpoints.Location = new System.Drawing.Point(361, 3); this.grpBreakpoints.Name = "grpBreakpoints"; - this.grpBreakpoints.Size = new System.Drawing.Size(352, 141); + this.grpBreakpoints.Size = new System.Drawing.Size(352, 147); this.grpBreakpoints.TabIndex = 3; this.grpBreakpoints.TabStop = false; this.grpBreakpoints.Text = "Breakpoints"; @@ -541,7 +543,7 @@ namespace Mesen.GUI.Debugger this.ctrlBreakpoints.Dock = System.Windows.Forms.DockStyle.Fill; this.ctrlBreakpoints.Location = new System.Drawing.Point(3, 16); this.ctrlBreakpoints.Name = "ctrlBreakpoints"; - this.ctrlBreakpoints.Size = new System.Drawing.Size(346, 122); + this.ctrlBreakpoints.Size = new System.Drawing.Size(346, 128); this.ctrlBreakpoints.TabIndex = 0; this.ctrlBreakpoints.BreakpointNavigation += new System.EventHandler(this.ctrlBreakpoints_BreakpointNavigation); // @@ -551,7 +553,7 @@ namespace Mesen.GUI.Debugger this.grpCallstack.Dock = System.Windows.Forms.DockStyle.Fill; this.grpCallstack.Location = new System.Drawing.Point(719, 3); this.grpCallstack.Name = "grpCallstack"; - this.grpCallstack.Size = new System.Drawing.Size(353, 141); + this.grpCallstack.Size = new System.Drawing.Size(353, 147); this.grpCallstack.TabIndex = 4; this.grpCallstack.TabStop = false; this.grpCallstack.Text = "Call Stack"; @@ -561,7 +563,7 @@ namespace Mesen.GUI.Debugger this.ctrlCallstack.Dock = System.Windows.Forms.DockStyle.Fill; this.ctrlCallstack.Location = new System.Drawing.Point(3, 16); this.ctrlCallstack.Name = "ctrlCallstack"; - this.ctrlCallstack.Size = new System.Drawing.Size(347, 122); + this.ctrlCallstack.Size = new System.Drawing.Size(347, 128); this.ctrlCallstack.TabIndex = 0; this.ctrlCallstack.FunctionSelected += new System.EventHandler(this.ctrlCallstack_FunctionSelected); // @@ -1181,7 +1183,9 @@ namespace Mesen.GUI.Debugger this.mnuBreakOnDebuggerFocus, this.toolStripMenuItem20, this.mnuBringToFrontOnBreak, - this.mnuBringToFrontOnPause}); + this.mnuBringToFrontOnPause, + this.toolStripMenuItem28, + this.mnuEnableSubInstructionBreakpoints}); this.mnuBreakOptions.Name = "mnuBreakOptions"; this.mnuBreakOptions.Size = new System.Drawing.Size(266, 22); this.mnuBreakOptions.Text = "Break Options"; @@ -1303,6 +1307,14 @@ namespace Mesen.GUI.Debugger this.mnuBringToFrontOnPause.Text = "Bring debugger to front on pause"; this.mnuBringToFrontOnPause.Click += new System.EventHandler(this.mnuBringToFrontOnPause_Click); // + // mnuBreakOnFirstCycle + // + this.mnuEnableSubInstructionBreakpoints.CheckOnClick = true; + this.mnuEnableSubInstructionBreakpoints.Name = "mnuEnableSubInstructionBreakpoints"; + this.mnuEnableSubInstructionBreakpoints.Size = new System.Drawing.Size(261, 22); + this.mnuEnableSubInstructionBreakpoints.Text = "Enable sub-instruction breakpoints"; + this.mnuEnableSubInstructionBreakpoints.Click += new System.EventHandler(this.mnuBreakOnFirstCycle_Click); + // // toolStripMenuItem12 // this.toolStripMenuItem12.Name = "toolStripMenuItem12"; @@ -1572,6 +1584,19 @@ namespace Mesen.GUI.Debugger this.mnuShowBreakNotifications.Text = "Show break notifications"; this.mnuShowBreakNotifications.Click += new System.EventHandler(this.mnuShowBreakNotifications_Click); // + // mnuShowInstructionProgression + // + this.mnuShowInstructionProgression.CheckOnClick = true; + this.mnuShowInstructionProgression.Name = "mnuShowInstructionProgression"; + this.mnuShowInstructionProgression.Size = new System.Drawing.Size(266, 22); + this.mnuShowInstructionProgression.Text = "Show instruction progression"; + this.mnuShowInstructionProgression.Click += new System.EventHandler(this.mnuShowInstructionProgression_Click); + // + // toolStripMenuItem27 + // + this.toolStripMenuItem27.Name = "toolStripMenuItem27"; + this.toolStripMenuItem27.Size = new System.Drawing.Size(263, 6); + // // mnuAlwaysScrollToCenter // this.mnuAlwaysScrollToCenter.CheckOnClick = true; @@ -1874,18 +1899,10 @@ namespace Mesen.GUI.Debugger this.tsToolbar.Text = "toolStrip1"; this.tsToolbar.Visible = false; // - // mnuShowInstructionProgression + // toolStripMenuItem28 // - this.mnuShowInstructionProgression.CheckOnClick = true; - this.mnuShowInstructionProgression.Name = "mnuShowInstructionProgression"; - this.mnuShowInstructionProgression.Size = new System.Drawing.Size(266, 22); - this.mnuShowInstructionProgression.Text = "Show instruction progression"; - this.mnuShowInstructionProgression.Click += new System.EventHandler(this.mnuShowInstructionProgression_Click); - // - // toolStripMenuItem27 - // - this.toolStripMenuItem27.Name = "toolStripMenuItem27"; - this.toolStripMenuItem27.Size = new System.Drawing.Size(263, 6); + this.toolStripMenuItem28.Name = "toolStripMenuItem28"; + this.toolStripMenuItem28.Size = new System.Drawing.Size(258, 6); // // frmDebugger // @@ -2120,5 +2137,7 @@ namespace Mesen.GUI.Debugger private System.Windows.Forms.ToolStripMenuItem mnuShowBreakNotifications; private System.Windows.Forms.ToolStripMenuItem mnuShowInstructionProgression; private System.Windows.Forms.ToolStripSeparator toolStripMenuItem27; + private System.Windows.Forms.ToolStripMenuItem mnuEnableSubInstructionBreakpoints; + private System.Windows.Forms.ToolStripSeparator toolStripMenuItem28; } } \ No newline at end of file diff --git a/GUI.NET/Debugger/frmDebugger.cs b/GUI.NET/Debugger/frmDebugger.cs index 78175620..e1ee38c0 100644 --- a/GUI.NET/Debugger/frmDebugger.cs +++ b/GUI.NET/Debugger/frmDebugger.cs @@ -102,6 +102,7 @@ namespace Mesen.GUI.Debugger this.mnuShowPpuMemoryMapping.Checked = ConfigManager.Config.DebugInfo.ShowPpuMemoryMapping; this.mnuAutoLoadDbgFiles.Checked = ConfigManager.Config.DebugInfo.AutoLoadDbgFiles; this.mnuAutoLoadCdlFiles.Checked = ConfigManager.Config.DebugInfo.AutoLoadCdlFiles; + this.mnuEnableSubInstructionBreakpoints.Checked = !ConfigManager.Config.DebugInfo.BreakOnFirstCycle; this.mnuBreakOnReset.Checked = ConfigManager.Config.DebugInfo.BreakOnReset; this.mnuBreakOnInit.Checked = ConfigManager.Config.DebugInfo.BreakOnInit; this.mnuBreakOnPlay.Checked = ConfigManager.Config.DebugInfo.BreakOnPlay; @@ -484,6 +485,7 @@ namespace Mesen.GUI.Debugger SetFlag(DebuggerFlags.BreakOnDecayedOamRead, config.BreakOnDecayedOamRead); SetFlag(DebuggerFlags.BreakOnInit, config.BreakOnInit); SetFlag(DebuggerFlags.BreakOnPlay, config.BreakOnPlay); + SetFlag(DebuggerFlags.BreakOnFirstCycle, config.BreakOnFirstCycle); SetFlag(DebuggerFlags.HidePauseIcon, config.HidePauseIcon); InteropEmu.SetFlag(EmulationFlags.DebuggerWindowEnabled, true); } @@ -497,7 +499,8 @@ namespace Mesen.GUI.Debugger message = ResourceHelper.GetEnumText(source); if(source == BreakSource.Breakpoint) { int breakpointId = (int)(param >> 32); - BreakpointType bpType = (BreakpointType)(byte)(param >> 8); + BreakpointType bpType = (BreakpointType)(byte)((param >> 8) & 0x0F); + InteropMemoryOperationType memOpType = (InteropMemoryOperationType)(byte)((param >> 12) & 0x0F); UInt16 bpAddress = (UInt16)(param >> 16); ReadOnlyCollection breakpoints = BreakpointManager.Breakpoints; @@ -506,9 +509,7 @@ namespace Mesen.GUI.Debugger if(bpType != BreakpointType.Global) { string prefix = ""; if(bpType == BreakpointType.ReadRam || bpType == BreakpointType.WriteRam) { - InstructionProgress progress = new InstructionProgress(); - InteropEmu.DebugGetInstructionProgress(ref progress); - if(progress.OpMemoryOperationType == InteropMemoryOperationType.DummyRead || progress.OpMemoryOperationType == InteropMemoryOperationType.DummyWrite) { + if(memOpType == InteropMemoryOperationType.DummyRead || memOpType == InteropMemoryOperationType.DummyWrite) { prefix = "(Dummy) "; } } @@ -523,6 +524,9 @@ namespace Mesen.GUI.Debugger } } } + } else if(source == BreakSource.BreakOnUninitMemoryRead) { + UInt16 address = (UInt16)(param >> 16); + message += " ($" + address.ToString("X4") + ")"; } else if(source == BreakSource.CpuStep || source == BreakSource.PpuStep) { //Don't display anything when breaking due to stepping message = null; @@ -1189,6 +1193,13 @@ namespace Mesen.GUI.Debugger ConfigManager.Config.DebugInfo.OnlyShowTooltipsOnShift = mnuOnlyShowTooltipOnShift.Checked; ConfigManager.ApplyChanges(); } + + private void mnuBreakOnFirstCycle_Click(object sender, EventArgs e) + { + ConfigManager.Config.DebugInfo.BreakOnFirstCycle = !mnuEnableSubInstructionBreakpoints.Checked; + ConfigManager.ApplyChanges(); + UpdateDebuggerFlags(); + } private void mnuBreakOnReset_Click(object sender, EventArgs e) { diff --git a/GUI.NET/InteropEmu.cs b/GUI.NET/InteropEmu.cs index 6b26a3e0..049936b3 100644 --- a/GUI.NET/InteropEmu.cs +++ b/GUI.NET/InteropEmu.cs @@ -1322,6 +1322,8 @@ namespace Mesen.GUI public UInt32 NmiScanline; public UInt32 ScanlineCount; public UInt32 SafeOamScanline; + public UInt16 BusAddress; + public byte MemoryReadBuffer; } public struct PPUState @@ -1690,6 +1692,8 @@ namespace Mesen.GUI BreakOnDecayedOamRead = 0x2000, BreakOnInit = 0x4000, BreakOnPlay = 0x8000, + + BreakOnFirstCycle = 0x10000, } public struct InteropRomInfo