Debugger: Added option to evaluate all breakpoints on the first cycle of an instruction

This commit is contained in:
Sour 2018-12-24 15:21:21 -05:00
parent 35192daeed
commit 937a90626d
16 changed files with 378 additions and 79 deletions

View file

@ -10,6 +10,7 @@
CPU::CPU(shared_ptr<Console> 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> 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> 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

View file

@ -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;
}
};
#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

View file

@ -533,6 +533,7 @@
<ClInclude Include="Dance2000.h" />
<ClInclude Include="DragonFighter.h" />
<ClInclude Include="DrawScreenBufferCommand.h" />
<ClInclude Include="DummyCpu.h" />
<ClInclude Include="FaridSlrom.h" />
<ClInclude Include="FaridUnrom.h" />
<ClInclude Include="FdsSystemActionManager.h" />

View file

@ -1471,6 +1471,9 @@
<ClInclude Include="ConsolePauseHelper.h">
<Filter>Misc</Filter>
</ClInclude>
<ClInclude Include="DummyCpu.h">
<Filter>Debugger</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="stdafx.cpp">

View file

@ -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> console, shared_ptr<CPU> 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);
}

View file

@ -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> _apu;
shared_ptr<MemoryManager> _memoryManager;
shared_ptr<BaseMapper> _mapper;
shared_ptr<DummyCpu> _dummyCpu;
bool _breakOnFirstCycle;
bool _hasScript;
SimpleLock _scriptLock;
@ -138,13 +142,14 @@ private:
vector<vector<int>> _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);

View file

@ -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

10
Core/DummyCpu.h Normal file
View file

@ -0,0 +1,10 @@
#pragma once
#include "stdafx.h"
#define DUMMYCPU
#define CPU DummyCpu
#include "CPU.h"
#include "CPU.cpp"
#undef CPU
#undef DUMMYCPU

View file

@ -42,6 +42,15 @@ vector<int32_t>& 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;

View file

@ -21,12 +21,14 @@ private:
vector<uint8_t> _uninitReads[4];
vector<int32_t>& 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[]);

View file

@ -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)

View file

@ -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,

View file

@ -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;

View file

@ -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;
}
}

View file

@ -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<Breakpoint> 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)
{

View file

@ -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