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) CPU::CPU(shared_ptr<Console> console)
{ {
_console = console; _console = console;
_memoryManager = _console->GetMemoryManager();
Func opTable[] = { Func opTable[] = {
// 0 1 2 3 4 5 6 7 8 9 A B C D E F // 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; _dmcCounter = 0;
_dmcDmaRunning = false; _dmcDmaRunning = false;
_cpuWrite = false; _cpuWrite = false;
_writeAddr = false; _writeAddr = 0;
_irqMask = 0; _irqMask = 0;
_state = {}; _state = {};
_prevRunIrq = false; _prevRunIrq = false;
@ -73,7 +74,6 @@ CPU::CPU(shared_ptr<Console> console)
void CPU::Reset(bool softReset, NesModel model) void CPU::Reset(bool softReset, NesModel model)
{ {
_memoryManager = _console->GetMemoryManager();
_state.NMIFlag = false; _state.NMIFlag = false;
_state.IRQFlag = 0; _state.IRQFlag = 0;
_cycleCount = -1; _cycleCount = -1;
@ -140,15 +140,19 @@ void CPU::IRQ()
SetPC(MemoryReadWord(CPU::NMIVector)); SetPC(MemoryReadWord(CPU::NMIVector));
_state.NMIFlag = false; _state.NMIFlag = false;
#ifndef DUMMYCPU
_console->DebugAddTrace("NMI"); _console->DebugAddTrace("NMI");
_console->DebugProcessInterrupt(originalPc, _state.PC, true); _console->DebugProcessInterrupt(originalPc, _state.PC, true);
#endif
} else { } else {
Push((uint8_t)(PS() | PSFlags::Reserved)); Push((uint8_t)(PS() | PSFlags::Reserved));
SetFlags(PSFlags::Interrupt); SetFlags(PSFlags::Interrupt);
SetPC(MemoryReadWord(CPU::IRQVector)); SetPC(MemoryReadWord(CPU::IRQVector));
#ifndef DUMMYCPU
_console->DebugAddTrace("IRQ"); _console->DebugAddTrace("IRQ");
_console->DebugProcessInterrupt(originalPc, _state.PC, false); _console->DebugProcessInterrupt(originalPc, _state.PC, false);
#endif
} }
} }
@ -162,14 +166,18 @@ void CPU::BRK() {
SetPC(MemoryReadWord(CPU::NMIVector)); SetPC(MemoryReadWord(CPU::NMIVector));
#ifndef DUMMYCPU
_console->DebugAddTrace("NMI"); _console->DebugAddTrace("NMI");
#endif
} else { } else {
Push((uint8_t)flags); Push((uint8_t)flags);
SetFlags(PSFlags::Interrupt); SetFlags(PSFlags::Interrupt);
SetPC(MemoryReadWord(CPU::IRQVector)); SetPC(MemoryReadWord(CPU::IRQVector));
#ifndef DUMMYCPU
_console->DebugAddTrace("IRQ"); _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) //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) { while(_dmcDmaRunning) {
IncCycleCount(); 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); _memoryManager->Write(addr, value, operationType);
#endif
//DMA DMC might have started after a write to $4015, stall CPU if needed //DMA DMC might have started after a write to $4015, stall CPU if needed
while(_dmcDmaRunning) { 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 //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. //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) //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); _memoryManager->Read(addr);
#endif
} }
IncCycleCount(); 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) { if(operationType == MemoryOperationType::ExecOpCode) {
_state.DebugPC = _state.PC; _state.DebugPC = _state.PC;
} }
uint8_t value = _memoryManager->Read(addr, operationType); uint8_t value = _memoryManager->Read(addr, operationType);
return value; return value;
#endif
} }
uint16_t CPU::FetchOperand() uint16_t CPU::FetchOperand()
@ -236,7 +269,7 @@ uint16_t CPU::FetchOperand()
default: break; default: break;
} }
#ifndef LIBRETRO #if !defined(LIBRETRO) && !defined(DUMMYCPU)
if(_warnOnCrash && _console->GetSettings()->CheckFlag(EmulationFlags::DeveloperMode)) { if(_warnOnCrash && _console->GetSettings()->CheckFlag(EmulationFlags::DeveloperMode)) {
MessageManager::DisplayMessage("Error", "GameCrash", "Invalid OP code - CPU crashed."); MessageManager::DisplayMessage("Error", "GameCrash", "Invalid OP code - CPU crashed.");
_warnOnCrash = false; _warnOnCrash = false;
@ -270,12 +303,16 @@ void CPU::IncCycleCount()
if(_dmcCounter == 0) { if(_dmcCounter == 0) {
//Update the DMC buffer when the stall period is completed //Update the DMC buffer when the stall period is completed
_dmcDmaRunning = false; _dmcDmaRunning = false;
#ifndef DUMMYCPU
_console->GetApu()->FillDmcReadBuffer(); _console->GetApu()->FillDmcReadBuffer();
_console->DebugAddTrace("DMC DMA End"); _console->DebugAddTrace("DMC DMA End");
#endif
} }
} }
#ifndef DUMMYCPU
_console->ProcessCpuClock(); _console->ProcessCpuClock();
#endif
if(!_spriteDmaTransfer && !_dmcDmaRunning) { if(!_spriteDmaTransfer && !_dmcDmaRunning) {
//IRQ flags are ignored during Sprite DMA - fixes irq_and_dma //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 "stdafx.h"
#include "Snapshotable.h" #include "Snapshotable.h"
@ -7,24 +12,12 @@
enum class NesModel; enum class NesModel;
class Console; class Console;
class MemoryManager; class MemoryManager;
class DummyCpu;
namespace PSFlags
{
enum PSFlags : uint8_t
{
Carry = 0x01,
Zero = 0x02,
Interrupt = 0x04,
Decimal = 0x08,
Break = 0x10,
Reserved = 0x20,
Overflow = 0x40,
Negative = 0x80
};
}
class CPU : public Snapshotable class CPU : public Snapshotable
{ {
friend DummyCpu;
public: public:
static constexpr uint16_t NMIVector = 0xFFFA; static constexpr uint16_t NMIVector = 0xFFFA;
static constexpr uint16_t ResetVector = 0xFFFC; static constexpr uint16_t ResetVector = 0xFFFC;
@ -62,6 +55,17 @@ private:
bool _warnOnCrash = true; 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(); void IncCycleCount();
uint16_t FetchOperand(); uint16_t FetchOperand();
void IRQ(); void IRQ();
@ -818,4 +822,53 @@ public:
state.PC = originalPc; state.PC = originalPc;
state.DebugPC = originalDebugPc; 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="Dance2000.h" />
<ClInclude Include="DragonFighter.h" /> <ClInclude Include="DragonFighter.h" />
<ClInclude Include="DrawScreenBufferCommand.h" /> <ClInclude Include="DrawScreenBufferCommand.h" />
<ClInclude Include="DummyCpu.h" />
<ClInclude Include="FaridSlrom.h" /> <ClInclude Include="FaridSlrom.h" />
<ClInclude Include="FaridUnrom.h" /> <ClInclude Include="FaridUnrom.h" />
<ClInclude Include="FdsSystemActionManager.h" /> <ClInclude Include="FdsSystemActionManager.h" />

View file

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

View file

@ -29,6 +29,7 @@
#include "CodeDataLogger.h" #include "CodeDataLogger.h"
#include "NotificationManager.h" #include "NotificationManager.h"
#include "DebugHud.h" #include "DebugHud.h"
#include "DummyCpu.h"
const int Debugger::BreakpointTypeCount; const int Debugger::BreakpointTypeCount;
string Debugger::_disassemblerOutput = ""; string Debugger::_disassemblerOutput = "";
@ -42,6 +43,9 @@ Debugger::Debugger(shared_ptr<Console> console, shared_ptr<CPU> cpu, shared_ptr<
_memoryManager = memoryManager; _memoryManager = memoryManager;
_mapper = mapper; _mapper = mapper;
_dummyCpu.reset(new DummyCpu(console));
_breakOnFirstCycle = false;
_labelManager.reset(new LabelManager(_mapper)); _labelManager.reset(new LabelManager(_mapper));
_assembler.reset(new Assembler(_labelManager)); _assembler.reset(new Assembler(_labelManager));
_disassembler.reset(new Disassembler(memoryManager.get(), mapper.get(), this)); _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; bool needUpdate = ((flags ^ _flags) & (int)DebuggerFlags::DisplayOpCodesInLowerCase) != 0;
_flags = flags; _flags = flags;
_breakOnFirstCycle = CheckFlag(DebuggerFlags::BreakOnFirstCycle);
if(needUpdate) { if(needUpdate) {
_disassembler->BuildOpCodeTables(CheckFlag(DebuggerFlags::DisplayOpCodesInLowerCase)); _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) { if(_runToCycle != 0) {
//Disable all breakpoints while stepping backwards //Disable all breakpoints while stepping backwards
return; return false;
} }
AddressTypeInfo info { -1, AddressType::InternalRam }; 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++) { for(size_t i = 0, len = breakpoints.size(); i < len; i++) {
Breakpoint &breakpoint = breakpoints[i]; Breakpoint &breakpoint = breakpoints[i];
if(!((breakpoint.IsEnabled() && allowBreak) || (breakpoint.IsMarked() && allowMark))) {
//Skip breakpoints we don't need to process
continue;
}
if( if(
type == BreakpointType::Global || type == BreakpointType::Global ||
(!isPpuBreakpoint && breakpoint.Matches(operationInfo.Address, info, operationInfo.OperationType)) || (!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 //No need to process remaining breakpoints
break; break;
} }
} }
if(needMark) { if(needMark && allowMark) {
AddDebugEvent(DebugEventType::Breakpoint, operationInfo.Address, (uint8_t)operationInfo.Value, markBreakpointId); AddDebugEvent(DebugEventType::Breakpoint, operationInfo.Address, (uint8_t)operationInfo.Value, markBreakpointId);
} }
if(needBreak && allowBreak) { if(needBreak && allowBreak) {
//Found a matching breakpoint, stop execution //Found a matching breakpoint, stop execution
Step(1); 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 { } else {
if(_memoryAccessCounter->ProcessMemoryAccess(addressInfo, type, _cpu->GetCycleCount())) { if(_memoryAccessCounter->ProcessMemoryAccess(addressInfo, type, _cpu->GetCycleCount())) {
if(_enableBreakOnUninitRead && CheckFlag(DebuggerFlags::BreakOnUninitMemoryRead)) { if(!_breakOnFirstCycle && _enableBreakOnUninitRead && CheckFlag(DebuggerFlags::BreakOnUninitMemoryRead)) {
//Break on uninit memory read //Break on uninit memory read
Step(1); Step(1);
breakDone = SleepUntilResume(BreakSource::BreakOnUninitMemoryRead); breakDone = SleepUntilResume(BreakSource::BreakOnUninitMemoryRead);
@ -691,8 +798,17 @@ bool Debugger::ProcessRamOperation(MemoryOperationType type, uint16_t &addr, uin
case MemoryOperationType::Write: breakpointType = BreakpointType::WriteRam; break; case MemoryOperationType::Write: breakpointType = BreakpointType::WriteRam; break;
} }
if(_hasBreakpoint[breakpointType]) { if(_breakOnFirstCycle) {
ProcessBreakpoints(breakpointType, operationInfo, !breakDone); 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; _currentReadAddr = nullptr;
@ -726,7 +842,7 @@ bool Debugger::ProcessRamOperation(MemoryOperationType type, uint16_t &addr, uin
return true; 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(); int32_t stepCount = _stepCount.load();
if(stepCount > 0) { if(stepCount > 0) {
@ -753,7 +869,14 @@ bool Debugger::SleepUntilResume(BreakSource source, uint32_t breakpointId, Break
} }
_breakSource = BreakSource::Unspecified; _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); _console->GetNotificationManager()->SendNotification(ConsoleNotificationType::CodeBreak, (void*)(uint64_t)param);
ProcessEvent(EventType::CodeBreak); ProcessEvent(EventType::CodeBreak);
@ -784,7 +907,7 @@ void Debugger::ProcessVramReadOperation(MemoryOperationType type, uint16_t addr,
int32_t absoluteAddr = _mapper->ToAbsoluteChrAddress(addr); int32_t absoluteAddr = _mapper->ToAbsoluteChrAddress(addr);
_codeDataLogger->SetFlag(absoluteAddr, type == MemoryOperationType::Read ? CdlChrFlags::Read : CdlChrFlags::Drawn); _codeDataLogger->SetFlag(absoluteAddr, type == MemoryOperationType::Read ? CdlChrFlags::Read : CdlChrFlags::Drawn);
if(_hasBreakpoint[BreakpointType::ReadVram]) { if(!_breakOnFirstCycle && _hasBreakpoint[BreakpointType::ReadVram]) {
OperationInfo operationInfo{ addr, value, type }; OperationInfo operationInfo{ addr, value, type };
ProcessBreakpoints(BreakpointType::ReadVram, operationInfo); 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) void Debugger::ProcessVramWriteOperation(uint16_t addr, uint8_t &value)
{ {
if(_hasBreakpoint[BreakpointType::WriteVram]) { if(!_breakOnFirstCycle && _hasBreakpoint[BreakpointType::WriteVram]) {
OperationInfo operationInfo{ addr, value, MemoryOperationType::Write }; OperationInfo operationInfo{ addr, value, MemoryOperationType::Write };
ProcessBreakpoints(BreakpointType::WriteVram, operationInfo); ProcessBreakpoints(BreakpointType::WriteVram, operationInfo);
} }

View file

@ -29,6 +29,7 @@ class TraceLogger;
class Breakpoint; class Breakpoint;
class CodeDataLogger; class CodeDataLogger;
class ExpressionEvaluator; class ExpressionEvaluator;
class DummyCpu;
struct ExpressionData; struct ExpressionData;
enum EvalResultType : int32_t; enum EvalResultType : int32_t;
@ -59,6 +60,9 @@ private:
shared_ptr<MemoryManager> _memoryManager; shared_ptr<MemoryManager> _memoryManager;
shared_ptr<BaseMapper> _mapper; shared_ptr<BaseMapper> _mapper;
shared_ptr<DummyCpu> _dummyCpu;
bool _breakOnFirstCycle;
bool _hasScript; bool _hasScript;
SimpleLock _scriptLock; SimpleLock _scriptLock;
int _nextScriptId; int _nextScriptId;
@ -138,13 +142,14 @@ private:
vector<vector<int>> _debugEventMarkerRpn; vector<vector<int>> _debugEventMarkerRpn;
private: 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 AddCallstackFrame(uint16_t source, uint16_t target, StackFrameFlags flags);
void UpdateCallstack(uint8_t currentInstruction, uint32_t addr); void UpdateCallstack(uint8_t currentInstruction, uint32_t addr);
void ProcessStepConditions(uint16_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); 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, BreakOnDecayedOamRead = 0x2000,
BreakOnInit = 0x4000, BreakOnInit = 0x4000,
BreakOnPlay = 0x8000, BreakOnPlay = 0x8000,
BreakOnFirstCycle = 0x10000,
}; };
enum class BreakSource enum class BreakSource
@ -117,6 +119,8 @@ struct PPUDebugState
uint32_t NmiScanline; uint32_t NmiScanline;
uint32_t ScanlineCount; uint32_t ScanlineCount;
uint32_t SafeOamScanline; uint32_t SafeOamScanline;
uint16_t BusAddress;
uint8_t MemoryReadBuffer;
}; };
struct DebugState 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) bool MemoryAccessCounter::ProcessMemoryAccess(AddressTypeInfo &addressInfo, MemoryOperationType operation, int32_t cpuCycle)
{ {
int index = (int)addressInfo.Type; int index = (int)addressInfo.Type;

View file

@ -28,6 +28,8 @@ public:
bool ProcessMemoryAccess(AddressTypeInfo &addressInfo, MemoryOperationType operation, int32_t cpuCycle); bool ProcessMemoryAccess(AddressTypeInfo &addressInfo, MemoryOperationType operation, int32_t cpuCycle);
void ResetCounts(); void ResetCounts();
bool IsAddressUninitialized(AddressTypeInfo &addressInfo);
void GetAccessCounts(AddressType memoryType, MemoryOperationType operationType, uint32_t counts[], bool forUninitReads); 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[]); void GetAccessCountsEx(uint32_t offset, uint32_t length, DebugMemoryType memoryType, MemoryOperationType operationType, int32_t counts[]);
void GetAccessStamps(uint32_t offset, uint32_t length, DebugMemoryType memoryType, MemoryOperationType operationType, uint32_t stamps[]); void GetAccessStamps(uint32_t offset, uint32_t length, DebugMemoryType memoryType, MemoryOperationType operationType, uint32_t stamps[]);

View file

@ -150,6 +150,8 @@ void PPU::GetState(PPUDebugState &state)
state.NmiScanline = _nmiScanline; state.NmiScanline = _nmiScanline;
state.ScanlineCount = _vblankEnd + 2; state.ScanlineCount = _vblankEnd + 2;
state.SafeOamScanline = _nesModel == NesModel::NTSC ? _nmiScanline + 19 : _palSpriteEvalScanline; state.SafeOamScanline = _nesModel == NesModel::NTSC ? _nmiScanline + 19 : _palSpriteEvalScanline;
state.BusAddress = _ppuBusAddress;
state.MemoryReadBuffer = _memoryReadBuffer;
} }
void PPU::SetState(PPUDebugState &state) void PPU::SetState(PPUDebugState &state)

View file

@ -1,6 +1,21 @@
#pragma once #pragma once
#include "stdafx.h" #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 enum class AddrMode
{ {
None, Acc, Imp, Imm, Rel, None, Acc, Imp, Imm, Rel,

View file

@ -301,6 +301,7 @@ namespace Mesen.GUI.Config
public bool BreakOnUninitMemoryRead = false; public bool BreakOnUninitMemoryRead = false;
public bool BreakOnInit = true; public bool BreakOnInit = true;
public bool BreakOnPlay = false; public bool BreakOnPlay = false;
public bool BreakOnFirstCycle = true;
public bool BringToFrontOnPause = false; public bool BringToFrontOnPause = false;
public bool BringToFrontOnBreak = true; public bool BringToFrontOnBreak = true;

View file

@ -140,6 +140,7 @@ namespace Mesen.GUI.Debugger
this.toolStripMenuItem20 = new System.Windows.Forms.ToolStripSeparator(); this.toolStripMenuItem20 = new System.Windows.Forms.ToolStripSeparator();
this.mnuBringToFrontOnBreak = new System.Windows.Forms.ToolStripMenuItem(); this.mnuBringToFrontOnBreak = new System.Windows.Forms.ToolStripMenuItem();
this.mnuBringToFrontOnPause = 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.toolStripMenuItem12 = new System.Windows.Forms.ToolStripSeparator();
this.mnuShowOptions = new System.Windows.Forms.ToolStripMenuItem(); this.mnuShowOptions = new System.Windows.Forms.ToolStripMenuItem();
this.mnuShowToolbar = 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.mnuPpuShowPreviousFrame = new System.Windows.Forms.ToolStripMenuItem();
this.toolStripMenuItem19 = new System.Windows.Forms.ToolStripSeparator(); this.toolStripMenuItem19 = new System.Windows.Forms.ToolStripSeparator();
this.mnuShowBreakNotifications = new System.Windows.Forms.ToolStripMenuItem(); 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.mnuAlwaysScrollToCenter = new System.Windows.Forms.ToolStripMenuItem();
this.mnuRefreshWhileRunning = new System.Windows.Forms.ToolStripMenuItem(); this.mnuRefreshWhileRunning = new System.Windows.Forms.ToolStripMenuItem();
this.toolStripMenuItem6 = new System.Windows.Forms.ToolStripSeparator(); this.toolStripMenuItem6 = new System.Windows.Forms.ToolStripSeparator();
@ -211,8 +214,7 @@ namespace Mesen.GUI.Debugger
this.ctrlPpuMemoryMapping = new Mesen.GUI.Debugger.Controls.ctrlMemoryMapping(); this.ctrlPpuMemoryMapping = new Mesen.GUI.Debugger.Controls.ctrlMemoryMapping();
this.ctrlCpuMemoryMapping = new Mesen.GUI.Debugger.Controls.ctrlMemoryMapping(); this.ctrlCpuMemoryMapping = new Mesen.GUI.Debugger.Controls.ctrlMemoryMapping();
this.tsToolbar = new Mesen.GUI.Controls.ctrlMesenToolStrip(); this.tsToolbar = new Mesen.GUI.Controls.ctrlMesenToolStrip();
this.mnuShowInstructionProgression = new System.Windows.Forms.ToolStripMenuItem(); this.toolStripMenuItem28 = new System.Windows.Forms.ToolStripSeparator();
this.toolStripMenuItem27 = new System.Windows.Forms.ToolStripSeparator();
((System.ComponentModel.ISupportInitialize)(this.splitContainer)).BeginInit(); ((System.ComponentModel.ISupportInitialize)(this.splitContainer)).BeginInit();
this.splitContainer.Panel1.SuspendLayout(); this.splitContainer.Panel1.SuspendLayout();
this.splitContainer.Panel2.SuspendLayout(); this.splitContainer.Panel2.SuspendLayout();
@ -257,7 +259,7 @@ namespace Mesen.GUI.Debugger
this.splitContainer.Panel2.Controls.Add(this.tableLayoutPanel10); this.splitContainer.Panel2.Controls.Add(this.tableLayoutPanel10);
this.splitContainer.Panel2MinSize = 100; this.splitContainer.Panel2MinSize = 100;
this.splitContainer.Size = new System.Drawing.Size(1075, 570); this.splitContainer.Size = new System.Drawing.Size(1075, 570);
this.splitContainer.SplitterDistance = 416; this.splitContainer.SplitterDistance = 410;
this.splitContainer.SplitterWidth = 7; this.splitContainer.SplitterWidth = 7;
this.splitContainer.TabIndex = 1; this.splitContainer.TabIndex = 1;
this.splitContainer.TabStop = false; this.splitContainer.TabStop = false;
@ -281,7 +283,7 @@ namespace Mesen.GUI.Debugger
// //
this.ctrlSplitContainerTop.Panel2.Controls.Add(this.tlpFunctionLabelLists); this.ctrlSplitContainerTop.Panel2.Controls.Add(this.tlpFunctionLabelLists);
this.ctrlSplitContainerTop.Panel2MinSize = 150; 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.SplitterDistance = 750;
this.ctrlSplitContainerTop.SplitterWidth = 7; this.ctrlSplitContainerTop.SplitterWidth = 7;
this.ctrlSplitContainerTop.TabIndex = 3; this.ctrlSplitContainerTop.TabIndex = 3;
@ -302,8 +304,8 @@ namespace Mesen.GUI.Debugger
this.tlpTop.Name = "tlpTop"; this.tlpTop.Name = "tlpTop";
this.tlpTop.RowCount = 1; 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.Percent, 100F));
this.tlpTop.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 416F)); this.tlpTop.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 410F));
this.tlpTop.Size = new System.Drawing.Size(750, 416); this.tlpTop.Size = new System.Drawing.Size(750, 410);
this.tlpTop.TabIndex = 2; this.tlpTop.TabIndex = 2;
// //
// panel1 // panel1
@ -314,7 +316,7 @@ namespace Mesen.GUI.Debugger
this.panel1.Location = new System.Drawing.Point(3, 0); this.panel1.Location = new System.Drawing.Point(3, 0);
this.panel1.Margin = new System.Windows.Forms.Padding(3, 0, 3, 0); this.panel1.Margin = new System.Windows.Forms.Padding(3, 0, 3, 0);
this.panel1.Name = "panel1"; 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; this.panel1.TabIndex = 5;
// //
// ctrlSourceViewer // ctrlSourceViewer
@ -323,7 +325,7 @@ namespace Mesen.GUI.Debugger
this.ctrlSourceViewer.Dock = System.Windows.Forms.DockStyle.Fill; this.ctrlSourceViewer.Dock = System.Windows.Forms.DockStyle.Fill;
this.ctrlSourceViewer.Location = new System.Drawing.Point(0, 0); this.ctrlSourceViewer.Location = new System.Drawing.Point(0, 0);
this.ctrlSourceViewer.Name = "ctrlSourceViewer"; 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.SymbolProvider = null;
this.ctrlSourceViewer.TabIndex = 7; this.ctrlSourceViewer.TabIndex = 7;
this.ctrlSourceViewer.Visible = false; this.ctrlSourceViewer.Visible = false;
@ -336,7 +338,7 @@ namespace Mesen.GUI.Debugger
this.ctrlDebuggerCode.Location = new System.Drawing.Point(0, 0); this.ctrlDebuggerCode.Location = new System.Drawing.Point(0, 0);
this.ctrlDebuggerCode.Name = "ctrlDebuggerCode"; this.ctrlDebuggerCode.Name = "ctrlDebuggerCode";
this.ctrlDebuggerCode.ShowMemoryValues = false; 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.SymbolProvider = null;
this.ctrlDebuggerCode.TabIndex = 2; this.ctrlDebuggerCode.TabIndex = 2;
this.ctrlDebuggerCode.OnEditCode += new Mesen.GUI.Debugger.ctrlDebuggerCode.AssemblerEventHandler(this.ctrlDebuggerCode_OnEditCode); 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.Location = new System.Drawing.Point(292, 0);
this.panel2.Margin = new System.Windows.Forms.Padding(0, 0, 3, 0); this.panel2.Margin = new System.Windows.Forms.Padding(0, 0, 3, 0);
this.panel2.Name = "panel2"; 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; this.panel2.TabIndex = 6;
// //
// ctrlSourceViewerSplit // ctrlSourceViewerSplit
@ -359,7 +361,7 @@ namespace Mesen.GUI.Debugger
this.ctrlSourceViewerSplit.Dock = System.Windows.Forms.DockStyle.Fill; this.ctrlSourceViewerSplit.Dock = System.Windows.Forms.DockStyle.Fill;
this.ctrlSourceViewerSplit.Location = new System.Drawing.Point(0, 0); this.ctrlSourceViewerSplit.Location = new System.Drawing.Point(0, 0);
this.ctrlSourceViewerSplit.Name = "ctrlSourceViewerSplit"; 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.SymbolProvider = null;
this.ctrlSourceViewerSplit.TabIndex = 8; this.ctrlSourceViewerSplit.TabIndex = 8;
this.ctrlSourceViewerSplit.Visible = false; this.ctrlSourceViewerSplit.Visible = false;
@ -372,7 +374,7 @@ namespace Mesen.GUI.Debugger
this.ctrlDebuggerCodeSplit.Location = new System.Drawing.Point(0, 0); this.ctrlDebuggerCodeSplit.Location = new System.Drawing.Point(0, 0);
this.ctrlDebuggerCodeSplit.Name = "ctrlDebuggerCodeSplit"; this.ctrlDebuggerCodeSplit.Name = "ctrlDebuggerCodeSplit";
this.ctrlDebuggerCodeSplit.ShowMemoryValues = false; 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.SymbolProvider = null;
this.ctrlDebuggerCodeSplit.TabIndex = 4; this.ctrlDebuggerCodeSplit.TabIndex = 4;
this.ctrlDebuggerCodeSplit.Visible = false; this.ctrlDebuggerCodeSplit.Visible = false;
@ -392,7 +394,7 @@ namespace Mesen.GUI.Debugger
this.tableLayoutPanel1.RowCount = 2; this.tableLayoutPanel1.RowCount = 2;
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle()); 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.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; this.tableLayoutPanel1.TabIndex = 7;
// //
// ctrlConsoleStatus // ctrlConsoleStatus
@ -416,7 +418,7 @@ namespace Mesen.GUI.Debugger
this.tlpVerticalLayout.Name = "tlpVerticalLayout"; this.tlpVerticalLayout.Name = "tlpVerticalLayout";
this.tlpVerticalLayout.RowCount = 1; this.tlpVerticalLayout.RowCount = 1;
this.tlpVerticalLayout.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 50F)); 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; this.tlpVerticalLayout.TabIndex = 4;
// //
// tlpFunctionLabelLists // tlpFunctionLabelLists
@ -432,16 +434,16 @@ namespace Mesen.GUI.Debugger
this.tlpFunctionLabelLists.RowCount = 2; 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.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; this.tlpFunctionLabelLists.TabIndex = 5;
// //
// grpLabels // grpLabels
// //
this.grpLabels.Controls.Add(this.ctrlLabelList); this.grpLabels.Controls.Add(this.ctrlLabelList);
this.grpLabels.Dock = System.Windows.Forms.DockStyle.Fill; 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.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.TabIndex = 6;
this.grpLabels.TabStop = false; this.grpLabels.TabStop = false;
this.grpLabels.Text = "Labels"; this.grpLabels.Text = "Labels";
@ -451,7 +453,7 @@ namespace Mesen.GUI.Debugger
this.ctrlLabelList.Dock = System.Windows.Forms.DockStyle.Fill; this.ctrlLabelList.Dock = System.Windows.Forms.DockStyle.Fill;
this.ctrlLabelList.Location = new System.Drawing.Point(3, 16); this.ctrlLabelList.Location = new System.Drawing.Point(3, 16);
this.ctrlLabelList.Name = "ctrlLabelList"; 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.TabIndex = 0;
this.ctrlLabelList.OnFindOccurrence += new System.EventHandler(this.ctrlLabelList_OnFindOccurrence); this.ctrlLabelList.OnFindOccurrence += new System.EventHandler(this.ctrlLabelList_OnFindOccurrence);
this.ctrlLabelList.OnLabelSelected += new System.EventHandler(this.ctrlLabelList_OnLabelSelected); 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.Dock = System.Windows.Forms.DockStyle.Fill;
this.grpFunctions.Location = new System.Drawing.Point(3, 3); this.grpFunctions.Location = new System.Drawing.Point(3, 3);
this.grpFunctions.Name = "grpFunctions"; 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.TabIndex = 5;
this.grpFunctions.TabStop = false; this.grpFunctions.TabStop = false;
this.grpFunctions.Text = "Functions"; this.grpFunctions.Text = "Functions";
@ -472,7 +474,7 @@ namespace Mesen.GUI.Debugger
this.ctrlFunctionList.Dock = System.Windows.Forms.DockStyle.Fill; this.ctrlFunctionList.Dock = System.Windows.Forms.DockStyle.Fill;
this.ctrlFunctionList.Location = new System.Drawing.Point(3, 16); this.ctrlFunctionList.Location = new System.Drawing.Point(3, 16);
this.ctrlFunctionList.Name = "ctrlFunctionList"; 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.TabIndex = 0;
this.ctrlFunctionList.OnFindOccurrence += new System.EventHandler(this.ctrlFunctionList_OnFindOccurrence); this.ctrlFunctionList.OnFindOccurrence += new System.EventHandler(this.ctrlFunctionList_OnFindOccurrence);
this.ctrlFunctionList.OnFunctionSelected += new System.EventHandler(this.ctrlFunctionList_OnFunctionSelected); 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(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.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; this.tableLayoutPanel10.TabIndex = 0;
// //
// grpWatch // grpWatch
@ -512,7 +514,7 @@ namespace Mesen.GUI.Debugger
this.grpWatch.Dock = System.Windows.Forms.DockStyle.Fill; this.grpWatch.Dock = System.Windows.Forms.DockStyle.Fill;
this.grpWatch.Location = new System.Drawing.Point(3, 3); this.grpWatch.Location = new System.Drawing.Point(3, 3);
this.grpWatch.Name = "grpWatch"; 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.TabIndex = 2;
this.grpWatch.TabStop = false; this.grpWatch.TabStop = false;
this.grpWatch.Text = "Watch"; this.grpWatch.Text = "Watch";
@ -522,7 +524,7 @@ namespace Mesen.GUI.Debugger
this.ctrlWatch.Dock = System.Windows.Forms.DockStyle.Fill; this.ctrlWatch.Dock = System.Windows.Forms.DockStyle.Fill;
this.ctrlWatch.Location = new System.Drawing.Point(3, 16); this.ctrlWatch.Location = new System.Drawing.Point(3, 16);
this.ctrlWatch.Name = "ctrlWatch"; 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; this.ctrlWatch.TabIndex = 0;
// //
// grpBreakpoints // grpBreakpoints
@ -531,7 +533,7 @@ namespace Mesen.GUI.Debugger
this.grpBreakpoints.Dock = System.Windows.Forms.DockStyle.Fill; this.grpBreakpoints.Dock = System.Windows.Forms.DockStyle.Fill;
this.grpBreakpoints.Location = new System.Drawing.Point(361, 3); this.grpBreakpoints.Location = new System.Drawing.Point(361, 3);
this.grpBreakpoints.Name = "grpBreakpoints"; 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.TabIndex = 3;
this.grpBreakpoints.TabStop = false; this.grpBreakpoints.TabStop = false;
this.grpBreakpoints.Text = "Breakpoints"; this.grpBreakpoints.Text = "Breakpoints";
@ -541,7 +543,7 @@ namespace Mesen.GUI.Debugger
this.ctrlBreakpoints.Dock = System.Windows.Forms.DockStyle.Fill; this.ctrlBreakpoints.Dock = System.Windows.Forms.DockStyle.Fill;
this.ctrlBreakpoints.Location = new System.Drawing.Point(3, 16); this.ctrlBreakpoints.Location = new System.Drawing.Point(3, 16);
this.ctrlBreakpoints.Name = "ctrlBreakpoints"; 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.TabIndex = 0;
this.ctrlBreakpoints.BreakpointNavigation += new System.EventHandler(this.ctrlBreakpoints_BreakpointNavigation); 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.Dock = System.Windows.Forms.DockStyle.Fill;
this.grpCallstack.Location = new System.Drawing.Point(719, 3); this.grpCallstack.Location = new System.Drawing.Point(719, 3);
this.grpCallstack.Name = "grpCallstack"; 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.TabIndex = 4;
this.grpCallstack.TabStop = false; this.grpCallstack.TabStop = false;
this.grpCallstack.Text = "Call Stack"; this.grpCallstack.Text = "Call Stack";
@ -561,7 +563,7 @@ namespace Mesen.GUI.Debugger
this.ctrlCallstack.Dock = System.Windows.Forms.DockStyle.Fill; this.ctrlCallstack.Dock = System.Windows.Forms.DockStyle.Fill;
this.ctrlCallstack.Location = new System.Drawing.Point(3, 16); this.ctrlCallstack.Location = new System.Drawing.Point(3, 16);
this.ctrlCallstack.Name = "ctrlCallstack"; 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.TabIndex = 0;
this.ctrlCallstack.FunctionSelected += new System.EventHandler(this.ctrlCallstack_FunctionSelected); this.ctrlCallstack.FunctionSelected += new System.EventHandler(this.ctrlCallstack_FunctionSelected);
// //
@ -1181,7 +1183,9 @@ namespace Mesen.GUI.Debugger
this.mnuBreakOnDebuggerFocus, this.mnuBreakOnDebuggerFocus,
this.toolStripMenuItem20, this.toolStripMenuItem20,
this.mnuBringToFrontOnBreak, this.mnuBringToFrontOnBreak,
this.mnuBringToFrontOnPause}); this.mnuBringToFrontOnPause,
this.toolStripMenuItem28,
this.mnuEnableSubInstructionBreakpoints});
this.mnuBreakOptions.Name = "mnuBreakOptions"; this.mnuBreakOptions.Name = "mnuBreakOptions";
this.mnuBreakOptions.Size = new System.Drawing.Size(266, 22); this.mnuBreakOptions.Size = new System.Drawing.Size(266, 22);
this.mnuBreakOptions.Text = "Break Options"; this.mnuBreakOptions.Text = "Break Options";
@ -1303,6 +1307,14 @@ namespace Mesen.GUI.Debugger
this.mnuBringToFrontOnPause.Text = "Bring debugger to front on pause"; this.mnuBringToFrontOnPause.Text = "Bring debugger to front on pause";
this.mnuBringToFrontOnPause.Click += new System.EventHandler(this.mnuBringToFrontOnPause_Click); 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 // toolStripMenuItem12
// //
this.toolStripMenuItem12.Name = "toolStripMenuItem12"; this.toolStripMenuItem12.Name = "toolStripMenuItem12";
@ -1572,6 +1584,19 @@ namespace Mesen.GUI.Debugger
this.mnuShowBreakNotifications.Text = "Show break notifications"; this.mnuShowBreakNotifications.Text = "Show break notifications";
this.mnuShowBreakNotifications.Click += new System.EventHandler(this.mnuShowBreakNotifications_Click); 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 // mnuAlwaysScrollToCenter
// //
this.mnuAlwaysScrollToCenter.CheckOnClick = true; this.mnuAlwaysScrollToCenter.CheckOnClick = true;
@ -1874,18 +1899,10 @@ namespace Mesen.GUI.Debugger
this.tsToolbar.Text = "toolStrip1"; this.tsToolbar.Text = "toolStrip1";
this.tsToolbar.Visible = false; this.tsToolbar.Visible = false;
// //
// mnuShowInstructionProgression // toolStripMenuItem28
// //
this.mnuShowInstructionProgression.CheckOnClick = true; this.toolStripMenuItem28.Name = "toolStripMenuItem28";
this.mnuShowInstructionProgression.Name = "mnuShowInstructionProgression"; this.toolStripMenuItem28.Size = new System.Drawing.Size(258, 6);
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);
// //
// frmDebugger // frmDebugger
// //
@ -2120,5 +2137,7 @@ namespace Mesen.GUI.Debugger
private System.Windows.Forms.ToolStripMenuItem mnuShowBreakNotifications; private System.Windows.Forms.ToolStripMenuItem mnuShowBreakNotifications;
private System.Windows.Forms.ToolStripMenuItem mnuShowInstructionProgression; private System.Windows.Forms.ToolStripMenuItem mnuShowInstructionProgression;
private System.Windows.Forms.ToolStripSeparator toolStripMenuItem27; 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.mnuShowPpuMemoryMapping.Checked = ConfigManager.Config.DebugInfo.ShowPpuMemoryMapping;
this.mnuAutoLoadDbgFiles.Checked = ConfigManager.Config.DebugInfo.AutoLoadDbgFiles; this.mnuAutoLoadDbgFiles.Checked = ConfigManager.Config.DebugInfo.AutoLoadDbgFiles;
this.mnuAutoLoadCdlFiles.Checked = ConfigManager.Config.DebugInfo.AutoLoadCdlFiles; this.mnuAutoLoadCdlFiles.Checked = ConfigManager.Config.DebugInfo.AutoLoadCdlFiles;
this.mnuEnableSubInstructionBreakpoints.Checked = !ConfigManager.Config.DebugInfo.BreakOnFirstCycle;
this.mnuBreakOnReset.Checked = ConfigManager.Config.DebugInfo.BreakOnReset; this.mnuBreakOnReset.Checked = ConfigManager.Config.DebugInfo.BreakOnReset;
this.mnuBreakOnInit.Checked = ConfigManager.Config.DebugInfo.BreakOnInit; this.mnuBreakOnInit.Checked = ConfigManager.Config.DebugInfo.BreakOnInit;
this.mnuBreakOnPlay.Checked = ConfigManager.Config.DebugInfo.BreakOnPlay; this.mnuBreakOnPlay.Checked = ConfigManager.Config.DebugInfo.BreakOnPlay;
@ -484,6 +485,7 @@ namespace Mesen.GUI.Debugger
SetFlag(DebuggerFlags.BreakOnDecayedOamRead, config.BreakOnDecayedOamRead); SetFlag(DebuggerFlags.BreakOnDecayedOamRead, config.BreakOnDecayedOamRead);
SetFlag(DebuggerFlags.BreakOnInit, config.BreakOnInit); SetFlag(DebuggerFlags.BreakOnInit, config.BreakOnInit);
SetFlag(DebuggerFlags.BreakOnPlay, config.BreakOnPlay); SetFlag(DebuggerFlags.BreakOnPlay, config.BreakOnPlay);
SetFlag(DebuggerFlags.BreakOnFirstCycle, config.BreakOnFirstCycle);
SetFlag(DebuggerFlags.HidePauseIcon, config.HidePauseIcon); SetFlag(DebuggerFlags.HidePauseIcon, config.HidePauseIcon);
InteropEmu.SetFlag(EmulationFlags.DebuggerWindowEnabled, true); InteropEmu.SetFlag(EmulationFlags.DebuggerWindowEnabled, true);
} }
@ -497,7 +499,8 @@ namespace Mesen.GUI.Debugger
message = ResourceHelper.GetEnumText(source); message = ResourceHelper.GetEnumText(source);
if(source == BreakSource.Breakpoint) { if(source == BreakSource.Breakpoint) {
int breakpointId = (int)(param >> 32); 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); UInt16 bpAddress = (UInt16)(param >> 16);
ReadOnlyCollection<Breakpoint> breakpoints = BreakpointManager.Breakpoints; ReadOnlyCollection<Breakpoint> breakpoints = BreakpointManager.Breakpoints;
@ -506,9 +509,7 @@ namespace Mesen.GUI.Debugger
if(bpType != BreakpointType.Global) { if(bpType != BreakpointType.Global) {
string prefix = ""; string prefix = "";
if(bpType == BreakpointType.ReadRam || bpType == BreakpointType.WriteRam) { if(bpType == BreakpointType.ReadRam || bpType == BreakpointType.WriteRam) {
InstructionProgress progress = new InstructionProgress(); if(memOpType == InteropMemoryOperationType.DummyRead || memOpType == InteropMemoryOperationType.DummyWrite) {
InteropEmu.DebugGetInstructionProgress(ref progress);
if(progress.OpMemoryOperationType == InteropMemoryOperationType.DummyRead || progress.OpMemoryOperationType == InteropMemoryOperationType.DummyWrite) {
prefix = "(Dummy) "; 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) { } else if(source == BreakSource.CpuStep || source == BreakSource.PpuStep) {
//Don't display anything when breaking due to stepping //Don't display anything when breaking due to stepping
message = null; message = null;
@ -1190,6 +1194,13 @@ namespace Mesen.GUI.Debugger
ConfigManager.ApplyChanges(); 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) private void mnuBreakOnReset_Click(object sender, EventArgs e)
{ {
ConfigManager.Config.DebugInfo.BreakOnReset = mnuBreakOnReset.Checked; ConfigManager.Config.DebugInfo.BreakOnReset = mnuBreakOnReset.Checked;

View file

@ -1322,6 +1322,8 @@ namespace Mesen.GUI
public UInt32 NmiScanline; public UInt32 NmiScanline;
public UInt32 ScanlineCount; public UInt32 ScanlineCount;
public UInt32 SafeOamScanline; public UInt32 SafeOamScanline;
public UInt16 BusAddress;
public byte MemoryReadBuffer;
} }
public struct PPUState public struct PPUState
@ -1690,6 +1692,8 @@ namespace Mesen.GUI
BreakOnDecayedOamRead = 0x2000, BreakOnDecayedOamRead = 0x2000,
BreakOnInit = 0x4000, BreakOnInit = 0x4000,
BreakOnPlay = 0x8000, BreakOnPlay = 0x8000,
BreakOnFirstCycle = 0x10000,
} }
public struct InteropRomInfo public struct InteropRomInfo