Debugger: SPC debugger/breakpoints/call stack

This commit is contained in:
Sour 2019-04-07 12:25:14 -04:00
parent f8392d2f65
commit d89f4ba0cb
48 changed files with 1677 additions and 356 deletions

View file

@ -4,7 +4,7 @@
bool Breakpoint::Matches(uint32_t memoryAddr, AddressInfo &info)
{
if(_memoryType == SnesMemoryType::CpuMemory) {
if(_memoryType <= SnesMemoryType::SpcMemory) {
if(_startAddr == -1) {
return true;
} else if(_endAddr == -1) {

View file

@ -420,7 +420,9 @@
<ClCompile Include="CpuDisUtils.cpp">
<Filter>Debugger\Disassembler</Filter>
</ClCompile>
<ClCompile Include="SpcDisUtils.cpp" />
<ClCompile Include="SpcDisUtils.cpp">
<Filter>Debugger\Disassembler</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<Filter Include="SNES">

View file

@ -408,7 +408,9 @@ void Cpu::Idle()
uint8_t Cpu::ReadOperandByte()
{
return ReadCode(_state.PC++, MemoryOperationType::ExecOperand);
uint8_t value = ReadCode(_state.PC, MemoryOperationType::ExecOperand);
_state.PC++;
return value;
}
uint16_t Cpu::ReadOperandWord()

View file

@ -214,6 +214,9 @@ enum class StepType
CpuStep,
CpuStepOut,
CpuStepOver,
SpcStep,
SpcStepOut,
SpcStepOver,
PpuStep,
SpecificScanline,
};
@ -222,6 +225,6 @@ enum class CpuType : uint8_t
{
Cpu,
Spc,
SuperFx,
Sa1,
//SuperFx,
//Sa1,
};

View file

@ -43,11 +43,15 @@ Debugger::Debugger(shared_ptr<Console> console)
_ppuTools.reset(new PpuTools(_console.get(), _ppu.get()));
_eventManager.reset(new EventManager(this, _cpu.get(), _ppu.get()));
_callstackManager.reset(new CallstackManager(this));
_spcCallstackManager.reset(new CallstackManager(this));
_cpuStepCount = -1;
_spcStepCount = -1;
_ppuStepCount = -1;
_breakAddress = -1;
_cpuBreakAddress = -1;
_spcBreakAddress = -1;
_breakScanline = -1;
_executionStopped = false;
_breakRequestCount = 0;
@ -195,6 +199,32 @@ void Debugger::ProcessSpcRead(uint16_t addr, uint8_t value, MemoryOperationType
DisassemblyInfo disInfo = _disassembler->GetDisassemblyInfo(addressInfo);
_traceLogger->Log(debugState, disInfo);
if(_spcPrevOpCode == 0x3F || _spcPrevOpCode == 0x0F) {
//JSR, BRK
uint8_t opSize = DisassemblyInfo::GetOpSize(_spcPrevOpCode, 0, CpuType::Spc);
uint16_t returnPc = _spcPrevProgramCounter + opSize;
_spcCallstackManager->Push(_spcPrevProgramCounter, debugState.Spc.PC, returnPc, StackFrameFlags::None);
} else if(_spcPrevOpCode == 0x6F || _spcPrevOpCode == 0x7F) {
//RTS, RTI
_spcCallstackManager->Pop(debugState.Spc.PC);
}
if(_spcBreakAddress == (int32_t)debugState.Spc.PC && (_spcPrevOpCode == 0x6F || _spcPrevOpCode == 0x7F)) {
//RTS/RTI found, if we're on the expected return address, break immediately (for step over/step out)
_cpuStepCount = 0;
}
_spcPrevOpCode = value;
_spcPrevProgramCounter = debugState.Spc.PC;
if(_spcStepCount > 0) {
_spcStepCount--;
if(_spcStepCount == 0) {
_spcStepCount = -1;
_cpuStepCount = 0;
}
}
}
ProcessBreakConditions(operation, addressInfo);
@ -253,7 +283,8 @@ void Debugger::ProcessPpuCycle()
void Debugger::SleepUntilResume()
{
_console->GetSoundMixer()->StopAudio();
_disassembler->Disassemble();
_disassembler->Disassemble(CpuType::Cpu);
_disassembler->Disassemble(CpuType::Spc);
_executionStopped = true;
@ -271,7 +302,7 @@ void Debugger::SleepUntilResume()
void Debugger::ProcessStepConditions(uint8_t opCode, uint32_t currentPc)
{
if(_breakAddress == (int32_t)currentPc && (opCode == 0x60 || opCode == 0x40 || opCode == 0x6B || opCode == 0x44 || opCode == 0x54)) {
if(_cpuBreakAddress == (int32_t)currentPc && (opCode == 0x60 || opCode == 0x40 || opCode == 0x6B || opCode == 0x44 || opCode == 0x54)) {
//RTS/RTL/RTI found, if we're on the expected return address, break immediately (for step over/step out)
_cpuStepCount = 0;
}
@ -322,8 +353,10 @@ int32_t Debugger::EvaluateExpression(string expression, EvalResultType &resultTy
void Debugger::Run()
{
_cpuStepCount = -1;
_spcStepCount = -1;
_ppuStepCount = -1;
_breakAddress = -1;
_cpuBreakAddress = -1;
_spcBreakAddress = -1;
_breakScanline = -1;
}
@ -332,29 +365,75 @@ void Debugger::Step(int32_t stepCount, StepType type)
switch(type) {
case StepType::CpuStep:
_cpuStepCount = stepCount;
_breakAddress = -1;
_cpuBreakAddress = -1;
_spcBreakAddress = -1;
_spcStepCount = -1;
_ppuStepCount = -1;
_breakScanline = -1;
break;
case StepType::CpuStepOut:
_breakAddress = _callstackManager->GetReturnAddress();
_cpuBreakAddress = _callstackManager->GetReturnAddress();
_cpuStepCount = -1;
_spcStepCount = -1;
_ppuStepCount = -1;
_spcBreakAddress = -1;
_breakScanline = -1;
break;
case StepType::CpuStepOver:
if(_prevOpCode == 0x20 || _prevOpCode == 0x22 || _prevOpCode == 0xFC || _prevOpCode == 0x00 || _prevOpCode == 0x02 || _prevOpCode == 0x44 || _prevOpCode == 0x54) {
//JSR, JSL, BRK, COP, MVP, MVN
_breakAddress = (_prevProgramCounter & 0xFF0000) | (((_prevProgramCounter & 0xFFFF) + DisassemblyInfo::GetOpSize(_prevOpCode, 0, CpuType::Cpu)) & 0xFFFF);
_cpuBreakAddress = (_prevProgramCounter & 0xFF0000) | (((_prevProgramCounter & 0xFFFF) + DisassemblyInfo::GetOpSize(_prevOpCode, 0, CpuType::Cpu)) & 0xFFFF);
_cpuStepCount = -1;
_spcStepCount = -1;
_ppuStepCount = -1;
_spcBreakAddress = -1;
_breakScanline = -1;
} else {
//For any other instruction, step over is the same as step into
_cpuStepCount = 1;
_breakAddress = -1;
_spcStepCount = -1;
_cpuBreakAddress = -1;
_spcBreakAddress = -1;
_ppuStepCount = -1;
_breakScanline = -1;
}
break;
case StepType::SpcStep:
_spcStepCount = stepCount;
_cpuStepCount = -1;
_cpuBreakAddress = -1;
_spcBreakAddress = -1;
_ppuStepCount = -1;
_breakScanline = -1;
break;
case StepType::SpcStepOut:
_spcBreakAddress = _spcCallstackManager->GetReturnAddress();
_spcStepCount = -1;
_cpuBreakAddress = -1;
_cpuStepCount = -1;
_ppuStepCount = -1;
_breakScanline = -1;
break;
case StepType::SpcStepOver:
if(_spcPrevOpCode == 0x3F || _spcPrevOpCode == 0x0F) {
//JSR, BRK
_spcBreakAddress = _spcPrevProgramCounter + DisassemblyInfo::GetOpSize(_spcPrevOpCode, 0, CpuType::Spc);
_cpuStepCount = -1;
_spcStepCount = -1;
_ppuStepCount = -1;
_cpuBreakAddress = -1;
_breakScanline = -1;
} else {
//For any other instruction, step over is the same as step into
_spcStepCount = 1;
_cpuStepCount = -1;
_cpuBreakAddress = -1;
_spcBreakAddress = -1;
_ppuStepCount = -1;
_breakScanline = -1;
}
@ -363,7 +442,9 @@ void Debugger::Step(int32_t stepCount, StepType type)
case StepType::PpuStep:
_ppuStepCount = stepCount;
_cpuStepCount = -1;
_breakAddress = -1;
_spcStepCount = -1;
_cpuBreakAddress = -1;
_spcBreakAddress = -1;
_breakScanline = -1;
break;
@ -371,7 +452,9 @@ void Debugger::Step(int32_t stepCount, StepType type)
_breakScanline = stepCount;
_ppuStepCount = -1;
_cpuStepCount = -1;
_breakAddress = -1;
_spcStepCount = -1;
_cpuBreakAddress = -1;
_spcBreakAddress = -1;
break;
}
}
@ -438,9 +521,9 @@ shared_ptr<EventManager> Debugger::GetEventManager()
return _eventManager;
}
shared_ptr<CallstackManager> Debugger::GetCallstackManager()
shared_ptr<CallstackManager> Debugger::GetCallstackManager(CpuType cpuType)
{
return _callstackManager;
return cpuType == CpuType::Cpu ? _callstackManager : _spcCallstackManager;
}
shared_ptr<Console> Debugger::GetConsole()

View file

@ -44,6 +44,7 @@ private:
shared_ptr<PpuTools> _ppuTools;
shared_ptr<EventManager> _eventManager;
shared_ptr<CallstackManager> _callstackManager;
shared_ptr<CallstackManager> _spcCallstackManager;
unique_ptr<ExpressionEvaluator> _watchExpEval;
@ -51,13 +52,18 @@ private:
atomic<uint32_t> _breakRequestCount;
atomic<int32_t> _cpuStepCount;
atomic<int32_t> _spcStepCount;
atomic<int32_t> _ppuStepCount;
atomic<int32_t> _breakAddress;
atomic<int32_t> _cpuBreakAddress;
atomic<int32_t> _spcBreakAddress;
atomic<int32_t> _breakScanline;
uint8_t _prevOpCode = 0;
uint32_t _prevProgramCounter = 0;
uint8_t _spcPrevOpCode = 0;
uint32_t _spcPrevProgramCounter = 0;
void SleepUntilResume();
void ProcessStepConditions(uint8_t opCode, uint32_t currentPc);
void ProcessBreakConditions(MemoryOperationInfo &operation, AddressInfo &addressInfo);
@ -101,6 +107,6 @@ public:
shared_ptr<BreakpointManager> GetBreakpointManager();
shared_ptr<PpuTools> GetPpuTools();
shared_ptr<EventManager> GetEventManager();
shared_ptr<CallstackManager> GetCallstackManager();
shared_ptr<CallstackManager> GetCallstackManager(CpuType cpuType);
shared_ptr<Console> GetConsole();
};

View file

@ -15,6 +15,7 @@ Disassembler::Disassembler(shared_ptr<Console> console, shared_ptr<CodeDataLogge
{
_cdl = cdl;
_console = console.get();
_spc = console->GetSpc().get();
_memoryManager = console->GetMemoryManager().get();
_prgRom = console->GetCartridge()->DebugGetPrgRom();
@ -86,7 +87,7 @@ uint32_t Disassembler::BuildCache(AddressInfo &addrInfo, uint8_t cpuFlags, CpuTy
if(!disInfo.IsInitialized()) {
DisassemblyInfo disassemblyInfo(source+addrInfo.Address, cpuFlags, type);
(*cache)[addrInfo.Address] = disassemblyInfo;
_needDisassemble = true;
_needDisassemble[(int)type] = true;
disInfo = disassemblyInfo;
}
return disInfo.GetOpSize();
@ -105,7 +106,8 @@ void Disassembler::InvalidateCache(AddressInfo addrInfo)
for(int i = 0; i < 4; i++) {
if(addrInfo.Address >= i) {
if((*cache)[addrInfo.Address - i].IsInitialized()) {
_needDisassemble = true;
_needDisassemble[(int)CpuType::Cpu] = true;
_needDisassemble[(int)CpuType::Spc] = true;
(*cache)[addrInfo.Address - i].Reset();
}
}
@ -113,17 +115,20 @@ void Disassembler::InvalidateCache(AddressInfo addrInfo)
}
}
void Disassembler::Disassemble()
void Disassembler::Disassemble(CpuType cpuType)
{
if(!_needDisassemble) {
if(!_needDisassemble[(int)cpuType]) {
return;
}
_needDisassemble = false;
_needDisassemble[(int)cpuType] = false;
auto lock = _disassemblyLock.AcquireSafe();
_disassembly.clear();
bool isSpc = cpuType == CpuType::Spc;
vector<DisassemblyResult> &results = isSpc ? _spcDisassembly : _disassembly;
int32_t maxAddr = isSpc ? 0xFFFF : 0xFFFFFF;
results.clear();
uint8_t *source;
uint32_t sourceLength;
@ -134,9 +139,9 @@ void Disassembler::Disassemble()
AddressInfo addrInfo = {};
AddressInfo prevAddrInfo = {};
for(int32_t i = 0; i <= 0xFFFFFF; i++) {
for(int32_t i = 0; i <= maxAddr; i++) {
prevAddrInfo = addrInfo;
addrInfo = _memoryManager->GetAbsoluteAddress(i);
addrInfo = isSpc ? _spc->GetAbsoluteAddress(i) : _memoryManager->GetAbsoluteAddress(i);
if(addrInfo.Address < 0) {
continue;
@ -150,7 +155,7 @@ void Disassembler::Disassemble()
uint8_t opCode = (source + addrInfo.Address)[0];
bool needRealign = true;
if(!disassemblyInfo.IsInitialized() && disassembleAll) {
opSize = DisassemblyInfo::GetOpSize(opCode, 0, CpuType::Cpu);
opSize = DisassemblyInfo::GetOpSize(opCode, 0, cpuType);
} else if(disassemblyInfo.IsInitialized()) {
opSize = disassemblyInfo.GetOpSize();
needRealign = false;
@ -158,15 +163,15 @@ void Disassembler::Disassemble()
if(disassemblyInfo.IsInitialized() || disassembleAll) {
if(inUnknownBlock) {
_disassembly.push_back(DisassemblyResult(prevAddrInfo, i - 1, LineFlags::BlockEnd));
results.push_back(DisassemblyResult(prevAddrInfo, i - 1, LineFlags::BlockEnd));
inUnknownBlock = false;
}
if(addrInfo.Type == SnesMemoryType::PrgRom && _cdl->IsSubEntryPoint(addrInfo.Address)) {
_disassembly.push_back(DisassemblyResult(-1, LineFlags::SubStart | LineFlags::BlockStart | LineFlags::VerifiedCode));
results.push_back(DisassemblyResult(-1, LineFlags::SubStart | LineFlags::BlockStart | LineFlags::VerifiedCode));
}
_disassembly.push_back(DisassemblyResult(addrInfo, i));
results.push_back(DisassemblyResult(addrInfo, i));
if(needRealign) {
for(int j = 1; j < opSize; j++) {
if((*cache)[addrInfo.Address + j].IsInitialized()) {
@ -178,21 +183,21 @@ void Disassembler::Disassemble()
i += opSize - 1;
}
if(opCode == 0x60 || opCode == 0x6B) {
if(DisassemblyInfo::IsReturnInstruction(opCode, cpuType)) {
//End of function
_disassembly.push_back(DisassemblyResult(-1, LineFlags::VerifiedCode | LineFlags::BlockEnd));
results.push_back(DisassemblyResult(-1, LineFlags::VerifiedCode | LineFlags::BlockEnd));
}
} else {
if(!inUnknownBlock) {
inUnknownBlock = true;
_disassembly.push_back(DisassemblyResult(addrInfo, i, LineFlags::BlockStart));
_disassembly.push_back(DisassemblyResult(-1, LineFlags::None));
results.push_back(DisassemblyResult(addrInfo, i, LineFlags::BlockStart));
results.push_back(DisassemblyResult(-1, LineFlags::None));
}
}
}
if(inUnknownBlock) {
_disassembly.push_back(DisassemblyResult(addrInfo, 0xFFFFFF, LineFlags::BlockEnd));
results.push_back(DisassemblyResult(addrInfo, maxAddr, LineFlags::BlockEnd));
}
}
@ -215,37 +220,40 @@ DisassemblyInfo Disassembler::GetDisassemblyInfo(AddressInfo &info)
}
}
uint32_t Disassembler::GetLineCount()
uint32_t Disassembler::GetLineCount(CpuType type)
{
auto lock = _disassemblyLock.AcquireSafe();
return (uint32_t)_disassembly.size();
vector<DisassemblyResult> &source = type == CpuType::Cpu ? _disassembly : _spcDisassembly;
return (uint32_t)source.size();
}
uint32_t Disassembler::GetLineIndex(uint32_t cpuAddress)
uint32_t Disassembler::GetLineIndex(CpuType type, uint32_t cpuAddress)
{
auto lock = _disassemblyLock.AcquireSafe();
vector<DisassemblyResult> &source = type == CpuType::Cpu ? _disassembly : _spcDisassembly;
uint32_t lastAddress = 0;
for(size_t i = 1; i < _disassembly.size(); i++) {
if(_disassembly[i].CpuAddress < 0) {
for(size_t i = 1; i < source.size(); i++) {
if(source[i].CpuAddress < 0) {
continue;
}
if(cpuAddress == (uint32_t)_disassembly[i].CpuAddress) {
if(cpuAddress == (uint32_t)source[i].CpuAddress) {
return (uint32_t)i;
} else if(cpuAddress >= lastAddress && cpuAddress < (uint32_t)_disassembly[i].CpuAddress) {
} else if(cpuAddress >= lastAddress && cpuAddress < (uint32_t)source[i].CpuAddress) {
return (uint32_t)i - 1;
}
lastAddress = _disassembly[i].CpuAddress;
lastAddress = source[i].CpuAddress;
}
return 0;
}
bool Disassembler::GetLineData(uint32_t lineIndex, CodeLineData &data)
bool Disassembler::GetLineData(CpuType type, uint32_t lineIndex, CodeLineData &data)
{
auto lock =_disassemblyLock.AcquireSafe();
if(lineIndex < _disassembly.size()) {
DisassemblyResult result = _disassembly[lineIndex];
vector<DisassemblyResult> &source = type == CpuType::Cpu ? _disassembly : _spcDisassembly;
if(lineIndex < source.size()) {
DisassemblyResult result = source[lineIndex];
data.Address = result.CpuAddress;
data.AbsoluteAddress = result.Address.Address;
data.Flags = result.Flags;
@ -267,29 +275,36 @@ bool Disassembler::GetLineData(uint32_t lineIndex, CodeLineData &data)
GetSource(result.Address, &source, sourceLength, &cache);
disInfo = (*cache)[result.Address.Address];
CpuState state = _console->GetCpu()->GetState();
state.PC = (uint16_t)result.CpuAddress;
state.K = (result.CpuAddress >> 16);
data.OpSize = disInfo.GetOpSize();
if(!disInfo.IsInitialized()) {
disInfo = DisassemblyInfo(source + result.Address.Address, state.PS, CpuType::Cpu);
if(type == CpuType::Cpu) {
CpuState state = _console->GetCpu()->GetState();
state.PC = (uint16_t)result.CpuAddress;
state.K = (result.CpuAddress >> 16);
if(!disInfo.IsInitialized()) {
disInfo = DisassemblyInfo(source + result.Address.Address, state.PS, CpuType::Cpu);
} else {
data.Flags |= (uint8_t)LineFlags::VerifiedCode;
}
data.EffectiveAddress = disInfo.GetEffectiveAddress(_console, &state);
if(data.EffectiveAddress >= 0) {
data.Value = disInfo.GetMemoryValue(data.EffectiveAddress, _console->GetMemoryManager().get(), data.ValueSize);
} else {
data.ValueSize = 0;
}
} else {
data.Flags |= (uint8_t)LineFlags::VerifiedCode;
//TODO
data.EffectiveAddress = -1;
data.ValueSize = 0;
}
string text;
disInfo.GetDisassembly(text, result.CpuAddress);
memcpy(data.Text, text.c_str(), std::min<int>((int)text.size(), 1000));
data.OpSize = disInfo.GetOpSize();
data.EffectiveAddress = disInfo.GetEffectiveAddress(_console, &state);
if(data.EffectiveAddress >= 0) {
data.Value = disInfo.GetMemoryValue(data.EffectiveAddress, _console->GetMemoryManager().get(), data.ValueSize);
} else {
data.ValueSize = 0;
}
disInfo.GetByteCode(data.ByteCode);
data.Comment[0] = 0;
} else {
@ -306,13 +321,14 @@ bool Disassembler::GetLineData(uint32_t lineIndex, CodeLineData &data)
return false;
}
int32_t Disassembler::SearchDisassembly(const char *searchString, int32_t startPosition, int32_t endPosition, bool searchBackwards)
int32_t Disassembler::SearchDisassembly(CpuType type, const char *searchString, int32_t startPosition, int32_t endPosition, bool searchBackwards)
{
auto lock = _disassemblyLock.AcquireSafe();
vector<DisassemblyResult> &source = type == CpuType::Cpu ? _disassembly : _spcDisassembly;
int step = searchBackwards ? -1 : 1;
CodeLineData lineData = {};
for(int i = startPosition; i != endPosition; i += step) {
GetLineData(i, lineData);
GetLineData(type, i, lineData);
string line = lineData.Text;
std::transform(line.begin(), line.end(), line.begin(), ::tolower);
@ -321,10 +337,10 @@ int32_t Disassembler::SearchDisassembly(const char *searchString, int32_t startP
}
//Continue search from start/end of document
if(!searchBackwards && i == (int)(_disassembly.size() - 1)) {
if(!searchBackwards && i == (int)(source.size() - 1)) {
i = 0;
} else if(searchBackwards && i == 0) {
i = (int32_t)(_disassembly.size() - 1);
i = (int32_t)(source.size() - 1);
}
}

View file

@ -6,6 +6,7 @@
class MemoryManager;
class Console;
class Spc;
class CodeDataLogger;
struct CpuState;
enum class CpuType : uint8_t;
@ -15,6 +16,7 @@ class Disassembler
private:
MemoryManager *_memoryManager;
Console *_console;
Spc *_spc;
shared_ptr<CodeDataLogger> _cdl;
vector<DisassemblyInfo> _prgCache;
@ -25,8 +27,9 @@ private:
SimpleLock _disassemblyLock;
vector<DisassemblyResult> _disassembly;
vector<DisassemblyResult> _spcDisassembly;
bool _needDisassemble = true;
bool _needDisassemble[2] = { true, true };
uint8_t *_prgRom;
uint32_t _prgRomSize;
@ -46,12 +49,12 @@ public:
uint32_t BuildCache(AddressInfo &addrInfo, uint8_t cpuFlags, CpuType type);
void InvalidateCache(AddressInfo addrInfo);
void Disassemble();
void Disassemble(CpuType cpuType);
DisassemblyInfo GetDisassemblyInfo(AddressInfo &info);
uint32_t GetLineCount();
uint32_t GetLineIndex(uint32_t cpuAddress);
bool GetLineData(uint32_t lineIndex, CodeLineData &data);
int32_t SearchDisassembly(const char* searchString, int32_t startPosition, int32_t endPosition, bool searchBackwards);
uint32_t GetLineCount(CpuType type);
uint32_t GetLineIndex(CpuType type, uint32_t cpuAddress);
bool GetLineData(CpuType type, uint32_t lineIndex, CodeLineData &data);
int32_t SearchDisassembly(CpuType type, const char* searchString, int32_t startPosition, int32_t endPosition, bool searchBackwards);
};

View file

@ -105,6 +105,25 @@ uint8_t DisassemblyInfo::GetOpSize(uint8_t opCode, uint8_t flags, CpuType type)
return 0;
}
bool DisassemblyInfo::IsJumpToSub(uint8_t opCode, CpuType type)
{
switch(type) {
case CpuType::Cpu: return opCode == 0x20 || opCode == 0x22 || opCode == 0xFC; //JSR, JSL
case CpuType::Spc: return opCode == 0x3F || opCode == 0x0F; //JSR, BRK
}
}
bool DisassemblyInfo::IsReturnInstruction(uint8_t opCode, CpuType type)
{
//RTS/RTI
switch(type) {
case CpuType::Cpu: return opCode == 0x60 || opCode == 0x6B || opCode == 0x40;
case CpuType::Spc: return opCode == 0x6F || opCode == 0x7F;
}
return false;
}
uint16_t DisassemblyInfo::GetMemoryValue(uint32_t effectiveAddress, MemoryManager *memoryManager, uint8_t &valueSize)
{
if(_flags & ProcFlags::MemoryMode8) {

View file

@ -38,7 +38,9 @@ public:
void GetByteCode(string &out);
static uint8_t GetOpSize(uint8_t opCode, uint8_t flags, CpuType type);
static bool IsJumpToSub(uint8_t opCode, CpuType type);
static bool IsReturnInstruction(uint8_t opCode, CpuType type);
int32_t GetEffectiveAddress(Console *console, void *cpuState);
uint16_t GetMemoryValue(uint32_t effectiveAddress, MemoryManager *memoryManager, uint8_t &valueSize);
};

View file

@ -25,6 +25,7 @@ void MemoryDumper::SetMemoryState(SnesMemoryType type, uint8_t *buffer, uint32_t
switch(type) {
default:
case SnesMemoryType::CpuMemory:
case SnesMemoryType::SpcMemory:
break;
case SnesMemoryType::PrgRom: memcpy(_cartridge->DebugGetPrgRom(), buffer, length); break;
@ -43,6 +44,7 @@ uint32_t MemoryDumper::GetMemorySize(SnesMemoryType type)
switch(type) {
default: return 0;
case SnesMemoryType::CpuMemory: return 0x1000000;
case SnesMemoryType::SpcMemory: return 0x10000;
case SnesMemoryType::PrgRom: return _cartridge->DebugGetPrgRomSize();
case SnesMemoryType::WorkRam: return MemoryManager::WorkRamSize;
case SnesMemoryType::SaveRam: return _cartridge->DebugGetSaveRamSize();

View file

@ -292,12 +292,16 @@ void Spc::Serialize(Serializer &s)
uint8_t Spc::GetOpCode()
{
return Read(_state.PC++, MemoryOperationType::ExecOpCode);
uint8_t value = Read(_state.PC, MemoryOperationType::ExecOpCode);
_state.PC++;
return value;
}
uint8_t Spc::ReadOperandByte()
{
return Read(_state.PC++, MemoryOperationType::ExecOperand);
uint8_t value = Read(_state.PC, MemoryOperationType::ExecOperand);
_state.PC++;
return value;
}
uint16_t Spc::ReadWord(uint16_t addr, MemoryOperationType type)

View file

@ -4,7 +4,7 @@
#include "../Utilities/FastString.h"
#include "../Utilities/HexUtilities.h"
constexpr const char* _opTemplate[256] = {
/*constexpr const char* _opTemplate[256] = {
"NOP", "TCALL 0", "SET1 d.0", "BBS d.0, q", "OR A, d", "OR A, !a", "OR A, (X)", "OR A, [d+X]", "OR A, #i", "OR t, s", "OR1 C, m.b", "ASL d", "ASL !a", "PUSH PSW", "TSET1 !a", "BRK",
"BPL r", "TCALL 1", "CLR1 d.0", "BBC d.0, q", "OR A, d+X", "OR A, !a+X", "OR A, !a+Y", "OR A, [d]+Y", "OR e, #i", "OR (X), (Y)", "DECW d", "ASL d+X", "ASL A", "DEC X", "CMP X, !a", "JMP [!a+X]",
"CLRP", "TCALL 2", "SET1 d.1", "BBS d.1, q", "AND A, d", "AND A, !a", "AND A, (X)", "AND A, [d+X]", "AND A, #i", "AND t, s", "OR1 C, /m.b", "ROL d", "ROL !a", "PUSH A", "CBNE d, q", "BRA r",
@ -21,6 +21,25 @@ constexpr const char* _opTemplate[256] = {
"BNE r", "TCALL 13", "CLR1 d.6", "BBC d.6, q", "MOV d+X, A", "MOV !a+X, A", "MOV !a+Y, A", "MOV [d]+Y, A", "MOV e, X", "MOV d+Y, X", "MOVW d, YA", "MOV d+X, Y", "DEC Y", "MOV A, Y", "CBNE d+X, q", "DAA A",
"CLRV", "TCALL 14", "SET1 d.7", "BBS d.7, q", "MOV A, d", "MOV A, !a", "MOV A, (X)", "MOV A, [d+X]", "MOV A, #i", "MOV X, !a", "NOT1 m.b", "MOV Y, d", "MOV Y, !a","NOTC", "POP Y", "SLEEP",
"BEQ r", "TCALL 15", "CLR1 d.7", "BBC d.7, q", "MOV A, d+X", "MOV A, !a+X", "MOV A, !a+Y", "MOV A, [d]+Y", "MOV X, d", "MOV X, d+Y", "MOV t, s", "MOV Y, d+X", "INC Y", "MOV Y, A", "DBNZ Y, q", "STOP"
};*/
constexpr const char* _opTemplate[256] = {
"NOP", "JST0", "SET1 d.0", "BBS d.0, q", "ORA d", "ORA a", "ORA (X)", "ORA [d,X]", "ORA #i", "OR t, s", "ORC m.b", "ASL d", "ASL a", "PHP", "SET1 a", "BRK",
"BPL r", "JST1", "CLR1 d.0", "BBC d.0, q", "ORA d,X", "ORA a,X", "ORA a,Y", "ORA [d],Y", "OR e, #i", "OR (X), (Y)", "DEW d", "ASL d,X", "ASL A", "DEX", "CPX a", "JMP [a,X]",
"CLP", "JST2", "SET1 d.1", "BBS d.1, q", "AND d", "AND a", "AND (X)", "AND [d,X]", "AND #i", "AND t, s", "ORC /m.b", "ROL d", "ROL a", "PHA", "CBNE d, q", "BRA r",
"BMI r", "JST3", "CLR1 d.1", "BBC d.1, q", "AND d,X", "AND a,X", "AND a,Y", "AND [d],Y", "AND e, #i", "AND (X), (Y)","INW d", "ROL d,X", "ROL A", "INX", "CPX d", "JSR a",
"SEP", "JST4", "SET1 d.2", "BBS d.2, q", "EOR d", "EOR a", "EOR (X)", "EOR [d,X]", "EOR #i", "EOR t, s", "ANDC, m.b", "LSR d", "LSR a", "PHX", "CLR1 a", "JSP u",
"BVC r", "JST5", "CLR1 d.2", "BBC d.2, q", "EOR d,X", "EOR a,X", "EOR a,Y", "EOR [d],Y", "EOR e, #i", "EOR (X), (Y)","CPW d", "LSR d,X", "LSR A", "TAX", "CPY a", "JMP a",
"CLC", "JST6", "SET1 d.3", "BBS d.3, q", "CMP d", "CMP a", "CMP (X)", "CMP [d,X]", "CMP #i", "CMP t, s", "ANDC, /m.b", "ROR d", "ROR a", "PHY", "DBNZ d, q", "RTS",
"BVS r", "JST7", "CLR1 d.3", "BBC d.3, q", "CMP d,X", "CMP a,X", "CMP a,Y", "CMP [d],Y", "CMP e, #i", "CMP (X), (Y)","ADW d", "ROR d,X", "ROR A", "TXA", "CPY, d", "RTI",
"SEC", "JST8", "SET1 d.4", "BBS d.4, q", "ADC d", "ADC a", "ADC (X)", "ADC [d,X]", "ADC #i", "ADC t, s", "EORC, m.b", "DEC d", "DEC a", "LDY #i","PLP", "MOV e, #i",
"BCC r", "JST9", "CLR1 d.4", "BBC d.4, q", "ADC d,X", "ADC a,X", "ADC a,Y", "ADC [d],Y", "ADC e, #i", "ADC (X), (Y)","SBW d", "DEC d,X", "DEC A", "TSX", "DIV YA, X", "XCN A",
"CLI", "JSTA", "SET1 d.5", "BBS d.5, q", "SBC d", "SBC a", "SBC (X)", "SBC [d,X]", "SBC #i", "SBC t, s", "LDC m.b", "INC d", "INC a", "CMY #i","PLA", "STA (X)+, A",
"BCS r", "JSTB", "CLR1 d.5", "BBC d.5, q", "SBC d,X", "SBC a,X", "SBC a,Y", "SBC [d],Y", "SBC e, #i", "SBC (X), (Y)","LDW d", "INC d,X", "INC A", "TXS", "DAS A", "LDA (X)+",
"SEI", "JSTC", "SET1 d.6", "BBS d.6, q", "STA d", "STA a", "STA (X)", "STA [d,X]", "CPX #i", "STX a", "STC m.b", "STY d", "STY a", "LDX #i","PLX", "MUL YA",
"BNE r", "JSTD", "CLR1 d.6", "BBC d.6, q", "STA d,X", "STA a,X", "STA a,Y", "STA [d],Y", "STX e", "STX d,Y", "STW d", "STY d,X", "DEY", "TYA", "CBNE d,X, q", "DAA A",
"CLV", "JSTE", "SET1 d.7", "BBS d.7, q", "LDA d", "LDA a", "LDA (X)", "LDA [d,X]", "LDA #i", "LDX a", "NOT m.b", "LDY d", "LDY, a","NOTC", "PLY", "WAI",
"BEQ r", "JSTF", "CLR1 d.7", "BBC d.7, q", "LDA d,X", "LDA a,X", "LDA a,Y", "LDA [d],Y", "LDX d", "LDX d,Y", "MOV t, s", "LDY d,X", "INC Y", "TAY", "DBNZ Y, q", "HLT"
};
constexpr const uint8_t _opSize[256] = {
@ -51,8 +70,8 @@ void SpcDisUtils::GetDisassembly(DisassemblyInfo &info, string &out, uint32_t me
int i = 0;
while(op[i]) {
switch(op[i]) {
case 'r': str.Write('$', HexUtilities::ToHex(memoryAddr + (int8_t)byteCode[1])); break;
case 'q': str.Write('$', HexUtilities::ToHex(memoryAddr + (int8_t)byteCode[2])); break; //relative 2nd byte
case 'r': str.Write('$', HexUtilities::ToHex(memoryAddr + (int8_t)byteCode[1] + GetOpSize(byteCode[0]))); break;
case 'q': str.Write('$', HexUtilities::ToHex(memoryAddr + (int8_t)byteCode[2] + GetOpSize(byteCode[0]))); break; //relative 2nd byte
case 'a': str.Write('$', HexUtilities::ToHex(byteCode[1] | (byteCode[2] << 8))); break;

View file

@ -42,10 +42,10 @@ extern "C"
DllExport void __stdcall ResumeExecution() { if(IsDebuggerRunning()) GetDebugger()->Run(); }
DllExport void __stdcall Step(uint32_t count, StepType type) { GetDebugger()->Step(count, type); }
DllExport void __stdcall GetDisassemblyLineData(uint32_t lineIndex, CodeLineData &data) { GetDebugger()->GetDisassembler()->GetLineData(lineIndex, data); }
DllExport uint32_t __stdcall GetDisassemblyLineCount() { return GetDebugger()->GetDisassembler()->GetLineCount(); }
DllExport uint32_t __stdcall GetDisassemblyLineIndex(uint32_t cpuAddress) { return GetDebugger()->GetDisassembler()->GetLineIndex(cpuAddress); }
DllExport int32_t __stdcall SearchDisassembly(const char* searchString, int32_t startPosition, int32_t endPosition, bool searchBackwards) { return GetDebugger()->GetDisassembler()->SearchDisassembly(searchString, startPosition, endPosition, searchBackwards); }
DllExport void __stdcall GetDisassemblyLineData(CpuType type, uint32_t lineIndex, CodeLineData &data) { GetDebugger()->GetDisassembler()->GetLineData(type, lineIndex, data); }
DllExport uint32_t __stdcall GetDisassemblyLineCount(CpuType type) { return GetDebugger()->GetDisassembler()->GetLineCount(type); }
DllExport uint32_t __stdcall GetDisassemblyLineIndex(CpuType type, uint32_t cpuAddress) { return GetDebugger()->GetDisassembler()->GetLineIndex(type, cpuAddress); }
DllExport int32_t __stdcall SearchDisassembly(CpuType type, const char* searchString, int32_t startPosition, int32_t endPosition, bool searchBackwards) { return GetDebugger()->GetDisassembler()->SearchDisassembly(type, searchString, startPosition, endPosition, searchBackwards); }
DllExport void __stdcall SetTraceOptions(TraceLoggerOptions options) { GetDebugger()->GetTraceLogger()->SetOptions(options); }
DllExport void __stdcall StartTraceLogger(char* filename) { GetDebugger()->GetTraceLogger()->StartLogging(filename); }
@ -54,7 +54,7 @@ extern "C"
DllExport void __stdcall SetBreakpoints(Breakpoint breakpoints[], uint32_t length) { GetDebugger()->GetBreakpointManager()->SetBreakpoints(breakpoints, length); }
DllExport int32_t __stdcall EvaluateExpression(char* expression, EvalResultType *resultType, bool useCache) { return GetDebugger()->EvaluateExpression(expression, *resultType, useCache); }
DllExport void __stdcall GetCallstack(StackFrameInfo *callstackArray, uint32_t &callstackSize) { GetDebugger()->GetCallstackManager()->GetCallstack(callstackArray, callstackSize); }
DllExport void __stdcall GetCallstack(CpuType cpuType, StackFrameInfo *callstackArray, uint32_t &callstackSize) { GetDebugger()->GetCallstackManager(cpuType)->GetCallstack(callstackArray, callstackSize); }
DllExport void __stdcall GetState(DebugState &state) { GetDebugger()->GetState(state); }

View file

@ -33,22 +33,23 @@ namespace Mesen.GUI.Debugger
public string GetAddressString(bool showLabel)
{
string addr = "";
string format = _memoryType == SnesMemoryType.SpcMemory ? "X4" : "X6";
switch(AddressType) {
case BreakpointAddressType.AnyAddress:
return "<any>";
case BreakpointAddressType.SingleAddress:
if(IsAbsoluteAddress) {
addr += $"[${Address.ToString("X6")}]";
addr += $"[${Address.ToString(format)}]";
} else {
addr = $"${Address.ToString("X6")}";
addr = $"${Address.ToString(format)}";
}
break;
case BreakpointAddressType.AddressRange:
if(IsAbsoluteAddress) {
addr = $"[${StartAddress.ToString("X6")}] - [${EndAddress.ToString("X6")}]";
addr = $"[${StartAddress.ToString(format)}] - [${EndAddress.ToString(format)}]";
} else {
addr = $"${StartAddress.ToString("X6")} - ${EndAddress.ToString("X6")}";
addr = $"${StartAddress.ToString(format)} - ${EndAddress.ToString(format)}";
}
break;
}
@ -65,6 +66,7 @@ namespace Mesen.GUI.Debugger
{
return (
type == SnesMemoryType.CpuMemory ||
type == SnesMemoryType.SpcMemory ||
type == SnesMemoryType.WorkRam ||
type == SnesMemoryType.SaveRam ||
type == SnesMemoryType.PrgRom
@ -83,7 +85,7 @@ namespace Mesen.GUI.Debugger
BreakpointManager.RefreshBreakpoints(this);
}
public bool IsAbsoluteAddress { get { return MemoryType != SnesMemoryType.CpuMemory; } }
public bool IsAbsoluteAddress { get { return MemoryType != SnesMemoryType.CpuMemory && MemoryType != SnesMemoryType.SpcMemory; } }
public bool IsCpuBreakpoint { get { return this._isCpuBreakpoint; } }
private BreakpointTypeFlags Type
@ -111,6 +113,7 @@ namespace Mesen.GUI.Debugger
switch(MemoryType) {
default: throw new Exception("invalid type");
case SnesMemoryType.CpuMemory: type = "CPU"; break;
case SnesMemoryType.SpcMemory: type = "SPC"; break;
case SnesMemoryType.PrgRom: type = "PRG"; break;
case SnesMemoryType.WorkRam: type = "WRAM"; break;
case SnesMemoryType.SaveRam: type = "SRAM"; break;
@ -153,14 +156,20 @@ namespace Mesen.GUI.Debugger
return -1;
}
public bool Matches(CpuType type)
{
return (
(type == CpuType.Spc && _memoryType == SnesMemoryType.SpcMemory) ||
(type == CpuType.Cpu && _memoryType != SnesMemoryType.SpcMemory)
);
}
public bool Matches(UInt32 address, SnesMemoryType type)
{
if(IsTypeCpuBreakpoint(type) != this.IsCpuBreakpoint) {
return false;
}
bool isRelativeMemory = type == SnesMemoryType.CpuMemory;
if(this.AddressType == BreakpointAddressType.SingleAddress) {
return address == this.Address && type == this.MemoryType;
} else if(this.AddressType == BreakpointAddressType.AddressRange) {

View file

@ -18,6 +18,7 @@ namespace Mesen.GUI.Debugger.Controls
public delegate void BreakpointNavigationHandler(Breakpoint bp);
public event BreakpointNavigationHandler BreakpointNavigation;
private Font _markedColumnFont;
private CpuType _cpuType;
public ctrlBreakpoints()
{
@ -53,6 +54,15 @@ namespace Mesen.GUI.Debugger.Controls
mnuGoToLocation.InitShortcut(this, nameof(DebuggerShortcutsConfig.BreakpointList_GoToLocation));
}
public CpuType CpuType
{
set
{
_cpuType = value;
RefreshList();
}
}
private void BreakpointManager_OnBreakpointChanged(object sender, EventArgs e)
{
RefreshList();
@ -63,6 +73,10 @@ namespace Mesen.GUI.Debugger.Controls
lstBreakpoints.BeginUpdate();
ReadOnlyCollection<Breakpoint> breakpoints = BreakpointManager.Breakpoints;
for(int i = 0; i < breakpoints.Count; i++) {
if(!breakpoints[i].Matches(_cpuType)) {
continue;
}
lstBreakpoints.Items[i].SubItems[3].Text = breakpoints[i].GetAddressString(mnuShowLabels.Checked);
}
lstBreakpoints.EndUpdate();
@ -76,6 +90,10 @@ namespace Mesen.GUI.Debugger.Controls
lstBreakpoints.BeginUpdate();
lstBreakpoints.Items.Clear();
foreach(Breakpoint breakpoint in BreakpointManager.Breakpoints) {
if(!breakpoint.Matches(_cpuType)) {
continue;
}
ListViewItem item = new ListViewItem();
item.Tag = breakpoint;
item.Checked = breakpoint.Enabled;
@ -117,7 +135,7 @@ namespace Mesen.GUI.Debugger.Controls
private void mnuAddBreakpoint_Click(object sender, EventArgs e)
{
Breakpoint breakpoint = new Breakpoint();
Breakpoint breakpoint = new Breakpoint() { MemoryType = _cpuType == CpuType.Cpu ? SnesMemoryType.CpuMemory : SnesMemoryType.SpcMemory };
if(new frmBreakpoint(breakpoint).ShowDialog() == DialogResult.OK) {
BreakpointManager.AddBreakpoint(breakpoint);
}

View file

@ -21,40 +21,46 @@ namespace Mesen.GUI.Debugger
case BreakpointAddressType.AddressRange: radRange.Checked = true; break;
}
AddBinding("MemoryType", cboBreakpointType);
AddBinding("Enabled", chkEnabled);
AddBinding("MarkEvent", chkMarkOnEventViewer);
AddBinding("Address", txtAddress);
AddBinding("StartAddress", txtFrom);
AddBinding("EndAddress", txtTo);
AddBinding("BreakOnRead", chkRead);
AddBinding("BreakOnWrite", chkWrite);
AddBinding("BreakOnExec", chkExec);
AddBinding("Condition", txtCondition);
AddBinding(nameof(Breakpoint.MemoryType), cboBreakpointType);
AddBinding(nameof(Breakpoint.Enabled), chkEnabled);
AddBinding(nameof(Breakpoint.MarkEvent), chkMarkOnEventViewer);
AddBinding(nameof(Breakpoint.Address), txtAddress);
AddBinding(nameof(Breakpoint.StartAddress), txtFrom);
AddBinding(nameof(Breakpoint.EndAddress), txtTo);
AddBinding(nameof(Breakpoint.BreakOnRead), chkRead);
AddBinding(nameof(Breakpoint.BreakOnWrite), chkWrite);
AddBinding(nameof(Breakpoint.BreakOnExec), chkExec);
AddBinding(nameof(Breakpoint.Condition), txtCondition);
CpuType cpuType = breakpoint.MemoryType == SnesMemoryType.SpcMemory ? CpuType.Spc : CpuType.Cpu;
cboBreakpointType.Items.Clear();
cboBreakpointType.Items.Add(ResourceHelper.GetEnumText(SnesMemoryType.CpuMemory));
cboBreakpointType.Items.Add("-");
//TODO - Might not be useful on the SNES?
/*if(DebugApi.GetMemorySize(SnesMemoryType.PrgRom) > 0) {
cboBreakpointType.Items.Add(ResourceHelper.GetEnumText(SnesMemoryType.PrgRom));
}
if(DebugApi.GetMemorySize(SnesMemoryType.WorkRam) > 0) {
cboBreakpointType.Items.Add(ResourceHelper.GetEnumText(SnesMemoryType.WorkRam));
}
if(DebugApi.GetMemorySize(SnesMemoryType.SaveRam) > 0) {
cboBreakpointType.Items.Add(ResourceHelper.GetEnumText(SnesMemoryType.SaveRam));
}
if(cboBreakpointType.Items.Count > 2) {
if(cpuType == CpuType.Cpu) {
cboBreakpointType.Items.Add(ResourceHelper.GetEnumText(SnesMemoryType.CpuMemory));
cboBreakpointType.Items.Add("-");
}*/
cboBreakpointType.Items.Add(ResourceHelper.GetEnumText(SnesMemoryType.VideoRam));
cboBreakpointType.Items.Add(ResourceHelper.GetEnumText(SnesMemoryType.SpriteRam));
cboBreakpointType.Items.Add(ResourceHelper.GetEnumText(SnesMemoryType.CGRam));
//TODO - Might not be useful on the SNES?
/*if(DebugApi.GetMemorySize(SnesMemoryType.PrgRom) > 0) {
cboBreakpointType.Items.Add(ResourceHelper.GetEnumText(SnesMemoryType.PrgRom));
}
if(DebugApi.GetMemorySize(SnesMemoryType.WorkRam) > 0) {
cboBreakpointType.Items.Add(ResourceHelper.GetEnumText(SnesMemoryType.WorkRam));
}
if(DebugApi.GetMemorySize(SnesMemoryType.SaveRam) > 0) {
cboBreakpointType.Items.Add(ResourceHelper.GetEnumText(SnesMemoryType.SaveRam));
}
if(cboBreakpointType.Items.Count > 2) {
cboBreakpointType.Items.Add("-");
}*/
cboBreakpointType.Items.Add(ResourceHelper.GetEnumText(SnesMemoryType.VideoRam));
cboBreakpointType.Items.Add(ResourceHelper.GetEnumText(SnesMemoryType.SpriteRam));
cboBreakpointType.Items.Add(ResourceHelper.GetEnumText(SnesMemoryType.CGRam));
} else if(cpuType == CpuType.Spc) {
cboBreakpointType.Items.Add(ResourceHelper.GetEnumText(SnesMemoryType.SpcMemory));
}
this.toolTip.SetToolTip(this.picExpressionWarning, "Condition contains invalid syntax or symbols.");
this.toolTip.SetToolTip(this.picHelp, frmBreakpoint.GetConditionTooltip(false));
}

View file

@ -0,0 +1,49 @@
using Mesen.GUI.Config;
using Mesen.GUI.Debugger.Controls;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Mesen.GUI.Debugger.Code
{
public abstract class BaseStyleProvider : ctrlTextbox.ILineStyleProvider
{
public int? ActiveAddress { get; set; }
public abstract string GetLineComment(int lineIndex);
public abstract LineProperties GetLineStyle(CodeLineData lineData, int lineIndex);
protected void SetBreakpointLineProperties(LineProperties props, Breakpoint breakpoint)
{
DebuggerInfo config = ConfigManager.Config.Debug.Debugger;
Color fgColor = Color.White;
Color? bgColor = null;
Color bpColor = breakpoint.BreakOnExec ? config.CodeExecBreakpointColor : (breakpoint.BreakOnWrite ? config.CodeWriteBreakpointColor : config.CodeReadBreakpointColor);
Color outlineColor = bpColor;
LineSymbol symbol;
if(breakpoint.Enabled) {
bgColor = bpColor;
symbol = LineSymbol.Circle;
} else {
fgColor = Color.Black;
symbol = LineSymbol.CircleOutline;
}
if(breakpoint.MarkEvent) {
symbol |= LineSymbol.Mark;
}
if(!string.IsNullOrWhiteSpace(breakpoint.Condition)) {
symbol |= LineSymbol.Plus;
}
props.FgColor = fgColor;
props.TextBgColor = bgColor;
props.OutlineColor = outlineColor;
props.Symbol = symbol;
}
}
}

View file

@ -7,23 +7,25 @@ using System.Threading.Tasks;
namespace Mesen.GUI.Debugger.Code
{
public class CpuCodeDataProvider : ICodeDataProvider
public class CodeDataProvider : ICodeDataProvider
{
private int _lineCount;
protected CpuType _type;
public CpuCodeDataProvider()
public CodeDataProvider(CpuType type)
{
_lineCount = (int)DebugApi.GetDisassemblyLineCount();
_type = type;
_lineCount = (int)DebugApi.GetDisassemblyLineCount(_type);
}
public CodeLineData GetCodeLineData(int lineIndex)
{
return DebugApi.GetDisassemblyLineData((UInt32)lineIndex);
return DebugApi.GetDisassemblyLineData(_type, (UInt32)lineIndex);
}
public int GetLineAddress(int lineIndex)
{
return DebugApi.GetDisassemblyLineData((UInt32)lineIndex).Address;
return DebugApi.GetDisassemblyLineData(_type, (UInt32)lineIndex).Address;
}
public int GetLineCount()
@ -33,14 +35,14 @@ namespace Mesen.GUI.Debugger.Code
public int GetLineIndex(uint cpuAddress)
{
return (int)DebugApi.GetDisassemblyLineIndex(cpuAddress);
return (int)DebugApi.GetDisassemblyLineIndex(_type, cpuAddress);
}
public bool UseOptimizedSearch { get { return true; } }
public int GetNextResult(string searchString, int startPosition, int endPosition, bool searchBackwards)
{
return DebugApi.SearchDisassembly(searchString, startPosition, endPosition, searchBackwards);
return DebugApi.SearchDisassembly(_type, searchString, startPosition, endPosition, searchBackwards);
}
}
}

View file

@ -9,13 +9,15 @@ namespace Mesen.GUI.Debugger.Code
{
public class CpuDisassemblyManager : IDisassemblyManager
{
private CpuCodeDataProvider _provider;
private CodeDataProvider _provider;
public ICodeDataProvider Provider { get { return this._provider; } }
public int AddressSize { get { return 6; } }
public int ByteCodeSize { get { return 4; } }
public void RefreshCode()
{
this._provider = new CpuCodeDataProvider();
this._provider = new CodeDataProvider(CpuType.Cpu);
}
public void ToggleBreakpoint(int lineIndex)

View file

@ -9,15 +9,13 @@ using System.Threading.Tasks;
namespace Mesen.GUI.Debugger.Code
{
public class CpuLineStyleProvider : ctrlTextbox.ILineStyleProvider
public class CpuLineStyleProvider : BaseStyleProvider
{
public CpuLineStyleProvider()
{
}
public int? ActiveAddress { get; set; }
public string GetLineComment(int lineNumber)
public override string GetLineComment(int lineNumber)
{
return null;
}
@ -29,7 +27,7 @@ namespace Mesen.GUI.Debugger.Code
props.Symbol |= LineSymbol.Arrow;
}
public LineProperties GetLineStyle(CodeLineData lineData, int lineIndex)
public override LineProperties GetLineStyle(CodeLineData lineData, int lineIndex)
{
DebuggerInfo cfg = ConfigManager.Config.Debug.Debugger;
LineProperties props = new LineProperties();
@ -65,37 +63,12 @@ namespace Mesen.GUI.Debugger.Code
return props;
}
public static void GetBreakpointLineProperties(LineProperties props, int cpuAddress)
public void GetBreakpointLineProperties(LineProperties props, int cpuAddress)
{
DebuggerInfo config = ConfigManager.Config.Debug.Debugger;
foreach(Breakpoint breakpoint in BreakpointManager.Breakpoints) {
if(breakpoint.Matches((uint)cpuAddress, SnesMemoryType.CpuMemory)) {
Color fgColor = Color.White;
Color? bgColor = null;
Color bpColor = breakpoint.BreakOnExec ? config.CodeExecBreakpointColor : (breakpoint.BreakOnWrite ? config.CodeWriteBreakpointColor : config.CodeReadBreakpointColor);
Color outlineColor = bpColor;
LineSymbol symbol;
if(breakpoint.Enabled) {
bgColor = bpColor;
symbol = LineSymbol.Circle;
} else {
fgColor = Color.Black;
symbol = LineSymbol.CircleOutline;
}
if(breakpoint.MarkEvent) {
symbol |= LineSymbol.Mark;
}
if(!string.IsNullOrWhiteSpace(breakpoint.Condition)) {
symbol |= LineSymbol.Plus;
}
props.FgColor = fgColor;
props.TextBgColor = bgColor;
props.OutlineColor = outlineColor;
props.Symbol = symbol;
return;
SetBreakpointLineProperties(props, breakpoint);
}
}
}

View file

@ -11,6 +11,9 @@ namespace Mesen.GUI.Debugger.Code
{
ICodeDataProvider Provider { get; }
int AddressSize { get; }
int ByteCodeSize { get; }
void RefreshCode();
void ToggleBreakpoint(int lineIndex);
void EnableDisableBreakpoint(int lineIndex);

View file

@ -0,0 +1,45 @@
using Mesen.GUI.Debugger.Controls;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Mesen.GUI.Debugger.Code
{
public class SpcDisassemblyManager : IDisassemblyManager
{
private CodeDataProvider _provider;
public ICodeDataProvider Provider { get { return this._provider; } }
public int AddressSize { get { return 4; } }
public int ByteCodeSize { get { return 3; } }
public void RefreshCode()
{
this._provider = new CodeDataProvider(CpuType.Spc);
}
public void ToggleBreakpoint(int lineIndex)
{
int address = this._provider.GetLineAddress(lineIndex);
if(address >= 0) {
BreakpointManager.ToggleBreakpoint(new AddressInfo() {
Address = address,
Type = SnesMemoryType.SpcMemory
});
}
}
public void EnableDisableBreakpoint(int lineIndex)
{
int address = this._provider.GetLineAddress(lineIndex);
if(address >= 0) {
BreakpointManager.EnableDisableBreakpoint(new AddressInfo() {
Address = address,
Type = SnesMemoryType.SpcMemory
});
}
}
}
}

View file

@ -0,0 +1,57 @@
using Mesen.GUI.Config;
using Mesen.GUI.Debugger.Controls;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Mesen.GUI.Debugger.Code
{
public class SpcLineStyleProvider : BaseStyleProvider
{
public SpcLineStyleProvider()
{
}
public override string GetLineComment(int lineNumber)
{
return null;
}
public static void ConfigureActiveStatement(LineProperties props)
{
props.FgColor = Color.Black;
props.TextBgColor = ConfigManager.Config.Debug.Debugger.CodeActiveStatementColor;
props.Symbol |= LineSymbol.Arrow;
}
public override LineProperties GetLineStyle(CodeLineData lineData, int lineIndex)
{
DebuggerInfo cfg = ConfigManager.Config.Debug.Debugger;
LineProperties props = new LineProperties();
if(lineData.Address >= 0) {
GetBreakpointLineProperties(props, lineData.Address);
}
bool isActiveStatement = ActiveAddress.HasValue && ActiveAddress.Value == lineData.Address;
if(isActiveStatement) {
ConfigureActiveStatement(props);
}
return props;
}
private void GetBreakpointLineProperties(LineProperties props, int cpuAddress)
{
foreach(Breakpoint breakpoint in BreakpointManager.Breakpoints) {
if(breakpoint.Matches((uint)cpuAddress, SnesMemoryType.SpcMemory)) {
SetBreakpointLineProperties(props, breakpoint);
return;
}
}
}
}
}

View file

@ -70,6 +70,8 @@ namespace Mesen.GUI.Config
public XmlKeys OpenAssembler = Keys.Control | Keys.K;
[ShortcutName("Open Debugger")]
public XmlKeys OpenDebugger = Keys.Control | Keys.D;
[ShortcutName("Open SPC Debugger")]
public XmlKeys OpenSpcDebugger = Keys.Control | Keys.F;
[ShortcutName("Open Event Viewer")]
public XmlKeys OpenEventViewer = Keys.Control | Keys.E;
[ShortcutName("Open Memory Tools")]

View file

@ -18,23 +18,30 @@ namespace Mesen.GUI.Debugger.Controls
private StackFrameInfo[] _stackFrames;
private UInt32 _programCounter;
private string _format = "X6";
public ctrlCallstack()
{
InitializeComponent();
}
public void UpdateCallstack()
public void UpdateCallstack(CpuType cpuType)
{
List<StackInfo> stack = GetStackInfo();
_format = cpuType == CpuType.Cpu ? "X6" : "X4";
List<StackInfo> stack = GetStackInfo(cpuType);
this.UpdateList(stack);
}
private List<StackInfo> GetStackInfo()
private List<StackInfo> GetStackInfo(CpuType cpuType)
{
_stackFrames = DebugApi.GetCallstack();
_stackFrames = DebugApi.GetCallstack(cpuType);
DebugState state = DebugApi.GetState();
_programCounter = (uint)(state.Cpu.K << 16) | state.Cpu.PC;
if(cpuType == CpuType.Cpu) {
_programCounter = (uint)(state.Cpu.K << 16) | state.Cpu.PC;
} else {
_programCounter = (uint)state.Spc.PC;
}
int relDestinationAddr = -1;
@ -74,7 +81,7 @@ namespace Mesen.GUI.Debugger.Controls
ListViewItem item = this.lstCallstack.Items[len - i - 1];
item.Text = stackInfo.SubName;
item.SubItems[1].Text = "@ $" + stackInfo.Address.ToString("X6");
item.SubItems[1].Text = "@ $" + stackInfo.Address.ToString(_format);
item.Font = new Font(item.Font, FontStyle.Regular);
}
this.lstCallstack.EndUpdate();
@ -101,7 +108,7 @@ namespace Mesen.GUI.Debugger.Controls
} else if(flags == StackFrameFlags.Irq) {
funcName = "[irq] ";
}
funcName += "$" + relSubEntryAddr.ToString("X6");
funcName += "$" + relSubEntryAddr.ToString(_format);
return funcName;
}

View file

@ -1,6 +1,6 @@
namespace Mesen.GUI.Debugger.Controls
{
partial class ctrlConsoleStatus
partial class ctrlCpuStatus
{
/// <summary>
/// Required designer variable.
@ -58,19 +58,9 @@
this.txtStack = new System.Windows.Forms.TextBox();
this.chkNmi = new System.Windows.Forms.CheckBox();
this.chkIrq = new System.Windows.Forms.CheckBox();
this.grpPpu = new System.Windows.Forms.GroupBox();
this.tableLayoutPanel3 = new System.Windows.Forms.TableLayoutPanel();
this.txtScanline = new System.Windows.Forms.TextBox();
this.label8 = new System.Windows.Forms.Label();
this.label9 = new System.Windows.Forms.Label();
this.txtCycle = new System.Windows.Forms.TextBox();
this.label10 = new System.Windows.Forms.Label();
this.txtHClocks = new System.Windows.Forms.TextBox();
this.grpCpu.SuspendLayout();
this.tableLayoutPanel1.SuspendLayout();
this.tableLayoutPanel2.SuspendLayout();
this.grpPpu.SuspendLayout();
this.tableLayoutPanel3.SuspendLayout();
this.SuspendLayout();
//
// grpCpu
@ -420,111 +410,18 @@
this.chkIrq.Text = "IRQ";
this.chkIrq.UseVisualStyleBackColor = true;
//
// grpPpu
//
this.grpPpu.Controls.Add(this.tableLayoutPanel3);
this.grpPpu.Dock = System.Windows.Forms.DockStyle.Top;
this.grpPpu.Location = new System.Drawing.Point(0, 146);
this.grpPpu.Name = "grpPpu";
this.grpPpu.Size = new System.Drawing.Size(342, 47);
this.grpPpu.TabIndex = 1;
this.grpPpu.TabStop = false;
this.grpPpu.Text = "PPU";
//
// tableLayoutPanel3
//
this.tableLayoutPanel3.ColumnCount = 6;
this.tableLayoutPanel3.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
this.tableLayoutPanel3.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
this.tableLayoutPanel3.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
this.tableLayoutPanel3.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
this.tableLayoutPanel3.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
this.tableLayoutPanel3.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F));
this.tableLayoutPanel3.Controls.Add(this.txtScanline, 0, 0);
this.tableLayoutPanel3.Controls.Add(this.label8, 0, 0);
this.tableLayoutPanel3.Controls.Add(this.label9, 2, 0);
this.tableLayoutPanel3.Controls.Add(this.txtCycle, 3, 0);
this.tableLayoutPanel3.Controls.Add(this.label10, 4, 0);
this.tableLayoutPanel3.Controls.Add(this.txtHClocks, 5, 0);
this.tableLayoutPanel3.Dock = System.Windows.Forms.DockStyle.Fill;
this.tableLayoutPanel3.Location = new System.Drawing.Point(3, 16);
this.tableLayoutPanel3.Name = "tableLayoutPanel3";
this.tableLayoutPanel3.RowCount = 2;
this.tableLayoutPanel3.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tableLayoutPanel3.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F));
this.tableLayoutPanel3.Size = new System.Drawing.Size(336, 28);
this.tableLayoutPanel3.TabIndex = 0;
//
// txtScanline
//
this.txtScanline.Location = new System.Drawing.Point(60, 3);
this.txtScanline.Name = "txtScanline";
this.txtScanline.Size = new System.Drawing.Size(33, 20);
this.txtScanline.TabIndex = 3;
this.txtScanline.Text = "555";
//
// label8
//
this.label8.Anchor = System.Windows.Forms.AnchorStyles.Left;
this.label8.AutoSize = true;
this.label8.Location = new System.Drawing.Point(3, 6);
this.label8.Name = "label8";
this.label8.Size = new System.Drawing.Size(51, 13);
this.label8.TabIndex = 1;
this.label8.Text = "Scanline:";
//
// label9
//
this.label9.Anchor = System.Windows.Forms.AnchorStyles.Left;
this.label9.AutoSize = true;
this.label9.Location = new System.Drawing.Point(99, 6);
this.label9.Name = "label9";
this.label9.Size = new System.Drawing.Size(36, 13);
this.label9.TabIndex = 2;
this.label9.Text = "Cycle:";
//
// txtCycle
//
this.txtCycle.Location = new System.Drawing.Point(141, 3);
this.txtCycle.Name = "txtCycle";
this.txtCycle.Size = new System.Drawing.Size(33, 20);
this.txtCycle.TabIndex = 4;
this.txtCycle.Text = "555";
//
// label10
//
this.label10.Anchor = System.Windows.Forms.AnchorStyles.Left;
this.label10.AutoSize = true;
this.label10.Location = new System.Drawing.Point(180, 6);
this.label10.Name = "label10";
this.label10.Size = new System.Drawing.Size(53, 13);
this.label10.TabIndex = 5;
this.label10.Text = "H Clocks:";
//
// txtHClocks
//
this.txtHClocks.Location = new System.Drawing.Point(239, 3);
this.txtHClocks.Name = "txtHClocks";
this.txtHClocks.Size = new System.Drawing.Size(33, 20);
this.txtHClocks.TabIndex = 6;
this.txtHClocks.Text = "555";
//
// ctrlConsoleStatus
// ctrlCpuStatus
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.Controls.Add(this.grpPpu);
this.Controls.Add(this.grpCpu);
this.Name = "ctrlConsoleStatus";
this.Size = new System.Drawing.Size(342, 220);
this.Name = "ctrlCpuStatus";
this.Size = new System.Drawing.Size(342, 146);
this.grpCpu.ResumeLayout(false);
this.tableLayoutPanel1.ResumeLayout(false);
this.tableLayoutPanel1.PerformLayout();
this.tableLayoutPanel2.ResumeLayout(false);
this.tableLayoutPanel2.PerformLayout();
this.grpPpu.ResumeLayout(false);
this.tableLayoutPanel3.ResumeLayout(false);
this.tableLayoutPanel3.PerformLayout();
this.ResumeLayout(false);
}
@ -562,13 +459,5 @@
private System.Windows.Forms.TextBox txtStack;
private System.Windows.Forms.CheckBox chkNmi;
private System.Windows.Forms.CheckBox chkIrq;
private System.Windows.Forms.GroupBox grpPpu;
private System.Windows.Forms.TableLayoutPanel tableLayoutPanel3;
private System.Windows.Forms.TextBox txtScanline;
private System.Windows.Forms.Label label8;
private System.Windows.Forms.Label label9;
private System.Windows.Forms.TextBox txtCycle;
private System.Windows.Forms.Label label10;
private System.Windows.Forms.TextBox txtHClocks;
}
}

View file

@ -12,12 +12,12 @@ using Mesen.GUI.Forms;
namespace Mesen.GUI.Debugger.Controls
{
public partial class ctrlConsoleStatus : BaseControl
public partial class ctrlCpuStatus : BaseControl
{
private EntityBinder _cpuBinder = new EntityBinder();
private DebugState _lastState;
public ctrlConsoleStatus()
public ctrlCpuStatus()
{
InitializeComponent();
if(IsDesignMode) {
@ -25,15 +25,15 @@ namespace Mesen.GUI.Debugger.Controls
}
_cpuBinder.Entity = new CpuState();
_cpuBinder.AddBinding("A", txtA);
_cpuBinder.AddBinding("X", txtX);
_cpuBinder.AddBinding("Y", txtY);
_cpuBinder.AddBinding("D", txtD);
_cpuBinder.AddBinding("DBR", txtDB);
_cpuBinder.AddBinding("SP", txtS);
_cpuBinder.AddBinding("PS", txtP);
_cpuBinder.AddBinding(nameof(CpuState.A), txtA);
_cpuBinder.AddBinding(nameof(CpuState.X), txtX);
_cpuBinder.AddBinding(nameof(CpuState.Y), txtY);
_cpuBinder.AddBinding(nameof(CpuState.D), txtD);
_cpuBinder.AddBinding(nameof(CpuState.DBR), txtDB);
_cpuBinder.AddBinding(nameof(CpuState.SP), txtS);
_cpuBinder.AddBinding(nameof(CpuState.PS), txtP);
_cpuBinder.AddBinding("NmiFlag", chkNmi);
_cpuBinder.AddBinding(nameof(CpuState.NmiFlag), chkNmi);
}
public void UpdateStatus(DebugState state)
@ -44,9 +44,6 @@ namespace Mesen.GUI.Debugger.Controls
_cpuBinder.UpdateUI();
txtPC.Text = ((state.Cpu.K << 16) | state.Cpu.PC).ToString("X6");
txtCycle.Text = state.Ppu.Cycle.ToString();
txtScanline.Text = state.Ppu.Scanline.ToString();
txtHClocks.Text = (state.Ppu.Cycle * 4).ToString();
UpdateCpuFlags();

View file

@ -15,7 +15,7 @@ namespace Mesen.GUI.Debugger.Controls
{
public partial class ctrlDisassemblyView : BaseControl
{
private CpuLineStyleProvider _styleProvider;
private BaseStyleProvider _styleProvider;
private IDisassemblyManager _manager;
public ctrlDisassemblyView()
@ -25,14 +25,6 @@ namespace Mesen.GUI.Debugger.Controls
return;
}
_manager = new CpuDisassemblyManager();
_manager.RefreshCode();
_styleProvider = new CpuLineStyleProvider();
ctrlCode.StyleProvider = _styleProvider;
ctrlCode.ShowContentNotes = false;
ctrlCode.ShowMemoryValues = true;
InitShortcuts();
BreakpointManager.BreakpointsChanged += BreakpointManager_BreakpointsChanged;
@ -50,6 +42,20 @@ namespace Mesen.GUI.Debugger.Controls
ctrlCode.Invalidate();
}
public void Initialize(IDisassemblyManager manager, BaseStyleProvider styleProvider)
{
_manager = manager;
_styleProvider = styleProvider;
ctrlCode.StyleProvider = _styleProvider;
ctrlCode.ShowContentNotes = false;
ctrlCode.ShowMemoryValues = true;
ctrlCode.ExtendedMarginWidth = manager.ByteCodeSize * 4;
ctrlCode.AddressSize = manager.AddressSize;
_manager.RefreshCode();
}
private void InitShortcuts()
{
mnuToggleBreakpoint.InitShortcut(this, nameof(DebuggerShortcutsConfig.CodeWindow_ToggleBreakpoint));

View file

@ -0,0 +1,155 @@
namespace Mesen.GUI.Debugger.Controls
{
partial class ctrlPpuStatus
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if(disposing && (components != null)) {
components.Dispose();
}
base.Dispose(disposing);
}
#region Component Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.grpPpu = new System.Windows.Forms.GroupBox();
this.tableLayoutPanel3 = new System.Windows.Forms.TableLayoutPanel();
this.txtScanline = new System.Windows.Forms.TextBox();
this.label8 = new System.Windows.Forms.Label();
this.label9 = new System.Windows.Forms.Label();
this.txtCycle = new System.Windows.Forms.TextBox();
this.label10 = new System.Windows.Forms.Label();
this.txtHClocks = new System.Windows.Forms.TextBox();
this.grpPpu.SuspendLayout();
this.tableLayoutPanel3.SuspendLayout();
this.SuspendLayout();
//
// grpPpu
//
this.grpPpu.Controls.Add(this.tableLayoutPanel3);
this.grpPpu.Dock = System.Windows.Forms.DockStyle.Top;
this.grpPpu.Location = new System.Drawing.Point(0, 0);
this.grpPpu.Name = "grpPpu";
this.grpPpu.Size = new System.Drawing.Size(342, 47);
this.grpPpu.TabIndex = 1;
this.grpPpu.TabStop = false;
this.grpPpu.Text = "PPU";
//
// tableLayoutPanel3
//
this.tableLayoutPanel3.ColumnCount = 6;
this.tableLayoutPanel3.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
this.tableLayoutPanel3.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
this.tableLayoutPanel3.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
this.tableLayoutPanel3.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
this.tableLayoutPanel3.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
this.tableLayoutPanel3.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F));
this.tableLayoutPanel3.Controls.Add(this.txtScanline, 0, 0);
this.tableLayoutPanel3.Controls.Add(this.label8, 0, 0);
this.tableLayoutPanel3.Controls.Add(this.label9, 2, 0);
this.tableLayoutPanel3.Controls.Add(this.txtCycle, 3, 0);
this.tableLayoutPanel3.Controls.Add(this.label10, 4, 0);
this.tableLayoutPanel3.Controls.Add(this.txtHClocks, 5, 0);
this.tableLayoutPanel3.Dock = System.Windows.Forms.DockStyle.Fill;
this.tableLayoutPanel3.Location = new System.Drawing.Point(3, 16);
this.tableLayoutPanel3.Name = "tableLayoutPanel3";
this.tableLayoutPanel3.RowCount = 2;
this.tableLayoutPanel3.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tableLayoutPanel3.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F));
this.tableLayoutPanel3.Size = new System.Drawing.Size(336, 28);
this.tableLayoutPanel3.TabIndex = 0;
//
// txtScanline
//
this.txtScanline.Location = new System.Drawing.Point(60, 3);
this.txtScanline.Name = "txtScanline";
this.txtScanline.Size = new System.Drawing.Size(33, 20);
this.txtScanline.TabIndex = 3;
this.txtScanline.Text = "555";
//
// label8
//
this.label8.Anchor = System.Windows.Forms.AnchorStyles.Left;
this.label8.AutoSize = true;
this.label8.Location = new System.Drawing.Point(3, 6);
this.label8.Name = "label8";
this.label8.Size = new System.Drawing.Size(51, 13);
this.label8.TabIndex = 1;
this.label8.Text = "Scanline:";
//
// label9
//
this.label9.Anchor = System.Windows.Forms.AnchorStyles.Left;
this.label9.AutoSize = true;
this.label9.Location = new System.Drawing.Point(99, 6);
this.label9.Name = "label9";
this.label9.Size = new System.Drawing.Size(36, 13);
this.label9.TabIndex = 2;
this.label9.Text = "Cycle:";
//
// txtCycle
//
this.txtCycle.Location = new System.Drawing.Point(141, 3);
this.txtCycle.Name = "txtCycle";
this.txtCycle.Size = new System.Drawing.Size(33, 20);
this.txtCycle.TabIndex = 4;
this.txtCycle.Text = "555";
//
// label10
//
this.label10.Anchor = System.Windows.Forms.AnchorStyles.Left;
this.label10.AutoSize = true;
this.label10.Location = new System.Drawing.Point(180, 6);
this.label10.Name = "label10";
this.label10.Size = new System.Drawing.Size(53, 13);
this.label10.TabIndex = 5;
this.label10.Text = "H Clocks:";
//
// txtHClocks
//
this.txtHClocks.Location = new System.Drawing.Point(239, 3);
this.txtHClocks.Name = "txtHClocks";
this.txtHClocks.Size = new System.Drawing.Size(33, 20);
this.txtHClocks.TabIndex = 6;
this.txtHClocks.Text = "555";
//
// ctrlPpuStatus
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.Controls.Add(this.grpPpu);
this.Name = "ctrlPpuStatus";
this.Size = new System.Drawing.Size(342, 47);
this.grpPpu.ResumeLayout(false);
this.tableLayoutPanel3.ResumeLayout(false);
this.tableLayoutPanel3.PerformLayout();
this.ResumeLayout(false);
}
#endregion
private System.Windows.Forms.GroupBox grpPpu;
private System.Windows.Forms.TableLayoutPanel tableLayoutPanel3;
private System.Windows.Forms.TextBox txtScanline;
private System.Windows.Forms.Label label8;
private System.Windows.Forms.Label label9;
private System.Windows.Forms.TextBox txtCycle;
private System.Windows.Forms.Label label10;
private System.Windows.Forms.TextBox txtHClocks;
}
}

View file

@ -0,0 +1,42 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using Mesen.GUI.Controls;
using Mesen.GUI.Forms;
namespace Mesen.GUI.Debugger.Controls
{
public partial class ctrlPpuStatus : BaseControl
{
private EntityBinder _binder = new EntityBinder();
private DebugState _lastState;
public ctrlPpuStatus()
{
InitializeComponent();
if(IsDesignMode) {
return;
}
_binder.Entity = new PpuState();
_binder.AddBinding(nameof(PpuState.Cycle), txtCycle, eNumberFormat.Decimal);
_binder.AddBinding(nameof(PpuState.Scanline), txtScanline, eNumberFormat.Decimal);
}
public void UpdateStatus(DebugState state)
{
_lastState = state;
_binder.Entity = state.Ppu;
_binder.UpdateUI();
txtHClocks.Text = (state.Ppu.Cycle * 4).ToString();
}
}
}

View file

@ -0,0 +1,120 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

View file

@ -412,6 +412,8 @@ namespace Mesen.GUI.Debugger.Controls
public int SelectionLength { get { return this.ctrlTextbox.SelectionLength; } }
public int MarginWidth { set { this.ctrlTextbox.MarginWidth = value; } }
public int ExtendedMarginWidth { set { this.ctrlTextbox.ExtendedMarginWidth = value; } }
public int AddressSize { set { this.ctrlTextbox.AddressSize = value; } }
public void OpenSearchBox(bool forceFocus = false)
{

View file

@ -0,0 +1,380 @@
namespace Mesen.GUI.Debugger.Controls
{
partial class ctrlSpcStatus
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if(disposing && (components != null)) {
components.Dispose();
}
base.Dispose(disposing);
}
#region Component Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.grpSpc = new System.Windows.Forms.GroupBox();
this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel();
this.label1 = new System.Windows.Forms.Label();
this.lblA = new System.Windows.Forms.Label();
this.txtA = new System.Windows.Forms.TextBox();
this.label2 = new System.Windows.Forms.Label();
this.txtX = new System.Windows.Forms.TextBox();
this.txtY = new System.Windows.Forms.TextBox();
this.label6 = new System.Windows.Forms.Label();
this.txtPC = new System.Windows.Forms.TextBox();
this.label7 = new System.Windows.Forms.Label();
this.txtP = new System.Windows.Forms.TextBox();
this.tableLayoutPanel2 = new System.Windows.Forms.TableLayoutPanel();
this.chkHalfCarry = new System.Windows.Forms.CheckBox();
this.chkInterrupt = new System.Windows.Forms.CheckBox();
this.chkCarry = new System.Windows.Forms.CheckBox();
this.chkZero = new System.Windows.Forms.CheckBox();
this.chkBreak = new System.Windows.Forms.CheckBox();
this.chkPage = new System.Windows.Forms.CheckBox();
this.chkNegative = new System.Windows.Forms.CheckBox();
this.chkOverflow = new System.Windows.Forms.CheckBox();
this.txtS = new System.Windows.Forms.TextBox();
this.label5 = new System.Windows.Forms.Label();
this.txtStack = new System.Windows.Forms.TextBox();
this.grpSpc.SuspendLayout();
this.tableLayoutPanel1.SuspendLayout();
this.tableLayoutPanel2.SuspendLayout();
this.SuspendLayout();
//
// grpSpc
//
this.grpSpc.Controls.Add(this.tableLayoutPanel1);
this.grpSpc.Dock = System.Windows.Forms.DockStyle.Top;
this.grpSpc.Location = new System.Drawing.Point(0, 0);
this.grpSpc.Name = "grpSpc";
this.grpSpc.Size = new System.Drawing.Size(342, 120);
this.grpSpc.TabIndex = 0;
this.grpSpc.TabStop = false;
this.grpSpc.Text = "SPC";
//
// tableLayoutPanel1
//
this.tableLayoutPanel1.ColumnCount = 10;
this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
this.tableLayoutPanel1.Controls.Add(this.label1, 2, 0);
this.tableLayoutPanel1.Controls.Add(this.lblA, 0, 0);
this.tableLayoutPanel1.Controls.Add(this.txtA, 1, 0);
this.tableLayoutPanel1.Controls.Add(this.label2, 4, 0);
this.tableLayoutPanel1.Controls.Add(this.txtX, 3, 0);
this.tableLayoutPanel1.Controls.Add(this.txtY, 5, 0);
this.tableLayoutPanel1.Controls.Add(this.label7, 0, 2);
this.tableLayoutPanel1.Controls.Add(this.txtP, 1, 2);
this.tableLayoutPanel1.Controls.Add(this.tableLayoutPanel2, 2, 2);
this.tableLayoutPanel1.Controls.Add(this.txtStack, 8, 2);
this.tableLayoutPanel1.Controls.Add(this.label6, 6, 0);
this.tableLayoutPanel1.Controls.Add(this.txtPC, 7, 0);
this.tableLayoutPanel1.Controls.Add(this.label5, 8, 0);
this.tableLayoutPanel1.Controls.Add(this.txtS, 9, 0);
this.tableLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Fill;
this.tableLayoutPanel1.Location = new System.Drawing.Point(3, 16);
this.tableLayoutPanel1.Name = "tableLayoutPanel1";
this.tableLayoutPanel1.RowCount = 5;
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tableLayoutPanel1.Size = new System.Drawing.Size(336, 101);
this.tableLayoutPanel1.TabIndex = 0;
//
// label1
//
this.label1.Anchor = System.Windows.Forms.AnchorStyles.Left;
this.label1.AutoSize = true;
this.label1.Location = new System.Drawing.Point(57, 6);
this.label1.Name = "label1";
this.label1.Size = new System.Drawing.Size(17, 13);
this.label1.TabIndex = 2;
this.label1.Text = "X:";
//
// lblA
//
this.lblA.Anchor = System.Windows.Forms.AnchorStyles.Left;
this.lblA.AutoSize = true;
this.lblA.Location = new System.Drawing.Point(3, 6);
this.lblA.Name = "lblA";
this.lblA.Size = new System.Drawing.Size(17, 13);
this.lblA.TabIndex = 0;
this.lblA.Text = "A:";
//
// txtA
//
this.txtA.Location = new System.Drawing.Point(26, 3);
this.txtA.Name = "txtA";
this.txtA.Size = new System.Drawing.Size(25, 20);
this.txtA.TabIndex = 1;
this.txtA.Text = "DDDD";
//
// label2
//
this.label2.Anchor = System.Windows.Forms.AnchorStyles.Left;
this.label2.AutoSize = true;
this.label2.Location = new System.Drawing.Point(111, 6);
this.label2.Name = "label2";
this.label2.Size = new System.Drawing.Size(17, 13);
this.label2.TabIndex = 3;
this.label2.Text = "Y:";
//
// txtX
//
this.txtX.Location = new System.Drawing.Point(80, 3);
this.txtX.Name = "txtX";
this.txtX.Size = new System.Drawing.Size(25, 20);
this.txtX.TabIndex = 4;
//
// txtY
//
this.txtY.Location = new System.Drawing.Point(134, 3);
this.txtY.Name = "txtY";
this.txtY.Size = new System.Drawing.Size(25, 20);
this.txtY.TabIndex = 5;
//
// label6
//
this.label6.Anchor = System.Windows.Forms.AnchorStyles.Left;
this.label6.AutoSize = true;
this.label6.Location = new System.Drawing.Point(165, 6);
this.label6.Name = "label6";
this.label6.Size = new System.Drawing.Size(24, 13);
this.label6.TabIndex = 12;
this.label6.Text = "PC:";
//
// txtPC
//
this.txtPC.Location = new System.Drawing.Point(195, 3);
this.txtPC.Name = "txtPC";
this.txtPC.Size = new System.Drawing.Size(40, 20);
this.txtPC.TabIndex = 13;
this.txtPC.Text = "DDDD";
//
// label7
//
this.label7.Anchor = System.Windows.Forms.AnchorStyles.Left;
this.label7.AutoSize = true;
this.label7.Location = new System.Drawing.Point(3, 32);
this.label7.Name = "label7";
this.label7.Size = new System.Drawing.Size(17, 13);
this.label7.TabIndex = 14;
this.label7.Text = "P:";
//
// txtP
//
this.txtP.Anchor = System.Windows.Forms.AnchorStyles.Left;
this.txtP.Location = new System.Drawing.Point(26, 29);
this.txtP.Name = "txtP";
this.txtP.Size = new System.Drawing.Size(25, 20);
this.txtP.TabIndex = 15;
this.txtP.Text = "DD";
//
// tableLayoutPanel2
//
this.tableLayoutPanel2.ColumnCount = 5;
this.tableLayoutPanel1.SetColumnSpan(this.tableLayoutPanel2, 6);
this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 40F));
this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 20F));
this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 20F));
this.tableLayoutPanel2.Controls.Add(this.chkHalfCarry, 0, 1);
this.tableLayoutPanel2.Controls.Add(this.chkInterrupt, 1, 1);
this.tableLayoutPanel2.Controls.Add(this.chkCarry, 3, 1);
this.tableLayoutPanel2.Controls.Add(this.chkZero, 2, 1);
this.tableLayoutPanel2.Controls.Add(this.chkBreak, 3, 0);
this.tableLayoutPanel2.Controls.Add(this.chkPage, 2, 0);
this.tableLayoutPanel2.Controls.Add(this.chkNegative, 0, 0);
this.tableLayoutPanel2.Controls.Add(this.chkOverflow, 1, 0);
this.tableLayoutPanel2.Location = new System.Drawing.Point(57, 29);
this.tableLayoutPanel2.Name = "tableLayoutPanel2";
this.tableLayoutPanel2.RowCount = 2;
this.tableLayoutPanel1.SetRowSpan(this.tableLayoutPanel2, 2);
this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tableLayoutPanel2.Size = new System.Drawing.Size(159, 46);
this.tableLayoutPanel2.TabIndex = 16;
//
// chkHalfCarry
//
this.chkHalfCarry.AutoSize = true;
this.chkHalfCarry.Location = new System.Drawing.Point(3, 26);
this.chkHalfCarry.Name = "chkHalfCarry";
this.chkHalfCarry.Size = new System.Drawing.Size(34, 17);
this.chkHalfCarry.TabIndex = 25;
this.chkHalfCarry.Text = "H";
this.chkHalfCarry.UseVisualStyleBackColor = true;
//
// chkInterrupt
//
this.chkInterrupt.AutoSize = true;
this.chkInterrupt.Location = new System.Drawing.Point(43, 26);
this.chkInterrupt.Name = "chkInterrupt";
this.chkInterrupt.Size = new System.Drawing.Size(29, 17);
this.chkInterrupt.TabIndex = 24;
this.chkInterrupt.Text = "I";
this.chkInterrupt.UseVisualStyleBackColor = true;
//
// chkCarry
//
this.chkCarry.AutoSize = true;
this.chkCarry.Location = new System.Drawing.Point(121, 26);
this.chkCarry.Name = "chkCarry";
this.chkCarry.Size = new System.Drawing.Size(33, 17);
this.chkCarry.TabIndex = 23;
this.chkCarry.Text = "C";
this.chkCarry.UseVisualStyleBackColor = true;
//
// chkZero
//
this.chkZero.AutoSize = true;
this.chkZero.Location = new System.Drawing.Point(82, 26);
this.chkZero.Name = "chkZero";
this.chkZero.Size = new System.Drawing.Size(33, 17);
this.chkZero.TabIndex = 21;
this.chkZero.Text = "Z";
this.chkZero.UseVisualStyleBackColor = true;
//
// chkBreak
//
this.chkBreak.AutoSize = true;
this.chkBreak.Location = new System.Drawing.Point(121, 3);
this.chkBreak.Name = "chkBreak";
this.chkBreak.Size = new System.Drawing.Size(33, 17);
this.chkBreak.TabIndex = 18;
this.chkBreak.Text = "B";
this.chkBreak.UseVisualStyleBackColor = true;
//
// chkPage
//
this.chkPage.AutoSize = true;
this.chkPage.Location = new System.Drawing.Point(82, 3);
this.chkPage.Name = "chkPage";
this.chkPage.Size = new System.Drawing.Size(33, 17);
this.chkPage.TabIndex = 19;
this.chkPage.Text = "P";
this.chkPage.UseVisualStyleBackColor = true;
//
// chkNegative
//
this.chkNegative.AutoSize = true;
this.chkNegative.Location = new System.Drawing.Point(3, 3);
this.chkNegative.Name = "chkNegative";
this.chkNegative.Size = new System.Drawing.Size(34, 17);
this.chkNegative.TabIndex = 17;
this.chkNegative.Text = "N";
this.chkNegative.UseVisualStyleBackColor = true;
//
// chkOverflow
//
this.chkOverflow.AutoSize = true;
this.chkOverflow.Location = new System.Drawing.Point(43, 3);
this.chkOverflow.Name = "chkOverflow";
this.chkOverflow.Size = new System.Drawing.Size(33, 17);
this.chkOverflow.TabIndex = 20;
this.chkOverflow.Text = "V";
this.chkOverflow.UseVisualStyleBackColor = true;
//
// txtS
//
this.txtS.Location = new System.Drawing.Point(264, 3);
this.txtS.Name = "txtS";
this.txtS.Size = new System.Drawing.Size(34, 20);
this.txtS.TabIndex = 11;
//
// label5
//
this.label5.Anchor = System.Windows.Forms.AnchorStyles.Left;
this.label5.AutoSize = true;
this.label5.Location = new System.Drawing.Point(241, 6);
this.label5.Name = "label5";
this.label5.Size = new System.Drawing.Size(17, 13);
this.label5.TabIndex = 10;
this.label5.Text = "S:";
//
// txtStack
//
this.txtStack.BackColor = System.Drawing.SystemColors.Window;
this.tableLayoutPanel1.SetColumnSpan(this.txtStack, 2);
this.txtStack.Dock = System.Windows.Forms.DockStyle.Fill;
this.txtStack.Location = new System.Drawing.Point(241, 29);
this.txtStack.Multiline = true;
this.txtStack.Name = "txtStack";
this.txtStack.ReadOnly = true;
this.tableLayoutPanel1.SetRowSpan(this.txtStack, 3);
this.txtStack.ScrollBars = System.Windows.Forms.ScrollBars.Vertical;
this.txtStack.Size = new System.Drawing.Size(92, 69);
this.txtStack.TabIndex = 23;
//
// ctrlSpcStatus
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.Controls.Add(this.grpSpc);
this.Name = "ctrlSpcStatus";
this.Size = new System.Drawing.Size(342, 120);
this.grpSpc.ResumeLayout(false);
this.tableLayoutPanel1.ResumeLayout(false);
this.tableLayoutPanel1.PerformLayout();
this.tableLayoutPanel2.ResumeLayout(false);
this.tableLayoutPanel2.PerformLayout();
this.ResumeLayout(false);
}
#endregion
private System.Windows.Forms.GroupBox grpSpc;
private System.Windows.Forms.TableLayoutPanel tableLayoutPanel1;
private System.Windows.Forms.Label label1;
private System.Windows.Forms.Label lblA;
private System.Windows.Forms.TextBox txtA;
private System.Windows.Forms.Label label2;
private System.Windows.Forms.TextBox txtX;
private System.Windows.Forms.TextBox txtY;
private System.Windows.Forms.Label label5;
private System.Windows.Forms.TextBox txtS;
private System.Windows.Forms.Label label6;
private System.Windows.Forms.TextBox txtPC;
private System.Windows.Forms.Label label7;
private System.Windows.Forms.TextBox txtP;
private System.Windows.Forms.TableLayoutPanel tableLayoutPanel2;
private System.Windows.Forms.CheckBox chkHalfCarry;
private System.Windows.Forms.CheckBox chkInterrupt;
private System.Windows.Forms.CheckBox chkCarry;
private System.Windows.Forms.CheckBox chkZero;
private System.Windows.Forms.CheckBox chkBreak;
private System.Windows.Forms.CheckBox chkPage;
private System.Windows.Forms.CheckBox chkNegative;
private System.Windows.Forms.CheckBox chkOverflow;
private System.Windows.Forms.TextBox txtStack;
}
}

View file

@ -0,0 +1,75 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using Mesen.GUI.Controls;
using Mesen.GUI.Forms;
namespace Mesen.GUI.Debugger.Controls
{
public partial class ctrlSpcStatus : BaseControl
{
private EntityBinder _binder = new EntityBinder();
private DebugState _lastState;
public ctrlSpcStatus()
{
InitializeComponent();
if(IsDesignMode) {
return;
}
_binder.Entity = new SpcState();
_binder.AddBinding(nameof(SpcState.A), txtA);
_binder.AddBinding(nameof(SpcState.X), txtX);
_binder.AddBinding(nameof(SpcState.Y), txtY);
_binder.AddBinding(nameof(SpcState.PC), txtPC);
_binder.AddBinding(nameof(SpcState.SP), txtS);
_binder.AddBinding(nameof(SpcState.PS), txtP);
}
public void UpdateStatus(DebugState state)
{
_lastState = state;
_binder.Entity = state.Spc;
_binder.UpdateUI();
UpdateCpuFlags();
UpdateStack();
}
private void UpdateCpuFlags()
{
SpcFlags flags = _lastState.Spc.PS;
chkNegative.Checked = flags.HasFlag(SpcFlags.Negative);
chkOverflow.Checked = flags.HasFlag(SpcFlags.Overflow);
chkPage.Checked = flags.HasFlag(SpcFlags.DirectPage);
chkBreak.Checked = flags.HasFlag(SpcFlags.Break);
chkHalfCarry.Checked = flags.HasFlag(SpcFlags.HalfCarry);
chkInterrupt.Checked = flags.HasFlag(SpcFlags.IrqEnable);
chkZero.Checked = flags.HasFlag(SpcFlags.Zero);
chkCarry.Checked = flags.HasFlag(SpcFlags.Carry);
}
private void UpdateStack()
{
StringBuilder sb = new StringBuilder();
for(UInt32 i = (uint)_lastState.Spc.SP + 1; (i & 0xFF) != 0; i++) {
sb.Append("$");
sb.Append(DebugApi.GetMemoryValue(SnesMemoryType.SpcMemory, i).ToString("X2"));
sb.Append(", ");
}
string stack = sb.ToString();
if(stack.Length > 2) {
stack = stack.Substring(0, stack.Length - 2);
}
txtStack.Text = stack;
}
}
}

View file

@ -0,0 +1,120 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

View file

@ -45,6 +45,7 @@ namespace Mesen.GUI.Debugger.Controls
private Font _noteFont = null;
private int _marginWidth = 9;
private int _extendedMarginWidth = 16;
private string _addressFormat = "X6";
private float _maxLineWidth = 0;
private TextboxMessageInfo _message;
@ -201,6 +202,24 @@ namespace Mesen.GUI.Debugger.Controls
}
}
public int ExtendedMarginWidth
{
set
{
this._extendedMarginWidth = value;
this.Invalidate();
}
}
public int AddressSize
{
set
{
this._addressFormat = "X" + value.ToString();
this.Invalidate();
}
}
public bool CodeHighlightingEnabled { get; set; } = true;
public bool Search(string searchString, bool searchBackwards, bool isNewSearch)
@ -872,7 +891,7 @@ namespace Mesen.GUI.Debugger.Controls
g.DrawString(lineNumber, this.Font, numberBrush, marginLeft - width, positionY, StringFormat.GenericTypographic);
} else {
//Display line number
string lineNumber = lineData.Address >= 0 ? lineData.Address.ToString("X6") : "..";
string lineNumber = lineData.Address >= 0 ? lineData.Address.ToString(_addressFormat) : "..";
if(ShowCompactPrgAddresses) {
string lineNumberNote = lineData.AbsoluteAddress.ToString("X6");

View file

@ -32,7 +32,8 @@ namespace Mesen.GUI.Debugger
} else {
BaseForm frm = null;
switch(window) {
case DebugWindow.Debugger: frm = new frmDebugger(); frm.Icon = Properties.Resources.Debugger; break;
case DebugWindow.Debugger: frm = new frmDebugger(CpuType.Cpu); frm.Icon = Properties.Resources.Debugger; break;
case DebugWindow.SpcDebugger: frm = new frmDebugger(CpuType.Spc); frm.Icon = Properties.Resources.SpcDebugger; break;
case DebugWindow.TraceLogger: frm = new frmTraceLogger(); frm.Icon = Properties.Resources.LogWindow; break;
case DebugWindow.MemoryTools: frm = new frmMemoryTools(); frm.Icon = Properties.Resources.CheatCode; break;
case DebugWindow.TileViewer: frm = new frmTileViewer(); frm.Icon = Properties.Resources.VerticalLayout; break;
@ -96,7 +97,8 @@ namespace Mesen.GUI.Debugger
{
//Only one of each of these windows can be opened at once, check if one is already opened
switch(window) {
case DebugWindow.Debugger: return _openedWindows.ToList().Find((form) => form.GetType() == typeof(frmDebugger));
case DebugWindow.Debugger: return _openedWindows.ToList().Find((form) => form.GetType() == typeof(frmDebugger) && ((frmDebugger)form).CpuType == CpuType.Cpu);
case DebugWindow.SpcDebugger: return _openedWindows.ToList().Find((form) => form.GetType() == typeof(frmDebugger) && ((frmDebugger)form).CpuType == CpuType.Spc);
case DebugWindow.TraceLogger: return _openedWindows.ToList().Find((form) => form.GetType() == typeof(frmTraceLogger));
}
@ -123,6 +125,7 @@ namespace Mesen.GUI.Debugger
public enum DebugWindow
{
Debugger,
SpcDebugger,
MemoryTools,
TraceLogger,
TileViewer,

View file

@ -82,7 +82,10 @@
this.toolStripMenuItem4 = new System.Windows.Forms.ToolStripSeparator();
this.mnuPreferences = new System.Windows.Forms.ToolStripMenuItem();
this.ctrlSplitContainer = new Mesen.GUI.Controls.ctrlSplitContainer();
this.ctrlStatus = new Mesen.GUI.Debugger.Controls.ctrlConsoleStatus();
this.panel1 = new System.Windows.Forms.Panel();
this.ctrlPpuStatus = new Mesen.GUI.Debugger.Controls.ctrlPpuStatus();
this.ctrlSpcStatus = new Mesen.GUI.Debugger.Controls.ctrlSpcStatus();
this.ctrlCpuStatus = new Mesen.GUI.Debugger.Controls.ctrlCpuStatus();
this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel();
this.grpWatch = new System.Windows.Forms.GroupBox();
this.picWatchHelp = new System.Windows.Forms.PictureBox();
@ -97,6 +100,7 @@
this.ctrlSplitContainer.Panel1.SuspendLayout();
this.ctrlSplitContainer.Panel2.SuspendLayout();
this.ctrlSplitContainer.SuspendLayout();
this.panel1.SuspendLayout();
this.tableLayoutPanel1.SuspendLayout();
this.grpWatch.SuspendLayout();
((System.ComponentModel.ISupportInitialize)(this.picWatchHelp)).BeginInit();
@ -492,7 +496,7 @@
// ctrlSplitContainer.Panel1
//
this.ctrlSplitContainer.Panel1.Controls.Add(this.ctrlDisassemblyView);
this.ctrlSplitContainer.Panel1.Controls.Add(this.ctrlStatus);
this.ctrlSplitContainer.Panel1.Controls.Add(this.panel1);
//
// ctrlSplitContainer.Panel2
//
@ -501,14 +505,43 @@
this.ctrlSplitContainer.SplitterDistance = 421;
this.ctrlSplitContainer.TabIndex = 2;
//
// ctrlStatus
// panel1
//
this.ctrlStatus.Dock = System.Windows.Forms.DockStyle.Right;
this.ctrlStatus.Location = new System.Drawing.Point(484, 0);
this.ctrlStatus.Name = "ctrlStatus";
this.ctrlStatus.Padding = new System.Windows.Forms.Padding(3, 0, 3, 0);
this.ctrlStatus.Size = new System.Drawing.Size(348, 421);
this.ctrlStatus.TabIndex = 1;
this.panel1.Controls.Add(this.ctrlPpuStatus);
this.panel1.Controls.Add(this.ctrlSpcStatus);
this.panel1.Controls.Add(this.ctrlCpuStatus);
this.panel1.Dock = System.Windows.Forms.DockStyle.Right;
this.panel1.Location = new System.Drawing.Point(484, 0);
this.panel1.Name = "panel1";
this.panel1.Size = new System.Drawing.Size(348, 421);
this.panel1.TabIndex = 2;
//
// ctrlPpuStatus
//
this.ctrlPpuStatus.Dock = System.Windows.Forms.DockStyle.Top;
this.ctrlPpuStatus.Location = new System.Drawing.Point(0, 268);
this.ctrlPpuStatus.Name = "ctrlPpuStatus";
this.ctrlPpuStatus.Padding = new System.Windows.Forms.Padding(3, 0, 3, 0);
this.ctrlPpuStatus.Size = new System.Drawing.Size(348, 47);
this.ctrlPpuStatus.TabIndex = 3;
//
// ctrlSpcStatus
//
this.ctrlSpcStatus.Dock = System.Windows.Forms.DockStyle.Top;
this.ctrlSpcStatus.Location = new System.Drawing.Point(0, 148);
this.ctrlSpcStatus.Name = "ctrlSpcStatus";
this.ctrlSpcStatus.Padding = new System.Windows.Forms.Padding(3, 0, 3, 0);
this.ctrlSpcStatus.Size = new System.Drawing.Size(348, 120);
this.ctrlSpcStatus.TabIndex = 2;
//
// ctrlCpuStatus
//
this.ctrlCpuStatus.Dock = System.Windows.Forms.DockStyle.Top;
this.ctrlCpuStatus.Location = new System.Drawing.Point(0, 0);
this.ctrlCpuStatus.Name = "ctrlCpuStatus";
this.ctrlCpuStatus.Padding = new System.Windows.Forms.Padding(3, 0, 3, 0);
this.ctrlCpuStatus.Size = new System.Drawing.Size(348, 148);
this.ctrlCpuStatus.TabIndex = 1;
//
// tableLayoutPanel1
//
@ -621,6 +654,7 @@
this.ctrlSplitContainer.Panel2.ResumeLayout(false);
((System.ComponentModel.ISupportInitialize)(this.ctrlSplitContainer)).EndInit();
this.ctrlSplitContainer.ResumeLayout(false);
this.panel1.ResumeLayout(false);
this.tableLayoutPanel1.ResumeLayout(false);
this.grpWatch.ResumeLayout(false);
((System.ComponentModel.ISupportInitialize)(this.picWatchHelp)).EndInit();
@ -662,7 +696,7 @@
private System.Windows.Forms.GroupBox grpWatch;
private System.Windows.Forms.GroupBox grpBreakpoints;
private Controls.ctrlBreakpoints ctrlBreakpoints;
private Controls.ctrlConsoleStatus ctrlStatus;
private Controls.ctrlCpuStatus ctrlCpuStatus;
private GUI.Controls.ctrlMesenToolStrip tsToolbar;
private System.Windows.Forms.GroupBox grpCallstack;
private Controls.ctrlCallstack ctrlCallstack;
@ -694,5 +728,8 @@
private System.Windows.Forms.ToolStripSeparator toolStripMenuItem4;
private System.Windows.Forms.ToolStripMenuItem mnuShowByteCode;
private System.Windows.Forms.ToolStripSeparator toolStripMenuItem5;
private System.Windows.Forms.Panel panel1;
private Controls.ctrlPpuStatus ctrlPpuStatus;
private Controls.ctrlSpcStatus ctrlSpcStatus;
}
}

View file

@ -1,4 +1,5 @@
using Mesen.GUI.Config;
using Mesen.GUI.Debugger.Code;
using Mesen.GUI.Forms;
using System;
using System.Collections.Generic;
@ -16,10 +17,16 @@ namespace Mesen.GUI.Debugger
{
private EntityBinder _entityBinder = new EntityBinder();
private NotificationListener _notifListener;
private CpuType _cpuType;
public frmDebugger()
public CpuType CpuType { get { return _cpuType; } }
public frmDebugger(CpuType cpuType)
{
InitializeComponent();
_cpuType = cpuType;
if(DesignMode) {
return;
}
@ -29,9 +36,17 @@ namespace Mesen.GUI.Debugger
{
base.OnLoad(e);
this.Text = _cpuType == CpuType.Cpu ? "CPU Debugger" : "SPC Debugger";
_notifListener = new NotificationListener();
_notifListener.OnNotification += OnNotificationReceived;
switch(_cpuType) {
case CpuType.Cpu: ctrlDisassemblyView.Initialize(new CpuDisassemblyManager(), new CpuLineStyleProvider()); break;
case CpuType.Spc: ctrlDisassemblyView.Initialize(new SpcDisassemblyManager(), new SpcLineStyleProvider()); break;
}
ctrlBreakpoints.CpuType = _cpuType;
InitShortcuts();
InitToolbar();
LoadConfig();
@ -39,7 +54,7 @@ namespace Mesen.GUI.Debugger
toolTip.SetToolTip(picWatchHelp, ctrlWatch.GetTooltipText());
BreakpointManager.BreakpointsEnabled = true;
DebugApi.Step(10000);
DebugApi.Step(10000, StepType.CpuStep);
}
protected override void OnClosing(CancelEventArgs e)
@ -65,7 +80,7 @@ namespace Mesen.GUI.Debugger
if(EmuApi.IsPaused()) {
DebugApi.ResumeExecution();
} else {
DebugApi.Step(1);
DebugApi.Step(1, _cpuType == CpuType.Cpu ? StepType.CpuStep : StepType.SpcStep);
}
return true;
}
@ -112,9 +127,9 @@ namespace Mesen.GUI.Debugger
mnuDecreaseFontSize.InitShortcut(this, nameof(DebuggerShortcutsConfig.DecreaseFontSize));
mnuResetFontSize.InitShortcut(this, nameof(DebuggerShortcutsConfig.ResetFontSize));
mnuStepInto.Click += (s, e) => { DebugApi.Step(1); };
mnuStepOver.Click += (s, e) => { DebugApi.Step(1, StepType.CpuStepOver); };
mnuStepOut.Click += (s, e) => { DebugApi.Step(1, StepType.CpuStepOut); };
mnuStepInto.Click += (s, e) => { DebugApi.Step(1, _cpuType == CpuType.Cpu ? StepType.CpuStep : StepType.SpcStep); };
mnuStepOver.Click += (s, e) => { DebugApi.Step(1, _cpuType == CpuType.Cpu ? StepType.CpuStepOver : StepType.SpcStepOver); };
mnuStepOut.Click += (s, e) => { DebugApi.Step(1, _cpuType == CpuType.Cpu ? StepType.CpuStepOut : StepType.SpcStepOut); };
mnuRunPpuCycle.Click += (s, e) => { DebugApi.Step(1, StepType.PpuStep); };
mnuRunScanline.Click += (s, e) => { DebugApi.Step(341, StepType.PpuStep); };
mnuRunOneFrame.Click += (s, e) => { DebugApi.Step(341*262, StepType.PpuStep); }; //TODO ntsc/pal
@ -193,7 +208,7 @@ namespace Mesen.GUI.Debugger
private void GoToAddress()
{
GoToAddress address = new GoToAddress();
using(frmGoToLine frm = new frmGoToLine(address, 6)) {
using(frmGoToLine frm = new frmGoToLine(address, _cpuType == CpuType.Spc ? 4 : 6)) {
frm.StartPosition = FormStartPosition.CenterParent;
if(frm.ShowDialog(ctrlDisassemblyView) == DialogResult.OK) {
ctrlDisassemblyView.GoToAddress((int)address.Address);
@ -216,11 +231,23 @@ namespace Mesen.GUI.Debugger
private void UpdateDebugger(DebugState state, int? activeAddress)
{
ctrlStatus.UpdateStatus(state);
if(_cpuType == CpuType.Cpu) {
ctrlCpuStatus.UpdateStatus(state);
} else {
ctrlCpuStatus.Visible = false;
}
if(_cpuType == CpuType.Spc) {
ctrlSpcStatus.UpdateStatus(state);
} else {
ctrlSpcStatus.Visible = false;
}
ctrlPpuStatus.UpdateStatus(state);
ctrlDisassemblyView.UpdateCode();
ctrlDisassemblyView.SetActiveAddress(activeAddress);
ctrlWatch.UpdateWatch(true);
ctrlCallstack.UpdateCallstack();
ctrlCallstack.UpdateCallstack(_cpuType);
}
private void OnNotificationReceived(NotificationEventArgs e)
@ -242,7 +269,7 @@ namespace Mesen.GUI.Debugger
case ConsoleNotificationType.CodeBreak: {
DebugState state = DebugApi.GetState();
int activeAddress = (int)((state.Cpu.K << 16) | state.Cpu.PC);
int activeAddress = _cpuType == CpuType.Cpu ? (int)((state.Cpu.K << 16) | state.Cpu.PC) : (int)state.Spc.PC;
this.BeginInvoke((MethodInvoker)(() => {
UpdateContinueAction();

View file

@ -123,6 +123,7 @@
this.mnuTakeScreenshot = new System.Windows.Forms.ToolStripMenuItem();
this.debugToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.mnuDebugger = new System.Windows.Forms.ToolStripMenuItem();
this.mnuSpcDebugger = new System.Windows.Forms.ToolStripMenuItem();
this.mnuMemoryTools = new System.Windows.Forms.ToolStripMenuItem();
this.mnuTraceLogger = new System.Windows.Forms.ToolStripMenuItem();
this.toolStripMenuItem12 = new System.Windows.Forms.ToolStripSeparator();
@ -313,7 +314,7 @@
this.mnuShowFPS});
this.mnuEmulationSpeed.Image = global::Mesen.GUI.Properties.Resources.Speed;
this.mnuEmulationSpeed.Name = "mnuEmulationSpeed";
this.mnuEmulationSpeed.Size = new System.Drawing.Size(152, 22);
this.mnuEmulationSpeed.Size = new System.Drawing.Size(135, 22);
this.mnuEmulationSpeed.Text = "Speed";
this.mnuEmulationSpeed.DropDownOpening += new System.EventHandler(this.mnuEmulationSpeed_DropDownOpening);
//
@ -400,7 +401,7 @@
this.mnuFullscreen});
this.mnuVideoScale.Image = global::Mesen.GUI.Properties.Resources.Fullscreen;
this.mnuVideoScale.Name = "mnuVideoScale";
this.mnuVideoScale.Size = new System.Drawing.Size(152, 22);
this.mnuVideoScale.Size = new System.Drawing.Size(135, 22);
this.mnuVideoScale.Text = "Video Size";
this.mnuVideoScale.DropDownOpening += new System.EventHandler(this.mnuVideoScale_DropDownOpening);
//
@ -486,7 +487,7 @@
this.mnuBilinearInterpolation});
this.mnuVideoFilter.Image = global::Mesen.GUI.Properties.Resources.VideoFilter;
this.mnuVideoFilter.Name = "mnuVideoFilter";
this.mnuVideoFilter.Size = new System.Drawing.Size(152, 22);
this.mnuVideoFilter.Size = new System.Drawing.Size(135, 22);
this.mnuVideoFilter.Text = "Video Filter";
this.mnuVideoFilter.DropDownOpening += new System.EventHandler(this.mnuVideoFilter_DropDownOpening);
//
@ -673,7 +674,7 @@
this.mnuRegionPal});
this.mnuRegion.Image = global::Mesen.GUI.Properties.Resources.WebBrowser;
this.mnuRegion.Name = "mnuRegion";
this.mnuRegion.Size = new System.Drawing.Size(152, 22);
this.mnuRegion.Size = new System.Drawing.Size(135, 22);
this.mnuRegion.Text = "Region";
this.mnuRegion.DropDownOpening += new System.EventHandler(this.mnuRegion_DropDownOpening);
//
@ -703,13 +704,13 @@
// toolStripMenuItem4
//
this.toolStripMenuItem4.Name = "toolStripMenuItem4";
this.toolStripMenuItem4.Size = new System.Drawing.Size(149, 6);
this.toolStripMenuItem4.Size = new System.Drawing.Size(132, 6);
//
// mnuAudioConfig
//
this.mnuAudioConfig.Image = global::Mesen.GUI.Properties.Resources.Audio;
this.mnuAudioConfig.Name = "mnuAudioConfig";
this.mnuAudioConfig.Size = new System.Drawing.Size(152, 22);
this.mnuAudioConfig.Size = new System.Drawing.Size(135, 22);
this.mnuAudioConfig.Text = "Audio";
this.mnuAudioConfig.Click += new System.EventHandler(this.mnuAudioConfig_Click);
//
@ -717,7 +718,7 @@
//
this.mnuInputConfig.Image = global::Mesen.GUI.Properties.Resources.Controller;
this.mnuInputConfig.Name = "mnuInputConfig";
this.mnuInputConfig.Size = new System.Drawing.Size(152, 22);
this.mnuInputConfig.Size = new System.Drawing.Size(135, 22);
this.mnuInputConfig.Text = "Input";
this.mnuInputConfig.Click += new System.EventHandler(this.mnuInputConfig_Click);
//
@ -725,7 +726,7 @@
//
this.mnuVideoConfig.Image = global::Mesen.GUI.Properties.Resources.VideoOptions;
this.mnuVideoConfig.Name = "mnuVideoConfig";
this.mnuVideoConfig.Size = new System.Drawing.Size(152, 22);
this.mnuVideoConfig.Size = new System.Drawing.Size(135, 22);
this.mnuVideoConfig.Text = "Video";
this.mnuVideoConfig.Click += new System.EventHandler(this.mnuVideoConfig_Click);
//
@ -733,20 +734,20 @@
//
this.mnuEmulationConfig.Image = global::Mesen.GUI.Properties.Resources.DipSwitches;
this.mnuEmulationConfig.Name = "mnuEmulationConfig";
this.mnuEmulationConfig.Size = new System.Drawing.Size(152, 22);
this.mnuEmulationConfig.Size = new System.Drawing.Size(135, 22);
this.mnuEmulationConfig.Text = "Emulation";
this.mnuEmulationConfig.Click += new System.EventHandler(this.mnuEmulationConfig_Click);
//
// toolStripMenuItem3
//
this.toolStripMenuItem3.Name = "toolStripMenuItem3";
this.toolStripMenuItem3.Size = new System.Drawing.Size(149, 6);
this.toolStripMenuItem3.Size = new System.Drawing.Size(132, 6);
//
// mnuPreferences
//
this.mnuPreferences.Image = global::Mesen.GUI.Properties.Resources.Settings;
this.mnuPreferences.Name = "mnuPreferences";
this.mnuPreferences.Size = new System.Drawing.Size(152, 22);
this.mnuPreferences.Size = new System.Drawing.Size(135, 22);
this.mnuPreferences.Text = "Preferences";
this.mnuPreferences.Click += new System.EventHandler(this.mnuPreferences_Click);
//
@ -846,6 +847,7 @@
//
this.debugToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.mnuDebugger,
this.mnuSpcDebugger,
this.mnuMemoryTools,
this.mnuTraceLogger,
this.toolStripMenuItem12,
@ -865,6 +867,13 @@
this.mnuDebugger.Size = new System.Drawing.Size(155, 22);
this.mnuDebugger.Text = "Debugger";
//
// mnuSpcDebugger
//
this.mnuSpcDebugger.Image = global::Mesen.GUI.Properties.Resources.SpcDebugger;
this.mnuSpcDebugger.Name = "mnuSpcDebugger";
this.mnuSpcDebugger.Size = new System.Drawing.Size(155, 22);
this.mnuSpcDebugger.Text = "SPC Debugger";
//
// mnuMemoryTools
//
this.mnuMemoryTools.Image = global::Mesen.GUI.Properties.Resources.CheatCode;
@ -1117,5 +1126,6 @@
private System.Windows.Forms.ToolStripMenuItem mnuPaletteViewer;
private System.Windows.Forms.ToolStripSeparator toolStripMenuItem22;
private System.Windows.Forms.ToolStripMenuItem mnuTileViewer;
private System.Windows.Forms.ToolStripMenuItem mnuSpcDebugger;
}
}

View file

@ -201,6 +201,7 @@ namespace Mesen.GUI.Forms
_shortcuts.BindShortcut(mnuTakeScreenshot, EmulatorShortcut.TakeScreenshot);
mnuDebugger.InitShortcut(this, nameof(DebuggerShortcutsConfig.OpenDebugger));
mnuSpcDebugger.InitShortcut(this, nameof(DebuggerShortcutsConfig.OpenSpcDebugger));
mnuMemoryTools.InitShortcut(this, nameof(DebuggerShortcutsConfig.OpenMemoryTools));
mnuEventViewer.InitShortcut(this, nameof(DebuggerShortcutsConfig.OpenEventViewer));
mnuTilemapViewer.InitShortcut(this, nameof(DebuggerShortcutsConfig.OpenTilemapViewer));
@ -243,6 +244,7 @@ namespace Mesen.GUI.Forms
mnuRegionPal.Click += (s, e) => { _shortcuts.SetRegion(ConsoleRegion.Pal); };
mnuDebugger.Click += (s, e) => { DebugWindowManager.OpenDebugWindow(DebugWindow.Debugger); };
mnuSpcDebugger.Click += (s, e) => { DebugWindowManager.OpenDebugWindow(DebugWindow.SpcDebugger); };
mnuTraceLogger.Click += (s, e) => { DebugWindowManager.OpenDebugWindow(DebugWindow.TraceLogger); };
mnuMemoryTools.Click += (s, e) => { DebugWindowManager.OpenDebugWindow(DebugWindow.MemoryTools); };
mnuTilemapViewer.Click += (s, e) => { DebugWindowManager.OpenDebugWindow(DebugWindow.TilemapViewer); };
@ -257,6 +259,7 @@ namespace Mesen.GUI.Forms
{
bool running = EmuRunner.IsRunning();
mnuDebugger.Enabled = running;
mnuSpcDebugger.Enabled = running;
mnuTraceLogger.Enabled = running;
mnuMemoryTools.Enabled = running;
mnuTilemapViewer.Enabled = running;

View file

@ -26,21 +26,21 @@ namespace Mesen.GUI
[DllImport(DllPath)] public static extern void StopTraceLogger();
[DllImport(DllPath)] public static extern void SetTraceOptions(InteropTraceLoggerOptions options);
[DllImport(DllPath, EntryPoint = "GetDisassemblyLineData")] private static extern void GetDisassemblyLineDataWrapper(UInt32 lineIndex, ref InteropCodeLineData lineData);
public static CodeLineData GetDisassemblyLineData(UInt32 lineIndex)
[DllImport(DllPath, EntryPoint = "GetDisassemblyLineData")] private static extern void GetDisassemblyLineDataWrapper(CpuType type, UInt32 lineIndex, ref InteropCodeLineData lineData);
public static CodeLineData GetDisassemblyLineData(CpuType type, UInt32 lineIndex)
{
InteropCodeLineData data = new InteropCodeLineData();
data.Comment = new byte[1000];
data.Text = new byte[1000];
data.ByteCode = new byte[4];
DebugApi.GetDisassemblyLineDataWrapper(lineIndex, ref data);
DebugApi.GetDisassemblyLineDataWrapper(type, lineIndex, ref data);
return new CodeLineData(data);
}
[DllImport(DllPath)] public static extern UInt32 GetDisassemblyLineCount();
[DllImport(DllPath)] public static extern UInt32 GetDisassemblyLineIndex(UInt32 cpuAddress);
[DllImport(DllPath)] public static extern int SearchDisassembly([MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(Utf8Marshaler))]string searchString, int startPosition, int endPosition, [MarshalAs(UnmanagedType.I1)]bool searchBackwards);
[DllImport(DllPath)] public static extern UInt32 GetDisassemblyLineCount(CpuType type);
[DllImport(DllPath)] public static extern UInt32 GetDisassemblyLineIndex(CpuType type, UInt32 cpuAddress);
[DllImport(DllPath)] public static extern int SearchDisassembly(CpuType type, [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(Utf8Marshaler))]string searchString, int startPosition, int endPosition, [MarshalAs(UnmanagedType.I1)]bool searchBackwards);
[DllImport(DllPath, EntryPoint = "GetExecutionTrace")] private static extern IntPtr GetExecutionTraceWrapper(UInt32 lineCount);
public static string GetExecutionTrace(UInt32 lineCount) { return Utf8Marshaler.PtrToStringUtf8(DebugApi.GetExecutionTraceWrapper(lineCount)); }
@ -103,13 +103,13 @@ namespace Mesen.GUI
return buffer;
}
[DllImport(DllPath, EntryPoint = "GetCallstack")] private static extern void DebugGetCallstackWrapper([In, Out]StackFrameInfo[] callstackArray, ref UInt32 callstackSize);
public static StackFrameInfo[] GetCallstack()
[DllImport(DllPath, EntryPoint = "GetCallstack")] private static extern void GetCallstackWrapper(CpuType type, [In, Out]StackFrameInfo[] callstackArray, ref UInt32 callstackSize);
public static StackFrameInfo[] GetCallstack(CpuType type)
{
StackFrameInfo[] callstack = new StackFrameInfo[512];
UInt32 callstackSize = 0;
DebugApi.DebugGetCallstackWrapper(callstack, ref callstackSize);
DebugApi.GetCallstackWrapper(type, callstack, ref callstackSize);
Array.Resize(ref callstack, (int)callstackSize);
return callstack;
@ -181,6 +181,19 @@ namespace Mesen.GUI
Negative = 0x80
}
[Flags]
public enum SpcFlags : byte
{
Carry = 0x01,
Zero = 0x02,
IrqEnable = 0x04,
HalfCarry = 0x08,
Break = 0x10,
DirectPage = 0x20,
Overflow = 0x40,
Negative = 0x80
};
public struct CpuState
{
public UInt64 CycleCount;
@ -254,11 +267,56 @@ namespace Mesen.GUI
[MarshalAs(UnmanagedType.I1)] public bool ExtBgEnabled;
}
public struct SpcTimer
{
[MarshalAs(UnmanagedType.I1)] public bool Enabled;
[MarshalAs(UnmanagedType.I1)] public bool TimersEnabled;
public byte Output;
public byte Stage0;
public byte Stage1;
public byte PrevStage1;
public byte Stage2;
public byte Target;
}
public struct SpcState
{
public UInt64 Cycle;
public UInt16 PC;
public byte A;
public byte X;
public byte Y;
public byte SP;
public SpcFlags PS;
[MarshalAs(UnmanagedType.I1)] public bool WriteEnabled;
[MarshalAs(UnmanagedType.I1)] public bool RomEnabled;
public byte InternalSpeed;
public byte ExternalSpeed;
[MarshalAs(UnmanagedType.I1)] public bool TimersEnabled;
public byte DspReg;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
public byte[] OutputReg;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
public byte[] RamReg;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
public byte[] CpuRegs;
public SpcTimer Timer0;
public SpcTimer Timer1;
public SpcTimer Timer2;
};
public struct DebugState
{
public UInt64 MasterClock;
public CpuState Cpu;
public PpuState Ppu;
public SpcState Spc;
}
public enum MemoryOperationType
@ -400,12 +458,21 @@ namespace Mesen.GUI
Nmi = 1,
Irq = 2
}
public enum CpuType
{
Cpu,
Spc,
}
public enum StepType
{
CpuStep,
CpuStepOut,
CpuStepOver,
SpcStep,
SpcStepOut,
SpcStepOver,
PpuStep,
SpecificScanline,
}

View file

@ -960,6 +960,16 @@ namespace Mesen.GUI.Properties {
}
}
/// <summary>
/// Looks up a localized resource of type System.Drawing.Bitmap.
/// </summary>
internal static System.Drawing.Bitmap SpcDebugger {
get {
object obj = ResourceManager.GetObject("SpcDebugger", resourceCulture);
return ((System.Drawing.Bitmap)(obj));
}
}
/// <summary>
/// Looks up a localized resource of type System.Drawing.Bitmap.
/// </summary>

View file

@ -451,4 +451,7 @@
<data name="MesenSIcon" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\MesenSIcon.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="SpcDebugger" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\SpcDebugger.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
</root>

Binary file not shown.

After

Width:  |  Height:  |  Size: 821 B

View file

@ -243,12 +243,27 @@
<DependentUpon>frmBreakpoint.cs</DependentUpon>
</Compile>
<Compile Include="Debugger\Breakpoints\InteropBreakpoint.cs" />
<Compile Include="Debugger\Code\CpuCodeProvider.cs" />
<Compile Include="Debugger\Code\BaseStyleProvider.cs" />
<Compile Include="Debugger\Code\SpcLineStyleProvider.cs" />
<Compile Include="Debugger\Code\CodeDataProvider.cs" />
<Compile Include="Debugger\Code\SpcDisassemblyManager.cs" />
<Compile Include="Debugger\Code\CpuDisassemblyManager.cs" />
<Compile Include="Debugger\Code\CpuLineStyleProvider.cs" />
<Compile Include="Debugger\Code\IDisassemblyManager.cs" />
<Compile Include="Debugger\Config\DebuggerShortcutsConfig.cs" />
<Compile Include="Debugger\Config\DebuggerInfo.cs" />
<Compile Include="Debugger\Controls\ctrlPpuStatus.cs">
<SubType>UserControl</SubType>
</Compile>
<Compile Include="Debugger\Controls\ctrlPpuStatus.Designer.cs">
<DependentUpon>ctrlPpuStatus.cs</DependentUpon>
</Compile>
<Compile Include="Debugger\Controls\ctrlSpcStatus.cs">
<SubType>UserControl</SubType>
</Compile>
<Compile Include="Debugger\Controls\ctrlSpcStatus.Designer.cs">
<DependentUpon>ctrlSpcStatus.cs</DependentUpon>
</Compile>
<Compile Include="Debugger\frmBreakIn.cs">
<SubType>Form</SubType>
</Compile>
@ -343,11 +358,11 @@
<Compile Include="Debugger\Controls\ctrlColorPicker.cs">
<SubType>Component</SubType>
</Compile>
<Compile Include="Debugger\Controls\ctrlConsoleStatus.cs">
<Compile Include="Debugger\Controls\ctrlCpuStatus.cs">
<SubType>UserControl</SubType>
</Compile>
<Compile Include="Debugger\Controls\ctrlConsoleStatus.Designer.cs">
<DependentUpon>ctrlConsoleStatus.cs</DependentUpon>
<Compile Include="Debugger\Controls\ctrlCpuStatus.Designer.cs">
<DependentUpon>ctrlCpuStatus.cs</DependentUpon>
</Compile>
<Compile Include="Debugger\Controls\ctrlDbgShortcuts.cs">
<SubType>UserControl</SubType>
@ -682,6 +697,7 @@
<Compile Include="Utilities\Md5Helper.cs" />
<Compile Include="Updates\UpdateHelper.cs" />
<Compile Include="Utilities\XmlColor.cs" />
<None Include="Resources\SpcDebugger.png" />
<None Include="Resources\MesenSIcon.png" />
<None Include="app.manifest" />
<EmbeddedResource Include="Controls\ctrlPathSelection.resx">
@ -717,8 +733,14 @@
<EmbeddedResource Include="Debugger\Controls\ctrlCallstack.resx">
<DependentUpon>ctrlCallstack.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="Debugger\Controls\ctrlConsoleStatus.resx">
<DependentUpon>ctrlConsoleStatus.cs</DependentUpon>
<EmbeddedResource Include="Debugger\Controls\ctrlPpuStatus.resx">
<DependentUpon>ctrlPpuStatus.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="Debugger\Controls\ctrlSpcStatus.resx">
<DependentUpon>ctrlSpcStatus.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="Debugger\Controls\ctrlCpuStatus.resx">
<DependentUpon>ctrlCpuStatus.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="Debugger\Controls\ctrlDbgShortcuts.resx">
<DependentUpon>ctrlDbgShortcuts.cs</DependentUpon>