mirror of
https://github.com/SourMesen/Mesen2.git
synced 2025-04-02 10:21:44 -04:00
Debugger: SNES - Added coprocessor debuggers
This commit is contained in:
parent
cb2e7ef80e
commit
85482d34f1
31 changed files with 216 additions and 91 deletions
|
@ -3,6 +3,7 @@
|
|||
#include "Core/MemoryOperationType.h"
|
||||
|
||||
enum class MemoryType;
|
||||
enum class CpuType : uint8_t;
|
||||
|
||||
struct AddressInfo
|
||||
{
|
||||
|
@ -278,6 +279,7 @@ enum class BreakSource
|
|||
struct BreakEvent
|
||||
{
|
||||
BreakSource Source;
|
||||
CpuType SourceCpu;
|
||||
MemoryOperationInfo Operation;
|
||||
int32_t BreakpointId;
|
||||
};
|
||||
|
|
|
@ -220,7 +220,7 @@ void Debugger::ProcessPpuCycle()
|
|||
}
|
||||
}
|
||||
|
||||
void Debugger::SleepUntilResume(BreakSource source, MemoryOperationInfo *operation, int breakpointId)
|
||||
void Debugger::SleepUntilResume(CpuType sourceCpu, BreakSource source, MemoryOperationInfo *operation, int breakpointId)
|
||||
{
|
||||
if(_suspendRequestCount) {
|
||||
return;
|
||||
|
@ -234,6 +234,7 @@ void Debugger::SleepUntilResume(BreakSource source, MemoryOperationInfo *operati
|
|||
|
||||
//Only trigger code break event if the pause was caused by user action
|
||||
BreakEvent evt = {};
|
||||
evt.SourceCpu = sourceCpu;
|
||||
evt.BreakpointId = breakpointId;
|
||||
evt.Source = source;
|
||||
if(operation) {
|
||||
|
@ -255,14 +256,14 @@ void Debugger::SleepUntilResume(BreakSource source, MemoryOperationInfo *operati
|
|||
_executionStopped = false;
|
||||
}
|
||||
|
||||
void Debugger::ProcessBreakConditions(bool needBreak, BreakpointManager* bpManager, MemoryOperationInfo &operation, AddressInfo &addressInfo, BreakSource source)
|
||||
void Debugger::ProcessBreakConditions(CpuType sourceCpu, bool needBreak, BreakpointManager* bpManager, MemoryOperationInfo &operation, AddressInfo &addressInfo, BreakSource source)
|
||||
{
|
||||
if(needBreak || _breakRequestCount || _waitForBreakResume) {
|
||||
SleepUntilResume(source);
|
||||
SleepUntilResume(sourceCpu, source);
|
||||
} else {
|
||||
int breakpointId = bpManager->CheckBreakpoint(operation, addressInfo);
|
||||
if(breakpointId >= 0) {
|
||||
SleepUntilResume(BreakSource::Breakpoint, &operation, breakpointId);
|
||||
SleepUntilResume(sourceCpu, BreakSource::Breakpoint, &operation, breakpointId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -393,7 +394,7 @@ void Debugger::SuspendDebugger(bool release)
|
|||
}
|
||||
}
|
||||
|
||||
void Debugger::BreakImmediately(BreakSource source)
|
||||
void Debugger::BreakImmediately(CpuType sourceCpu, BreakSource source)
|
||||
{
|
||||
//TODO
|
||||
bool gbDebugger = _settings->CheckDebuggerFlag(DebuggerFlags::GbDebuggerEnabled);
|
||||
|
@ -404,7 +405,7 @@ void Debugger::BreakImmediately(BreakSource source)
|
|||
} else if(source == BreakSource::GbInvalidOamAccess && (!gbDebugger || !_settings->CheckDebuggerFlag(DebuggerFlags::GbBreakOnInvalidOamAccess))) {
|
||||
return;
|
||||
}
|
||||
SleepUntilResume(source);
|
||||
SleepUntilResume(sourceCpu, source);
|
||||
}
|
||||
|
||||
void Debugger::GetCpuState(BaseState &dstState, CpuType cpuType)
|
||||
|
|
|
@ -107,10 +107,10 @@ public:
|
|||
void ResetSuspendCounter();
|
||||
void SuspendDebugger(bool release);
|
||||
|
||||
void BreakImmediately(BreakSource source);
|
||||
void BreakImmediately(CpuType sourceCpu, BreakSource source);
|
||||
|
||||
void ProcessBreakConditions(bool needBreak, BreakpointManager *bpManager, MemoryOperationInfo &operation, AddressInfo &addressInfo, BreakSource source = BreakSource::Unspecified);
|
||||
void SleepUntilResume(BreakSource source, MemoryOperationInfo* operation = nullptr, int breakpointId = -1);
|
||||
void ProcessBreakConditions(CpuType sourceCpu, bool needBreak, BreakpointManager *bpManager, MemoryOperationInfo &operation, AddressInfo &addressInfo, BreakSource source = BreakSource::Unspecified);
|
||||
void SleepUntilResume(CpuType sourceCpu, BreakSource source, MemoryOperationInfo* operation = nullptr, int breakpointId = -1);
|
||||
|
||||
void GetCpuState(BaseState& dstState, CpuType cpuType);
|
||||
void SetCpuState(BaseState& srcState, CpuType cpuType);
|
||||
|
|
|
@ -134,6 +134,7 @@ vector<DisassemblyResult> Disassembler::Disassemble(CpuType cpuType, uint16_t ba
|
|||
|
||||
int32_t bankStart = bank << 16;
|
||||
int32_t bankEnd = (bank + 1) << 16;
|
||||
bankEnd = std::min<int32_t>(bankEnd, (int32_t)_memoryDumper->GetMemorySize(relAddress.Type));
|
||||
|
||||
AddressInfo addrInfo = {};
|
||||
|
||||
|
|
|
@ -70,6 +70,7 @@ uint32_t MemoryDumper::GetMemorySize(MemoryType type)
|
|||
switch(type) {
|
||||
case MemoryType::SnesMemory: return 0x1000000;
|
||||
case MemoryType::SpcMemory: return 0x10000;
|
||||
case MemoryType::NecDspMemory: return _emu->GetMemory(MemoryType::DspProgramRom).Size;
|
||||
case MemoryType::Sa1Memory: return 0x1000000;
|
||||
case MemoryType::GsuMemory: return 0x1000000;
|
||||
case MemoryType::Cx4Memory: return 0x1000000;
|
||||
|
@ -152,6 +153,10 @@ void MemoryDumper::GetMemoryState(MemoryType type, uint8_t *buffer)
|
|||
break;
|
||||
}
|
||||
|
||||
case MemoryType::NecDspMemory:
|
||||
GetMemoryState(MemoryType::DspProgramRom, buffer);
|
||||
break;
|
||||
|
||||
default:
|
||||
uint8_t* src = GetMemoryBuffer(type);
|
||||
if(src) {
|
||||
|
@ -198,6 +203,9 @@ void MemoryDumper::SetMemoryValue(MemoryType memoryType, uint32_t address, uint8
|
|||
case MemoryType::GameboyMemory: _gameboy->GetMemoryManager()->DebugWrite(address, value); break;
|
||||
case MemoryType::NesMemory: _nesConsole->DebugWrite(address, value); break;
|
||||
case MemoryType::NesPpuMemory: _nesConsole->DebugWriteVram(address, value); break;
|
||||
case MemoryType::NecDspMemory:
|
||||
SetMemoryValue(MemoryType::DspProgramRom, address, value, disableSideEffects);
|
||||
return;
|
||||
|
||||
default:
|
||||
uint8_t* src = GetMemoryBuffer(memoryType);
|
||||
|
@ -233,7 +241,8 @@ uint8_t MemoryDumper::GetMemoryValue(MemoryType memoryType, uint32_t address, bo
|
|||
case MemoryType::GameboyMemory: return _gameboy->GetMemoryManager()->DebugRead(address);
|
||||
case MemoryType::NesMemory: return _nesConsole->DebugRead(address);
|
||||
case MemoryType::NesPpuMemory: return _nesConsole->DebugReadVram(address);
|
||||
|
||||
case MemoryType::NecDspMemory: return GetMemoryValue(MemoryType::DspProgramRom, address);
|
||||
|
||||
default:
|
||||
uint8_t* src = GetMemoryBuffer(memoryType);
|
||||
return src ? src[address] : 0;
|
||||
|
|
|
@ -174,14 +174,14 @@ void GbDebugger::ProcessRead(uint32_t addr, uint8_t value, MemoryOperationType t
|
|||
}
|
||||
}
|
||||
|
||||
_debugger->ProcessBreakConditions(_step->StepCount == 0, GetBreakpointManager(), operation, addressInfo, breakSource);
|
||||
_debugger->ProcessBreakConditions(CpuType::Gameboy, _step->StepCount == 0, GetBreakpointManager(), operation, addressInfo, breakSource);
|
||||
}
|
||||
|
||||
void GbDebugger::ProcessWrite(uint32_t addr, uint8_t value, MemoryOperationType type)
|
||||
{
|
||||
AddressInfo addressInfo = _gameboy->GetAbsoluteAddress(addr);
|
||||
MemoryOperationInfo operation(addr, value, type, MemoryType::GameboyMemory);
|
||||
_debugger->ProcessBreakConditions(false, GetBreakpointManager(), operation, addressInfo);
|
||||
_debugger->ProcessBreakConditions(CpuType::Gameboy, false, GetBreakpointManager(), operation, addressInfo);
|
||||
|
||||
if(addressInfo.Type == MemoryType::GbWorkRam || addressInfo.Type == MemoryType::GbCartRam || addressInfo.Type == MemoryType::GbHighRam) {
|
||||
_disassembler->InvalidateCache(addressInfo, CpuType::Gameboy);
|
||||
|
@ -245,7 +245,7 @@ void GbDebugger::ProcessPpuRead(uint16_t addr, uint8_t value, MemoryType memoryT
|
|||
{
|
||||
MemoryOperationInfo operation(addr, value, MemoryOperationType::Read, memoryType);
|
||||
AddressInfo addressInfo { addr, memoryType };
|
||||
_debugger->ProcessBreakConditions(false, _breakpointManager.get(), operation, addressInfo);
|
||||
_debugger->ProcessBreakConditions(CpuType::Gameboy, false, _breakpointManager.get(), operation, addressInfo);
|
||||
_memoryAccessCounter->ProcessMemoryRead(addressInfo, _gameboy->GetMasterClock());
|
||||
}
|
||||
|
||||
|
@ -253,7 +253,7 @@ void GbDebugger::ProcessPpuWrite(uint16_t addr, uint8_t value, MemoryType memory
|
|||
{
|
||||
MemoryOperationInfo operation(addr, value, MemoryOperationType::Write, memoryType);
|
||||
AddressInfo addressInfo { addr, memoryType };
|
||||
_debugger->ProcessBreakConditions(false, _breakpointManager.get(), operation, addressInfo);
|
||||
_debugger->ProcessBreakConditions(CpuType::Gameboy, false, _breakpointManager.get(), operation, addressInfo);
|
||||
_memoryAccessCounter->ProcessMemoryWrite(addressInfo, _gameboy->GetMasterClock());
|
||||
}
|
||||
|
||||
|
@ -265,11 +265,11 @@ void GbDebugger::ProcessPpuCycle()
|
|||
|
||||
if(_step->HasRequest) {
|
||||
if(_step->HasScanlineBreakRequest() && _ppu->GetCycle() == 0 && _ppu->GetScanline() == _step->BreakScanline) {
|
||||
_debugger->SleepUntilResume(BreakSource::PpuStep);
|
||||
_debugger->SleepUntilResume(CpuType::Gameboy, BreakSource::PpuStep);
|
||||
} else if(_step->PpuStepCount > 0) {
|
||||
_step->PpuStepCount--;
|
||||
if(_step->PpuStepCount == 0) {
|
||||
_debugger->SleepUntilResume(BreakSource::PpuStep);
|
||||
_debugger->SleepUntilResume(CpuType::Gameboy, BreakSource::PpuStep);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -721,7 +721,7 @@ void GbPpu::Write(uint16_t addr, uint8_t value)
|
|||
if(!_state.LcdEnabled) {
|
||||
//Reset LCD to top of screen when it gets turned off
|
||||
if(_state.Mode != PpuMode::VBlank) {
|
||||
_emu->BreakIfDebugging(BreakSource::GbDisableLcdOutsideVblank);
|
||||
_emu->BreakIfDebugging(CpuType::Gameboy, BreakSource::GbDisableLcdOutsideVblank);
|
||||
SendFrame();
|
||||
}
|
||||
|
||||
|
@ -814,7 +814,7 @@ uint8_t GbPpu::ReadVram(uint16_t addr)
|
|||
_emu->ProcessPpuRead<CpuType::Gameboy>(vramAddr, _vram[vramAddr], MemoryType::GbVideoRam);
|
||||
return _vram[vramAddr];
|
||||
} else {
|
||||
_emu->BreakIfDebugging(BreakSource::GbInvalidVramAccess);
|
||||
_emu->BreakIfDebugging(CpuType::Gameboy, BreakSource::GbInvalidVramAccess);
|
||||
return 0xFF;
|
||||
}
|
||||
}
|
||||
|
@ -831,7 +831,7 @@ void GbPpu::WriteVram(uint16_t addr, uint8_t value)
|
|||
_emu->ProcessPpuWrite<CpuType::Gameboy>(vramAddr, value, MemoryType::GbVideoRam);
|
||||
_vram[vramAddr] = value;
|
||||
} else {
|
||||
_emu->BreakIfDebugging(BreakSource::GbInvalidVramAccess);
|
||||
_emu->BreakIfDebugging(CpuType::Gameboy, BreakSource::GbInvalidVramAccess);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -876,7 +876,7 @@ uint8_t GbPpu::ReadOam(uint8_t addr)
|
|||
_emu->ProcessPpuRead<CpuType::Gameboy>(addr, _oam[addr], MemoryType::GbSpriteRam);
|
||||
return _oam[addr];
|
||||
} else {
|
||||
_emu->BreakIfDebugging(BreakSource::GbInvalidOamAccess);
|
||||
_emu->BreakIfDebugging(CpuType::Gameboy, BreakSource::GbInvalidOamAccess);
|
||||
return 0xFF;
|
||||
}
|
||||
}
|
||||
|
@ -896,7 +896,7 @@ void GbPpu::WriteOam(uint8_t addr, uint8_t value, bool forDma)
|
|||
_oam[addr] = value;
|
||||
_emu->ProcessPpuWrite<CpuType::Gameboy>(addr, value, MemoryType::GbSpriteRam);
|
||||
} else {
|
||||
_emu->BreakIfDebugging(BreakSource::GbInvalidOamAccess);
|
||||
_emu->BreakIfDebugging(CpuType::Gameboy, BreakSource::GbInvalidOamAccess);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -169,7 +169,7 @@ void NesDebugger::ProcessRead(uint32_t addr, uint8_t value, MemoryOperationType
|
|||
}
|
||||
}
|
||||
|
||||
_debugger->ProcessBreakConditions(_step->StepCount == 0, _breakpointManager.get(), operation, addressInfo, breakSource);
|
||||
_debugger->ProcessBreakConditions(CpuType::Nes, _step->StepCount == 0, _breakpointManager.get(), operation, addressInfo, breakSource);
|
||||
}
|
||||
|
||||
void NesDebugger::ProcessWrite(uint32_t addr, uint8_t value, MemoryOperationType type)
|
||||
|
@ -190,7 +190,7 @@ void NesDebugger::ProcessWrite(uint32_t addr, uint8_t value, MemoryOperationType
|
|||
|
||||
_memoryAccessCounter->ProcessMemoryWrite(addressInfo, _cpu->GetCycleCount());
|
||||
|
||||
_debugger->ProcessBreakConditions(false, _breakpointManager.get(), operation, addressInfo);
|
||||
_debugger->ProcessBreakConditions(CpuType::Nes, false, _breakpointManager.get(), operation, addressInfo);
|
||||
}
|
||||
|
||||
void NesDebugger::Run()
|
||||
|
@ -238,7 +238,7 @@ void NesDebugger::ProcessPpuRead(uint16_t addr, uint8_t value, MemoryType memory
|
|||
if(DebugUtilities::IsRelativeMemory(memoryType)) {
|
||||
_mapper->GetPpuAbsoluteAddress(addr, addressInfo);
|
||||
}
|
||||
_debugger->ProcessBreakConditions(false, _breakpointManager.get(), operation, addressInfo);
|
||||
_debugger->ProcessBreakConditions(CpuType::Nes, false, _breakpointManager.get(), operation, addressInfo);
|
||||
_memoryAccessCounter->ProcessMemoryRead(addressInfo, _console->GetMasterClock());
|
||||
}
|
||||
|
||||
|
@ -249,7 +249,7 @@ void NesDebugger::ProcessPpuWrite(uint16_t addr, uint8_t value, MemoryType memor
|
|||
if(DebugUtilities::IsRelativeMemory(memoryType)) {
|
||||
_mapper->GetPpuAbsoluteAddress(addr, addressInfo);
|
||||
}
|
||||
_debugger->ProcessBreakConditions(false, _breakpointManager.get(), operation, addressInfo);
|
||||
_debugger->ProcessBreakConditions(CpuType::Nes, false, _breakpointManager.get(), operation, addressInfo);
|
||||
_memoryAccessCounter->ProcessMemoryWrite(addressInfo, _console->GetMasterClock());
|
||||
}
|
||||
|
||||
|
@ -261,11 +261,11 @@ void NesDebugger::ProcessPpuCycle()
|
|||
|
||||
if(_step->HasRequest) {
|
||||
if(_step->HasScanlineBreakRequest() && _ppu->GetCurrentCycle() == 0 && _ppu->GetCurrentScanline() == _step->BreakScanline) {
|
||||
_debugger->SleepUntilResume(BreakSource::PpuStep);
|
||||
_debugger->SleepUntilResume(CpuType::Nes, BreakSource::PpuStep);
|
||||
} else if(_step->PpuStepCount > 0) {
|
||||
_step->PpuStepCount--;
|
||||
if(_step->PpuStepCount == 0) {
|
||||
_debugger->SleepUntilResume(BreakSource::PpuStep);
|
||||
_debugger->SleepUntilResume(CpuType::Nes, BreakSource::PpuStep);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -294,7 +294,7 @@ uint16_t NesCpu::FetchOperand()
|
|||
if(_console->GetNesConfig().BreakOnCrash) {
|
||||
//When "Break on Crash" is enabled, open the debugger and break immediately if a crash occurs
|
||||
_emu->InitDebugger();
|
||||
_emu->BreakIfDebugging(BreakSource::BreakOnCpuCrash);
|
||||
_emu->BreakIfDebugging(CpuType::Nes, BreakSource::BreakOnCpuCrash);
|
||||
}
|
||||
|
||||
if(_console->GetRomFormat() == RomFormat::Nsf) {
|
||||
|
|
|
@ -1025,7 +1025,7 @@ template<class T> uint8_t NesPpu<T>::ReadSpriteRam(uint8_t addr)
|
|||
if(_mask.SpritesEnabled) {
|
||||
if(_settings->CheckDebuggerFlag(DebuggerFlags::NesBreakOnDecayedOamRead)) {
|
||||
//When debugging with the break on decayed oam read flag turned on, break (only if sprite rendering is enabled to avoid false positives)
|
||||
_emu->BreakIfDebugging(BreakSource::NesBreakOnDecayedOamRead);
|
||||
_emu->BreakIfDebugging(CpuType::Nes, BreakSource::NesBreakOnDecayedOamRead);
|
||||
}
|
||||
}
|
||||
//If this 8-byte row hasn't been read/written to in over 3000 cpu cycles (~1.7ms), return 0x10 to simulate decay
|
||||
|
@ -1336,12 +1336,12 @@ template<class T> void NesPpu<T>::UpdateState()
|
|||
if(_cycle == 257) {
|
||||
_videoRamAddr &= _updateVramAddr;
|
||||
if(_settings->CheckDebuggerFlag(DebuggerFlags::NesBreakOnPpu2006ScrollGlitch)) {
|
||||
_emu->BreakIfDebugging(BreakSource::NesBreakOnPpu2006ScrollGlitch);
|
||||
_emu->BreakIfDebugging(CpuType::Nes, BreakSource::NesBreakOnPpu2006ScrollGlitch);
|
||||
}
|
||||
} else if(_cycle > 0 && (_cycle & 0x07) == 0 && (_cycle <= 256 || _cycle > 320)) {
|
||||
_videoRamAddr = (_updateVramAddr & ~0x41F) | (_videoRamAddr & _updateVramAddr & 0x41F);
|
||||
if(_settings->CheckDebuggerFlag(DebuggerFlags::NesBreakOnPpu2006ScrollGlitch)) {
|
||||
_emu->BreakIfDebugging(BreakSource::NesBreakOnPpu2006ScrollGlitch);
|
||||
_emu->BreakIfDebugging(CpuType::Nes, BreakSource::NesBreakOnPpu2006ScrollGlitch);
|
||||
}
|
||||
} else {
|
||||
_videoRamAddr = _updateVramAddr;
|
||||
|
|
|
@ -80,14 +80,14 @@ void Cx4Debugger::ProcessRead(uint32_t addr, uint8_t value, MemoryOperationType
|
|||
_memoryAccessCounter->ProcessMemoryRead(addressInfo, _memoryManager->GetMasterClock());
|
||||
}
|
||||
|
||||
_debugger->ProcessBreakConditions(_step->StepCount == 0, GetBreakpointManager(), operation, addressInfo);
|
||||
_debugger->ProcessBreakConditions(CpuType::Cx4, _step->StepCount == 0, GetBreakpointManager(), operation, addressInfo);
|
||||
}
|
||||
|
||||
void Cx4Debugger::ProcessWrite(uint32_t addr, uint8_t value, MemoryOperationType type)
|
||||
{
|
||||
AddressInfo addressInfo = _cx4->GetMemoryMappings()->GetAbsoluteAddress(addr);
|
||||
MemoryOperationInfo operation(addr, value, type, MemoryType::Cx4Memory);
|
||||
_debugger->ProcessBreakConditions(_step->StepCount == 0, GetBreakpointManager(), operation, addressInfo);
|
||||
_debugger->ProcessBreakConditions(CpuType::Cx4, _step->StepCount == 0, GetBreakpointManager(), operation, addressInfo);
|
||||
_memoryAccessCounter->ProcessMemoryWrite(addressInfo, _memoryManager->GetMasterClock());
|
||||
if(_traceLogger->IsEnabled()) {
|
||||
_traceLogger->LogNonExec(operation);
|
||||
|
@ -126,7 +126,7 @@ BreakpointManager* Cx4Debugger::GetBreakpointManager()
|
|||
|
||||
CallstackManager* Cx4Debugger::GetCallstackManager()
|
||||
{
|
||||
throw std::runtime_error("Call stack not supported for CX4");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
IAssembler* Cx4Debugger::GetAssembler()
|
||||
|
|
|
@ -83,14 +83,14 @@ void GsuDebugger::ProcessRead(uint32_t addr, uint8_t value, MemoryOperationType
|
|||
_memoryAccessCounter->ProcessMemoryRead(addressInfo, _memoryManager->GetMasterClock());
|
||||
}
|
||||
|
||||
_debugger->ProcessBreakConditions(_step->StepCount == 0, GetBreakpointManager(), operation, addressInfo);
|
||||
_debugger->ProcessBreakConditions(CpuType::Gsu, _step->StepCount == 0, GetBreakpointManager(), operation, addressInfo);
|
||||
}
|
||||
|
||||
void GsuDebugger::ProcessWrite(uint32_t addr, uint8_t value, MemoryOperationType type)
|
||||
{
|
||||
AddressInfo addressInfo = _gsu->GetMemoryMappings()->GetAbsoluteAddress(addr);
|
||||
MemoryOperationInfo operation(addr, value, type, MemoryType::GsuMemory);
|
||||
_debugger->ProcessBreakConditions(false, GetBreakpointManager(), operation, addressInfo);
|
||||
_debugger->ProcessBreakConditions(CpuType::Gsu, false, GetBreakpointManager(), operation, addressInfo);
|
||||
|
||||
if(_traceLogger->IsEnabled()) {
|
||||
_traceLogger->LogNonExec(operation);
|
||||
|
@ -129,7 +129,7 @@ BreakpointManager* GsuDebugger::GetBreakpointManager()
|
|||
|
||||
CallstackManager* GsuDebugger::GetCallstackManager()
|
||||
{
|
||||
throw std::runtime_error("Call stack not supported for GSU");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
IAssembler* GsuDebugger::GetAssembler()
|
||||
|
|
|
@ -54,14 +54,14 @@ void NecDspDebugger::ProcessRead(uint32_t addr, uint8_t value, MemoryOperationTy
|
|||
_step->ProcessCpuExec();
|
||||
}
|
||||
|
||||
_debugger->ProcessBreakConditions(_step->StepCount == 0, GetBreakpointManager(), operation, addressInfo);
|
||||
_debugger->ProcessBreakConditions(CpuType::NecDsp, _step->StepCount == 0, GetBreakpointManager(), operation, addressInfo);
|
||||
}
|
||||
|
||||
void NecDspDebugger::ProcessWrite(uint32_t addr, uint8_t value, MemoryOperationType type)
|
||||
{
|
||||
AddressInfo addressInfo { (int32_t)addr, MemoryType::DspDataRam }; //Writes never affect the DSP ROM
|
||||
MemoryOperationInfo operation(addr, value, type, MemoryType::NecDspMemory);
|
||||
_debugger->ProcessBreakConditions(false, GetBreakpointManager(), operation, addressInfo);
|
||||
_debugger->ProcessBreakConditions(CpuType::NecDsp, false, GetBreakpointManager(), operation, addressInfo);
|
||||
|
||||
if(_traceLogger->IsEnabled()) {
|
||||
_traceLogger->LogNonExec(operation);
|
||||
|
@ -95,7 +95,7 @@ void NecDspDebugger::Step(int32_t stepCount, StepType type)
|
|||
|
||||
CallstackManager* NecDspDebugger::GetCallstackManager()
|
||||
{
|
||||
throw std::runtime_error("Callstack not supported for NEC DSP");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
BreakpointManager* NecDspDebugger::GetBreakpointManager()
|
||||
|
|
|
@ -57,6 +57,9 @@ SnesDebugger::SnesDebugger(Debugger* debugger, CpuType cpuType)
|
|||
|
||||
if(cpuType == CpuType::Snes) {
|
||||
_codeDataLogger.reset(new CodeDataLogger(MemoryType::SnesPrgRom, console->GetCartridge()->DebugGetPrgRomSize(), CpuType::Snes));
|
||||
_cdl = _codeDataLogger.get();
|
||||
} else {
|
||||
_cdl = _debugger->GetCodeDataLogger(CpuType::Snes);
|
||||
}
|
||||
|
||||
_eventManager.reset(new SnesEventManager(debugger, _cpu, console->GetPpu(), _memoryManager, console->GetDmaController()));
|
||||
|
@ -105,7 +108,7 @@ void SnesDebugger::ProcessRead(uint32_t addr, uint8_t value, MemoryOperationType
|
|||
if(_prevOpCode == 0x20 || _prevOpCode == 0x22 || _prevOpCode == 0xFC) {
|
||||
flags |= CdlFlags::SubEntryPoint;
|
||||
}
|
||||
_codeDataLogger->SetFlags(addressInfo.Address, flags);
|
||||
_cdl->SetFlags(addressInfo.Address, flags);
|
||||
}
|
||||
if(_traceLogger->IsEnabled() || _settings->CheckDebuggerFlag(_debuggerEnabledFlag)) {
|
||||
_disassembler->BuildCache(addressInfo, cpuFlags, _cpuType);
|
||||
|
@ -162,7 +165,7 @@ void SnesDebugger::ProcessRead(uint32_t addr, uint8_t value, MemoryOperationType
|
|||
_memoryAccessCounter->ProcessMemoryExec(addressInfo, _memoryManager->GetMasterClock());
|
||||
} else if(type == MemoryOperationType::ExecOperand) {
|
||||
if(addressInfo.Type == MemoryType::SnesPrgRom && addressInfo.Address >= 0) {
|
||||
_codeDataLogger->SetFlags(addressInfo.Address, CdlFlags::Code | (state.PS & (CdlFlags::IndexMode8 | CdlFlags::MemoryMode8)));
|
||||
_cdl->SetFlags(addressInfo.Address, CdlFlags::Code | (state.PS & (CdlFlags::IndexMode8 | CdlFlags::MemoryMode8)));
|
||||
}
|
||||
if(_traceLogger->IsEnabled()) {
|
||||
_traceLogger->LogNonExec(operation);
|
||||
|
@ -170,7 +173,7 @@ void SnesDebugger::ProcessRead(uint32_t addr, uint8_t value, MemoryOperationType
|
|||
_memoryAccessCounter->ProcessMemoryExec(addressInfo, _memoryManager->GetMasterClock());
|
||||
} else {
|
||||
if(addressInfo.Type == MemoryType::SnesPrgRom && addressInfo.Address >= 0) {
|
||||
_codeDataLogger->SetFlags(addressInfo.Address, CdlFlags::Data | (state.PS & (CdlFlags::IndexMode8 | CdlFlags::MemoryMode8)));
|
||||
_cdl->SetFlags(addressInfo.Address, CdlFlags::Data | (state.PS & (CdlFlags::IndexMode8 | CdlFlags::MemoryMode8)));
|
||||
}
|
||||
if(_traceLogger->IsEnabled()) {
|
||||
_traceLogger->LogNonExec(operation);
|
||||
|
@ -191,7 +194,7 @@ void SnesDebugger::ProcessRead(uint32_t addr, uint8_t value, MemoryOperationType
|
|||
}
|
||||
}
|
||||
|
||||
_debugger->ProcessBreakConditions(_step->StepCount == 0, _breakpointManager.get(), operation, addressInfo, breakSource);
|
||||
_debugger->ProcessBreakConditions(_cpuType, _step->StepCount == 0, _breakpointManager.get(), operation, addressInfo, breakSource);
|
||||
}
|
||||
|
||||
void SnesDebugger::ProcessWrite(uint32_t addr, uint8_t value, MemoryOperationType type)
|
||||
|
@ -212,7 +215,7 @@ void SnesDebugger::ProcessWrite(uint32_t addr, uint8_t value, MemoryOperationTyp
|
|||
|
||||
_memoryAccessCounter->ProcessMemoryWrite(addressInfo, _memoryManager->GetMasterClock());
|
||||
|
||||
_debugger->ProcessBreakConditions(false, _breakpointManager.get(), operation, addressInfo);
|
||||
_debugger->ProcessBreakConditions(_cpuType, false, _breakpointManager.get(), operation, addressInfo);
|
||||
}
|
||||
|
||||
void SnesDebugger::Run()
|
||||
|
@ -262,7 +265,7 @@ void SnesDebugger::ProcessPpuRead(uint16_t addr, uint8_t value, MemoryType memor
|
|||
{
|
||||
MemoryOperationInfo operation(addr, value, MemoryOperationType::Read, memoryType);
|
||||
AddressInfo addressInfo { addr, memoryType };
|
||||
_debugger->ProcessBreakConditions(false, _breakpointManager.get(), operation, addressInfo);
|
||||
_debugger->ProcessBreakConditions(CpuType::Snes, false, _breakpointManager.get(), operation, addressInfo);
|
||||
_memoryAccessCounter->ProcessMemoryRead(addressInfo, _console->GetMasterClock());
|
||||
}
|
||||
|
||||
|
@ -270,31 +273,34 @@ void SnesDebugger::ProcessPpuWrite(uint16_t addr, uint8_t value, MemoryType memo
|
|||
{
|
||||
MemoryOperationInfo operation(addr, value, MemoryOperationType::Write, memoryType);
|
||||
AddressInfo addressInfo { addr, memoryType };
|
||||
_debugger->ProcessBreakConditions(false, _breakpointManager.get(), operation, addressInfo);
|
||||
_debugger->ProcessBreakConditions(CpuType::Snes, false, _breakpointManager.get(), operation, addressInfo);
|
||||
_memoryAccessCounter->ProcessMemoryWrite(addressInfo, _console->GetMasterClock());
|
||||
}
|
||||
|
||||
void SnesDebugger::ProcessPpuCycle()
|
||||
{
|
||||
//Catch up SPC/DSP as needed (if we're tracing or debugging those particular CPUs)
|
||||
if(_spcTraceLogger->IsEnabled()) {
|
||||
if(_spcTraceLogger->IsEnabled() || _settings->CheckDebuggerFlag(DebuggerFlags::SpcDebuggerEnabled)) {
|
||||
_spc->Run();
|
||||
}
|
||||
if(_dspTraceLogger && _dspTraceLogger->IsEnabled()) {
|
||||
if(_dspTraceLogger && _dspTraceLogger->IsEnabled() || _settings->CheckDebuggerFlag(DebuggerFlags::NecDspDebuggerEnabled)) {
|
||||
_cart->RunCoprocessors();
|
||||
} else if(_settings->CheckDebuggerFlag(DebuggerFlags::GbDebuggerEnabled)) {
|
||||
_cart->RunCoprocessors();
|
||||
}
|
||||
|
||||
|
||||
if(_ppuTools->HasOpenedViewer()) {
|
||||
_ppuTools->UpdateViewers(_ppu->GetScanline(), _ppu->GetCycle());
|
||||
}
|
||||
|
||||
if(_step->HasRequest) {
|
||||
if(_step->HasScanlineBreakRequest() && _ppu->GetScanline() == _step->BreakScanline && _memoryManager->GetHClock() == 0) {
|
||||
_debugger->SleepUntilResume(BreakSource::PpuStep);
|
||||
_debugger->SleepUntilResume(CpuType::Snes, BreakSource::PpuStep);
|
||||
} else if(_step->PpuStepCount > 0) {
|
||||
_step->PpuStepCount--;
|
||||
if(_step->PpuStepCount == 0) {
|
||||
_debugger->SleepUntilResume(BreakSource::PpuStep);
|
||||
_debugger->SleepUntilResume(CpuType::Snes, BreakSource::PpuStep);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -341,11 +347,7 @@ BaseEventManager* SnesDebugger::GetEventManager()
|
|||
|
||||
CodeDataLogger* SnesDebugger::GetCodeDataLogger()
|
||||
{
|
||||
if(_cpuType == CpuType::Sa1) {
|
||||
return _debugger->GetCodeDataLogger(CpuType::Snes);
|
||||
} else {
|
||||
return _codeDataLogger.get();
|
||||
}
|
||||
return _cdl;
|
||||
}
|
||||
|
||||
PpuTools* SnesDebugger::GetPpuTools()
|
||||
|
|
|
@ -41,6 +41,7 @@ class SnesDebugger final : public IDebugger
|
|||
Spc* _spc;
|
||||
SnesPpu* _ppu;
|
||||
MemoryMappings* _memoryMappings;
|
||||
CodeDataLogger* _cdl;
|
||||
|
||||
unique_ptr<CodeDataLogger> _codeDataLogger;
|
||||
unique_ptr<BaseEventManager> _eventManager;
|
||||
|
|
|
@ -107,14 +107,14 @@ void SpcDebugger::ProcessRead(uint32_t addr, uint8_t value, MemoryOperationType
|
|||
}
|
||||
}
|
||||
|
||||
_debugger->ProcessBreakConditions(_step->StepCount == 0, GetBreakpointManager(), operation, addressInfo, breakSource);
|
||||
_debugger->ProcessBreakConditions(CpuType::Spc, _step->StepCount == 0, GetBreakpointManager(), operation, addressInfo, breakSource);
|
||||
}
|
||||
|
||||
void SpcDebugger::ProcessWrite(uint32_t addr, uint8_t value, MemoryOperationType type)
|
||||
{
|
||||
AddressInfo addressInfo { (int32_t)addr, MemoryType::SpcRam }; //Writes never affect the SPC ROM
|
||||
MemoryOperationInfo operation(addr, value, type, MemoryType::SpcMemory);
|
||||
_debugger->ProcessBreakConditions(false, GetBreakpointManager(), operation, addressInfo);
|
||||
_debugger->ProcessBreakConditions(CpuType::Spc, false, GetBreakpointManager(), operation, addressInfo);
|
||||
|
||||
_disassembler->InvalidateCache(addressInfo, CpuType::Spc);
|
||||
|
||||
|
|
|
@ -985,10 +985,10 @@ void Emulator::AddDebugEvent(DebugEventType evtType)
|
|||
}
|
||||
}
|
||||
|
||||
void Emulator::BreakIfDebugging(BreakSource source)
|
||||
void Emulator::BreakIfDebugging(CpuType sourceCpu, BreakSource source)
|
||||
{
|
||||
if(_debugger) {
|
||||
_debugger->BreakImmediately(source);
|
||||
_debugger->BreakImmediately(sourceCpu, source);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -273,7 +273,7 @@ public:
|
|||
template<CpuType type> void ProcessInterrupt(uint32_t originalPc, uint32_t currentPc, bool forNmi);
|
||||
void ProcessEvent(EventType type);
|
||||
template<CpuType cpuType> void AddDebugEvent(DebugEventType evtType);
|
||||
void BreakIfDebugging(BreakSource source);
|
||||
void BreakIfDebugging(CpuType sourceCpu, BreakSource source);
|
||||
};
|
||||
|
||||
enum class HashType
|
||||
|
|
|
@ -80,9 +80,20 @@ extern "C"
|
|||
|
||||
DllExport void __stdcall SetBreakpoints(Breakpoint breakpoints[], uint32_t length) { WithDebugger(void, SetBreakpoints(breakpoints, length)); }
|
||||
DllExport int32_t __stdcall EvaluateExpression(const char* expression, CpuType cpuType, EvalResultType *resultType, bool useCache) { return WithDebugger(int32_t, EvaluateExpression(expression, cpuType, *resultType, useCache)); }
|
||||
DllExport void __stdcall GetCallstack(CpuType cpuType, StackFrameInfo *callstackArray, uint32_t &callstackSize) { WithDebugger(void, GetCallstackManager(cpuType)->GetCallstack(callstackArray, callstackSize)); }
|
||||
DllExport void __stdcall GetProfilerData(CpuType cpuType, ProfiledFunction* profilerData, uint32_t& functionCount) { WithDebugger(void, GetCallstackManager(cpuType)->GetProfiler()->GetProfilerData(profilerData, functionCount)); }
|
||||
DllExport void __stdcall ResetProfiler(CpuType cpuType) { WithDebugger(void, GetCallstackManager(cpuType)->GetProfiler()->Reset()); }
|
||||
|
||||
DllExport void __stdcall GetCallstack(CpuType cpuType, StackFrameInfo *callstackArray, uint32_t &callstackSize)
|
||||
{
|
||||
callstackSize = 0;
|
||||
WithToolVoid(GetCallstackManager(cpuType), GetCallstack(callstackArray, callstackSize));
|
||||
}
|
||||
|
||||
DllExport void __stdcall GetProfilerData(CpuType cpuType, ProfiledFunction* profilerData, uint32_t& functionCount)
|
||||
{
|
||||
functionCount = 0;
|
||||
WithToolVoid(GetCallstackManager(cpuType), GetProfiler()->GetProfilerData(profilerData, functionCount));
|
||||
}
|
||||
|
||||
DllExport void __stdcall ResetProfiler(CpuType cpuType) { WithToolVoid(GetCallstackManager(cpuType), GetProfiler()->Reset()); }
|
||||
|
||||
DllExport void __stdcall GetConsoleState(BaseState& state, ConsoleType consoleType) { WithDebugger(void, GetConsoleState(state, consoleType)); }
|
||||
DllExport void __stdcall GetCpuState(BaseState& state, CpuType cpuType) { WithDebugger(void, GetCpuState(state, cpuType)); }
|
||||
|
|
Before Width: | Height: | Size: 643 B After Width: | Height: | Size: 643 B |
|
@ -11,6 +11,7 @@ namespace Mesen.Debugger
|
|||
{
|
||||
public static uint GetProgramCounter(CpuType cpuType)
|
||||
{
|
||||
//TODO move to C++ core
|
||||
switch(cpuType) {
|
||||
case CpuType.Snes:
|
||||
case CpuType.Sa1: {
|
||||
|
@ -33,6 +34,21 @@ namespace Mesen.Debugger
|
|||
return (uint)state.PC;
|
||||
}
|
||||
|
||||
case CpuType.NecDsp: {
|
||||
NecDspState state = DebugApi.GetCpuState<NecDspState>(cpuType);
|
||||
return state.PC;
|
||||
}
|
||||
|
||||
case CpuType.Gsu: {
|
||||
GsuState state = DebugApi.GetCpuState<GsuState>(cpuType);
|
||||
return state.R[15];
|
||||
}
|
||||
|
||||
case CpuType.Cx4: {
|
||||
Cx4State state = DebugApi.GetCpuState<Cx4State>(cpuType);
|
||||
return (uint)(state.Cache.Address[state.Cache.Page] + (state.PC * 2)) & 0xFFFFFF;
|
||||
}
|
||||
|
||||
default: throw new Exception("Invalid cpu type");
|
||||
}
|
||||
|
||||
|
|
|
@ -356,5 +356,15 @@ namespace Mesen.Debugger.Utilities
|
|||
|
||||
[IconFile("SpcDebugger")]
|
||||
OpenSpcDebugger,
|
||||
[IconFile("Cx4Debugger")]
|
||||
OpenCx4Debugger,
|
||||
[IconFile("NecDspDebugger")]
|
||||
OpenNecDspDebugger,
|
||||
[IconFile("GsuDebugger")]
|
||||
OpenGsuDebugger,
|
||||
[IconFile("Sa1Debugger")]
|
||||
OpenSa1Debugger,
|
||||
[IconFile("GameboyDebugger")]
|
||||
OpenGameboyDebugger,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using Avalonia.Controls;
|
||||
using Avalonia.Media.Imaging;
|
||||
using Dock.Model.Controls;
|
||||
using Dock.Model.Core;
|
||||
using Dock.Model.ReactiveUI.Controls;
|
||||
|
@ -24,6 +25,10 @@ namespace Mesen.Debugger.ViewModels
|
|||
{
|
||||
public class DebuggerWindowViewModel : DisposableViewModel
|
||||
{
|
||||
[Reactive] public string Title { get; private set; } = "Debugger";
|
||||
[Reactive] public WindowIcon? Icon { get; private set; } = null;
|
||||
[Reactive] public bool IsMainCpuDebugger { get; private set; } = true;
|
||||
|
||||
[Reactive] public DebuggerConfig Config { get; private set; }
|
||||
|
||||
[Reactive] public DebuggerOptionsViewModel Options { get; private set; }
|
||||
|
@ -61,16 +66,24 @@ namespace Mesen.Debugger.ViewModels
|
|||
|
||||
if(Design.IsDesignMode) {
|
||||
CpuType = CpuType.Snes;
|
||||
} else if(cpuType != null) {
|
||||
CpuType = cpuType.Value;
|
||||
} else {
|
||||
RomInfo romInfo = EmuApi.GetRomInfo();
|
||||
CpuType = romInfo.ConsoleType.GetMainCpuType();
|
||||
if(cpuType != null) {
|
||||
CpuType = cpuType.Value;
|
||||
if(romInfo.ConsoleType.GetMainCpuType() != CpuType) {
|
||||
Title = ResourceHelper.GetEnumText(CpuType) + " Debugger";
|
||||
Icon = new WindowIcon(ImageUtilities.BitmapFromAsset("Assets/" + CpuType.ToString() + "Debugger.png"));
|
||||
IsMainCpuDebugger = false;
|
||||
}
|
||||
} else {
|
||||
CpuType = romInfo.ConsoleType.GetMainCpuType();
|
||||
Icon = new WindowIcon(ImageUtilities.BitmapFromAsset("Assets/Debugger.png"));
|
||||
|
||||
//TODO temporary - try to load DBG file if it exists
|
||||
string dbgPath = Path.ChangeExtension(romInfo.RomPath, ".dbg");
|
||||
if(File.Exists(dbgPath)) {
|
||||
SourceView = new(DbgImporter.Import(CpuType, romInfo.Format, dbgPath, true, true), CpuType);
|
||||
//TODO temporary - try to load DBG file if it exists
|
||||
string dbgPath = Path.ChangeExtension(romInfo.RomPath, ".dbg");
|
||||
if(File.Exists(dbgPath)) {
|
||||
SourceView = new(DbgImporter.Import(CpuType, romInfo.Format, dbgPath, true, true), CpuType);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -433,7 +446,17 @@ namespace Mesen.Debugger.ViewModels
|
|||
|
||||
private void Step(int instructionCount, StepType type)
|
||||
{
|
||||
DebugApi.Step(CpuType, instructionCount, type);
|
||||
switch(type) {
|
||||
case StepType.PpuStep:
|
||||
case StepType.PpuScanline:
|
||||
case StepType.PpuFrame:
|
||||
DebugApi.Step(CpuType.GetConsoleType().GetMainCpuType(), instructionCount, type);
|
||||
break;
|
||||
|
||||
default:
|
||||
DebugApi.Step(CpuType, instructionCount, type);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,9 +17,9 @@
|
|||
mc:Ignorable="d" d:DesignWidth="400" d:DesignHeight="500"
|
||||
x:Class="Mesen.Debugger.Windows.DebuggerWindow"
|
||||
x:DataType="vm:DebuggerWindowViewModel"
|
||||
Icon="/Assets/Debugger.png"
|
||||
Title="{CompiledBinding Title}"
|
||||
Icon="{CompiledBinding Icon}"
|
||||
Width="400" Height="500"
|
||||
Title="Debugger"
|
||||
x:Name="Debugger"
|
||||
>
|
||||
<Design.DataContext>
|
||||
|
|
|
@ -11,6 +11,7 @@ using Mesen.Config;
|
|||
using System.Runtime.InteropServices;
|
||||
using Mesen.Debugger.Utilities;
|
||||
using Mesen.Utilities;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Mesen.Debugger.Windows
|
||||
{
|
||||
|
@ -70,12 +71,16 @@ namespace Mesen.Debugger.Windows
|
|||
|
||||
public void ProcessNotification(NotificationEventArgs e)
|
||||
{
|
||||
if(_model.Disposed) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch(e.NotificationType) {
|
||||
case ConsoleNotificationType.CodeBreak:
|
||||
BreakEvent evt = Marshal.PtrToStructure<BreakEvent>(e.Parameter);
|
||||
Dispatcher.UIThread.Post(() => {
|
||||
_model.UpdateDebugger(true, evt);
|
||||
if(_model.Config.BringToFrontOnBreak) {
|
||||
if(_model.Config.BringToFrontOnBreak && evt.SourceCpu == _model.CpuType && evt.Source != BreakSource.PpuStep) {
|
||||
Activate();
|
||||
}
|
||||
});
|
||||
|
@ -95,14 +100,26 @@ namespace Mesen.Debugger.Windows
|
|||
break;
|
||||
|
||||
case ConsoleNotificationType.GameLoaded:
|
||||
if(!EmuApi.GetRomInfo().CpuTypes.Contains(_model.CpuType)) {
|
||||
_model.Dispose();
|
||||
_model = new DebuggerWindowViewModel(null);
|
||||
|
||||
Dispatcher.UIThread.Post(() => {
|
||||
_model.InitializeMenu(this);
|
||||
DataContext = _model;
|
||||
});
|
||||
RomInfo romInfo = EmuApi.GetRomInfo();
|
||||
HashSet<CpuType> cpuTypes = romInfo.CpuTypes;
|
||||
if(!cpuTypes.Contains(_model.CpuType)) {
|
||||
if(!_model.IsMainCpuDebugger || _model.CpuType == romInfo.ConsoleType.GetMainCpuType()) {
|
||||
//Close the debugger window if this is not the main cpu debugger,
|
||||
//and this cpu is not supported (or it's the main cpu type for this game)
|
||||
_model.Dispose();
|
||||
Dispatcher.UIThread.Post(() => {
|
||||
Dispatcher.UIThread.RunJobs();
|
||||
Close();
|
||||
});
|
||||
} else {
|
||||
_model.Dispose();
|
||||
_model = new DebuggerWindowViewModel(null);
|
||||
|
||||
Dispatcher.UIThread.Post(() => {
|
||||
_model.InitializeMenu(this);
|
||||
DataContext = _model;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if(_model.Config.BreakOnPowerCycleReset) {
|
||||
|
|
|
@ -937,6 +937,7 @@ namespace Mesen.Interop
|
|||
public struct BreakEvent
|
||||
{
|
||||
public BreakSource Source;
|
||||
public CpuType SourceCpu;
|
||||
public MemoryOperationInfo Operation;
|
||||
public Int32 BreakpointId;
|
||||
}
|
||||
|
|
|
@ -273,7 +273,7 @@ namespace Mesen.Interop
|
|||
[MarshalAs(UnmanagedType.I1)] public bool Sign1;
|
||||
}
|
||||
|
||||
public struct NecDspState
|
||||
public struct NecDspState : BaseState
|
||||
{
|
||||
public UInt16 A;
|
||||
public NecDspAccFlags FlagsA;
|
||||
|
@ -320,7 +320,7 @@ namespace Mesen.Interop
|
|||
public byte ValidBits;
|
||||
}
|
||||
|
||||
public struct GsuState
|
||||
public struct GsuState : BaseState
|
||||
{
|
||||
public UInt64 CycleCount;
|
||||
|
||||
|
@ -415,7 +415,7 @@ namespace Mesen.Interop
|
|||
public UInt32 Address;
|
||||
}
|
||||
|
||||
public struct Cx4State
|
||||
public struct Cx4State : BaseState
|
||||
{
|
||||
public UInt64 CycleCount;
|
||||
public UInt16 PB;
|
||||
|
|
|
@ -1756,6 +1756,7 @@ x == [$150] || y == [10]
|
|||
<Value ID="SpcMemory">SPC Memory</Value>
|
||||
<Value ID="Sa1Memory">SA-1 Memory</Value>
|
||||
<Value ID="GsuMemory">GSU Memory</Value>
|
||||
<Value ID="NecDspMemory">DSP-n Memory</Value>
|
||||
<Value ID="Cx4Memory">CX4 Memory</Value>
|
||||
<Value ID="SnesPrgRom">PRG ROM</Value>
|
||||
<Value ID="SnesWorkRam">Work RAM</Value>
|
||||
|
|
|
@ -66,8 +66,8 @@
|
|||
<None Remove="Assets\Font.png" />
|
||||
<None Remove="Assets\Fullscreen.png" />
|
||||
<None Remove="Assets\Function.png" />
|
||||
<None Remove="Assets\GameboyDebugger.png" />
|
||||
<None Remove="Assets\GameboyIcon.png" />
|
||||
<None Remove="Assets\GbDebugger.png" />
|
||||
<None Remove="Assets\GsuDebugger.png" />
|
||||
<None Remove="Assets\HdPack.png" />
|
||||
<None Remove="Assets\Help.png" />
|
||||
|
@ -446,7 +446,7 @@
|
|||
<AvaloniaResource Include="Assets\Fullscreen.png" />
|
||||
<AvaloniaResource Include="Assets\Function.png" />
|
||||
<AvaloniaResource Include="Assets\GameboyIcon.png" />
|
||||
<AvaloniaResource Include="Assets\GbDebugger.png" />
|
||||
<AvaloniaResource Include="Assets\GameboyDebugger.png" />
|
||||
<AvaloniaResource Include="Assets\GsuDebugger.png" />
|
||||
<AvaloniaResource Include="Assets\HdPack.png" />
|
||||
<AvaloniaResource Include="Assets\Help.png" />
|
||||
|
|
|
@ -109,6 +109,36 @@ namespace Mesen.ViewModels
|
|||
IsVisible = () => MainWindow.RomInfo.CpuTypes.Contains(CpuType.Spc),
|
||||
OnClick = () => DebugWindowManager.OpenDebugWindow(() => new DebuggerWindow(CpuType.Spc))
|
||||
},
|
||||
new ContextMenuAction() {
|
||||
ActionType = ActionType.OpenCx4Debugger,
|
||||
Shortcut = () => ConfigManager.Config.Debug.Shortcuts.Get(DebuggerShortcut.OpenCx4Debugger),
|
||||
IsVisible = () => MainWindow.RomInfo.CpuTypes.Contains(CpuType.Cx4),
|
||||
OnClick = () => DebugWindowManager.OpenDebugWindow(() => new DebuggerWindow(CpuType.Cx4))
|
||||
},
|
||||
new ContextMenuAction() {
|
||||
ActionType = ActionType.OpenNecDspDebugger,
|
||||
Shortcut = () => ConfigManager.Config.Debug.Shortcuts.Get(DebuggerShortcut.OpenNecDspDebugger),
|
||||
IsVisible = () => MainWindow.RomInfo.CpuTypes.Contains(CpuType.NecDsp),
|
||||
OnClick = () => DebugWindowManager.OpenDebugWindow(() => new DebuggerWindow(CpuType.NecDsp))
|
||||
},
|
||||
new ContextMenuAction() {
|
||||
ActionType = ActionType.OpenGsuDebugger,
|
||||
Shortcut = () => ConfigManager.Config.Debug.Shortcuts.Get(DebuggerShortcut.OpenGsuDebugger),
|
||||
IsVisible = () => MainWindow.RomInfo.CpuTypes.Contains(CpuType.Gsu),
|
||||
OnClick = () => DebugWindowManager.OpenDebugWindow(() => new DebuggerWindow(CpuType.Gsu))
|
||||
},
|
||||
new ContextMenuAction() {
|
||||
ActionType = ActionType.OpenSa1Debugger,
|
||||
Shortcut = () => ConfigManager.Config.Debug.Shortcuts.Get(DebuggerShortcut.OpenSa1Debugger),
|
||||
IsVisible = () => MainWindow.RomInfo.CpuTypes.Contains(CpuType.Sa1),
|
||||
OnClick = () => DebugWindowManager.OpenDebugWindow(() => new DebuggerWindow(CpuType.Sa1))
|
||||
},
|
||||
new ContextMenuAction() {
|
||||
ActionType = ActionType.OpenGameboyDebugger,
|
||||
Shortcut = () => ConfigManager.Config.Debug.Shortcuts.Get(DebuggerShortcut.OpenGameboyDebugger),
|
||||
IsVisible = () => MainWindow.RomInfo.ConsoleType == ConsoleType.Snes && MainWindow.RomInfo.CpuTypes.Contains(CpuType.Gameboy),
|
||||
OnClick = () => DebugWindowManager.OpenDebugWindow(() => new DebuggerWindow(CpuType.Gameboy))
|
||||
},
|
||||
new ContextMenuSeparator(),
|
||||
new ContextMenuAction() {
|
||||
ActionType = ActionType.OpenEventViewer,
|
||||
|
|
|
@ -12,15 +12,15 @@ namespace Mesen.ViewModels
|
|||
public class DisposableViewModel : ViewModelBase, IDisposable
|
||||
{
|
||||
private HashSet<IDisposable> _disposables = new();
|
||||
private bool _disposed = false;
|
||||
public bool Disposed { get; private set; } = false;
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if(_disposed) {
|
||||
if(Disposed) {
|
||||
return;
|
||||
}
|
||||
|
||||
_disposed = true;
|
||||
Disposed = true;
|
||||
|
||||
foreach(IDisposable obj in _disposables) {
|
||||
obj.Dispose();
|
||||
|
|
Loading…
Add table
Reference in a new issue