mirror of
https://github.com/SourMesen/Mesen2.git
synced 2025-04-02 10:21:44 -04:00
Debugger: Implemented "move program counter" for most CPUs
This commit is contained in:
parent
a4391d0bea
commit
56b05cced6
34 changed files with 389 additions and 151 deletions
|
@ -20,6 +20,7 @@
|
|||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="Debugger\BaseTraceLogger.h" />
|
||||
<ClInclude Include="Debugger\DebuggerFeatures.h" />
|
||||
<ClInclude Include="Debugger\ITraceLogger.h" />
|
||||
<ClInclude Include="Debugger\stdafx.h" />
|
||||
<ClInclude Include="Debugger\TraceLogFileSaver.h" />
|
||||
|
|
|
@ -818,6 +818,7 @@
|
|||
<ClInclude Include="Gameboy\Input\GbController.h" />
|
||||
<ClInclude Include="NES\Debugger\DummyNesCpu.h" />
|
||||
<ClInclude Include="Gameboy\Debugger\DummyGbCpu.h" />
|
||||
<ClInclude Include="Debugger\DebuggerFeatures.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="SNES\SnesCpu.cpp">
|
||||
|
|
|
@ -80,7 +80,6 @@ Debugger::Debugger(Emulator* emu, IConsole* console)
|
|||
}
|
||||
|
||||
_debuggers[(int)type].Evaluator.reset(new ExpressionEvaluator(this, _debuggers[(int)type].Debugger.get(), type));
|
||||
_debuggers[(int)type].IgnoreBreakpoints = false;
|
||||
}
|
||||
|
||||
for(CpuType type : _cpuTypes) {
|
||||
|
@ -146,7 +145,8 @@ DebuggerType* Debugger::GetDebugger()
|
|||
template<CpuType type>
|
||||
void Debugger::ProcessInstruction()
|
||||
{
|
||||
_debuggers[(int)type].IgnoreBreakpoints = false;
|
||||
_debuggers[(int)type].Debugger->IgnoreBreakpoints = false;
|
||||
_debuggers[(int)type].Debugger->AllowChangeProgramCounter = true;
|
||||
|
||||
switch(type) {
|
||||
case CpuType::Snes: GetDebugger<type, SnesDebugger>()->ProcessInstruction(); break;
|
||||
|
@ -158,6 +158,8 @@ void Debugger::ProcessInstruction()
|
|||
case CpuType::Gameboy: GetDebugger<type, GbDebugger>()->ProcessInstruction(); break;
|
||||
case CpuType::Nes: GetDebugger<type, NesDebugger>()->ProcessInstruction(); break;
|
||||
}
|
||||
|
||||
_debuggers[(int)type].Debugger->AllowChangeProgramCounter = false;
|
||||
}
|
||||
|
||||
template<CpuType type>
|
||||
|
@ -244,7 +246,7 @@ void Debugger::SleepUntilResume(CpuType sourceCpu, BreakSource source, MemoryOpe
|
|||
_emu->GetSoundMixer()->StopAudio();
|
||||
|
||||
if(_settings->CheckDebuggerFlag(DebuggerFlags::SingleBreakpointPerInstruction)) {
|
||||
_debuggers[(int)sourceCpu].IgnoreBreakpoints = true;
|
||||
_debuggers[(int)sourceCpu].Debugger->IgnoreBreakpoints = true;
|
||||
}
|
||||
|
||||
//Only trigger code break event if the pause was caused by user action
|
||||
|
@ -255,6 +257,7 @@ void Debugger::SleepUntilResume(CpuType sourceCpu, BreakSource source, MemoryOpe
|
|||
if(operation) {
|
||||
evt.Operation = *operation;
|
||||
}
|
||||
|
||||
_waitForBreakResume = true;
|
||||
_emu->GetNotificationManager()->SendNotification(ConsoleNotificationType::CodeBreak, &evt);
|
||||
notificationSent = true;
|
||||
|
@ -274,10 +277,10 @@ void Debugger::SleepUntilResume(CpuType sourceCpu, BreakSource source, MemoryOpe
|
|||
void Debugger::ProcessBreakConditions(CpuType sourceCpu, StepRequest& step, BreakpointManager* bpManager, MemoryOperationInfo& operation, AddressInfo& addressInfo)
|
||||
{
|
||||
int breakpointId = bpManager->CheckBreakpoint(operation, addressInfo, true);
|
||||
if(_breakRequestCount || _waitForBreakResume || (step.BreakNeeded && !_debuggers[(int)sourceCpu].IgnoreBreakpoints)) {
|
||||
if(_breakRequestCount || _waitForBreakResume || (step.BreakNeeded && !_debuggers[(int)sourceCpu].Debugger->IgnoreBreakpoints)) {
|
||||
SleepUntilResume(sourceCpu, step.Source);
|
||||
} else {
|
||||
if(breakpointId >= 0 && !_debuggers[(int)sourceCpu].IgnoreBreakpoints) {
|
||||
if(breakpointId >= 0 && !_debuggers[(int)sourceCpu].Debugger->IgnoreBreakpoints) {
|
||||
SleepUntilResume(sourceCpu, BreakSource::Breakpoint, &operation, breakpointId);
|
||||
}
|
||||
}
|
||||
|
@ -285,7 +288,7 @@ void Debugger::ProcessBreakConditions(CpuType sourceCpu, StepRequest& step, Brea
|
|||
|
||||
void Debugger::ProcessPredictiveBreakpoint(CpuType sourceCpu, BreakpointManager* bpManager, MemoryOperationInfo& operation, AddressInfo& addressInfo)
|
||||
{
|
||||
if(_debuggers[(int)sourceCpu].IgnoreBreakpoints) {
|
||||
if(_debuggers[(int)sourceCpu].Debugger->IgnoreBreakpoints) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -548,6 +551,26 @@ void Debugger::GetConsoleState(BaseState& state, ConsoleType consoleType)
|
|||
_console->GetConsoleState(state, consoleType);
|
||||
}
|
||||
|
||||
DebuggerFeatures Debugger::GetDebuggerFeatures(CpuType cpuType)
|
||||
{
|
||||
if(_debuggers[(int)cpuType].Debugger) {
|
||||
return _debuggers[(int)cpuType].Debugger->GetSupportedFeatures();
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
void Debugger::SetProgramCounter(CpuType cpuType, uint32_t addr)
|
||||
{
|
||||
if(_debuggers[(int)cpuType].Debugger->AllowChangeProgramCounter) {
|
||||
_debuggers[(int)cpuType].Debugger->SetProgramCounter(addr);
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t Debugger::GetProgramCounter(CpuType cpuType, bool getInstPc)
|
||||
{
|
||||
return _debuggers[(int)cpuType].Debugger->GetProgramCounter(getInstPc);
|
||||
}
|
||||
|
||||
AddressInfo Debugger::GetAbsoluteAddress(AddressInfo relAddress)
|
||||
{
|
||||
return _console->GetAbsoluteAddress(relAddress);
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
#include "Utilities/SimpleLock.h"
|
||||
#include "Debugger/DebugUtilities.h"
|
||||
#include "Debugger/DebugTypes.h"
|
||||
#include "Debugger/DebuggerFeatures.h"
|
||||
#include "Shared/SettingTypes.h"
|
||||
|
||||
class IConsole;
|
||||
|
@ -44,7 +45,6 @@ struct CpuInfo
|
|||
{
|
||||
unique_ptr<IDebugger> Debugger;
|
||||
unique_ptr<ExpressionEvaluator> Evaluator;
|
||||
bool IgnoreBreakpoints;
|
||||
};
|
||||
|
||||
class Debugger
|
||||
|
@ -129,6 +129,10 @@ public:
|
|||
|
||||
void GetConsoleState(BaseState& state, ConsoleType consoleType);
|
||||
|
||||
DebuggerFeatures GetDebuggerFeatures(CpuType cpuType);
|
||||
uint32_t GetProgramCounter(CpuType cpuType, bool forInstStart);
|
||||
void SetProgramCounter(CpuType cpuType, uint32_t addr);
|
||||
|
||||
AddressInfo GetAbsoluteAddress(AddressInfo relAddress);
|
||||
AddressInfo GetRelativeAddress(AddressInfo absAddress, CpuType cpuType);
|
||||
|
||||
|
|
13
Core/Debugger/DebuggerFeatures.h
Normal file
13
Core/Debugger/DebuggerFeatures.h
Normal file
|
@ -0,0 +1,13 @@
|
|||
#pragma once
|
||||
#include "stdafx.h"
|
||||
|
||||
struct DebuggerFeatures
|
||||
{
|
||||
bool RunToIrq;
|
||||
bool RunToNmi;
|
||||
bool StepOver;
|
||||
bool StepOut;
|
||||
bool StepBack;
|
||||
bool ChangeProgramCounter;
|
||||
bool CallStack;
|
||||
};
|
|
@ -1,5 +1,6 @@
|
|||
#pragma once
|
||||
#include "stdafx.h"
|
||||
#include "DebuggerFeatures.h"
|
||||
|
||||
enum class StepType;
|
||||
class BreakpointManager;
|
||||
|
@ -16,6 +17,9 @@ enum class MemoryOperationType;
|
|||
class IDebugger
|
||||
{
|
||||
public:
|
||||
bool IgnoreBreakpoints = false;
|
||||
bool AllowChangeProgramCounter = false;
|
||||
|
||||
virtual ~IDebugger() = default;
|
||||
|
||||
virtual void Step(int32_t stepCount, StepType type) = 0;
|
||||
|
@ -27,6 +31,11 @@ public:
|
|||
|
||||
virtual void ProcessInterrupt(uint32_t originalPc, uint32_t currentPc, bool forNmi) {}
|
||||
|
||||
virtual DebuggerFeatures GetSupportedFeatures() { return {}; }
|
||||
|
||||
virtual uint32_t GetProgramCounter(bool getInstPc) = 0;
|
||||
virtual void SetProgramCounter(uint32_t addr) = 0;
|
||||
|
||||
virtual BreakpointManager* GetBreakpointManager() = 0;
|
||||
virtual CallstackManager* GetCallstackManager() = 0;
|
||||
virtual IAssembler* GetAssembler() = 0;
|
||||
|
@ -38,4 +47,4 @@ public:
|
|||
virtual BaseState& GetState() = 0;
|
||||
virtual void GetPpuState(BaseState& state) {};
|
||||
virtual void SetPpuState(BaseState& state) {};
|
||||
};
|
||||
};
|
||||
|
|
|
@ -83,18 +83,11 @@ void GbDebugger::ProcessInstruction()
|
|||
uint8_t value = _gameboy->GetMemoryManager()->DebugRead(pc);
|
||||
MemoryOperationInfo operation(pc, value, MemoryOperationType::ExecOpCode, MemoryType::GameboyMemory);
|
||||
|
||||
if(_traceLogger->IsEnabled() || _settings->CheckDebuggerFlag(DebuggerFlags::GbDebuggerEnabled)) {
|
||||
if(addressInfo.Address >= 0) {
|
||||
if(addressInfo.Type == MemoryType::GbPrgRom) {
|
||||
_codeDataLogger->SetFlags(addressInfo.Address, CdlFlags::Code);
|
||||
}
|
||||
_disassembler->BuildCache(addressInfo, 0, CpuType::Gameboy);
|
||||
}
|
||||
|
||||
if(_traceLogger->IsEnabled()) {
|
||||
DisassemblyInfo disInfo = _disassembler->GetDisassemblyInfo(addressInfo, pc, 0, CpuType::Gameboy);
|
||||
_traceLogger->Log(state, disInfo, operation);
|
||||
if(addressInfo.Address >= 0) {
|
||||
if(addressInfo.Type == MemoryType::GbPrgRom) {
|
||||
_codeDataLogger->SetFlags(addressInfo.Address, CdlFlags::Code);
|
||||
}
|
||||
_disassembler->BuildCache(addressInfo, 0, CpuType::Gameboy);
|
||||
}
|
||||
|
||||
if(GameboyDisUtils::IsJumpToSub(_prevOpCode) && pc != _prevProgramCounter + GameboyDisUtils::GetOpSize(_prevOpCode)) {
|
||||
|
@ -131,7 +124,7 @@ void GbDebugger::ProcessInstruction()
|
|||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
_prevOpCode = value;
|
||||
_prevProgramCounter = pc;
|
||||
|
||||
|
@ -158,6 +151,10 @@ void GbDebugger::ProcessRead(uint32_t addr, uint8_t value, MemoryOperationType t
|
|||
MemoryOperationInfo operation(addr, value, type, MemoryType::GameboyMemory);
|
||||
|
||||
if(type == MemoryOperationType::ExecOpCode) {
|
||||
if(_traceLogger->IsEnabled()) {
|
||||
DisassemblyInfo disInfo = _disassembler->GetDisassemblyInfo(addressInfo, addr, 0, CpuType::Gameboy);
|
||||
_traceLogger->Log(_cpu->GetState(), disInfo, operation);
|
||||
}
|
||||
_memoryAccessCounter->ProcessMemoryExec(addressInfo, _emu->GetMasterClock());
|
||||
} else if(type == MemoryOperationType::ExecOperand) {
|
||||
if(addressInfo.Address >= 0 && addressInfo.Type == MemoryType::GbPrgRom) {
|
||||
|
@ -297,6 +294,30 @@ void GbDebugger::ProcessPpuCycle()
|
|||
}
|
||||
}
|
||||
|
||||
DebuggerFeatures GbDebugger::GetSupportedFeatures()
|
||||
{
|
||||
DebuggerFeatures features = {};
|
||||
features.RunToIrq = true;
|
||||
features.RunToNmi = false;
|
||||
features.StepOver = true;
|
||||
features.StepOut = true;
|
||||
features.CallStack = true;
|
||||
features.ChangeProgramCounter = AllowChangeProgramCounter;
|
||||
return features;
|
||||
}
|
||||
|
||||
void GbDebugger::SetProgramCounter(uint32_t addr)
|
||||
{
|
||||
_cpu->GetState().PC = (uint16_t)addr;
|
||||
_prevOpCode = _gameboy->GetMemoryManager()->DebugRead((uint16_t)addr);
|
||||
_prevProgramCounter = (uint16_t)addr;
|
||||
}
|
||||
|
||||
uint32_t GbDebugger::GetProgramCounter(bool getInstPc)
|
||||
{
|
||||
return getInstPc ? _prevProgramCounter : _cpu->GetState().PC;
|
||||
}
|
||||
|
||||
BaseEventManager* GbDebugger::GetEventManager()
|
||||
{
|
||||
return _eventManager.get();
|
||||
|
|
|
@ -67,6 +67,11 @@ public:
|
|||
|
||||
void SaveRomToDisk(string filename, bool saveAsIps, CdlStripOption stripOption);
|
||||
|
||||
void SetProgramCounter(uint32_t addr) override;
|
||||
uint32_t GetProgramCounter(bool getInstPc) override;
|
||||
|
||||
DebuggerFeatures GetSupportedFeatures() override;
|
||||
|
||||
BaseEventManager* GetEventManager() override;
|
||||
IAssembler* GetAssembler() override;
|
||||
CallstackManager* GetCallstackManager() override;
|
||||
|
|
|
@ -95,11 +95,6 @@ void NesDebugger::ProcessInstruction()
|
|||
}
|
||||
}
|
||||
|
||||
if(_traceLogger->IsEnabled()) {
|
||||
DisassemblyInfo disInfo = _disassembler->GetDisassemblyInfo(addressInfo, addr, state.PS, CpuType::Nes);
|
||||
_traceLogger->Log(state, disInfo, operation);
|
||||
}
|
||||
|
||||
uint32_t pc = state.PC;
|
||||
if(_prevOpCode == 0x20) {
|
||||
//JSR
|
||||
|
@ -156,6 +151,12 @@ void NesDebugger::ProcessRead(uint32_t addr, uint8_t value, MemoryOperationType
|
|||
}
|
||||
|
||||
if(type == MemoryOperationType::ExecOpCode) {
|
||||
if(_traceLogger->IsEnabled()) {
|
||||
NesCpuState& state = _cpu->GetState();
|
||||
DisassemblyInfo disInfo = _disassembler->GetDisassemblyInfo(addressInfo, addr, state.PS, CpuType::Nes);
|
||||
_traceLogger->Log(state, disInfo, operation);
|
||||
}
|
||||
|
||||
_memoryAccessCounter->ProcessMemoryExec(addressInfo, _cpu->GetCycleCount());
|
||||
} else if(type == MemoryOperationType::ExecOperand) {
|
||||
if(addressInfo.Type == MemoryType::NesPrgRom && addressInfo.Address >= 0) {
|
||||
|
@ -312,6 +313,30 @@ bool NesDebugger::IsRegister(MemoryOperationInfo& op)
|
|||
return false;
|
||||
}
|
||||
|
||||
DebuggerFeatures NesDebugger::GetSupportedFeatures()
|
||||
{
|
||||
DebuggerFeatures features = {};
|
||||
features.RunToIrq = true;
|
||||
features.RunToNmi = true;
|
||||
features.StepOver = true;
|
||||
features.StepOut = true;
|
||||
features.CallStack = true;
|
||||
features.ChangeProgramCounter = AllowChangeProgramCounter;
|
||||
return features;
|
||||
}
|
||||
|
||||
void NesDebugger::SetProgramCounter(uint32_t addr)
|
||||
{
|
||||
_cpu->GetState().PC = (uint16_t)addr;
|
||||
_prevOpCode = _memoryManager->DebugRead(addr);
|
||||
_prevProgramCounter = (uint16_t)addr;
|
||||
}
|
||||
|
||||
uint32_t NesDebugger::GetProgramCounter(bool getInstPc)
|
||||
{
|
||||
return getInstPc ? _prevProgramCounter : _cpu->GetState().PC;
|
||||
}
|
||||
|
||||
CallstackManager* NesDebugger::GetCallstackManager()
|
||||
{
|
||||
return _callstackManager.get();
|
||||
|
|
|
@ -58,6 +58,7 @@ class NesDebugger final : public IDebugger
|
|||
|
||||
bool IsRegister(MemoryOperationInfo& op);
|
||||
|
||||
|
||||
public:
|
||||
NesDebugger(Debugger* debugger);
|
||||
|
||||
|
@ -74,6 +75,10 @@ public:
|
|||
void Run() override;
|
||||
void Step(int32_t stepCount, StepType type) override;
|
||||
|
||||
DebuggerFeatures GetSupportedFeatures() override;
|
||||
void SetProgramCounter(uint32_t addr) override;
|
||||
uint32_t GetProgramCounter(bool getInstPc) override;
|
||||
|
||||
BreakpointManager* GetBreakpointManager() override;
|
||||
ITraceLogger* GetTraceLogger() override;
|
||||
PpuTools* GetPpuTools() override;
|
||||
|
|
|
@ -148,6 +148,7 @@ void NecDsp::BuildProgramCache()
|
|||
void NecDsp::ReadOpCode()
|
||||
{
|
||||
_opCode = _prgCache[_state.PC & _progMask];
|
||||
_emu->ProcessMemoryRead<CpuType::NecDsp>(_state.PC, _opCode, MemoryOperationType::ExecOpCode);
|
||||
}
|
||||
|
||||
void NecDsp::Run()
|
||||
|
@ -249,7 +250,6 @@ void NecDsp::Write(uint32_t addr, uint8_t value)
|
|||
|
||||
uint32_t NecDsp::GetOpCode(uint32_t addr)
|
||||
{
|
||||
//Avoid side effects for now
|
||||
return _prgCache[addr & _progMask];
|
||||
}
|
||||
|
||||
|
|
|
@ -53,13 +53,8 @@ void Cx4Debugger::ProcessInstruction()
|
|||
_codeDataLogger->SetFlags(addressInfo.Address + 1, CdlFlags::Code | CdlFlags::Cx4);
|
||||
}
|
||||
|
||||
if(_traceLogger->IsEnabled() || _settings->CheckDebuggerFlag(DebuggerFlags::Cx4DebuggerEnabled)) {
|
||||
if(_settings->CheckDebuggerFlag(DebuggerFlags::Cx4DebuggerEnabled)) {
|
||||
_disassembler->BuildCache(addressInfo, 0, CpuType::Cx4);
|
||||
|
||||
if(_traceLogger->IsEnabled()) {
|
||||
DisassemblyInfo disInfo = _disassembler->GetDisassemblyInfo(addressInfo, addr, 0, CpuType::Cx4);
|
||||
_traceLogger->Log(state, disInfo, operation);
|
||||
}
|
||||
}
|
||||
|
||||
_prevProgramCounter = addr;
|
||||
|
@ -77,6 +72,11 @@ void Cx4Debugger::ProcessRead(uint32_t addr, uint8_t value, MemoryOperationType
|
|||
MemoryOperationInfo operation(addr, value, type, MemoryType::Cx4Memory);
|
||||
|
||||
if(type == MemoryOperationType::ExecOpCode) {
|
||||
if(_traceLogger->IsEnabled()) {
|
||||
DisassemblyInfo disInfo = _disassembler->GetDisassemblyInfo(addressInfo, addr, 0, CpuType::Cx4);
|
||||
_traceLogger->Log(state, disInfo, operation);
|
||||
}
|
||||
|
||||
AddressInfo opCodeHighAddr = _cx4->GetMemoryMappings()->GetAbsoluteAddress(addr + 1);
|
||||
_memoryAccessCounter->ProcessMemoryExec(addressInfo, _memoryManager->GetMasterClock());
|
||||
_memoryAccessCounter->ProcessMemoryExec(opCodeHighAddr, _memoryManager->GetMasterClock());
|
||||
|
@ -129,6 +129,17 @@ void Cx4Debugger::Step(int32_t stepCount, StepType type)
|
|||
_step.reset(new StepRequest(step));
|
||||
}
|
||||
|
||||
void Cx4Debugger::SetProgramCounter(uint32_t addr)
|
||||
{
|
||||
//Not implemented
|
||||
}
|
||||
|
||||
uint32_t Cx4Debugger::GetProgramCounter(bool getInstPc)
|
||||
{
|
||||
Cx4State& state = _cx4->GetState();
|
||||
return getInstPc ? _prevProgramCounter : ((state.Cache.Address[state.Cache.Page] + (state.PC * 2)) & 0xFFFFFF);
|
||||
}
|
||||
|
||||
BreakpointManager* Cx4Debugger::GetBreakpointManager()
|
||||
{
|
||||
return _breakpointManager.get();
|
||||
|
|
|
@ -44,6 +44,9 @@ public:
|
|||
void Run() override;
|
||||
void Step(int32_t stepCount, StepType type) override;
|
||||
|
||||
void SetProgramCounter(uint32_t addr) override;
|
||||
uint32_t GetProgramCounter(bool getInstPc) override;
|
||||
|
||||
BreakpointManager* GetBreakpointManager() override;
|
||||
CallstackManager* GetCallstackManager() override;
|
||||
IAssembler* GetAssembler() override;
|
||||
|
|
|
@ -51,13 +51,8 @@ void GsuDebugger::ProcessInstruction()
|
|||
_codeDataLogger->SetFlags(addressInfo.Address, CdlFlags::Code | CdlFlags::Gsu);
|
||||
}
|
||||
|
||||
if(_traceLogger->IsEnabled() || _settings->CheckDebuggerFlag(DebuggerFlags::GsuDebuggerEnabled)) {
|
||||
if(_settings->CheckDebuggerFlag(DebuggerFlags::GsuDebuggerEnabled)) {
|
||||
_disassembler->BuildCache(addressInfo, state.SFR.GetFlagsHigh() & 0x13, CpuType::Gsu);
|
||||
|
||||
if(_traceLogger->IsEnabled()) {
|
||||
DisassemblyInfo disInfo = _disassembler->GetDisassemblyInfo(addressInfo, addr, 0, CpuType::Gsu);
|
||||
_traceLogger->Log(state, disInfo, operation);
|
||||
}
|
||||
}
|
||||
|
||||
_prevOpCode = state.ProgramReadBuffer;
|
||||
|
@ -72,8 +67,13 @@ void GsuDebugger::ProcessInstruction()
|
|||
void GsuDebugger::ProcessRead(uint32_t addr, uint8_t value, MemoryOperationType type)
|
||||
{
|
||||
AddressInfo addressInfo = _gsu->GetMemoryMappings()->GetAbsoluteAddress(addr);
|
||||
MemoryOperationInfo operation(addr, value, type, MemoryType::GsuMemory);
|
||||
|
||||
if(type == MemoryOperationType::ExecOpCode) {
|
||||
if(_traceLogger->IsEnabled()) {
|
||||
DisassemblyInfo disInfo = _disassembler->GetDisassemblyInfo(addressInfo, addr, 0, CpuType::Gsu);
|
||||
_traceLogger->Log(_gsu->GetState(), disInfo, operation);
|
||||
}
|
||||
_memoryAccessCounter->ProcessMemoryExec(addressInfo, _memoryManager->GetMasterClock());
|
||||
} else if(type == MemoryOperationType::ExecOperand) {
|
||||
if(addressInfo.Type == MemoryType::SnesPrgRom) {
|
||||
|
@ -81,7 +81,6 @@ void GsuDebugger::ProcessRead(uint32_t addr, uint8_t value, MemoryOperationType
|
|||
}
|
||||
_memoryAccessCounter->ProcessMemoryExec(addressInfo, _memoryManager->GetMasterClock());
|
||||
} else {
|
||||
MemoryOperationInfo operation(addr, value, type, MemoryType::GsuMemory);
|
||||
|
||||
if(addressInfo.Type == MemoryType::SnesPrgRom) {
|
||||
_codeDataLogger->SetFlags(addressInfo.Address, CdlFlags::Data | CdlFlags::Gsu);
|
||||
|
@ -130,6 +129,17 @@ void GsuDebugger::Step(int32_t stepCount, StepType type)
|
|||
_step.reset(new StepRequest(step));
|
||||
}
|
||||
|
||||
void GsuDebugger::SetProgramCounter(uint32_t addr)
|
||||
{
|
||||
//Not implemented
|
||||
}
|
||||
|
||||
uint32_t GsuDebugger::GetProgramCounter(bool getInstPc)
|
||||
{
|
||||
GsuState& state = _gsu->GetState();
|
||||
return getInstPc ? _prevProgramCounter : ((state.ProgramBank << 16) | state.R[15]);
|
||||
}
|
||||
|
||||
BreakpointManager* GsuDebugger::GetBreakpointManager()
|
||||
{
|
||||
return _breakpointManager.get();
|
||||
|
|
|
@ -44,6 +44,9 @@ public:
|
|||
void Run() override;
|
||||
void Step(int32_t stepCount, StepType type) override;
|
||||
|
||||
void SetProgramCounter(uint32_t addr) override;
|
||||
uint32_t GetProgramCounter(bool getInstPc) override;
|
||||
|
||||
BreakpointManager* GetBreakpointManager() override;
|
||||
CallstackManager* GetCallstackManager() override;
|
||||
IAssembler* GetAssembler() override;
|
||||
|
|
|
@ -42,14 +42,7 @@ void NecDspDebugger::ProcessInstruction()
|
|||
AddressInfo addressInfo = { (int32_t)addr, MemoryType::DspProgramRom };
|
||||
MemoryOperationInfo operation(addr, value, MemoryOperationType::ExecOpCode, MemoryType::NecDspMemory);
|
||||
|
||||
if(_traceLogger->IsEnabled() || _settings->CheckDebuggerFlag(DebuggerFlags::NecDspDebuggerEnabled)) {
|
||||
_disassembler->BuildCache(addressInfo, 0, CpuType::NecDsp);
|
||||
|
||||
if(_traceLogger->IsEnabled()) {
|
||||
DisassemblyInfo disInfo = _disassembler->GetDisassemblyInfo(addressInfo, addr, 0, CpuType::NecDsp);
|
||||
_traceLogger->Log(_dsp->GetState(), disInfo, operation);
|
||||
}
|
||||
}
|
||||
_disassembler->BuildCache(addressInfo, 0, CpuType::NecDsp);
|
||||
|
||||
_prevProgramCounter = addr;
|
||||
_step->ProcessCpuExec();
|
||||
|
@ -58,7 +51,13 @@ void NecDspDebugger::ProcessInstruction()
|
|||
|
||||
void NecDspDebugger::ProcessRead(uint32_t addr, uint8_t value, MemoryOperationType type)
|
||||
{
|
||||
//TODO
|
||||
AddressInfo addressInfo = { (int32_t)addr, MemoryType::DspProgramRom };
|
||||
MemoryOperationInfo operation(addr, value, MemoryOperationType::ExecOpCode, MemoryType::NecDspMemory);
|
||||
|
||||
if(_traceLogger->IsEnabled()) {
|
||||
DisassemblyInfo disInfo = _disassembler->GetDisassemblyInfo(addressInfo, addr, 0, CpuType::NecDsp);
|
||||
_traceLogger->Log(_dsp->GetState(), disInfo, operation);
|
||||
}
|
||||
}
|
||||
|
||||
void NecDspDebugger::ProcessWrite(uint32_t addr, uint8_t value, MemoryOperationType type)
|
||||
|
@ -91,6 +90,24 @@ void NecDspDebugger::Step(int32_t stepCount, StepType type)
|
|||
_step.reset(new StepRequest(step));
|
||||
}
|
||||
|
||||
DebuggerFeatures NecDspDebugger::GetSupportedFeatures()
|
||||
{
|
||||
DebuggerFeatures features = {};
|
||||
features.ChangeProgramCounter = AllowChangeProgramCounter;
|
||||
return features;
|
||||
}
|
||||
|
||||
void NecDspDebugger::SetProgramCounter(uint32_t addr)
|
||||
{
|
||||
_dsp->GetState().PC = addr / 3;
|
||||
_prevProgramCounter = addr;
|
||||
}
|
||||
|
||||
uint32_t NecDspDebugger::GetProgramCounter(bool getInstPc)
|
||||
{
|
||||
return getInstPc ? _prevProgramCounter : (_dsp->GetState().PC * 3);
|
||||
}
|
||||
|
||||
CallstackManager* NecDspDebugger::GetCallstackManager()
|
||||
{
|
||||
return nullptr;
|
||||
|
|
|
@ -40,6 +40,10 @@ public:
|
|||
void Run() override;
|
||||
void Step(int32_t stepCount, StepType type) override;
|
||||
|
||||
DebuggerFeatures GetSupportedFeatures() override;
|
||||
void SetProgramCounter(uint32_t addr) override;
|
||||
uint32_t GetProgramCounter(bool getInstPc) override;
|
||||
|
||||
CallstackManager* GetCallstackManager() override;
|
||||
BreakpointManager* GetBreakpointManager() override;
|
||||
IAssembler* GetAssembler() override;
|
||||
|
|
|
@ -128,11 +128,6 @@ void SnesDebugger::ProcessInstruction()
|
|||
}
|
||||
}
|
||||
|
||||
if(_traceLogger->IsEnabled()) {
|
||||
DisassemblyInfo disInfo = _disassembler->GetDisassemblyInfo(addressInfo, addr, state.PS, _cpuType);
|
||||
_traceLogger->Log(state, disInfo, operation);
|
||||
}
|
||||
|
||||
if(_prevOpCode == 0x20 || _prevOpCode == 0x22 || _prevOpCode == 0xFC) {
|
||||
//JSR, JSL
|
||||
uint8_t opSize = DisassemblyInfo::GetOpSize(_prevOpCode, state.PS, _cpuType);
|
||||
|
@ -196,6 +191,10 @@ void SnesDebugger::ProcessRead(uint32_t addr, uint8_t value, MemoryOperationType
|
|||
}
|
||||
|
||||
if(type == MemoryOperationType::ExecOpCode) {
|
||||
if(_traceLogger->IsEnabled()) {
|
||||
DisassemblyInfo disInfo = _disassembler->GetDisassemblyInfo(addressInfo, addr, state.PS, _cpuType);
|
||||
_traceLogger->Log(state, disInfo, operation);
|
||||
}
|
||||
_memoryAccessCounter->ProcessMemoryExec(addressInfo, _memoryManager->GetMasterClock());
|
||||
} else if(type == MemoryOperationType::ExecOperand) {
|
||||
if(addressInfo.Type == MemoryType::SnesPrgRom && addressInfo.Address >= 0) {
|
||||
|
@ -354,6 +353,32 @@ bool SnesDebugger::IsRegister(uint32_t addr)
|
|||
return _cpuType == CpuType::Snes && _memoryManager->IsRegister(addr);
|
||||
}
|
||||
|
||||
DebuggerFeatures SnesDebugger::GetSupportedFeatures()
|
||||
{
|
||||
DebuggerFeatures features = {};
|
||||
features.RunToIrq = true;
|
||||
features.RunToNmi = true;
|
||||
features.StepOver = true;
|
||||
features.StepOut = true;
|
||||
features.CallStack = true;
|
||||
features.ChangeProgramCounter = AllowChangeProgramCounter;
|
||||
return features;
|
||||
}
|
||||
|
||||
void SnesDebugger::SetProgramCounter(uint32_t addr)
|
||||
{
|
||||
GetCpuState().PC = (uint16_t)addr;
|
||||
GetCpuState().K = (uint8_t)(addr >> 16);
|
||||
|
||||
_prevOpCode = _memoryManager->Peek(addr);
|
||||
_prevProgramCounter = addr;
|
||||
}
|
||||
|
||||
uint32_t SnesDebugger::GetProgramCounter(bool getInstPc)
|
||||
{
|
||||
return getInstPc ? _prevProgramCounter : ((GetCpuState().K << 16) | GetCpuState().PC);
|
||||
}
|
||||
|
||||
CallstackManager* SnesDebugger::GetCallstackManager()
|
||||
{
|
||||
return _callstackManager.get();
|
||||
|
|
|
@ -91,6 +91,10 @@ public:
|
|||
|
||||
void Run() override;
|
||||
void Step(int32_t stepCount, StepType type) override;
|
||||
|
||||
DebuggerFeatures GetSupportedFeatures() override;
|
||||
void SetProgramCounter(uint32_t addr) override;
|
||||
uint32_t GetProgramCounter(bool getInstPc) override;
|
||||
|
||||
ITraceLogger* GetTraceLogger() override;
|
||||
BreakpointManager* GetBreakpointManager() override;
|
||||
|
|
|
@ -58,11 +58,6 @@ void SpcDebugger::ProcessInstruction()
|
|||
|
||||
_disassembler->BuildCache(addressInfo, 0, CpuType::Spc);
|
||||
|
||||
if(_traceLogger->IsEnabled()) {
|
||||
DisassemblyInfo disInfo = _disassembler->GetDisassemblyInfo(addressInfo, addr, 0, CpuType::Spc);
|
||||
_traceLogger->Log(state, disInfo, operation);
|
||||
}
|
||||
|
||||
if(_prevOpCode == 0x3F || _prevOpCode == 0x0F) {
|
||||
//JSR, BRK
|
||||
uint8_t opSize = DisassemblyInfo::GetOpSize(_prevOpCode, 0, CpuType::Spc);
|
||||
|
@ -115,6 +110,11 @@ void SpcDebugger::ProcessRead(uint32_t addr, uint8_t value, MemoryOperationType
|
|||
MemoryOperationInfo operation(addr, value, type, MemoryType::SpcMemory);
|
||||
|
||||
if(type == MemoryOperationType::ExecOpCode) {
|
||||
if(_traceLogger->IsEnabled()) {
|
||||
SpcState& state = _spc->GetState();
|
||||
DisassemblyInfo disInfo = _disassembler->GetDisassemblyInfo(addressInfo, addr, 0, CpuType::Spc);
|
||||
_traceLogger->Log(state, disInfo, operation);
|
||||
}
|
||||
_memoryAccessCounter->ProcessMemoryExec(addressInfo, _memoryManager->GetMasterClock());
|
||||
} else if(type == MemoryOperationType::ExecOperand) {
|
||||
_memoryAccessCounter->ProcessMemoryExec(addressInfo, _memoryManager->GetMasterClock());
|
||||
|
@ -176,6 +176,30 @@ void SpcDebugger::Step(int32_t stepCount, StepType type)
|
|||
_step.reset(new StepRequest(step));
|
||||
}
|
||||
|
||||
DebuggerFeatures SpcDebugger::GetSupportedFeatures()
|
||||
{
|
||||
DebuggerFeatures features = {};
|
||||
features.RunToIrq = false;
|
||||
features.RunToNmi = false;
|
||||
features.StepOver = true;
|
||||
features.StepOut = true;
|
||||
features.CallStack = true;
|
||||
features.ChangeProgramCounter = AllowChangeProgramCounter;
|
||||
return features;
|
||||
}
|
||||
|
||||
void SpcDebugger::SetProgramCounter(uint32_t addr)
|
||||
{
|
||||
_spc->GetState().PC = (uint16_t)addr;
|
||||
_prevOpCode = _spc->DebugRead(addr);
|
||||
_prevProgramCounter = (uint16_t)addr;
|
||||
}
|
||||
|
||||
uint32_t SpcDebugger::GetProgramCounter(bool getInstPc)
|
||||
{
|
||||
return getInstPc ? _prevProgramCounter : _spc->GetState().PC;
|
||||
}
|
||||
|
||||
CallstackManager* SpcDebugger::GetCallstackManager()
|
||||
{
|
||||
return _callstackManager.get();
|
||||
|
|
|
@ -51,6 +51,10 @@ public:
|
|||
void Run() override;
|
||||
void Step(int32_t stepCount, StepType type) override;
|
||||
|
||||
DebuggerFeatures GetSupportedFeatures() override;
|
||||
void SetProgramCounter(uint32_t addr) override;
|
||||
uint32_t GetProgramCounter(bool getInstPc) override;
|
||||
|
||||
CallstackManager* GetCallstackManager() override;
|
||||
BreakpointManager* GetBreakpointManager() override;
|
||||
IAssembler* GetAssembler() override;
|
||||
|
|
|
@ -102,6 +102,10 @@ extern "C"
|
|||
DllExport void __stdcall SetCpuState(BaseState& state, CpuType cpuType) { WithDebugger(void, SetCpuState(state, cpuType)); }
|
||||
DllExport void __stdcall SetPpuState(BaseState& state, CpuType cpuType) { WithDebugger(void, SetPpuState(state, cpuType)); }
|
||||
|
||||
DllExport uint32_t __stdcall GetProgramCounter(CpuType cpuType, bool getInstPc) { return WithDebugger(uint32_t, GetProgramCounter(cpuType, getInstPc)); }
|
||||
DllExport void __stdcall SetProgramCounter(CpuType cpuType, uint32_t addr) { WithDebugger(void, SetProgramCounter(cpuType, addr)); }
|
||||
DllExport DebuggerFeatures __stdcall GetDebuggerFeatures(CpuType cpuType) { return WithDebugger(DebuggerFeatures, GetDebuggerFeatures(cpuType)); }
|
||||
|
||||
DllExport const char* __stdcall GetDebuggerLog()
|
||||
{
|
||||
_logString = WithDebugger(string, GetLog());
|
||||
|
|
|
@ -150,7 +150,7 @@ namespace Mesen.Config
|
|||
Add(new() { Shortcut = DebuggerShortcut.CodeWindow_ViewInMemoryViewer, KeyBinding = new(Key.F1) });
|
||||
Add(new() { Shortcut = DebuggerShortcut.CodeWindow_AddToWatch, KeyBinding = new() });
|
||||
Add(new() { Shortcut = DebuggerShortcut.CodeWindow_GoToLocation, KeyBinding = new() });
|
||||
Add(new() { Shortcut = DebuggerShortcut.CodeWindow_SetNextStatement, KeyBinding = new(KeyModifiers.Control | KeyModifiers.Shift, Key.F10) });
|
||||
Add(new() { Shortcut = DebuggerShortcut.CodeWindow_MoveProgramCounter, KeyBinding = new(KeyModifiers.Control | KeyModifiers.Shift, Key.F10) });
|
||||
Add(new() { Shortcut = DebuggerShortcut.CodeWindow_EditSelectedCode, KeyBinding = new() });
|
||||
Add(new() { Shortcut = DebuggerShortcut.CodeWindow_EditSourceFile, KeyBinding = new(Key.F4) });
|
||||
Add(new() { Shortcut = DebuggerShortcut.CodeWindow_EditLabel, KeyBinding = new(Key.F2) });
|
||||
|
@ -274,7 +274,7 @@ namespace Mesen.Config
|
|||
BreakOn,
|
||||
FindOccurrences,
|
||||
GoToProgramCounter,
|
||||
CodeWindow_SetNextStatement,
|
||||
CodeWindow_MoveProgramCounter,
|
||||
CodeWindow_EditSelectedCode,
|
||||
CodeWindow_EditSourceFile,
|
||||
CodeWindow_EditLabel,
|
||||
|
|
|
@ -38,7 +38,7 @@
|
|||
</ItemsPresenter.ItemsPanel>
|
||||
<ItemsPresenter.DataTemplates>
|
||||
<DataTemplate DataType="{x:Type du:ContextMenuSeparator}">
|
||||
<StackPanel Width="2" Height="16" Margin="2 0">
|
||||
<StackPanel Width="2" Height="16" Margin="2 0" IsVisible="{Binding Visible}">
|
||||
<Rectangle
|
||||
Stroke="LightGray"
|
||||
StrokeThickness="1"
|
||||
|
@ -49,7 +49,7 @@
|
|||
</DataTemplate>
|
||||
|
||||
<DataTemplate DataType="{x:Type du:ContextMenuAction}">
|
||||
<Button ToolTip.Tip="{Binding Name}" Command="{Binding ClickCommand}" IsEnabled="{Binding Enabled}">
|
||||
<Button ToolTip.Tip="{Binding Name}" Command="{Binding ClickCommand}" IsEnabled="{Binding Enabled}" IsVisible="{Binding Visible}">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<ContentPresenter Content="{Binding Icon}" />
|
||||
<TextBlock
|
||||
|
|
|
@ -1,57 +0,0 @@
|
|||
using Mesen.Interop;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Mesen.Debugger
|
||||
{
|
||||
public static class DebugUtilities
|
||||
{
|
||||
public static uint GetProgramCounter(CpuType cpuType)
|
||||
{
|
||||
//TODO move to C++ core
|
||||
switch(cpuType) {
|
||||
case CpuType.Snes:
|
||||
case CpuType.Sa1: {
|
||||
SnesCpuState state = DebugApi.GetCpuState<SnesCpuState>(cpuType);
|
||||
return (uint)(state.K << 16) | state.PC;
|
||||
}
|
||||
|
||||
case CpuType.Spc: {
|
||||
SpcState state = DebugApi.GetCpuState<SpcState>(cpuType);
|
||||
return (uint)state.PC;
|
||||
}
|
||||
|
||||
case CpuType.Gameboy: {
|
||||
GbCpuState state = DebugApi.GetCpuState<GbCpuState>(cpuType);
|
||||
return (uint)state.PC;
|
||||
}
|
||||
|
||||
case CpuType.Nes: {
|
||||
NesCpuState state = DebugApi.GetCpuState<NesCpuState>(cpuType);
|
||||
return (uint)state.PC;
|
||||
}
|
||||
|
||||
case CpuType.NecDsp: {
|
||||
NecDspState state = DebugApi.GetCpuState<NecDspState>(cpuType);
|
||||
return (uint)(state.PC * 3);
|
||||
}
|
||||
|
||||
case CpuType.Gsu: {
|
||||
GsuState state = DebugApi.GetCpuState<GsuState>(cpuType);
|
||||
return (uint)((state.ProgramBank << 16) | 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");
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
|
@ -93,6 +93,8 @@ namespace Mesen.Debugger.Utilities
|
|||
public Func<bool>? IsEnabled { get; set; }
|
||||
public Func<bool>? IsSelected { get; set; }
|
||||
public Func<bool>? IsVisible { get; set; }
|
||||
|
||||
public bool AllowedWhenHidden { get; set; }
|
||||
|
||||
public abstract string ShortcutText { get; }
|
||||
|
||||
|
@ -117,7 +119,7 @@ namespace Mesen.Debugger.Utilities
|
|||
set
|
||||
{
|
||||
_onClick = () => {
|
||||
if((IsVisible == null || IsVisible()) && (IsEnabled == null || IsEnabled())) {
|
||||
if((IsVisible == null || AllowedWhenHidden || IsVisible()) && (IsEnabled == null || IsEnabled())) {
|
||||
if(ActionType == ActionType.Exit) {
|
||||
//When using exit, the command is disposed while the command is running, which causes a crash
|
||||
//Run the code in a posted action to prevent the crash
|
||||
|
@ -598,5 +600,7 @@ namespace Mesen.Debugger.Utilities
|
|||
LoadCdl,
|
||||
[IconFile("SaveFloppy")]
|
||||
SaveCdl,
|
||||
|
||||
MoveProgramCounter,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -124,7 +124,7 @@ namespace Mesen.Debugger.Utilities
|
|||
|
||||
switch(e.NotificationType) {
|
||||
case ConsoleNotificationType.GameLoaded:
|
||||
DebugWorkspaceManager.Load();
|
||||
Dispatcher.UIThread.Post(() => DebugWorkspaceManager.Load());
|
||||
break;
|
||||
|
||||
case ConsoleNotificationType.EmulationStopped:
|
||||
|
|
|
@ -7,6 +7,7 @@ using Mesen.Debugger.Labels;
|
|||
using Mesen.Debugger.Utilities;
|
||||
using Mesen.Debugger.Windows;
|
||||
using Mesen.Interop;
|
||||
using Mesen.Utilities;
|
||||
using Mesen.ViewModels;
|
||||
using ReactiveUI.Fody.Helpers;
|
||||
using System;
|
||||
|
@ -20,7 +21,7 @@ namespace Mesen.Debugger.ViewModels
|
|||
public CpuType CpuType { get; }
|
||||
public DisassemblyViewModel Disassembly { get; }
|
||||
|
||||
[Reactive] public List<StackInfo> CallStackContent { get; private set; } = new List<StackInfo>();
|
||||
[Reactive] public SwappableList<StackInfo> CallStackContent { get; private set; } = new();
|
||||
|
||||
private StackFrameInfo[] _stackFrames = Array.Empty<StackFrameInfo>();
|
||||
|
||||
|
@ -47,7 +48,7 @@ namespace Mesen.Debugger.ViewModels
|
|||
|
||||
public void RefreshCallStack()
|
||||
{
|
||||
CallStackContent = GetStackInfo();
|
||||
CallStackContent.Swap(GetStackInfo());
|
||||
}
|
||||
|
||||
private List<StackInfo> GetStackInfo()
|
||||
|
@ -71,8 +72,8 @@ namespace Mesen.Debugger.ViewModels
|
|||
stack.Insert(0, new StackInfo() {
|
||||
EntryPoint = GetEntryPoint(stackFrames.Length > 0 ? stackFrames[^1] : null),
|
||||
EntryPointAddr = stackFrames.Length > 0 ? stackFrames[^1].AbsTarget : null,
|
||||
RelAddress = DebugUtilities.GetProgramCounter(CpuType),
|
||||
Address = DebugApi.GetAbsoluteAddress(new AddressInfo() { Address = (int)DebugUtilities.GetProgramCounter(CpuType), Type = CpuType.ToMemoryType() })
|
||||
RelAddress = DebugApi.GetProgramCounter(CpuType, true),
|
||||
Address = DebugApi.GetAbsoluteAddress(new AddressInfo() { Address = (int)DebugApi.GetProgramCounter(CpuType, true), Type = CpuType.ToMemoryType() })
|
||||
});
|
||||
|
||||
return stack;
|
||||
|
|
|
@ -123,17 +123,17 @@ namespace Mesen.Debugger.ViewModels
|
|||
DebuggerShortcut.RunToIrq,
|
||||
//DebuggerShortcut.FindOccurrences,
|
||||
DebuggerShortcut.GoToProgramCounter,
|
||||
//DebuggerShortcut.CodeWindow_SetNextStatement,
|
||||
DebuggerShortcut.CodeWindow_EditSelectedCode,
|
||||
//DebuggerShortcut.CodeWindow_EditSourceFile,
|
||||
DebuggerShortcut.CodeWindow_AddToWatch,
|
||||
DebuggerShortcut.CodeWindow_GoToLocation,
|
||||
DebuggerShortcut.CodeWindow_ViewInMemoryViewer,
|
||||
DebuggerShortcut.CodeWindow_EditLabel,
|
||||
//DebuggerShortcut.CodeWindow_NavigateBack,
|
||||
//DebuggerShortcut.CodeWindow_NavigateForward,
|
||||
DebuggerShortcut.CodeWindow_ToggleBreakpoint,
|
||||
DebuggerShortcut.CodeWindow_DisableEnableBreakpoint,
|
||||
DebuggerShortcut.CodeWindow_MoveProgramCounter,
|
||||
DebuggerShortcut.CodeWindow_GoToLocation,
|
||||
//DebuggerShortcut.CodeWindow_SwitchView,
|
||||
//DebuggerShortcut.FunctionList_EditLabel,
|
||||
//DebuggerShortcut.FunctionList_AddBreakpoint,
|
||||
|
|
|
@ -97,7 +97,7 @@ namespace Mesen.Debugger.ViewModels
|
|||
Config = ConfigManager.Config.Debug.Debugger;
|
||||
|
||||
Options = new DebuggerOptionsViewModel(Config, CpuType);
|
||||
Disassembly = new DisassemblyViewModel(ConfigManager.Config.Debug, CpuType);
|
||||
Disassembly = new DisassemblyViewModel(this, ConfigManager.Config.Debug, CpuType);
|
||||
BreakpointList = new BreakpointListViewModel(CpuType, Disassembly);
|
||||
LabelList = new LabelListViewModel(CpuType, Disassembly);
|
||||
CallStack = new CallStackViewModel(CpuType, Disassembly);
|
||||
|
@ -225,11 +225,11 @@ namespace Mesen.Debugger.ViewModels
|
|||
}
|
||||
}
|
||||
|
||||
private void UpdateDisassembly(bool scrollToActiveAddress)
|
||||
public void UpdateDisassembly(bool scrollToActiveAddress)
|
||||
{
|
||||
if(scrollToActiveAddress) {
|
||||
//Scroll to the active address and highlight it
|
||||
Disassembly.SetActiveAddress((int)DebugUtilities.GetProgramCounter(CpuType));
|
||||
Disassembly.SetActiveAddress((int)DebugApi.GetProgramCounter(CpuType, true));
|
||||
if(!EmuApi.IsPaused()) {
|
||||
//Clear the highlight if the emulation is still running
|
||||
Disassembly.SetActiveAddress(null);
|
||||
|
@ -432,16 +432,21 @@ namespace Mesen.Debugger.ViewModels
|
|||
new ContextMenuAction() {
|
||||
ActionType = ActionType.StepOver,
|
||||
Shortcut = () => ConfigManager.Config.Debug.Shortcuts.Get(DebuggerShortcut.StepOver),
|
||||
IsVisible = () => DebugApi.GetDebuggerFeatures(CpuType).StepOver,
|
||||
AllowedWhenHidden = true,
|
||||
OnClick = () => Step(StepType.StepOver, 1)
|
||||
},
|
||||
new ContextMenuAction() {
|
||||
ActionType = ActionType.StepOut,
|
||||
Shortcut = () => ConfigManager.Config.Debug.Shortcuts.Get(DebuggerShortcut.StepOut),
|
||||
IsVisible = () => DebugApi.GetDebuggerFeatures(CpuType).StepOut,
|
||||
AllowedWhenHidden = true,
|
||||
OnClick = () => Step(StepType.StepOut, 1)
|
||||
},
|
||||
new ContextMenuAction() {
|
||||
ActionType = ActionType.StepBack,
|
||||
Shortcut = () => ConfigManager.Config.Debug.Shortcuts.Get(DebuggerShortcut.StepBack),
|
||||
IsVisible = () => DebugApi.GetDebuggerFeatures(CpuType).StepBack,
|
||||
IsEnabled = () => false,
|
||||
OnClick = () => { } //TODO
|
||||
},
|
||||
|
@ -464,16 +469,23 @@ namespace Mesen.Debugger.ViewModels
|
|||
OnClick = () => Step(StepType.PpuFrame, 1)
|
||||
},
|
||||
|
||||
new ContextMenuSeparator(),
|
||||
new ContextMenuSeparator() {
|
||||
IsVisible = () => {
|
||||
DebuggerFeatures features = DebugApi.GetDebuggerFeatures(CpuType);
|
||||
return features.RunToNmi || features.RunToIrq;
|
||||
}
|
||||
},
|
||||
|
||||
new ContextMenuAction() {
|
||||
ActionType = ActionType.RunToNmi,
|
||||
Shortcut = () => ConfigManager.Config.Debug.Shortcuts.Get(DebuggerShortcut.RunToNmi),
|
||||
IsVisible = () => DebugApi.GetDebuggerFeatures(CpuType).RunToNmi,
|
||||
OnClick = () => Step(StepType.RunToNmi)
|
||||
},
|
||||
new ContextMenuAction() {
|
||||
ActionType = ActionType.RunToIrq,
|
||||
Shortcut = () => ConfigManager.Config.Debug.Shortcuts.Get(DebuggerShortcut.RunToIrq),
|
||||
IsVisible = () => DebugApi.GetDebuggerFeatures(CpuType).RunToIrq,
|
||||
OnClick = () => Step(StepType.RunToIrq)
|
||||
},
|
||||
|
||||
|
|
|
@ -18,6 +18,8 @@ namespace Mesen.Debugger.ViewModels
|
|||
public class DisassemblyViewModel : ViewModelBase
|
||||
{
|
||||
public ICodeDataProvider DataProvider { get; }
|
||||
public CpuType CpuType { get; }
|
||||
public DebuggerWindowViewModel Debugger { get; }
|
||||
|
||||
[Reactive] public BaseStyleProvider StyleProvider { get; set; }
|
||||
[Reactive] public int ScrollPosition { get; set; } = 0;
|
||||
|
@ -38,11 +40,13 @@ namespace Mesen.Debugger.ViewModels
|
|||
private int _ignoreScrollUpdates = 0;
|
||||
|
||||
[Obsolete("For designer only")]
|
||||
public DisassemblyViewModel(): this(new DebugConfig(), CpuType.Snes) { }
|
||||
public DisassemblyViewModel(): this(new DebuggerWindowViewModel(), new DebugConfig(), CpuType.Snes) { }
|
||||
|
||||
public DisassemblyViewModel(DebugConfig config, CpuType cpuType)
|
||||
public DisassemblyViewModel(DebuggerWindowViewModel debugger, DebugConfig config, CpuType cpuType)
|
||||
{
|
||||
Config = config;
|
||||
CpuType = cpuType;
|
||||
Debugger = debugger;
|
||||
StyleProvider = new BaseStyleProvider(this);
|
||||
DataProvider = new CodeDataProvider(cpuType);
|
||||
|
||||
|
|
|
@ -11,6 +11,7 @@ using Mesen.Debugger.Utilities;
|
|||
using Mesen.Debugger.ViewModels;
|
||||
using Mesen.Debugger.Windows;
|
||||
using Mesen.Interop;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
|
@ -19,6 +20,8 @@ namespace Mesen.Debugger.Views
|
|||
public class DisassemblyView : UserControl
|
||||
{
|
||||
private DisassemblyViewModel Model => (DisassemblyViewModel)DataContext!;
|
||||
private CpuType CpuType => Model.CpuType;
|
||||
|
||||
private LocationInfo? _mouseOverCodeLocation;
|
||||
private LocationInfo? _contextMenuLocation;
|
||||
private ContextMenu _bpMarginContextMenu;
|
||||
|
@ -57,7 +60,7 @@ namespace Mesen.Debugger.Views
|
|||
{
|
||||
_mainContextMenu = DebugShortcutManager.CreateContextMenu(_viewer, new List<ContextMenuAction> {
|
||||
MarkSelectionHelper.GetAction(
|
||||
() => Model.DataProvider.CpuType.ToMemoryType(),
|
||||
() => CpuType.ToMemoryType(),
|
||||
() => Model.SelectionStart,
|
||||
() => Model.SelectionEnd,
|
||||
() => Model.Refresh()
|
||||
|
@ -65,10 +68,10 @@ namespace Mesen.Debugger.Views
|
|||
new ContextMenuAction() {
|
||||
ActionType = ActionType.EditSelectedCode,
|
||||
Shortcut = () => ConfigManager.Config.Debug.Shortcuts.Get(DebuggerShortcut.CodeWindow_EditSelectedCode),
|
||||
IsEnabled = () => Model.DataProvider.CpuType.SupportsAssembler() && EmuApi.IsPaused(),
|
||||
IsEnabled = () => CpuType.SupportsAssembler() && EmuApi.IsPaused(),
|
||||
OnClick = () => {
|
||||
string code = Model.GetSelection(false, false, true, false, out int byteCount);
|
||||
AssemblerWindow.EditCode(Model.DataProvider.CpuType, Model.SelectionStart, code, byteCount);
|
||||
AssemblerWindow.EditCode(CpuType, Model.SelectionStart, code, byteCount);
|
||||
}
|
||||
},
|
||||
new ContextMenuAction() {
|
||||
|
@ -84,9 +87,9 @@ namespace Mesen.Debugger.Views
|
|||
IsEnabled = () => ActionLocation.RelAddress != null || ActionLocation.AbsAddress != null,
|
||||
OnClick = () => {
|
||||
if(ActionLocation.AbsAddress != null) {
|
||||
BreakpointManager.ToggleBreakpoint(ActionLocation.AbsAddress.Value, Model.DataProvider.CpuType);
|
||||
BreakpointManager.ToggleBreakpoint(ActionLocation.AbsAddress.Value, CpuType);
|
||||
} else if(ActionLocation.RelAddress != null) {
|
||||
BreakpointManager.ToggleBreakpoint(ActionLocation.RelAddress.Value, Model.DataProvider.CpuType);
|
||||
BreakpointManager.ToggleBreakpoint(ActionLocation.RelAddress.Value, CpuType);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -97,9 +100,9 @@ namespace Mesen.Debugger.Views
|
|||
IsEnabled = () => ActionLocation.Label != null || ActionLocation.RelAddress != null,
|
||||
OnClick = () => {
|
||||
if(ActionLocation.Label != null) {
|
||||
WatchManager.GetWatchManager(Model.DataProvider.CpuType).AddWatch("[" + ActionLocation.Label.Label + "]");
|
||||
WatchManager.GetWatchManager(CpuType).AddWatch("[" + ActionLocation.Label.Label + "]");
|
||||
} else if(ActionLocation.RelAddress != null) {
|
||||
WatchManager.GetWatchManager(Model.DataProvider.CpuType).AddWatch("[$" + ActionLocation.RelAddress.Value.Address.ToString(GetFormatString()) + "]");
|
||||
WatchManager.GetWatchManager(CpuType).AddWatch("[$" + ActionLocation.RelAddress.Value.Address.ToString(GetFormatString()) + "]");
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -111,9 +114,9 @@ namespace Mesen.Debugger.Views
|
|||
OnClick = () => {
|
||||
CodeLabel? label = ActionLocation.Label ?? (ActionLocation.AbsAddress.HasValue ? LabelManager.GetLabel(ActionLocation.AbsAddress.Value) : null);
|
||||
if(label != null) {
|
||||
LabelEditWindow.EditLabel(Model.DataProvider.CpuType, this, label);
|
||||
LabelEditWindow.EditLabel(CpuType, this, label);
|
||||
} else if(ActionLocation.AbsAddress != null) {
|
||||
LabelEditWindow.EditLabel(Model.DataProvider.CpuType, this, new CodeLabel(ActionLocation.AbsAddress.Value));
|
||||
LabelEditWindow.EditLabel(CpuType, this, new CodeLabel(ActionLocation.AbsAddress.Value));
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -131,6 +134,21 @@ namespace Mesen.Debugger.Views
|
|||
}
|
||||
},
|
||||
new ContextMenuSeparator(),
|
||||
new ContextMenuAction() {
|
||||
ActionType = ActionType.MoveProgramCounter,
|
||||
Shortcut = () => ConfigManager.Config.Debug.Shortcuts.Get(DebuggerShortcut.CodeWindow_MoveProgramCounter),
|
||||
HintText = () => GetHint(ActionLocation),
|
||||
IsEnabled = () => ActionLocation.RelAddress != null && DebugApi.GetDebuggerFeatures(CpuType).ChangeProgramCounter,
|
||||
OnClick = () => {
|
||||
if(ActionLocation.RelAddress != null) {
|
||||
Model.Debugger.UpdateConsoleState();
|
||||
DebugApi.SetProgramCounter(CpuType, (uint)ActionLocation.RelAddress.Value.Address);
|
||||
Model.Debugger.ConsoleStatus?.UpdateUiState();
|
||||
Model.Debugger.UpdateDisassembly(true);
|
||||
}
|
||||
}
|
||||
},
|
||||
new ContextMenuSeparator(),
|
||||
new ContextMenuAction() {
|
||||
ActionType = ActionType.GoToLocation,
|
||||
Shortcut = () => ConfigManager.Config.Debug.Shortcuts.Get(DebuggerShortcut.CodeWindow_GoToLocation),
|
||||
|
@ -150,7 +168,7 @@ namespace Mesen.Debugger.Views
|
|||
{
|
||||
Breakpoint? GetBreakpoint()
|
||||
{
|
||||
return ActionLocation.AbsAddress != null ? BreakpointManager.GetMatchingBreakpoint(ActionLocation.AbsAddress.Value, Model.DataProvider.CpuType) : null;
|
||||
return ActionLocation.AbsAddress != null ? BreakpointManager.GetMatchingBreakpoint(ActionLocation.AbsAddress.Value, CpuType) : null;
|
||||
}
|
||||
|
||||
_bpMarginContextMenu = DebugShortcutManager.CreateContextMenu(_viewer, new List<ContextMenuAction> {
|
||||
|
@ -160,7 +178,7 @@ namespace Mesen.Debugger.Views
|
|||
IsVisible = () => GetBreakpoint() == null,
|
||||
OnClick = () => {
|
||||
if(ActionLocation.AbsAddress != null) {
|
||||
BreakpointManager.ToggleBreakpoint(ActionLocation.AbsAddress.Value, Model.DataProvider.CpuType);
|
||||
BreakpointManager.ToggleBreakpoint(ActionLocation.AbsAddress.Value, CpuType);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -170,7 +188,7 @@ namespace Mesen.Debugger.Views
|
|||
IsVisible = () => GetBreakpoint() != null,
|
||||
OnClick = () => {
|
||||
if(ActionLocation.AbsAddress != null) {
|
||||
BreakpointManager.ToggleBreakpoint(ActionLocation.AbsAddress.Value, Model.DataProvider.CpuType);
|
||||
BreakpointManager.ToggleBreakpoint(ActionLocation.AbsAddress.Value, CpuType);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -181,7 +199,7 @@ namespace Mesen.Debugger.Views
|
|||
IsEnabled = () => GetBreakpoint()?.Enabled == false,
|
||||
OnClick = () => {
|
||||
if(ActionLocation.AbsAddress != null) {
|
||||
BreakpointManager.EnableDisableBreakpoint(ActionLocation.AbsAddress.Value, Model.DataProvider.CpuType);
|
||||
BreakpointManager.EnableDisableBreakpoint(ActionLocation.AbsAddress.Value, CpuType);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -192,7 +210,7 @@ namespace Mesen.Debugger.Views
|
|||
IsEnabled = () => GetBreakpoint()?.Enabled == true,
|
||||
OnClick = () => {
|
||||
if(ActionLocation.AbsAddress != null) {
|
||||
BreakpointManager.EnableDisableBreakpoint(ActionLocation.AbsAddress.Value, Model.DataProvider.CpuType);
|
||||
BreakpointManager.EnableDisableBreakpoint(ActionLocation.AbsAddress.Value, CpuType);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -211,7 +229,7 @@ namespace Mesen.Debugger.Views
|
|||
|
||||
private string GetFormatString()
|
||||
{
|
||||
return Model.DataProvider.CpuType.ToMemoryType().GetFormatString();
|
||||
return CpuType.ToMemoryType().GetFormatString();
|
||||
}
|
||||
|
||||
private string GetHint(LocationInfo? codeLoc)
|
||||
|
@ -259,7 +277,7 @@ namespace Mesen.Debugger.Views
|
|||
|
||||
private LocationInfo GetSelectedRowLocation()
|
||||
{
|
||||
CpuType cpuType = Model.DataProvider.CpuType;
|
||||
CpuType cpuType = CpuType;
|
||||
AddressInfo relAddress = new AddressInfo() {
|
||||
Address = Model.SelectedRowAddress,
|
||||
Type = cpuType.ToMemoryType()
|
||||
|
@ -322,6 +340,8 @@ namespace Mesen.Debugger.Views
|
|||
ToolTip.SetHorizontalOffset(this, 15);
|
||||
ToolTip.SetIsOpen(this, true);
|
||||
}
|
||||
} else {
|
||||
_mouseOverCodeLocation = null;
|
||||
}
|
||||
|
||||
if(tooltip == null) {
|
||||
|
|
|
@ -74,6 +74,21 @@ namespace Mesen.Interop
|
|||
return Marshal.PtrToStructure<T>((IntPtr)ptr);
|
||||
}
|
||||
|
||||
public static BaseState GetCpuState(CpuType cpuType)
|
||||
{
|
||||
return cpuType switch {
|
||||
CpuType.Snes => GetCpuState<SnesCpuState>(cpuType),
|
||||
CpuType.Spc => GetCpuState<SpcState>(cpuType),
|
||||
CpuType.NecDsp => GetCpuState<NecDspState>(cpuType),
|
||||
CpuType.Sa1 => GetCpuState<SnesCpuState>(cpuType),
|
||||
CpuType.Gsu => GetCpuState<GsuState>(cpuType),
|
||||
CpuType.Cx4 => GetCpuState<Cx4State>(cpuType),
|
||||
CpuType.Gameboy => GetCpuState<GbCpuState>(cpuType),
|
||||
CpuType.Nes => GetCpuState<NesCpuState>(cpuType),
|
||||
_ => throw new Exception("Unsupport cpu type")
|
||||
};
|
||||
}
|
||||
|
||||
[DllImport(DllPath)] private static extern void GetPpuState(IntPtr state, CpuType cpuType);
|
||||
public unsafe static T GetPpuState<T>(CpuType cpuType) where T : struct, BaseState
|
||||
{
|
||||
|
@ -122,6 +137,9 @@ namespace Mesen.Interop
|
|||
return Marshal.PtrToStructure<T>((IntPtr)ptr);
|
||||
}
|
||||
|
||||
[DllImport(DllPath)] public static extern void SetProgramCounter(CpuType cpuType, UInt32 address);
|
||||
[DllImport(DllPath)] public static extern UInt32 GetProgramCounter(CpuType cpuType, [MarshalAs(UnmanagedType.I1)] bool getInstPc);
|
||||
|
||||
[DllImport(DllPath)] public static extern void SetScriptTimeout(UInt32 timeout);
|
||||
[DllImport(DllPath)] public static extern Int32 LoadScript(string name, [MarshalAs(UnmanagedType.LPUTF8Str)]string content, Int32 scriptId = -1);
|
||||
[DllImport(DllPath)] public static extern void RemoveScript(Int32 scriptId);
|
||||
|
@ -130,6 +148,8 @@ namespace Mesen.Interop
|
|||
|
||||
[DllImport(DllPath)] public static extern Int32 EvaluateExpression([MarshalAs(UnmanagedType.LPUTF8Str)]string expression, CpuType cpuType, out EvalResultType resultType, [MarshalAs(UnmanagedType.I1)]bool useCache);
|
||||
|
||||
[DllImport(DllPath)] public static extern DebuggerFeatures GetDebuggerFeatures(CpuType type);
|
||||
|
||||
[DllImport(DllPath)] public static extern Int32 GetMemorySize(MemoryType type);
|
||||
[DllImport(DllPath)] public static extern Byte GetMemoryValue(MemoryType type, UInt32 address);
|
||||
[DllImport(DllPath)] public static extern void SetMemoryValue(MemoryType type, UInt32 address, byte value);
|
||||
|
@ -377,8 +397,13 @@ namespace Mesen.Interop
|
|||
{
|
||||
return cpuType switch {
|
||||
CpuType.Snes => state is SnesCpuState,
|
||||
CpuType.Nes => state is NesCpuState,
|
||||
CpuType.Spc => state is SpcState,
|
||||
CpuType.NecDsp => state is NecDspState,
|
||||
CpuType.Sa1 => state is SnesCpuState,
|
||||
CpuType.Gsu => state is GsuState,
|
||||
CpuType.Cx4 => state is Cx4State,
|
||||
CpuType.Gameboy => state is GbCpuState,
|
||||
CpuType.Nes => state is NesCpuState,
|
||||
_ => false
|
||||
};
|
||||
}
|
||||
|
@ -858,6 +883,17 @@ namespace Mesen.Interop
|
|||
public byte[] Format;
|
||||
}
|
||||
|
||||
public struct DebuggerFeatures
|
||||
{
|
||||
[MarshalAs(UnmanagedType.I1)] public bool RunToIrq;
|
||||
[MarshalAs(UnmanagedType.I1)] public bool RunToNmi;
|
||||
[MarshalAs(UnmanagedType.I1)] public bool StepOver;
|
||||
[MarshalAs(UnmanagedType.I1)] public bool StepOut;
|
||||
[MarshalAs(UnmanagedType.I1)] public bool StepBack;
|
||||
[MarshalAs(UnmanagedType.I1)] public bool ChangeProgramCounter;
|
||||
[MarshalAs(UnmanagedType.I1)] public bool CallStack;
|
||||
}
|
||||
|
||||
public enum EvalResultType
|
||||
{
|
||||
Numeric = 0,
|
||||
|
|
|
@ -1914,7 +1914,7 @@ x == [$150] || y == [10]
|
|||
<Value ID="CodeWindow_ViewInMemoryViewer">Code Window: View in Memory Viewer</Value>
|
||||
<Value ID="CodeWindow_AddToWatch">Code Window: Add to Watch</Value>
|
||||
<Value ID="CodeWindow_GoToLocation">Code Window: Go to Location</Value>
|
||||
<Value ID="CodeWindow_SetNextStatement">Code Window: Set Next Statement</Value>
|
||||
<Value ID="CodeWindow_MoveProgramCounter">Code Window: Move Program Counter</Value>
|
||||
<Value ID="CodeWindow_EditSelectedCode">Code Window: Edit Selected Code</Value>
|
||||
<Value ID="CodeWindow_EditSourceFile">Code Window: Edit Source File (Source View)</Value>
|
||||
<Value ID="CodeWindow_EditLabel">Code Window: Edit Label</Value>
|
||||
|
@ -2171,6 +2171,8 @@ x == [$150] || y == [10]
|
|||
<Value ID="ResetCdl">Reset CDL data</Value>
|
||||
<Value ID="LoadCdl">Load CDL data from...</Value>
|
||||
<Value ID="SaveCdl">Save CDL data as...</Value>
|
||||
|
||||
<Value ID="MoveProgramCounter">Move Program Counter</Value>
|
||||
</Enum>
|
||||
</Enums>
|
||||
</Resources>
|
Loading…
Add table
Reference in a new issue