diff --git a/Core/Breakpoint.cpp b/Core/Breakpoint.cpp new file mode 100644 index 0000000..6378868 --- /dev/null +++ b/Core/Breakpoint.cpp @@ -0,0 +1,88 @@ +#include "stdafx.h" +#include "Breakpoint.h" +#include "DebugTypes.h" + +bool Breakpoint::Matches(uint32_t memoryAddr, AddressInfo &info) +{ + if(_memoryType == SnesMemoryType::CpuMemory) { + if(_startAddr == -1) { + return true; + } else if(_endAddr == -1) { + return (int32_t)memoryAddr == _startAddr; + } else { + return (int32_t)memoryAddr >= _startAddr && (int32_t)memoryAddr <= _endAddr; + } + } else if(_memoryType == info.Type) { + if(_startAddr == -1) { + return true; + } else if(_endAddr == -1) { + return info.Address == _startAddr; + } else { + return info.Address >= _startAddr && info.Address <= _endAddr; + } + } + + return false; +} + +bool Breakpoint::HasBreakpointType(BreakpointType type) +{ + switch(type) { + default: + case BreakpointType::Execute: return ((uint8_t)_type & (uint8_t)BreakpointTypeFlags::Execute) != 0; + case BreakpointType::Read: return ((uint8_t)_type & (uint8_t)BreakpointTypeFlags::Read) != 0; + case BreakpointType::Write: return ((uint8_t)_type & (uint8_t)BreakpointTypeFlags::Write) != 0; + } +} + +string Breakpoint::GetCondition() +{ + return _condition; +} + +bool Breakpoint::HasCondition() +{ + return _condition[0] != 0; +} + +uint32_t Breakpoint::GetId() +{ + return _id; +} + +BreakpointCategory Breakpoint::GetBreakpointCategory() +{ + return GetBreakpointCategory(_memoryType); +} + +BreakpointCategory Breakpoint::GetBreakpointCategory(SnesMemoryType memoryType) +{ + switch(memoryType) { + case SnesMemoryType::CpuMemory: + case SnesMemoryType::PrgRom: + case SnesMemoryType::WorkRam: + case SnesMemoryType::SaveRam: + return BreakpointCategory::Cpu; + + case SnesMemoryType::VideoRam: + return BreakpointCategory::VideoRam; + + case SnesMemoryType::SpriteRam: + return BreakpointCategory::Oam; + + case SnesMemoryType::CGRam: + return BreakpointCategory::CgRam; + + default: throw std::runtime_error("invalid memory type"); + } +} + +bool Breakpoint::IsEnabled() +{ + return _enabled; +} + +bool Breakpoint::IsMarked() +{ + return _markEvent; +} diff --git a/Core/Breakpoint.h b/Core/Breakpoint.h new file mode 100644 index 0000000..4ecb587 --- /dev/null +++ b/Core/Breakpoint.h @@ -0,0 +1,34 @@ +#pragma once +#include "stdafx.h" + +enum class SnesMemoryType; +struct AddressInfo; +enum class BreakpointType; +enum class BreakpointTypeFlags; +enum class BreakpointCategory; + +class Breakpoint +{ +public: + bool Matches(uint32_t memoryAddr, AddressInfo &info); + bool HasBreakpointType(BreakpointType type); + string GetCondition(); + bool HasCondition(); + + uint32_t GetId(); + bool IsEnabled(); + bool IsMarked(); + + BreakpointCategory GetBreakpointCategory(); + static BreakpointCategory GetBreakpointCategory(SnesMemoryType memoryType); + +private: + uint32_t _id; + SnesMemoryType _memoryType; + BreakpointTypeFlags _type; + int32_t _startAddr; + int32_t _endAddr; + bool _enabled; + bool _markEvent; + char _condition[1000]; +}; \ No newline at end of file diff --git a/Core/BreakpointManager.cpp b/Core/BreakpointManager.cpp new file mode 100644 index 0000000..0d63464 --- /dev/null +++ b/Core/BreakpointManager.cpp @@ -0,0 +1,86 @@ +#include "stdafx.h" +#include "BreakpointManager.h" +#include "DebugTypes.h" +#include "Debugger.h" +#include "Breakpoint.h" +#include "ExpressionEvaluator.h" + +BreakpointManager::BreakpointManager(Debugger *debugger) +{ + _debugger = debugger; +} + +void BreakpointManager::SetBreakpoints(Breakpoint breakpoints[], uint32_t count) +{ + for(int j = 0; j < BreakpointManager::CategoryCount; j++) { + for(int i = 0; i < BreakpointManager::BreakpointTypeCount; i++) { + _breakpoints[j][i].clear(); + _rpnList[j][i].clear(); + _hasBreakpoint[j][i] = false; + } + } + + _bpExpEval.reset(new ExpressionEvaluator(_debugger)); + for(uint32_t j = 0; j < count; j++) { + Breakpoint &bp = breakpoints[j]; + for(int i = 0; i < BreakpointManager::BreakpointTypeCount; i++) { + BreakpointType bpType = (BreakpointType)i; + bool isEnabled = bp.IsEnabled(); //TODO && _console->GetSettings()->CheckFlag(EmulationFlags::DebuggerWindowEnabled); + if((bp.IsMarked() || isEnabled) && bp.HasBreakpointType(bpType)) { + BreakpointCategory category = bp.GetBreakpointCategory(); + _breakpoints[(int)category][i].push_back(bp); + + if(bp.HasCondition()) { + bool success = true; + ExpressionData data = _bpExpEval->GetRpnList(bp.GetCondition(), success); + _rpnList[(int)category][i].push_back(success ? data : ExpressionData()); + } else { + _rpnList[(int)category][i].push_back(ExpressionData()); + } + + _hasBreakpoint[(int)category][i] = true; + } + } + } +} + +BreakpointType BreakpointManager::GetBreakpointType(MemoryOperationType type) +{ + switch(type) { + default: + case MemoryOperationType::ExecOperand: + case MemoryOperationType::ExecOpCode: + return BreakpointType::Execute; + + case MemoryOperationType::DmaRead: + case MemoryOperationType::Read: return BreakpointType::Read; + + case MemoryOperationType::DmaWrite: + case MemoryOperationType::Write: return BreakpointType::Write; + } +} + +bool BreakpointManager::CheckBreakpoint(MemoryOperationInfo operationInfo, AddressInfo &address) +{ + BreakpointCategory category = Breakpoint::GetBreakpointCategory(address.Type); + BreakpointType type = GetBreakpointType(operationInfo.Type); + + if(!_hasBreakpoint[(int)category][(int)type]) { + return false; + } + + DebugState state; + _debugger->GetState(state); + EvalResultType resultType; + vector &breakpoints = _breakpoints[(int)category][(int)type]; + for(size_t i = 0; i < breakpoints.size(); i++) { + Breakpoint bp = breakpoints[i]; + if(bp.Matches(operationInfo.Address, address)) { + if(!bp.HasCondition() || _bpExpEval->Evaluate(_rpnList[(int)category][(int)type][i], state, resultType, operationInfo)) { + return true; + } + } + } + + return false; +} diff --git a/Core/BreakpointManager.h b/Core/BreakpointManager.h new file mode 100644 index 0000000..422c098 --- /dev/null +++ b/Core/BreakpointManager.h @@ -0,0 +1,33 @@ +#pragma once +#include "stdafx.h" +#include "Breakpoint.h" + +class ExpressionEvaluator; +class Debugger; +struct MemoryOperationInfo; +struct ExpressionData; +struct AddressInfo; +enum class MemoryOperationType; + +class BreakpointManager +{ +private: + static constexpr int BreakpointTypeCount = 3; //Read, Write, Exec + static constexpr int CategoryCount = 4; //CPU, VRAM, OAM, CGRAM + + Debugger *_debugger; + + vector _breakpoints[CategoryCount][BreakpointTypeCount]; + vector _rpnList[CategoryCount][BreakpointTypeCount]; + bool _hasBreakpoint[CategoryCount][BreakpointTypeCount] = {}; + + unique_ptr _bpExpEval; + + BreakpointType GetBreakpointType(MemoryOperationType type); + +public: + BreakpointManager(Debugger *debugger); + + void SetBreakpoints(Breakpoint breakpoints[], uint32_t count); + bool CheckBreakpoint(MemoryOperationInfo operationInfo, AddressInfo &address); +}; \ No newline at end of file diff --git a/Core/Console.cpp b/Core/Console.cpp index 5becedb..942aa55 100644 --- a/Core/Console.cpp +++ b/Core/Console.cpp @@ -10,6 +10,7 @@ #include "BaseCartridge.h" #include "RamHandler.h" #include "Debugger.h" +#include "DebugTypes.h" #include "NotificationManager.h" #include "SoundMixer.h" #include "VideoDecoder.h" @@ -247,3 +248,30 @@ void Console::ProcessCpuWrite(uint32_t addr, uint8_t value, MemoryOperationType _debugger->ProcessCpuWrite(addr, value, type); } } + +void Console::ProcessPpuRead(uint32_t addr, uint8_t value, SnesMemoryType memoryType) +{ + if(_debugger) { + _debugger->ProcessPpuRead(addr, value, memoryType); + } +} + +void Console::ProcessPpuWrite(uint32_t addr, uint8_t value, SnesMemoryType memoryType) +{ + if(_debugger) { + _debugger->ProcessPpuWrite(addr, value, memoryType); + } +} + +void Console::ProcessWorkRamRead(uint32_t addr, uint8_t value) +{ + if(_debugger) { + _debugger->ProcessWorkRamRead(addr, value); + } +} +void Console::ProcessWorkRamWrite(uint32_t addr, uint8_t value) +{ + if(_debugger) { + _debugger->ProcessWorkRamWrite(addr, value); + } +} \ No newline at end of file diff --git a/Core/Console.h b/Core/Console.h index 66de507..201dd56 100644 --- a/Core/Console.h +++ b/Core/Console.h @@ -18,6 +18,7 @@ class VideoRenderer; class VideoDecoder; class NotificationManager; enum class MemoryOperationType; +enum class SnesMemoryType; class Console : public std::enable_shared_from_this { @@ -75,4 +76,8 @@ public: void ProcessCpuRead(uint32_t addr, uint8_t value, MemoryOperationType type); void ProcessCpuWrite(uint32_t addr, uint8_t value, MemoryOperationType type); + void ProcessPpuRead(uint32_t addr, uint8_t value, SnesMemoryType memoryType); + void ProcessPpuWrite(uint32_t addr, uint8_t value, SnesMemoryType memoryType); + void ProcessWorkRamRead(uint32_t addr, uint8_t value); + void ProcessWorkRamWrite(uint32_t addr, uint8_t value); }; \ No newline at end of file diff --git a/Core/Core.vcxproj b/Core/Core.vcxproj index 0381271..4aa9e7a 100644 --- a/Core/Core.vcxproj +++ b/Core/Core.vcxproj @@ -52,6 +52,8 @@ + + @@ -114,6 +116,8 @@ + + diff --git a/Core/Core.vcxproj.filters b/Core/Core.vcxproj.filters index 4979940..d3edd07 100644 --- a/Core/Core.vcxproj.filters +++ b/Core/Core.vcxproj.filters @@ -191,6 +191,12 @@ Debugger + + Debugger + + + Debugger + @@ -296,6 +302,10 @@ Debugger + + Debugger + + diff --git a/Core/CpuTypes.h b/Core/CpuTypes.h index e9b2ede..0984e18 100644 --- a/Core/CpuTypes.h +++ b/Core/CpuTypes.h @@ -92,10 +92,8 @@ enum class MemoryOperationType Write = 1, ExecOpCode = 2, ExecOperand = 3, - DummyRead = 5, - DummyWrite = 6, - DmaRead = 7, - DmaWrite = 8 + DmaRead = 4, + DmaWrite = 5 }; enum class IrqSource diff --git a/Core/DebugTypes.h b/Core/DebugTypes.h index 64b3716..7d42dc8 100644 --- a/Core/DebugTypes.h +++ b/Core/DebugTypes.h @@ -24,13 +24,53 @@ struct AddressInfo { int32_t Address; SnesMemoryType Type; + + AddressInfo() { } + + AddressInfo(int32_t address, SnesMemoryType type) + { + Address = address; + Type = type; + } }; struct MemoryOperationInfo { uint32_t Address; int32_t Value; - MemoryOperationType OperationType; + MemoryOperationType Type; + + MemoryOperationInfo() { } + + MemoryOperationInfo(uint32_t address, int32_t value, MemoryOperationType type) + { + Address = address; + Value = value; + Type = type; + } +}; + +enum class BreakpointTypeFlags +{ + None = 0, + Execute = 1, + Read = 2, + Write = 4, +}; + +enum class BreakpointType +{ + Execute = 0, + Read = 1, + Write = 2, +}; + +enum class BreakpointCategory +{ + Cpu = 0, + VideoRam = 1, + Oam = 2, + CgRam = 3 }; namespace CdlFlags diff --git a/Core/Debugger.cpp b/Core/Debugger.cpp index d90bc4e..2e3efbd 100644 --- a/Core/Debugger.cpp +++ b/Core/Debugger.cpp @@ -13,6 +13,7 @@ #include "MemoryDumper.h" #include "CodeDataLogger.h" #include "Disassembler.h" +#include "BreakpointManager.h" #include "ExpressionEvaluator.h" #include "../Utilities/HexUtilities.h" #include "../Utilities/FolderUtilities.h" @@ -29,6 +30,7 @@ Debugger::Debugger(shared_ptr console) _disassembler.reset(new Disassembler(console, _codeDataLogger)); _traceLogger.reset(new TraceLogger(this, _memoryManager)); _memoryDumper.reset(new MemoryDumper(_ppu, _memoryManager, console->GetCartridge())); + _breakpointManager.reset(new BreakpointManager(this)); _cpuStepCount = 0; string cdlFile = FolderUtilities::CombinePath(FolderUtilities::GetDebuggerFolder(), FolderUtilities::GetFilename(_console->GetCartridge()->GetRomInfo().RomPath, false) + ".cdl"); @@ -55,6 +57,7 @@ Debugger::~Debugger() void Debugger::ProcessCpuRead(uint32_t addr, uint8_t value, MemoryOperationType type) { AddressInfo addressInfo = _memoryManager->GetAbsoluteAddress(addr); + MemoryOperationInfo operation = { addr, value, type }; CpuState state = _cpu->GetState(); if(type == MemoryOperationType::ExecOpCode) { @@ -70,27 +73,20 @@ void Debugger::ProcessCpuRead(uint32_t addr, uint8_t value, MemoryOperationType } DebugState debugState; - GetState(&debugState); + GetState(debugState); DisassemblyInfo disInfo = _disassembler->GetDisassemblyInfo(addressInfo); _traceLogger->Log(debugState, disInfo); _prevOpCode = value; - if(value == 0x00 || value == 0xCB) { - //break on BRK/WAI - _cpuStepCount = 1; - } - if(_cpuStepCount > 0) { _cpuStepCount--; - if(_cpuStepCount == 0) { - _disassembler->Disassemble(); - _console->GetNotificationManager()->SendNotification(ConsoleNotificationType::CodeBreak); - while(_cpuStepCount == 0) { - std::this_thread::sleep_for(std::chrono::duration(10)); - } - } + } + + if(value == 0x00 || value == 0xCB) { + //Break on BRK/WAI + _cpuStepCount = 0; } } else if(type == MemoryOperationType::ExecOperand) { if(addressInfo.Type == SnesMemoryType::PrgRom && addressInfo.Address >= 0) { @@ -101,21 +97,71 @@ void Debugger::ProcessCpuRead(uint32_t addr, uint8_t value, MemoryOperationType _codeDataLogger->SetFlags(addressInfo.Address, CdlFlags::Data | (state.PS & (CdlFlags::IndexMode8 | CdlFlags::MemoryMode8))); } } + + ProcessBreakConditions(operation, addressInfo); } void Debugger::ProcessCpuWrite(uint32_t addr, uint8_t value, MemoryOperationType type) { AddressInfo addressInfo = _memoryManager->GetAbsoluteAddress(addr); + MemoryOperationInfo operation = { addr, value, type }; if(addressInfo.Address >= 0 && (addressInfo.Type == SnesMemoryType::WorkRam || addressInfo.Type == SnesMemoryType::SaveRam)) { _disassembler->InvalidateCache(addressInfo); } + + ProcessBreakConditions(operation, addressInfo); +} + +void Debugger::ProcessWorkRamRead(uint32_t addr, uint8_t value) +{ + AddressInfo addressInfo(addr, SnesMemoryType::WorkRam); + //TODO Make this more flexible/accurate + MemoryOperationInfo operation(0x7E0000 | addr, value, MemoryOperationType::Read); + ProcessBreakConditions(operation, addressInfo); +} + +void Debugger::ProcessWorkRamWrite(uint32_t addr, uint8_t value) +{ + AddressInfo addressInfo(addr, SnesMemoryType::WorkRam); + //TODO Make this more flexible/accurate + MemoryOperationInfo operation(0x7E0000 | addr, value, MemoryOperationType::Write); + ProcessBreakConditions(operation, addressInfo); +} + +void Debugger::ProcessPpuRead(uint16_t addr, uint8_t value, SnesMemoryType memoryType) +{ + AddressInfo addressInfo(addr, memoryType); + MemoryOperationInfo operation(addr, value, MemoryOperationType::Read); + ProcessBreakConditions(operation, addressInfo); +} + +void Debugger::ProcessPpuWrite(uint16_t addr, uint8_t value, SnesMemoryType memoryType) +{ + AddressInfo addressInfo(addr, memoryType); + MemoryOperationInfo operation(addr, value, MemoryOperationType::Write); + ProcessBreakConditions(operation, addressInfo); +} + +void Debugger::ProcessBreakConditions(MemoryOperationInfo &operation, AddressInfo &addressInfo) +{ + if(_breakpointManager->CheckBreakpoint(operation, addressInfo)) { + _cpuStepCount = 0; + } + + if(_cpuStepCount == 0) { + _disassembler->Disassemble(); + _console->GetNotificationManager()->SendNotification(ConsoleNotificationType::CodeBreak); + while(_cpuStepCount == 0) { + std::this_thread::sleep_for(std::chrono::duration(10)); + } + } } int32_t Debugger::EvaluateExpression(string expression, EvalResultType &resultType, bool useCache) { + MemoryOperationInfo operationInfo { 0, 0, MemoryOperationType::Read }; DebugState state; - MemoryOperationInfo operationInfo { 0, 0, MemoryOperationType::DummyRead }; - GetState(&state); + GetState(state); if(useCache) { return _watchExpEval->Evaluate(expression, state, resultType, operationInfo); } else { @@ -140,10 +186,10 @@ bool Debugger::IsExecutionStopped() return false; } -void Debugger::GetState(DebugState *state) +void Debugger::GetState(DebugState &state) { - state->Cpu = _cpu->GetState(); - state->Ppu = _ppu->GetState(); + state.Cpu = _cpu->GetState(); + state.Ppu = _ppu->GetState(); } shared_ptr Debugger::GetTraceLogger() @@ -160,3 +206,8 @@ shared_ptr Debugger::GetDisassembler() { return _disassembler; } + +shared_ptr Debugger::GetBreakpointManager() +{ + return _breakpointManager; +} diff --git a/Core/Debugger.h b/Core/Debugger.h index ec61bf9..4fd6f59 100644 --- a/Core/Debugger.h +++ b/Core/Debugger.h @@ -10,13 +10,18 @@ class BaseCartridge; class MemoryManager; class CodeDataLogger; +enum class SnesMemoryType; enum class MemoryOperationType; +enum class BreakpointCategory; enum class EvalResultType : int32_t; class TraceLogger; class ExpressionEvaluator; class MemoryDumper; class Disassembler; +class BreakpointManager; struct DebugState; +struct MemoryOperationInfo; +struct AddressInfo; class Debugger { @@ -31,6 +36,7 @@ private: shared_ptr _memoryDumper; shared_ptr _codeDataLogger; shared_ptr _disassembler; + shared_ptr _breakpointManager; unique_ptr _watchExpEval; @@ -44,15 +50,24 @@ public: void ProcessCpuRead(uint32_t addr, uint8_t value, MemoryOperationType type); void ProcessCpuWrite(uint32_t addr, uint8_t value, MemoryOperationType type); + void ProcessWorkRamRead(uint32_t addr, uint8_t value); + void ProcessWorkRamWrite(uint32_t addr, uint8_t value); + + void ProcessPpuRead(uint16_t addr, uint8_t value, SnesMemoryType memoryType); + void ProcessPpuWrite(uint16_t addr, uint8_t value, SnesMemoryType memoryType); + + void ProcessBreakConditions(MemoryOperationInfo &operation, AddressInfo &addressInfo); + int32_t EvaluateExpression(string expression, EvalResultType &resultType, bool useCache); void Run(); void Step(int32_t stepCount); bool IsExecutionStopped(); - void GetState(DebugState *state); + void GetState(DebugState &state); shared_ptr GetTraceLogger(); shared_ptr GetMemoryDumper(); shared_ptr GetDisassembler(); + shared_ptr GetBreakpointManager(); }; \ No newline at end of file diff --git a/Core/ExpressionEvaluator.cpp b/Core/ExpressionEvaluator.cpp index 8b12fe7..5f8d9f4 100644 --- a/Core/ExpressionEvaluator.cpp +++ b/Core/ExpressionEvaluator.cpp @@ -553,7 +553,7 @@ void ExpressionEvaluator::RunTests() //Some basic unit tests to run in debug mode auto test = [=](string expr, EvalResultType expectedType, int expectedResult) { DebugState state = { 0 }; - OperationInfo opInfo = { 0 }; + MemoryOperationInfo opInfo(0, 0, MemoryOperationType::Read); EvalResultType type; int32_t result = Evaluate(expr, state, type, opInfo); diff --git a/Core/MemoryManager.cpp b/Core/MemoryManager.cpp index 44b8238..4b6423c 100644 --- a/Core/MemoryManager.cpp +++ b/Core/MemoryManager.cpp @@ -29,6 +29,7 @@ void MemoryManager::Initialize(shared_ptr console) )); _registerHandlerB.reset(new RegisterHandlerB( + _console.get(), _ppu.get(), console->GetSpc().get(), _workRam diff --git a/Core/Ppu.cpp b/Core/Ppu.cpp index 0846a18..a007c5d 100644 --- a/Core/Ppu.cpp +++ b/Core/Ppu.cpp @@ -1065,8 +1065,10 @@ uint8_t Ppu::Read(uint16_t addr) uint8_t value; if(_internalOamAddress < 512) { value = _oamRam[_internalOamAddress]; + _console->ProcessPpuRead(_internalOamAddress, value, SnesMemoryType::SpriteRam); } else { value = _oamRam[0x200 | (_internalOamAddress & 0x1F)]; + _console->ProcessPpuRead(0x200 | (_internalOamAddress & 0x1F), value, SnesMemoryType::SpriteRam); } _internalOamAddress = (_internalOamAddress + 1) & 0x3FF; return value; @@ -1075,6 +1077,7 @@ uint8_t Ppu::Read(uint16_t addr) case 0x2139: { //VMDATALREAD - VRAM Data Read low byte uint8_t returnValue = (uint8_t)_vramReadBuffer; + _console->ProcessPpuRead(_vramAddress, returnValue, SnesMemoryType::VideoRam); if(!_vramAddrIncrementOnSecondReg) { UpdateVramReadBuffer(); _vramAddress = (_vramAddress + _vramIncrementValue) & 0x7FFF; @@ -1085,6 +1088,7 @@ uint8_t Ppu::Read(uint16_t addr) case 0x213A: { //VMDATAHREAD - VRAM Data Read high byte uint8_t returnValue = (uint8_t)(_vramReadBuffer >> 8); + _console->ProcessPpuRead(_vramAddress + 1, returnValue, SnesMemoryType::VideoRam); if(_vramAddrIncrementOnSecondReg) { UpdateVramReadBuffer(); _vramAddress = (_vramAddress + _vramIncrementValue) & 0x7FFF; @@ -1095,6 +1099,7 @@ uint8_t Ppu::Read(uint16_t addr) case 0x213B: { //CGDATAREAD - CGRAM Data read uint8_t value = _cgram[_cgramAddress]; + _console->ProcessPpuRead(_cgramAddress, value, SnesMemoryType::CGRam); _cgramAddress = (_cgramAddress + 1) & (Ppu::CgRamSize - 1); return value; } @@ -1195,7 +1200,10 @@ void Ppu::Write(uint32_t addr, uint8_t value) case 0x2104: if(_internalOamAddress < 512) { if(_internalOamAddress & 0x01) { + _console->ProcessPpuWrite(_internalOamAddress - 1, _oamWriteBuffer, SnesMemoryType::SpriteRam); _oamRam[_internalOamAddress - 1] = _oamWriteBuffer; + + _console->ProcessPpuWrite(_internalOamAddress, value, SnesMemoryType::SpriteRam); _oamRam[_internalOamAddress] = value; } else { _oamWriteBuffer = value; @@ -1205,6 +1213,7 @@ void Ppu::Write(uint32_t addr, uint8_t value) if((_internalOamAddress & 0x01) == 0) { _oamWriteBuffer = value; } + _console->ProcessPpuWrite(address, value, SnesMemoryType::SpriteRam); _oamRam[address] = value; } _internalOamAddress = (_internalOamAddress + 1) & 0x3FF; @@ -1303,6 +1312,8 @@ void Ppu::Write(uint32_t addr, uint8_t value) case 0x2118: //VMDATAL - VRAM Data Write low byte + _console->ProcessPpuWrite(_vramAddress << 1, value, SnesMemoryType::VideoRam); + _vram[_vramAddress << 1] = value; if(!_vramAddrIncrementOnSecondReg) { _vramAddress = (_vramAddress + _vramIncrementValue) & 0x7FFF; @@ -1311,6 +1322,8 @@ void Ppu::Write(uint32_t addr, uint8_t value) case 0x2119: //VMDATAH - VRAM Data Write high byte + _console->ProcessPpuWrite((_vramAddress << 1) + 1, value, SnesMemoryType::VideoRam); + _vram[(_vramAddress << 1) + 1] = value; if(_vramAddrIncrementOnSecondReg) { _vramAddress = (_vramAddress + _vramIncrementValue) & 0x7FFF; @@ -1350,6 +1363,8 @@ void Ppu::Write(uint32_t addr, uint8_t value) case 0x2122: //CGRAM Data write (CGDATA) + _console->ProcessPpuWrite(_cgramAddress, value, SnesMemoryType::CGRam); + _cgram[_cgramAddress] = value; _cgramAddress = (_cgramAddress + 1) & (Ppu::CgRamSize - 1); break; diff --git a/Core/RegisterHandlerB.h b/Core/RegisterHandlerB.h index bd61001..383699d 100644 --- a/Core/RegisterHandlerB.h +++ b/Core/RegisterHandlerB.h @@ -1,20 +1,23 @@ #pragma once #include "stdafx.h" #include "IMemoryHandler.h" +#include "Console.h" #include "Ppu.h" #include "Spc.h" class RegisterHandlerB : public IMemoryHandler { private: - Ppu * _ppu; + Console *_console; + Ppu *_ppu; Spc *_spc; uint8_t *_workRam; uint32_t _wramPosition; public: - RegisterHandlerB(Ppu *ppu, Spc *spc, uint8_t *workRam) + RegisterHandlerB(Console *console, Ppu *ppu, Spc *spc, uint8_t *workRam) { + _console = console; _ppu = ppu; _spc = spc; _workRam = workRam; @@ -28,6 +31,7 @@ public: return _spc->Read(addr & 0x03); } else if(addr == 0x2180) { uint8_t value = _workRam[_wramPosition]; + _console->ProcessWorkRamRead(_wramPosition, value); _wramPosition = (_wramPosition + 1) & 0x1FFFF; return value; } else { @@ -49,8 +53,9 @@ public: } if(addr >= 0x2180 && addr <= 0x2183) { switch(addr & 0xFFFF) { case 0x2180: + _console->ProcessWorkRamWrite(_wramPosition, value); _workRam[_wramPosition] = value; - _wramPosition = (_wramPosition + 1) & (0x1FFFF); + _wramPosition = (_wramPosition + 1) & 0x1FFFF; break; case 0x2181: _wramPosition = (_wramPosition & 0x1FF00) | value; break; diff --git a/InteropDLL/DebugApiWrapper.cpp b/InteropDLL/DebugApiWrapper.cpp index 9787826..288e991 100644 --- a/InteropDLL/DebugApiWrapper.cpp +++ b/InteropDLL/DebugApiWrapper.cpp @@ -5,6 +5,8 @@ #include "../Core/MemoryDumper.h" #include "../Core/Disassembler.h" #include "../Core/DebugTypes.h" +#include "../Core/Breakpoint.h" +#include "../Core/BreakpointManager.h" extern shared_ptr _console; @@ -33,7 +35,7 @@ extern "C" } DllExport bool __stdcall IsExecutionStopped() { return GetDebugger()->IsExecutionStopped(); } - DllExport void __stdcall ResumeExecution() { GetDebugger()->Run(); } + DllExport void __stdcall ResumeExecution() { if(IsDebuggerRunning()) GetDebugger()->Run(); } DllExport void __stdcall Step(uint32_t count) { GetDebugger()->Step(count); } DllExport void __stdcall GetDisassemblyLineData(uint32_t lineIndex, CodeLineData &data) { GetDebugger()->GetDisassembler()->GetLineData(lineIndex, data); } @@ -46,9 +48,10 @@ extern "C" DllExport void __stdcall StopTraceLogger() { GetDebugger()->GetTraceLogger()->StopLogging(); } DllExport const char* GetExecutionTrace(uint32_t lineCount) { return GetDebugger()->GetTraceLogger()->GetExecutionTrace(lineCount); } + DllExport void __stdcall SetBreakpoints(Breakpoint breakpoints[], uint32_t length) { GetDebugger()->GetBreakpointManager()->SetBreakpoints(breakpoints, length); } DllExport int32_t __stdcall EvaluateExpression(char* expression, EvalResultType *resultType, bool useCache) { return GetDebugger()->EvaluateExpression(expression, *resultType, useCache); } - DllExport void __stdcall GetState(DebugState *state) { GetDebugger()->GetState(state); } + DllExport void __stdcall GetState(DebugState &state) { GetDebugger()->GetState(state); } DllExport void __stdcall SetMemoryState(SnesMemoryType type, uint8_t *buffer, int32_t length) { GetDebugger()->GetMemoryDumper()->SetMemoryState(type, buffer, length); } DllExport uint32_t __stdcall GetMemorySize(SnesMemoryType type) { return GetDebugger()->GetMemoryDumper()->GetMemorySize(type); } diff --git a/UI/Debugger/Breakpoints/Breakpoint.cs b/UI/Debugger/Breakpoints/Breakpoint.cs new file mode 100644 index 0000000..aee6464 --- /dev/null +++ b/UI/Debugger/Breakpoints/Breakpoint.cs @@ -0,0 +1,221 @@ +using System; +using System.Text; + +namespace Mesen.GUI.Debugger +{ + public class Breakpoint + { + private SnesMemoryType _memoryType = SnesMemoryType.CpuMemory; + private bool _isCpuBreakpoint = true; + + public bool BreakOnRead = false; + public bool BreakOnWrite = false; + public bool BreakOnExec = true; + + public bool Enabled = true; + public bool MarkEvent = false; + public UInt32 Address = UInt32.MaxValue; + public UInt32 StartAddress; + public UInt32 EndAddress; + public BreakpointAddressType AddressType = BreakpointAddressType.SingleAddress; + public string Condition = ""; + + public SnesMemoryType MemoryType + { + get { return _memoryType; } + set + { + _memoryType = value; + _isCpuBreakpoint = IsTypeCpuBreakpoint(value); + } + } + + public string GetAddressString(bool showLabel) + { + string addr = ""; + switch(AddressType) { + case BreakpointAddressType.AnyAddress: + return ""; + case BreakpointAddressType.SingleAddress: + if(IsAbsoluteAddress) { + addr += $"[${Address.ToString("X6")}]"; + } else { + addr = $"${Address.ToString("X6")}"; + } + break; + + case BreakpointAddressType.AddressRange: + if(IsAbsoluteAddress) { + addr = $"[${StartAddress.ToString("X6")}] - [${EndAddress.ToString("X6")}]"; + } else { + addr = $"${StartAddress.ToString("X6")} - ${EndAddress.ToString("X6")}"; + } + break; + } + + //TODO LABELS + /*string label = GetAddressLabel(); + if(showLabel && !string.IsNullOrWhiteSpace(label)) { + addr = label + $", {addr}"; + }*/ + return addr; + } + + public static bool IsTypeCpuBreakpoint(SnesMemoryType type) + { + return ( + type == SnesMemoryType.CpuMemory || + type == SnesMemoryType.WorkRam || + type == SnesMemoryType.SaveRam || + type == SnesMemoryType.PrgRom + ); + } + + public void SetEnabled(bool enabled) + { + Enabled = enabled; + BreakpointManager.RefreshBreakpoints(this); + } + + public void SetMarked(bool marked) + { + MarkEvent = marked; + BreakpointManager.RefreshBreakpoints(this); + } + + public bool IsAbsoluteAddress { get { return MemoryType != SnesMemoryType.CpuMemory; } } + public bool IsCpuBreakpoint { get { return this._isCpuBreakpoint; } } + + private BreakpointTypeFlags Type + { + get + { + BreakpointTypeFlags type = BreakpointTypeFlags.None; + if(BreakOnRead) { + type |= BreakpointTypeFlags.Read; + } + if(BreakOnWrite) { + type |= BreakpointTypeFlags.Write; + } + if(BreakOnExec && IsCpuBreakpoint) { + type |= BreakpointTypeFlags.Execute; + } + return type; + } + } + + public string ToReadableType() + { + string type; + + switch(MemoryType) { + default: throw new Exception("invalid type"); + case SnesMemoryType.CpuMemory: type = "CPU"; break; + case SnesMemoryType.PrgRom: type = "PRG"; break; + case SnesMemoryType.WorkRam: type = "WRAM"; break; + case SnesMemoryType.SaveRam: type = "SRAM"; break; + case SnesMemoryType.VideoRam: type = "VRAM"; break; + case SnesMemoryType.SpriteRam: type = "OAM"; break; + case SnesMemoryType.CGRam: type = "CG"; break; + } + + type += ":"; + type += BreakOnRead ? "R" : "‒"; + type += BreakOnWrite ? "W" : "‒"; + if(IsCpuBreakpoint) { + type += BreakOnExec ? "X" : "‒"; + } + return type; + } + + public int GetRelativeAddress() + { + UInt32 address = AddressType == BreakpointAddressType.SingleAddress ? this.Address : this.StartAddress; + if(IsCpuBreakpoint && this.IsAbsoluteAddress) { + //TODO + //return InteropEmu.DebugGetRelativeAddress(address, this.MemoryType.ToAddressType()); + return -1; + } else { + return (int)address; + } + } + + private int GetRelativeAddressEnd() + { + if(this.AddressType == BreakpointAddressType.AddressRange){ + if(IsCpuBreakpoint && this.IsAbsoluteAddress) { + //TODO + //return InteropEmu.DebugGetRelativeAddress(this.EndAddress, this.MemoryType.ToAddressType()); + } else { + return (int)this.EndAddress; + } + } + return -1; + } + + public bool Matches(UInt32 address, SnesMemoryType type) + { + if(IsTypeCpuBreakpoint(type) != this.IsCpuBreakpoint) { + return false; + } + + bool isRelativeMemory = type == SnesMemoryType.CpuMemory; + + if(this.AddressType == BreakpointAddressType.SingleAddress) { + return address == this.Address && type == this.MemoryType; + } else if(this.AddressType == BreakpointAddressType.AddressRange) { + return address >= this.StartAddress && address <= this.EndAddress && type == this.MemoryType; + } + + return false; + } + + public InteropBreakpoint ToInteropBreakpoint(int breakpointId) + { + InteropBreakpoint bp = new InteropBreakpoint() { + Id = breakpointId, + MemoryType = MemoryType, + Type = Type, + MarkEvent = MarkEvent, + Enabled = Enabled + }; + switch(AddressType) { + case BreakpointAddressType.AnyAddress: + bp.StartAddress = -1; + bp.EndAddress = -1; + break; + + case BreakpointAddressType.SingleAddress: + bp.StartAddress = (Int32)Address; + bp.EndAddress = -1; + break; + + case BreakpointAddressType.AddressRange: + bp.StartAddress = (Int32)StartAddress; + bp.EndAddress = (Int32)EndAddress; + break; + } + + bp.Condition = new byte[1000]; + byte[] condition = Encoding.UTF8.GetBytes(Condition.Replace(Environment.NewLine, " ")); + Array.Copy(condition, bp.Condition, condition.Length); + return bp; + } + } + + public enum BreakpointAddressType + { + AnyAddress, + SingleAddress, + AddressRange, + } + + [Flags] + public enum BreakpointTypeFlags + { + None = 0, + Execute = 1, + Read = 2, + Write = 4, + } +} \ No newline at end of file diff --git a/UI/Debugger/Breakpoints/BreakpointManager.cs b/UI/Debugger/Breakpoints/BreakpointManager.cs new file mode 100644 index 0000000..d796e56 --- /dev/null +++ b/UI/Debugger/Breakpoints/BreakpointManager.cs @@ -0,0 +1,114 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Linq; +using System.Windows.Forms; + +namespace Mesen.GUI.Debugger +{ + public class BreakpointManager + { + public static event EventHandler BreakpointsChanged; + + private static List _breakpoints = new List(); + + public static ReadOnlyCollection Breakpoints + { + get { return _breakpoints.ToList().AsReadOnly(); } + } + + public static void RefreshBreakpoints(Breakpoint bp = null) + { + if(BreakpointsChanged != null) { + BreakpointsChanged(bp, null); + } + + SetBreakpoints(); + } + + public static void SetBreakpoints(List breakpoints) + { + _breakpoints = breakpoints.ToList(); + RefreshBreakpoints(); + } + + public static void EditBreakpoint(Breakpoint bp) + { + if(new frmBreakpoint(bp).ShowDialog() == DialogResult.OK) { + if(!_breakpoints.Contains(bp)) { + _breakpoints.Add(bp); + } + RefreshBreakpoints(bp); + } + } + + public static void RemoveBreakpoint(Breakpoint bp) + { + _breakpoints.Remove(bp); + RefreshBreakpoints(bp); + } + + public static void AddBreakpoint(Breakpoint bp) + { + _breakpoints.Add(bp); + RefreshBreakpoints(bp); + } + + public static Breakpoint GetMatchingBreakpoint(AddressInfo info) + { + return Breakpoints.Where((bp) => bp.Matches((UInt32)info.Address, info.Type)).FirstOrDefault(); + } + + public static Breakpoint GetMatchingBreakpoint(UInt32 startAddress, UInt32 endAddress, SnesMemoryType memoryType) + { + bool isAddressRange = startAddress != endAddress; + return Breakpoints.Where((bp) => + bp.MemoryType == memoryType && + ((!isAddressRange && bp.Address == startAddress) || (isAddressRange && bp.StartAddress == startAddress && bp.EndAddress == endAddress)) + ).FirstOrDefault(); + } + + public static void EnableDisableBreakpoint(AddressInfo info) + { + Breakpoint breakpoint = BreakpointManager.GetMatchingBreakpoint(info); + if(breakpoint != null) { + breakpoint.SetEnabled(!breakpoint.Enabled); + } + } + + public static void ToggleBreakpoint(AddressInfo info) + { + if(info.Address < 0) { + return; + } + + Breakpoint breakpoint = BreakpointManager.GetMatchingBreakpoint(info); + if(breakpoint != null) { + BreakpointManager.RemoveBreakpoint(breakpoint); + } else { + breakpoint = new Breakpoint() { + Enabled = true, + BreakOnExec = true, + Address = (UInt32)info.Address + }; + + if(info.Type != SnesMemoryType.PrgRom) { + breakpoint.BreakOnRead = true; + breakpoint.BreakOnWrite = true; + } + + breakpoint.MemoryType = info.Type; + BreakpointManager.AddBreakpoint(breakpoint); + } + } + + public static void SetBreakpoints() + { + List breakpoints = new List(); + for(int i = 0; i < Breakpoints.Count; i++) { + breakpoints.Add(Breakpoints[i].ToInteropBreakpoint(i)); + } + DebugApi.SetBreakpoints(breakpoints.ToArray(), (UInt32)breakpoints.Count); + } + } +} diff --git a/UI/Debugger/Breakpoints/InteropBreakpoint.cs b/UI/Debugger/Breakpoints/InteropBreakpoint.cs new file mode 100644 index 0000000..c9b54ae --- /dev/null +++ b/UI/Debugger/Breakpoints/InteropBreakpoint.cs @@ -0,0 +1,23 @@ +using System; +using System.Runtime.InteropServices; + +namespace Mesen.GUI.Debugger +{ + public struct InteropBreakpoint + { + public Int32 Id; + public SnesMemoryType MemoryType; + public BreakpointTypeFlags Type; + public Int32 StartAddress; + public Int32 EndAddress; + + [MarshalAs(UnmanagedType.I1)] + public bool Enabled; + + [MarshalAs(UnmanagedType.I1)] + public bool MarkEvent; + + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 1000)] + public byte[] Condition; + } +} diff --git a/UI/Debugger/Breakpoints/ctrlBreakpoints.cs b/UI/Debugger/Breakpoints/ctrlBreakpoints.cs new file mode 100644 index 0000000..05bd65e --- /dev/null +++ b/UI/Debugger/Breakpoints/ctrlBreakpoints.cs @@ -0,0 +1,176 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Drawing; +using System.Data; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; +using Mesen.GUI.Controls; +using System.Collections.ObjectModel; +using Mesen.GUI.Config; + +namespace Mesen.GUI.Debugger.Controls +{ + public partial class ctrlBreakpoints : BaseControl + { + public event EventHandler BreakpointNavigation; + private Font _markedColumnFont; + + public ctrlBreakpoints() + { + InitializeComponent(); + } + + protected override void OnLoad(EventArgs e) + { + base.OnLoad(e); + if(!IsDesignMode) { + _markedColumnFont = new Font(this.Font.FontFamily, 13f); + + //TODO Labels + //mnuShowLabels.Checked = ConfigManager.Config.Debug.ShowBreakpointLabels; + mnuShowLabels.CheckedChanged += mnuShowLabels_CheckedChanged; + + BreakpointManager.BreakpointsChanged += BreakpointManager_OnBreakpointChanged; + mnuRemoveBreakpoint.Enabled = false; + mnuEditBreakpoint.Enabled = false; + mnuGoToLocation.Enabled = false; + + InitShortcuts(); + } + } + + private void InitShortcuts() + { + mnuAddBreakpoint.InitShortcut(this, nameof(DebuggerShortcutsConfig.BreakpointList_Add)); + mnuEditBreakpoint.InitShortcut(this, nameof(DebuggerShortcutsConfig.BreakpointList_Edit)); + mnuRemoveBreakpoint.InitShortcut(this, nameof(DebuggerShortcutsConfig.BreakpointList_Delete)); + mnuGoToLocation.InitShortcut(this, nameof(DebuggerShortcutsConfig.BreakpointList_GoToLocation)); + } + + private void BreakpointManager_OnBreakpointChanged(object sender, EventArgs e) + { + RefreshList(); + } + + public void RefreshListAddresses() + { + lstBreakpoints.BeginUpdate(); + ReadOnlyCollection breakpoints = BreakpointManager.Breakpoints; + for(int i = 0; i < breakpoints.Count; i++) { + lstBreakpoints.Items[i].SubItems[3].Text = breakpoints[i].GetAddressString(mnuShowLabels.Checked); + } + lstBreakpoints.EndUpdate(); + } + + public void RefreshList() + { + lstBreakpoints.ItemChecked -= new ItemCheckedEventHandler(lstBreakpoints_ItemChecked); + + int topIndex = lstBreakpoints.TopItem != null ? lstBreakpoints.TopItem.Index : 0; + lstBreakpoints.BeginUpdate(); + lstBreakpoints.Items.Clear(); + foreach(Breakpoint breakpoint in BreakpointManager.Breakpoints) { + ListViewItem item = new ListViewItem(); + item.Tag = breakpoint; + item.Checked = breakpoint.Enabled; + item.UseItemStyleForSubItems = false; + item.SubItems.Add(breakpoint.MarkEvent ? "☑" : "☐").Font = _markedColumnFont; + item.SubItems.Add(breakpoint.ToReadableType()); + item.SubItems.Add(breakpoint.GetAddressString(mnuShowLabels.Checked)); + item.SubItems.Add(breakpoint.Condition); + lstBreakpoints.Items.Add(item); + } + lstBreakpoints.EndUpdate(); + if(lstBreakpoints.Items.Count > 0) { + lstBreakpoints.TopItem = lstBreakpoints.Items[lstBreakpoints.Items.Count > topIndex ? topIndex : lstBreakpoints.Items.Count - 1]; + } + + lstBreakpoints.ItemChecked += new ItemCheckedEventHandler(lstBreakpoints_ItemChecked); + } + + private void lstBreakpoints_ItemChecked(object sender, ItemCheckedEventArgs e) + { + if(((Breakpoint)e.Item.Tag).Enabled != e.Item.Checked) { + ((Breakpoint)e.Item.Tag).SetEnabled(e.Item.Checked); + } + } + + private void lstBreakpoints_DoubleClick(object sender, EventArgs e) + { + if(lstBreakpoints.SelectedItems.Count > 0) { + BreakpointManager.EditBreakpoint(((Breakpoint)lstBreakpoints.SelectedItems[0].Tag)); + } + } + + private void mnuRemoveBreakpoint_Click(object sender, EventArgs e) + { + foreach(ListViewItem item in lstBreakpoints.SelectedItems) { + BreakpointManager.RemoveBreakpoint((Breakpoint)item.Tag); + } + } + + private void mnuAddBreakpoint_Click(object sender, EventArgs e) + { + Breakpoint breakpoint = new Breakpoint(); + if(new frmBreakpoint(breakpoint).ShowDialog() == DialogResult.OK) { + BreakpointManager.AddBreakpoint(breakpoint); + } + } + + private void mnuGoToLocation_Click(object sender, EventArgs e) + { + if(BreakpointNavigation != null) { + Breakpoint bp = lstBreakpoints.SelectedItems[0].Tag as Breakpoint; + if(bp.IsCpuBreakpoint && bp.GetRelativeAddress() >= 0) { + BreakpointNavigation(bp, null); + } + } + } + + private void mnuEditBreakpoint_Click(object sender, EventArgs e) + { + if(lstBreakpoints.SelectedItems.Count > 0) { + BreakpointManager.EditBreakpoint(((Breakpoint)lstBreakpoints.SelectedItems[0].Tag)); + } + } + + private void lstBreakpoints_SelectedIndexChanged(object sender, EventArgs e) + { + mnuRemoveBreakpoint.Enabled = (lstBreakpoints.SelectedItems.Count > 0); + mnuEditBreakpoint.Enabled = (lstBreakpoints.SelectedItems.Count == 1); + if(lstBreakpoints.SelectedItems.Count == 1) { + Breakpoint bp = lstBreakpoints.SelectedItems[0].Tag as Breakpoint; + mnuGoToLocation.Enabled = bp.IsCpuBreakpoint && bp.GetRelativeAddress() >= 0; + } + + } + + private void mnuShowLabels_CheckedChanged(object sender, EventArgs e) + { + //TODO + /*ConfigManager.Config.Debug.ShowBreakpointLabels = mnuShowLabels.Checked; + ConfigManager.ApplyChanges(); + */ + this.RefreshListAddresses(); + } + + private void lstBreakpoints_MouseDown(object sender, MouseEventArgs e) + { + ListViewHitTestInfo info = lstBreakpoints.HitTest(e.X, e.Y); + if(info != null && info.Item != null) { + int row = info.Item.Index; + int col = info.Item.SubItems.IndexOf(info.SubItem); + + if(col == 1 && row < lstBreakpoints.Items.Count) { + this.BeginInvoke((Action)(() => { + Breakpoint bp = lstBreakpoints.Items[row].Tag as Breakpoint; + bp?.SetMarked(!bp.MarkEvent); + })); + } + } + } + } +} diff --git a/UI/Debugger/Breakpoints/ctrlBreakpoints.designer.cs b/UI/Debugger/Breakpoints/ctrlBreakpoints.designer.cs new file mode 100644 index 0000000..9981846 --- /dev/null +++ b/UI/Debugger/Breakpoints/ctrlBreakpoints.designer.cs @@ -0,0 +1,188 @@ +namespace Mesen.GUI.Debugger.Controls +{ + partial class ctrlBreakpoints + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if(disposing && (components != null)) { + components.Dispose(); + } + BreakpointManager.BreakpointsChanged -= BreakpointManager_OnBreakpointChanged; + base.Dispose(disposing); + } + + #region Component Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.components = new System.ComponentModel.Container(); + this.mnuBreakpoints = new System.Windows.Forms.ContextMenuStrip(this.components); + this.mnuAddBreakpoint = new System.Windows.Forms.ToolStripMenuItem(); + this.mnuEditBreakpoint = new System.Windows.Forms.ToolStripMenuItem(); + this.mnuRemoveBreakpoint = new System.Windows.Forms.ToolStripMenuItem(); + this.toolStripMenuItem1 = new System.Windows.Forms.ToolStripSeparator(); + this.mnuGoToLocation = new System.Windows.Forms.ToolStripMenuItem(); + this.toolStripMenuItem2 = new System.Windows.Forms.ToolStripSeparator(); + this.mnuShowLabels = new System.Windows.Forms.ToolStripMenuItem(); + this.lstBreakpoints = new Mesen.GUI.Controls.MyListView(); + this.colEnabled = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.colMarker = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.colType = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.colAddress = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.colCondition = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.mnuBreakpoints.SuspendLayout(); + this.SuspendLayout(); + // + // mnuBreakpoints + // + this.mnuBreakpoints.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.mnuAddBreakpoint, + this.mnuEditBreakpoint, + this.mnuRemoveBreakpoint, + this.toolStripMenuItem1, + this.mnuGoToLocation, + this.toolStripMenuItem2, + this.mnuShowLabels}); + this.mnuBreakpoints.Name = "mnuBreakpoints"; + this.mnuBreakpoints.Size = new System.Drawing.Size(150, 126); + // + // mnuAddBreakpoint + // + this.mnuAddBreakpoint.Image = global::Mesen.GUI.Properties.Resources.Add; + this.mnuAddBreakpoint.Name = "mnuAddBreakpoint"; + this.mnuAddBreakpoint.Size = new System.Drawing.Size(149, 22); + this.mnuAddBreakpoint.Text = "Add..."; + this.mnuAddBreakpoint.Click += new System.EventHandler(this.mnuAddBreakpoint_Click); + // + // mnuEditBreakpoint + // + this.mnuEditBreakpoint.Image = global::Mesen.GUI.Properties.Resources.Edit; + this.mnuEditBreakpoint.Name = "mnuEditBreakpoint"; + this.mnuEditBreakpoint.Size = new System.Drawing.Size(149, 22); + this.mnuEditBreakpoint.Text = "Edit"; + this.mnuEditBreakpoint.Click += new System.EventHandler(this.mnuEditBreakpoint_Click); + // + // mnuRemoveBreakpoint + // + this.mnuRemoveBreakpoint.Image = global::Mesen.GUI.Properties.Resources.Close; + this.mnuRemoveBreakpoint.Name = "mnuRemoveBreakpoint"; + this.mnuRemoveBreakpoint.Size = new System.Drawing.Size(149, 22); + this.mnuRemoveBreakpoint.Text = "Remove"; + this.mnuRemoveBreakpoint.Click += new System.EventHandler(this.mnuRemoveBreakpoint_Click); + // + // toolStripMenuItem1 + // + this.toolStripMenuItem1.Name = "toolStripMenuItem1"; + this.toolStripMenuItem1.Size = new System.Drawing.Size(146, 6); + // + // mnuGoToLocation + // + this.mnuGoToLocation.Name = "mnuGoToLocation"; + this.mnuGoToLocation.Size = new System.Drawing.Size(149, 22); + this.mnuGoToLocation.Text = "Go to location"; + this.mnuGoToLocation.Click += new System.EventHandler(this.mnuGoToLocation_Click); + // + // toolStripMenuItem2 + // + this.toolStripMenuItem2.Name = "toolStripMenuItem2"; + this.toolStripMenuItem2.Size = new System.Drawing.Size(146, 6); + // + // mnuShowLabels + // + this.mnuShowLabels.CheckOnClick = true; + this.mnuShowLabels.Name = "mnuShowLabels"; + this.mnuShowLabels.Size = new System.Drawing.Size(149, 22); + this.mnuShowLabels.Text = "Show Labels"; + // + // lstBreakpoints + // + this.lstBreakpoints.CheckBoxes = true; + this.lstBreakpoints.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] { + this.colEnabled, + this.colMarker, + this.colType, + this.colAddress, + this.colCondition}); + this.lstBreakpoints.ContextMenuStrip = this.mnuBreakpoints; + this.lstBreakpoints.Dock = System.Windows.Forms.DockStyle.Fill; + this.lstBreakpoints.FullRowSelect = true; + this.lstBreakpoints.GridLines = true; + this.lstBreakpoints.HeaderStyle = System.Windows.Forms.ColumnHeaderStyle.Nonclickable; + this.lstBreakpoints.Location = new System.Drawing.Point(0, 0); + this.lstBreakpoints.Name = "lstBreakpoints"; + this.lstBreakpoints.Size = new System.Drawing.Size(393, 101); + this.lstBreakpoints.TabIndex = 7; + this.lstBreakpoints.UseCompatibleStateImageBehavior = false; + this.lstBreakpoints.View = System.Windows.Forms.View.Details; + this.lstBreakpoints.SelectedIndexChanged += new System.EventHandler(this.lstBreakpoints_SelectedIndexChanged); + this.lstBreakpoints.DoubleClick += new System.EventHandler(this.lstBreakpoints_DoubleClick); + this.lstBreakpoints.MouseDown += new System.Windows.Forms.MouseEventHandler(this.lstBreakpoints_MouseDown); + // + // colEnabled + // + this.colEnabled.Text = ""; + this.colEnabled.Width = 21; + // + // colMarker + // + this.colMarker.Text = "M"; + this.colMarker.Width = 25; + // + // colType + // + this.colType.Text = "Type"; + this.colType.Width = 87; + // + // colAddress + // + this.colAddress.Text = "Address"; + this.colAddress.Width = 108; + // + // colCondition + // + this.colCondition.Text = "Condition"; + this.colCondition.Width = 142; + // + // ctrlBreakpoints + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.Controls.Add(this.lstBreakpoints); + this.Name = "ctrlBreakpoints"; + this.Size = new System.Drawing.Size(393, 101); + this.mnuBreakpoints.ResumeLayout(false); + this.ResumeLayout(false); + + } + + #endregion + + private Mesen.GUI.Controls.MyListView lstBreakpoints; + private System.Windows.Forms.ColumnHeader colType; + private System.Windows.Forms.ColumnHeader colAddress; + private System.Windows.Forms.ContextMenuStrip mnuBreakpoints; + private System.Windows.Forms.ToolStripMenuItem mnuAddBreakpoint; + private System.Windows.Forms.ToolStripMenuItem mnuRemoveBreakpoint; + private System.Windows.Forms.ColumnHeader colEnabled; + private System.Windows.Forms.ColumnHeader colCondition; + private System.Windows.Forms.ToolStripMenuItem mnuGoToLocation; + private System.Windows.Forms.ToolStripMenuItem mnuEditBreakpoint; + private System.Windows.Forms.ToolStripSeparator toolStripMenuItem1; + private System.Windows.Forms.ToolStripSeparator toolStripMenuItem2; + private System.Windows.Forms.ToolStripMenuItem mnuShowLabels; + private System.Windows.Forms.ColumnHeader colMarker; + } +} diff --git a/UI/Debugger/Breakpoints/ctrlBreakpoints.resx b/UI/Debugger/Breakpoints/ctrlBreakpoints.resx new file mode 100644 index 0000000..791e1ae --- /dev/null +++ b/UI/Debugger/Breakpoints/ctrlBreakpoints.resx @@ -0,0 +1,123 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 17, 17 + + \ No newline at end of file diff --git a/UI/Debugger/Breakpoints/frmBreakpoint.cs b/UI/Debugger/Breakpoints/frmBreakpoint.cs new file mode 100644 index 0000000..b10e746 --- /dev/null +++ b/UI/Debugger/Breakpoints/frmBreakpoint.cs @@ -0,0 +1,219 @@ +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Globalization; +using System.Windows.Forms; +using Mesen.GUI.Forms; + +namespace Mesen.GUI.Debugger +{ + public partial class frmBreakpoint : BaseConfigForm + { + public frmBreakpoint(Breakpoint breakpoint) + { + InitializeComponent(); + + Entity = breakpoint; + + switch(breakpoint.AddressType) { + case BreakpointAddressType.AnyAddress: radAnyAddress.Checked = true; break; + case BreakpointAddressType.SingleAddress: radSpecificAddress.Checked = true; break; + case BreakpointAddressType.AddressRange: radRange.Checked = true; break; + } + + AddBinding("MemoryType", cboBreakpointType); + AddBinding("Enabled", chkEnabled); + AddBinding("MarkEvent", chkMarkOnEventViewer); + AddBinding("Address", txtAddress); + AddBinding("StartAddress", txtFrom); + AddBinding("EndAddress", txtTo); + AddBinding("BreakOnRead", chkRead); + AddBinding("BreakOnWrite", chkWrite); + AddBinding("BreakOnExec", chkExec); + AddBinding("Condition", txtCondition); + + cboBreakpointType.Items.Clear(); + cboBreakpointType.Items.Add(ResourceHelper.GetEnumText(SnesMemoryType.CpuMemory)); + cboBreakpointType.Items.Add("-"); + + //TODO - Might not be useful on the SNES? + /*if(DebugApi.GetMemorySize(SnesMemoryType.PrgRom) > 0) { + cboBreakpointType.Items.Add(ResourceHelper.GetEnumText(SnesMemoryType.PrgRom)); + } + if(DebugApi.GetMemorySize(SnesMemoryType.WorkRam) > 0) { + cboBreakpointType.Items.Add(ResourceHelper.GetEnumText(SnesMemoryType.WorkRam)); + } + if(DebugApi.GetMemorySize(SnesMemoryType.SaveRam) > 0) { + cboBreakpointType.Items.Add(ResourceHelper.GetEnumText(SnesMemoryType.SaveRam)); + } + + if(cboBreakpointType.Items.Count > 2) { + cboBreakpointType.Items.Add("-"); + }*/ + + cboBreakpointType.Items.Add(ResourceHelper.GetEnumText(SnesMemoryType.VideoRam)); + cboBreakpointType.Items.Add(ResourceHelper.GetEnumText(SnesMemoryType.SpriteRam)); + cboBreakpointType.Items.Add(ResourceHelper.GetEnumText(SnesMemoryType.CGRam)); + + this.toolTip.SetToolTip(this.picExpressionWarning, "Condition contains invalid syntax or symbols."); + this.toolTip.SetToolTip(this.picHelp, frmBreakpoint.GetConditionTooltip(false)); + } + + protected override void OnShown(EventArgs e) + { + base.OnShown(e); + + Breakpoint bp = (Breakpoint)this.Entity; + if(!BreakpointManager.Breakpoints.Contains(bp)) { + //This is a new breakpoint, make sure address fields are empty instead of 0 + if(bp.Address == UInt32.MaxValue) { + txtAddress.Text = ""; + } + if(txtFrom.Text == "0") { + txtFrom.Text = ""; + } + if(txtTo.Text == "0") { + txtTo.Text = ""; + } + } + if(bp.Address == 0 && bp.AddressType != BreakpointAddressType.SingleAddress) { + txtAddress.Text = ""; + } + if(bp.StartAddress == 0 && bp.EndAddress == 0 && bp.AddressType != BreakpointAddressType.AddressRange) { + txtFrom.Text = ""; + txtTo.Text = ""; + } + + if(bp.AddressType == BreakpointAddressType.AddressRange) { + txtFrom.Focus(); + txtFrom.SelectionStart = 0; + txtFrom.SelectionLength = 0; + } else if(bp.AddressType == BreakpointAddressType.SingleAddress) { + txtAddress.Focus(); + txtAddress.SelectionStart = 0; + txtAddress.SelectionLength = 0; + } + } + + public static string GetConditionTooltip(bool forWatch) + { + string tooltip = + "Most expressions/operators are accepted (C++ syntax)." + Environment.NewLine + + "Note: Use the $ prefix to denote hexadecimal values." + Environment.NewLine + + "Note 2: Labels assigned to the code can be used (their value will match the label's address in CPU memory)." + Environment.NewLine + Environment.NewLine + + "A/X/Y/PS/SP: Value of registers" + Environment.NewLine + + "PC: Program Counter" + Environment.NewLine + + "OpPC: Address of the current instruction's first byte" + Environment.NewLine + + "PreviousOpPC: Address of the previous instruction's first byte" + Environment.NewLine + + "Irq/Nmi/Sprite0Hit/SpriteOverflow/VerticalBlank: True if the corresponding flags are set" + Environment.NewLine + + "Branched: True if the current instruction was reached by jumping or branching" + Environment.NewLine + + "Cycle/Scanline: Current cycle (0-340)/scanline(-1 to 260) of the PPU" + Environment.NewLine + + "Frame: PPU frame number (since power on/reset)" + Environment.NewLine + + "Value: Current value being read/written from/to memory" + Environment.NewLine + + "IsRead: True if the CPU is reading from a memory address" + Environment.NewLine + + "IsWrite: True if the CPU is writing to a memory address" + Environment.NewLine; + + if(!forWatch) { + tooltip += + "Address: Current CPU memory address being read/written" + Environment.NewLine + + "RomAddress: Current ROM address being read/written" + Environment.NewLine; + } + + tooltip += + "[
]: (Byte) Memory value at
(CPU)" + Environment.NewLine + + "{
}: (Word) Memory value at
(CPU)" + Environment.NewLine + Environment.NewLine + + + "Examples:" + Environment.NewLine + + "a == 10 || x == $23" + Environment.NewLine + + "scanline == 10 && (cycle >= 55 && cycle <= 100)" + Environment.NewLine + + "x == [$150] || y == [10]" + Environment.NewLine + + "[[$15] + y] -> Reads the value at address $15, adds Y to it and reads the value at the resulting address." + Environment.NewLine + + "{$FFFA} -> Returns the NMI handler's address."; + + return tooltip; + } + + protected override void UpdateConfig() + { + base.UpdateConfig(); + + if(radAnyAddress.Checked) { + ((Breakpoint)Entity).AddressType = BreakpointAddressType.AnyAddress; + } else if(radSpecificAddress.Checked) { + ((Breakpoint)Entity).AddressType = BreakpointAddressType.SingleAddress; + } else if(radRange.Checked) { + ((Breakpoint)Entity).AddressType = BreakpointAddressType.AddressRange; + } + } + + protected override bool ValidateInput() + { + if(txtCondition.Text.Trim().Length > 0) { + EvalResultType resultType; + DebugApi.EvaluateExpression(txtCondition.Text.Replace(Environment.NewLine, " "), out resultType, false); + if(resultType == EvalResultType.Invalid) { + picExpressionWarning.Visible = true; + return false; + } + } + picExpressionWarning.Visible = false; + + SnesMemoryType type = cboBreakpointType.GetEnumValue(); + int maxValue = DebugApi.GetMemorySize(type) - 1; + + if(radSpecificAddress.Checked) { + if(ValidateAddress(txtAddress, maxValue) < 0) { + return false; + } + } else if(radRange.Checked) { + int start = ValidateAddress(txtFrom, maxValue); + int end = ValidateAddress(txtTo, maxValue); + + if(start < 0 || end < 0 || end < start) { + return false; + } + } + + return chkRead.Checked || chkWrite.Checked || (chkExec.Checked && Breakpoint.IsTypeCpuBreakpoint(type)) || txtCondition.Text.Length > 0; + } + + private int ValidateAddress(TextBox field, int maxValue) + { + int value = -1; + if(!int.TryParse(field.Text, NumberStyles.HexNumber, null, out value) || value > maxValue) { + field.ForeColor = Color.Red; + value = -1; + } else { + field.ForeColor = SystemColors.ControlText; + } + return value; + } + + private void txtAddress_Enter(object sender, EventArgs e) + { + radSpecificAddress.Checked = true; + } + + private void txtFrom_Enter(object sender, EventArgs e) + { + radRange.Checked = true; + } + + private void txtTo_Enter(object sender, EventArgs e) + { + radRange.Checked = true; + } + + private void cboBreakpointType_SelectedIndexChanged(object sender, EventArgs e) + { + SnesMemoryType type = cboBreakpointType.GetEnumValue(); + + chkExec.Visible = Breakpoint.IsTypeCpuBreakpoint(type); + + string maxValue = (DebugApi.GetMemorySize(type) - 1).ToString("X2"); + string minValue = "".PadLeft(maxValue.Length, '0'); + + lblRange.Text = $"(range: ${minValue}-${maxValue})"; + } + } +} diff --git a/UI/Debugger/Breakpoints/frmBreakpoint.designer.cs b/UI/Debugger/Breakpoints/frmBreakpoint.designer.cs new file mode 100644 index 0000000..ba57a42 --- /dev/null +++ b/UI/Debugger/Breakpoints/frmBreakpoint.designer.cs @@ -0,0 +1,562 @@ +namespace Mesen.GUI.Debugger +{ + partial class frmBreakpoint + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if(disposing && (components != null)) { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel(); + this.lblBreakpointType = new System.Windows.Forms.Label(); + this.flowLayoutPanel2 = new System.Windows.Forms.FlowLayoutPanel(); + this.chkRead = new System.Windows.Forms.CheckBox(); + this.chkWrite = new System.Windows.Forms.CheckBox(); + this.chkExec = new System.Windows.Forms.CheckBox(); + this.lblBreakOn = new System.Windows.Forms.Label(); + this.lblAddress = new System.Windows.Forms.Label(); + this.tableLayoutPanel2 = new System.Windows.Forms.TableLayoutPanel(); + this.picHelp = new System.Windows.Forms.PictureBox(); + this.txtCondition = new System.Windows.Forms.TextBox(); + this.picExpressionWarning = new System.Windows.Forms.PictureBox(); + this.tableLayoutPanel3 = new System.Windows.Forms.TableLayoutPanel(); + this.txtAddress = new System.Windows.Forms.TextBox(); + this.radSpecificAddress = new System.Windows.Forms.RadioButton(); + this.radAnyAddress = new System.Windows.Forms.RadioButton(); + this.lblAddressSign = new System.Windows.Forms.Label(); + this.radRange = new System.Windows.Forms.RadioButton(); + this.tableLayoutPanel5 = new System.Windows.Forms.TableLayoutPanel(); + this.txtTo = new System.Windows.Forms.TextBox(); + this.lblTo = new System.Windows.Forms.Label(); + this.txtFrom = new System.Windows.Forms.TextBox(); + this.lblFrom = new System.Windows.Forms.Label(); + this.tableLayoutPanel4 = new System.Windows.Forms.TableLayoutPanel(); + this.cboBreakpointType = new Mesen.GUI.Debugger.Controls.ComboBoxWithSeparator(); + this.lblRange = new System.Windows.Forms.Label(); + this.tableLayoutPanel6 = new System.Windows.Forms.TableLayoutPanel(); + this.label1 = new System.Windows.Forms.Label(); + this.lblCondition = new System.Windows.Forms.Label(); + this.chkMarkOnEventViewer = new System.Windows.Forms.CheckBox(); + this.chkEnabled = new System.Windows.Forms.CheckBox(); + this.tableLayoutPanel7 = new System.Windows.Forms.TableLayoutPanel(); + this.tableLayoutPanel1.SuspendLayout(); + this.flowLayoutPanel2.SuspendLayout(); + this.tableLayoutPanel2.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)(this.picHelp)).BeginInit(); + ((System.ComponentModel.ISupportInitialize)(this.picExpressionWarning)).BeginInit(); + this.tableLayoutPanel3.SuspendLayout(); + this.tableLayoutPanel5.SuspendLayout(); + this.tableLayoutPanel4.SuspendLayout(); + this.tableLayoutPanel6.SuspendLayout(); + this.tableLayoutPanel7.SuspendLayout(); + this.SuspendLayout(); + // + // baseConfigPanel + // + this.baseConfigPanel.Location = new System.Drawing.Point(0, 197); + this.baseConfigPanel.Size = new System.Drawing.Size(426, 29); + // + // tableLayoutPanel1 + // + this.tableLayoutPanel1.ColumnCount = 2; + this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); + this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F)); + this.tableLayoutPanel1.Controls.Add(this.lblBreakpointType, 0, 0); + this.tableLayoutPanel1.Controls.Add(this.flowLayoutPanel2, 1, 1); + this.tableLayoutPanel1.Controls.Add(this.lblBreakOn, 0, 1); + this.tableLayoutPanel1.Controls.Add(this.lblAddress, 0, 2); + this.tableLayoutPanel1.Controls.Add(this.tableLayoutPanel2, 1, 3); + this.tableLayoutPanel1.Controls.Add(this.tableLayoutPanel3, 1, 2); + this.tableLayoutPanel1.Controls.Add(this.tableLayoutPanel4, 1, 0); + this.tableLayoutPanel1.Controls.Add(this.tableLayoutPanel6, 0, 3); + this.tableLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Fill; + this.tableLayoutPanel1.Location = new System.Drawing.Point(0, 0); + this.tableLayoutPanel1.Name = "tableLayoutPanel1"; + this.tableLayoutPanel1.RowCount = 6; + 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()); + 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()); + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 20F)); + this.tableLayoutPanel1.Size = new System.Drawing.Size(426, 226); + this.tableLayoutPanel1.TabIndex = 2; + // + // lblBreakpointType + // + this.lblBreakpointType.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.lblBreakpointType.AutoSize = true; + this.lblBreakpointType.Location = new System.Drawing.Point(3, 8); + this.lblBreakpointType.Margin = new System.Windows.Forms.Padding(3, 4, 3, 0); + this.lblBreakpointType.Name = "lblBreakpointType"; + this.lblBreakpointType.Size = new System.Drawing.Size(88, 13); + this.lblBreakpointType.TabIndex = 12; + this.lblBreakpointType.Text = "Breakpoint Type:"; + // + // flowLayoutPanel2 + // + this.flowLayoutPanel2.Controls.Add(this.chkRead); + this.flowLayoutPanel2.Controls.Add(this.chkWrite); + this.flowLayoutPanel2.Controls.Add(this.chkExec); + this.flowLayoutPanel2.Dock = System.Windows.Forms.DockStyle.Fill; + this.flowLayoutPanel2.Location = new System.Drawing.Point(94, 25); + this.flowLayoutPanel2.Margin = new System.Windows.Forms.Padding(0); + this.flowLayoutPanel2.Name = "flowLayoutPanel2"; + this.flowLayoutPanel2.Size = new System.Drawing.Size(332, 23); + this.flowLayoutPanel2.TabIndex = 4; + // + // chkRead + // + this.chkRead.AutoSize = true; + this.chkRead.Location = new System.Drawing.Point(3, 3); + this.chkRead.Name = "chkRead"; + this.chkRead.Size = new System.Drawing.Size(52, 17); + this.chkRead.TabIndex = 4; + this.chkRead.Text = "Read"; + this.chkRead.UseVisualStyleBackColor = true; + // + // chkWrite + // + this.chkWrite.AutoSize = true; + this.chkWrite.Location = new System.Drawing.Point(61, 3); + this.chkWrite.Name = "chkWrite"; + this.chkWrite.Size = new System.Drawing.Size(51, 17); + this.chkWrite.TabIndex = 5; + this.chkWrite.Text = "Write"; + this.chkWrite.UseVisualStyleBackColor = true; + // + // chkExec + // + this.chkExec.AutoSize = true; + this.chkExec.Location = new System.Drawing.Point(118, 3); + this.chkExec.Name = "chkExec"; + this.chkExec.Size = new System.Drawing.Size(73, 17); + this.chkExec.TabIndex = 3; + this.chkExec.Text = "Execution"; + this.chkExec.UseVisualStyleBackColor = true; + // + // lblBreakOn + // + this.lblBreakOn.AutoSize = true; + this.lblBreakOn.Location = new System.Drawing.Point(3, 29); + this.lblBreakOn.Margin = new System.Windows.Forms.Padding(3, 4, 3, 0); + this.lblBreakOn.Name = "lblBreakOn"; + this.lblBreakOn.Size = new System.Drawing.Size(53, 13); + this.lblBreakOn.TabIndex = 0; + this.lblBreakOn.Text = "Break on:"; + // + // lblAddress + // + this.lblAddress.AutoSize = true; + this.lblAddress.Location = new System.Drawing.Point(3, 53); + this.lblAddress.Margin = new System.Windows.Forms.Padding(3, 5, 3, 0); + this.lblAddress.Name = "lblAddress"; + this.lblAddress.Size = new System.Drawing.Size(48, 13); + this.lblAddress.TabIndex = 3; + this.lblAddress.Text = "Address:"; + // + // tableLayoutPanel2 + // + this.tableLayoutPanel2.ColumnCount = 3; + this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F)); + this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); + this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); + this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 20F)); + this.tableLayoutPanel2.Controls.Add(this.picHelp, 2, 0); + this.tableLayoutPanel2.Controls.Add(this.txtCondition, 0, 0); + this.tableLayoutPanel2.Controls.Add(this.picExpressionWarning, 1, 0); + this.tableLayoutPanel2.Location = new System.Drawing.Point(94, 123); + this.tableLayoutPanel2.Margin = new System.Windows.Forms.Padding(0); + this.tableLayoutPanel2.Name = "tableLayoutPanel2"; + this.tableLayoutPanel2.RowCount = 1; + this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F)); + this.tableLayoutPanel2.Size = new System.Drawing.Size(329, 65); + this.tableLayoutPanel2.TabIndex = 10; + // + // picHelp + // + this.picHelp.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.picHelp.Image = global::Mesen.GUI.Properties.Resources.Help; + this.picHelp.Location = new System.Drawing.Point(308, 24); + this.picHelp.Margin = new System.Windows.Forms.Padding(3, 5, 3, 3); + this.picHelp.Name = "picHelp"; + this.picHelp.Size = new System.Drawing.Size(18, 18); + this.picHelp.TabIndex = 8; + this.picHelp.TabStop = false; + // + // txtCondition + // + this.txtCondition.AcceptsReturn = true; + this.txtCondition.Dock = System.Windows.Forms.DockStyle.Fill; + this.txtCondition.Location = new System.Drawing.Point(3, 3); + this.txtCondition.MaxLength = 900; + this.txtCondition.Multiline = true; + this.txtCondition.Name = "txtCondition"; + this.txtCondition.ScrollBars = System.Windows.Forms.ScrollBars.Vertical; + this.txtCondition.Size = new System.Drawing.Size(275, 59); + this.txtCondition.TabIndex = 6; + // + // picExpressionWarning + // + this.picExpressionWarning.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.picExpressionWarning.Image = global::Mesen.GUI.Properties.Resources.Warning; + this.picExpressionWarning.Location = new System.Drawing.Point(284, 24); + this.picExpressionWarning.Margin = new System.Windows.Forms.Padding(3, 5, 3, 3); + this.picExpressionWarning.Name = "picExpressionWarning"; + this.picExpressionWarning.Size = new System.Drawing.Size(18, 18); + this.picExpressionWarning.TabIndex = 9; + this.picExpressionWarning.TabStop = false; + this.picExpressionWarning.Visible = false; + // + // tableLayoutPanel3 + // + this.tableLayoutPanel3.ColumnCount = 4; + this.tableLayoutPanel3.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); + this.tableLayoutPanel3.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); + this.tableLayoutPanel3.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F)); + this.tableLayoutPanel3.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); + this.tableLayoutPanel3.Controls.Add(this.txtAddress, 2, 0); + this.tableLayoutPanel3.Controls.Add(this.radSpecificAddress, 0, 0); + this.tableLayoutPanel3.Controls.Add(this.radAnyAddress, 0, 2); + this.tableLayoutPanel3.Controls.Add(this.lblAddressSign, 1, 0); + this.tableLayoutPanel3.Controls.Add(this.radRange, 0, 1); + this.tableLayoutPanel3.Controls.Add(this.tableLayoutPanel5, 1, 1); + this.tableLayoutPanel3.Location = new System.Drawing.Point(94, 48); + this.tableLayoutPanel3.Margin = new System.Windows.Forms.Padding(0); + this.tableLayoutPanel3.Name = "tableLayoutPanel3"; + this.tableLayoutPanel3.RowCount = 4; + this.tableLayoutPanel3.RowStyles.Add(new System.Windows.Forms.RowStyle()); + this.tableLayoutPanel3.RowStyles.Add(new System.Windows.Forms.RowStyle()); + this.tableLayoutPanel3.RowStyles.Add(new System.Windows.Forms.RowStyle()); + this.tableLayoutPanel3.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F)); + this.tableLayoutPanel3.Size = new System.Drawing.Size(271, 75); + this.tableLayoutPanel3.TabIndex = 11; + // + // txtAddress + // + this.txtAddress.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; + this.txtAddress.Location = new System.Drawing.Point(85, 3); + this.txtAddress.Margin = new System.Windows.Forms.Padding(0, 3, 3, 3); + this.txtAddress.Name = "txtAddress"; + this.txtAddress.Size = new System.Drawing.Size(64, 20); + this.txtAddress.TabIndex = 5; + this.txtAddress.Enter += new System.EventHandler(this.txtAddress_Enter); + // + // radSpecificAddress + // + this.radSpecificAddress.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.radSpecificAddress.AutoSize = true; + this.radSpecificAddress.Location = new System.Drawing.Point(3, 4); + this.radSpecificAddress.Name = "radSpecificAddress"; + this.radSpecificAddress.Size = new System.Drawing.Size(66, 17); + this.radSpecificAddress.TabIndex = 7; + this.radSpecificAddress.TabStop = true; + this.radSpecificAddress.Text = "Specific:"; + this.radSpecificAddress.UseVisualStyleBackColor = true; + // + // radAnyAddress + // + this.radAnyAddress.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.radAnyAddress.AutoSize = true; + this.radAnyAddress.Location = new System.Drawing.Point(3, 52); + this.radAnyAddress.Name = "radAnyAddress"; + this.radAnyAddress.Size = new System.Drawing.Size(43, 17); + this.radAnyAddress.TabIndex = 8; + this.radAnyAddress.TabStop = true; + this.radAnyAddress.Text = "Any"; + this.radAnyAddress.UseVisualStyleBackColor = true; + // + // lblAddressSign + // + this.lblAddressSign.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.lblAddressSign.AutoSize = true; + this.lblAddressSign.Location = new System.Drawing.Point(72, 6); + this.lblAddressSign.Margin = new System.Windows.Forms.Padding(0); + this.lblAddressSign.Name = "lblAddressSign"; + this.lblAddressSign.Size = new System.Drawing.Size(13, 13); + this.lblAddressSign.TabIndex = 9; + this.lblAddressSign.Text = "$"; + // + // radRange + // + this.radRange.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.radRange.AutoSize = true; + this.radRange.Location = new System.Drawing.Point(3, 29); + this.radRange.Name = "radRange"; + this.radRange.Size = new System.Drawing.Size(60, 17); + this.radRange.TabIndex = 10; + this.radRange.TabStop = true; + this.radRange.Text = "Range:"; + this.radRange.UseVisualStyleBackColor = true; + // + // tableLayoutPanel5 + // + this.tableLayoutPanel5.ColumnCount = 4; + this.tableLayoutPanel3.SetColumnSpan(this.tableLayoutPanel5, 2); + this.tableLayoutPanel5.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); + this.tableLayoutPanel5.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50F)); + this.tableLayoutPanel5.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); + this.tableLayoutPanel5.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50F)); + this.tableLayoutPanel5.Controls.Add(this.txtTo, 3, 0); + this.tableLayoutPanel5.Controls.Add(this.lblTo, 2, 0); + this.tableLayoutPanel5.Controls.Add(this.txtFrom, 1, 0); + this.tableLayoutPanel5.Controls.Add(this.lblFrom, 0, 0); + this.tableLayoutPanel5.Dock = System.Windows.Forms.DockStyle.Fill; + this.tableLayoutPanel5.Location = new System.Drawing.Point(72, 26); + this.tableLayoutPanel5.Margin = new System.Windows.Forms.Padding(0); + this.tableLayoutPanel5.Name = "tableLayoutPanel5"; + this.tableLayoutPanel5.RowCount = 1; + this.tableLayoutPanel5.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F)); + this.tableLayoutPanel5.Size = new System.Drawing.Size(199, 23); + this.tableLayoutPanel5.TabIndex = 12; + // + // txtTo + // + this.txtTo.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; + this.txtTo.Dock = System.Windows.Forms.DockStyle.Fill; + this.txtTo.Location = new System.Drawing.Point(131, 3); + this.txtTo.Margin = new System.Windows.Forms.Padding(0, 3, 3, 3); + this.txtTo.Name = "txtTo"; + this.txtTo.Size = new System.Drawing.Size(65, 20); + this.txtTo.TabIndex = 13; + this.txtTo.Enter += new System.EventHandler(this.txtTo_Enter); + // + // lblTo + // + this.lblTo.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.lblTo.AutoSize = true; + this.lblTo.Location = new System.Drawing.Point(106, 5); + this.lblTo.Margin = new System.Windows.Forms.Padding(0); + this.lblTo.Name = "lblTo"; + this.lblTo.Size = new System.Drawing.Size(25, 13); + this.lblTo.TabIndex = 11; + this.lblTo.Text = "to $"; + // + // txtFrom + // + this.txtFrom.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; + this.txtFrom.Dock = System.Windows.Forms.DockStyle.Fill; + this.txtFrom.Location = new System.Drawing.Point(39, 3); + this.txtFrom.Margin = new System.Windows.Forms.Padding(0, 3, 3, 3); + this.txtFrom.Name = "txtFrom"; + this.txtFrom.Size = new System.Drawing.Size(64, 20); + this.txtFrom.TabIndex = 12; + this.txtFrom.Enter += new System.EventHandler(this.txtFrom_Enter); + // + // lblFrom + // + this.lblFrom.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.lblFrom.AutoSize = true; + this.lblFrom.Location = new System.Drawing.Point(0, 5); + this.lblFrom.Margin = new System.Windows.Forms.Padding(0); + this.lblFrom.Name = "lblFrom"; + this.lblFrom.Size = new System.Drawing.Size(39, 13); + this.lblFrom.TabIndex = 10; + this.lblFrom.Text = "From $"; + // + // tableLayoutPanel4 + // + this.tableLayoutPanel4.ColumnCount = 2; + this.tableLayoutPanel4.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); + this.tableLayoutPanel4.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F)); + this.tableLayoutPanel4.Controls.Add(this.cboBreakpointType, 0, 0); + this.tableLayoutPanel4.Controls.Add(this.lblRange, 1, 0); + this.tableLayoutPanel4.Dock = System.Windows.Forms.DockStyle.Fill; + this.tableLayoutPanel4.Location = new System.Drawing.Point(94, 0); + this.tableLayoutPanel4.Margin = new System.Windows.Forms.Padding(0); + this.tableLayoutPanel4.Name = "tableLayoutPanel4"; + this.tableLayoutPanel4.RowCount = 1; + this.tableLayoutPanel4.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F)); + this.tableLayoutPanel4.Size = new System.Drawing.Size(332, 25); + this.tableLayoutPanel4.TabIndex = 13; + // + // cboBreakpointType + // + this.cboBreakpointType.DrawMode = System.Windows.Forms.DrawMode.OwnerDrawFixed; + this.cboBreakpointType.FormattingEnabled = true; + this.cboBreakpointType.Location = new System.Drawing.Point(3, 3); + this.cboBreakpointType.Name = "cboBreakpointType"; + this.cboBreakpointType.Size = new System.Drawing.Size(121, 21); + this.cboBreakpointType.TabIndex = 13; + this.cboBreakpointType.SelectedIndexChanged += new System.EventHandler(this.cboBreakpointType_SelectedIndexChanged); + // + // lblRange + // + this.lblRange.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.lblRange.AutoSize = true; + this.lblRange.ForeColor = System.Drawing.SystemColors.ControlDarkDark; + this.lblRange.Location = new System.Drawing.Point(130, 6); + this.lblRange.Name = "lblRange"; + this.lblRange.Size = new System.Drawing.Size(40, 13); + this.lblRange.TabIndex = 6; + this.lblRange.Text = "(range)"; + // + // tableLayoutPanel6 + // + this.tableLayoutPanel6.ColumnCount = 1; + this.tableLayoutPanel6.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50F)); + this.tableLayoutPanel6.Controls.Add(this.label1, 0, 1); + this.tableLayoutPanel6.Controls.Add(this.lblCondition, 0, 0); + this.tableLayoutPanel6.Dock = System.Windows.Forms.DockStyle.Fill; + this.tableLayoutPanel6.Location = new System.Drawing.Point(0, 123); + this.tableLayoutPanel6.Margin = new System.Windows.Forms.Padding(0); + this.tableLayoutPanel6.Name = "tableLayoutPanel6"; + this.tableLayoutPanel6.RowCount = 2; + this.tableLayoutPanel6.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 50F)); + this.tableLayoutPanel6.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 50F)); + this.tableLayoutPanel6.Size = new System.Drawing.Size(94, 65); + this.tableLayoutPanel6.TabIndex = 14; + // + // label1 + // + this.label1.AutoSize = true; + this.label1.ForeColor = System.Drawing.SystemColors.GrayText; + this.label1.Location = new System.Drawing.Point(3, 32); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(50, 13); + this.label1.TabIndex = 8; + this.label1.Text = "(optional)"; + // + // lblCondition + // + this.lblCondition.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); + this.lblCondition.AutoSize = true; + this.lblCondition.Location = new System.Drawing.Point(3, 19); + this.lblCondition.Name = "lblCondition"; + this.lblCondition.Size = new System.Drawing.Size(54, 13); + this.lblCondition.TabIndex = 7; + this.lblCondition.Text = "Condition:"; + // + // chkMarkOnEventViewer + // + this.chkMarkOnEventViewer.AutoSize = true; + this.chkMarkOnEventViewer.Location = new System.Drawing.Point(3, 3); + this.chkMarkOnEventViewer.Margin = new System.Windows.Forms.Padding(3, 0, 3, 0); + this.chkMarkOnEventViewer.Name = "chkMarkOnEventViewer"; + this.chkMarkOnEventViewer.Size = new System.Drawing.Size(131, 17); + this.chkMarkOnEventViewer.TabIndex = 15; + this.chkMarkOnEventViewer.Text = "Mark on Event Viewer"; + this.chkMarkOnEventViewer.UseVisualStyleBackColor = true; + // + // chkEnabled + // + this.chkEnabled.AutoSize = true; + this.chkEnabled.Location = new System.Drawing.Point(3, 20); + this.chkEnabled.Margin = new System.Windows.Forms.Padding(3, 0, 3, 0); + this.chkEnabled.Name = "chkEnabled"; + this.chkEnabled.Size = new System.Drawing.Size(104, 17); + this.chkEnabled.TabIndex = 2; + this.chkEnabled.Text = "Break Execution"; + this.chkEnabled.UseVisualStyleBackColor = true; + // + // tableLayoutPanel7 + // + this.tableLayoutPanel7.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); + this.tableLayoutPanel7.ColumnCount = 1; + this.tableLayoutPanel7.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F)); + this.tableLayoutPanel7.Controls.Add(this.chkEnabled, 0, 3); + this.tableLayoutPanel7.Controls.Add(this.chkMarkOnEventViewer, 0, 2); + this.tableLayoutPanel7.Location = new System.Drawing.Point(0, 188); + this.tableLayoutPanel7.Margin = new System.Windows.Forms.Padding(0); + this.tableLayoutPanel7.Name = "tableLayoutPanel7"; + this.tableLayoutPanel7.RowCount = 4; + this.tableLayoutPanel7.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F)); + this.tableLayoutPanel7.RowStyles.Add(new System.Windows.Forms.RowStyle()); + this.tableLayoutPanel7.RowStyles.Add(new System.Windows.Forms.RowStyle()); + this.tableLayoutPanel7.RowStyles.Add(new System.Windows.Forms.RowStyle()); + this.tableLayoutPanel7.Size = new System.Drawing.Size(243, 37); + this.tableLayoutPanel7.TabIndex = 3; + // + // frmBreakpoint + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(426, 226); + this.Controls.Add(this.tableLayoutPanel7); + this.Controls.Add(this.tableLayoutPanel1); + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedToolWindow; + this.Name = "frmBreakpoint"; + this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; + this.Text = "Breakpoint"; + this.Controls.SetChildIndex(this.tableLayoutPanel1, 0); + this.Controls.SetChildIndex(this.baseConfigPanel, 0); + this.Controls.SetChildIndex(this.tableLayoutPanel7, 0); + this.tableLayoutPanel1.ResumeLayout(false); + this.tableLayoutPanel1.PerformLayout(); + this.flowLayoutPanel2.ResumeLayout(false); + this.flowLayoutPanel2.PerformLayout(); + this.tableLayoutPanel2.ResumeLayout(false); + this.tableLayoutPanel2.PerformLayout(); + ((System.ComponentModel.ISupportInitialize)(this.picHelp)).EndInit(); + ((System.ComponentModel.ISupportInitialize)(this.picExpressionWarning)).EndInit(); + this.tableLayoutPanel3.ResumeLayout(false); + this.tableLayoutPanel3.PerformLayout(); + this.tableLayoutPanel5.ResumeLayout(false); + this.tableLayoutPanel5.PerformLayout(); + this.tableLayoutPanel4.ResumeLayout(false); + this.tableLayoutPanel4.PerformLayout(); + this.tableLayoutPanel6.ResumeLayout(false); + this.tableLayoutPanel6.PerformLayout(); + this.tableLayoutPanel7.ResumeLayout(false); + this.tableLayoutPanel7.PerformLayout(); + this.ResumeLayout(false); + + } + + #endregion + + private System.Windows.Forms.TableLayoutPanel tableLayoutPanel1; + private System.Windows.Forms.Label lblBreakOn; + private System.Windows.Forms.Label lblAddress; + private System.Windows.Forms.FlowLayoutPanel flowLayoutPanel2; + private System.Windows.Forms.TextBox txtAddress; + private System.Windows.Forms.CheckBox chkEnabled; + private System.Windows.Forms.TextBox txtCondition; + private System.Windows.Forms.Label lblCondition; + private System.Windows.Forms.PictureBox picHelp; + private System.Windows.Forms.TableLayoutPanel tableLayoutPanel2; + private System.Windows.Forms.CheckBox chkExec; + private System.Windows.Forms.CheckBox chkRead; + private System.Windows.Forms.CheckBox chkWrite; + private System.Windows.Forms.TableLayoutPanel tableLayoutPanel3; + private System.Windows.Forms.RadioButton radSpecificAddress; + private System.Windows.Forms.RadioButton radAnyAddress; + private System.Windows.Forms.Label lblAddressSign; + private System.Windows.Forms.PictureBox picExpressionWarning; + private System.Windows.Forms.RadioButton radRange; + private System.Windows.Forms.Label lblFrom; + private System.Windows.Forms.TextBox txtFrom; + private System.Windows.Forms.Label lblTo; + private System.Windows.Forms.TextBox txtTo; + private System.Windows.Forms.TableLayoutPanel tableLayoutPanel5; + private System.Windows.Forms.Label lblBreakpointType; + private Mesen.GUI.Debugger.Controls.ComboBoxWithSeparator cboBreakpointType; + private System.Windows.Forms.TableLayoutPanel tableLayoutPanel4; + private System.Windows.Forms.Label lblRange; + private System.Windows.Forms.TableLayoutPanel tableLayoutPanel6; + private System.Windows.Forms.Label label1; + private System.Windows.Forms.CheckBox chkMarkOnEventViewer; + private System.Windows.Forms.TableLayoutPanel tableLayoutPanel7; + } +} \ No newline at end of file diff --git a/UI/Debugger/Breakpoints/frmBreakpoint.resx b/UI/Debugger/Breakpoints/frmBreakpoint.resx new file mode 100644 index 0000000..8766f29 --- /dev/null +++ b/UI/Debugger/Breakpoints/frmBreakpoint.resx @@ -0,0 +1,123 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 17, 17 + + \ No newline at end of file diff --git a/UI/Debugger/Controls/ctrlDisassemblyView.cs b/UI/Debugger/Controls/ctrlDisassemblyView.cs index 139cbe9..353420f 100644 --- a/UI/Debugger/Controls/ctrlDisassemblyView.cs +++ b/UI/Debugger/Controls/ctrlDisassemblyView.cs @@ -116,13 +116,14 @@ namespace Mesen.GUI.Debugger.Controls props.Symbol |= LineSymbol.Arrow; } - public LineProperties GetLineStyle(CodeLineData lineData, int lineNumber) + public LineProperties GetLineStyle(CodeLineData lineData, int lineIndex) { DebugInfo info = ConfigManager.Config.Debug; LineProperties props = new LineProperties(); - //TODO - //AddressInfo addressInfo = _code.GetAddressInfo(lineNumber); - //GetBreakpointLineProperties(props, cpuAddress, addressInfo); + + if(lineData.Address >= 0) { + GetBreakpointLineProperties(props, lineData.Address); + } bool isActiveStatement = ActiveAddress.HasValue && ActiveAddress.Value == lineData.Address; if(isActiveStatement) { @@ -151,13 +152,11 @@ namespace Mesen.GUI.Debugger.Controls return props; } - public static void GetBreakpointLineProperties(LineProperties props, int cpuAddress, AddressInfo addressInfo) + public static void GetBreakpointLineProperties(LineProperties props, int cpuAddress) { - //TODO - - /*DebugInfo config = ConfigManager.Config.Debug; + DebugInfo config = ConfigManager.Config.Debug; foreach(Breakpoint breakpoint in BreakpointManager.Breakpoints) { - if(breakpoint.Matches(cpuAddress, addressInfo)) { + if(breakpoint.Matches((uint)cpuAddress, SnesMemoryType.CpuMemory)) { Color fgColor = Color.White; Color? bgColor = null; Color bpColor = breakpoint.BreakOnExec ? config.CodeExecBreakpointColor : (breakpoint.BreakOnWrite ? config.CodeWriteBreakpointColor : config.CodeReadBreakpointColor); @@ -185,7 +184,7 @@ namespace Mesen.GUI.Debugger.Controls props.Symbol = symbol; return; } - }*/ + } } } } diff --git a/UI/Debugger/frmDebugger.Designer.cs b/UI/Debugger/frmDebugger.Designer.cs index af629d7..9e5523d 100644 --- a/UI/Debugger/frmDebugger.Designer.cs +++ b/UI/Debugger/frmDebugger.Designer.cs @@ -58,12 +58,17 @@ this.ctrlSplitContainer = new Mesen.GUI.Controls.ctrlSplitContainer(); this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel(); this.ctrlWatch = new Mesen.GUI.Debugger.ctrlWatch(); + this.grpWatch = new System.Windows.Forms.GroupBox(); + this.grpBreakpoints = new System.Windows.Forms.GroupBox(); + this.ctrlBreakpoints = new Mesen.GUI.Debugger.Controls.ctrlBreakpoints(); this.ctrlMesenMenuStrip1.SuspendLayout(); ((System.ComponentModel.ISupportInitialize)(this.ctrlSplitContainer)).BeginInit(); this.ctrlSplitContainer.Panel1.SuspendLayout(); this.ctrlSplitContainer.Panel2.SuspendLayout(); this.ctrlSplitContainer.SuspendLayout(); this.tableLayoutPanel1.SuspendLayout(); + this.grpWatch.SuspendLayout(); + this.grpBreakpoints.SuspendLayout(); this.SuspendLayout(); // // ctrlDisassemblyView @@ -275,7 +280,8 @@ this.tableLayoutPanel1.ColumnCount = 2; this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50F)); this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50F)); - this.tableLayoutPanel1.Controls.Add(this.ctrlWatch, 0, 0); + this.tableLayoutPanel1.Controls.Add(this.grpWatch, 0, 0); + this.tableLayoutPanel1.Controls.Add(this.grpBreakpoints, 1, 0); this.tableLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Fill; this.tableLayoutPanel1.Location = new System.Drawing.Point(0, 0); this.tableLayoutPanel1.Name = "tableLayoutPanel1"; @@ -287,11 +293,41 @@ // ctrlWatch // this.ctrlWatch.Dock = System.Windows.Forms.DockStyle.Fill; - this.ctrlWatch.Location = new System.Drawing.Point(3, 3); + this.ctrlWatch.Location = new System.Drawing.Point(3, 16); this.ctrlWatch.Name = "ctrlWatch"; - this.ctrlWatch.Size = new System.Drawing.Size(420, 171); + this.ctrlWatch.Size = new System.Drawing.Size(414, 152); this.ctrlWatch.TabIndex = 0; // + // grpWatch + // + this.grpWatch.Controls.Add(this.ctrlWatch); + 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(420, 171); + this.grpWatch.TabIndex = 1; + this.grpWatch.TabStop = false; + this.grpWatch.Text = "Watch"; + // + // grpBreakpoints + // + this.grpBreakpoints.Controls.Add(this.ctrlBreakpoints); + this.grpBreakpoints.Dock = System.Windows.Forms.DockStyle.Fill; + this.grpBreakpoints.Location = new System.Drawing.Point(429, 3); + this.grpBreakpoints.Name = "grpBreakpoints"; + this.grpBreakpoints.Size = new System.Drawing.Size(420, 171); + this.grpBreakpoints.TabIndex = 2; + this.grpBreakpoints.TabStop = false; + this.grpBreakpoints.Text = "Breakpoints"; + // + // ctrlBreakpoints + // + 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(414, 152); + this.ctrlBreakpoints.TabIndex = 0; + // // frmDebugger // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); @@ -308,6 +344,8 @@ ((System.ComponentModel.ISupportInitialize)(this.ctrlSplitContainer)).EndInit(); this.ctrlSplitContainer.ResumeLayout(false); this.tableLayoutPanel1.ResumeLayout(false); + this.grpWatch.ResumeLayout(false); + this.grpBreakpoints.ResumeLayout(false); this.ResumeLayout(false); this.PerformLayout(); @@ -342,5 +380,8 @@ private GUI.Controls.ctrlSplitContainer ctrlSplitContainer; private System.Windows.Forms.TableLayoutPanel tableLayoutPanel1; private ctrlWatch ctrlWatch; + private System.Windows.Forms.GroupBox grpWatch; + private System.Windows.Forms.GroupBox grpBreakpoints; + private Controls.ctrlBreakpoints ctrlBreakpoints; } } \ No newline at end of file diff --git a/UI/Interop/DebugApi.cs b/UI/Interop/DebugApi.cs index 0970350..cbccbc7 100644 --- a/UI/Interop/DebugApi.cs +++ b/UI/Interop/DebugApi.cs @@ -61,6 +61,8 @@ namespace Mesen.GUI [DllImport(DllPath)] public static extern void SetMemoryValues(SnesMemoryType type, UInt32 address, [In] byte[] data, Int32 length); [DllImport(DllPath)] public static extern void SetMemoryState(SnesMemoryType type, [In] byte[] buffer, Int32 length); + [DllImport(DllPath)] public static extern void SetBreakpoints([MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)]InteropBreakpoint[] breakpoints, UInt32 length); + [DllImport(DllPath, EntryPoint = "GetMemoryState")] private static extern void GetMemoryStateWrapper(SnesMemoryType type, [In, Out] byte[] buffer); public static byte[] GetMemoryState(SnesMemoryType type) { diff --git a/UI/UI.csproj b/UI/UI.csproj index a909773..1fb786a 100644 --- a/UI/UI.csproj +++ b/UI/UI.csproj @@ -212,6 +212,21 @@ + + + + UserControl + + + ctrlBreakpoints.cs + + + Form + + + frmBreakpoint.cs + + @@ -454,6 +469,12 @@ ctrlRenderer.cs + + ctrlBreakpoints.cs + + + frmBreakpoint.cs + ctrlDbgShortcuts.cs