From 5414afdbb40603c382eda925c47bfcefced8991b Mon Sep 17 00:00:00 2001 From: Sour Date: Sun, 26 Jun 2022 14:44:59 -0400 Subject: [PATCH] Debugger: Added "Show jump labels" option --- Core/Debugger/CodeDataLogger.h | 5 +++ Core/Debugger/DebugTypes.h | 1 + Core/Debugger/Disassembler.cpp | 15 +++++++- Core/Gameboy/Debugger/GameboyDisUtils.cpp | 37 +++++++++++++++++++ Core/Gameboy/Debugger/GameboyDisUtils.h | 2 + Core/Gameboy/Debugger/GbDebugger.cpp | 10 ++--- Core/NES/Debugger/NesDebugger.cpp | 27 +++++++------- Core/NES/Debugger/NesDisUtils.cpp | 25 +++++++++++++ Core/NES/Debugger/NesDisUtils.h | 2 + Core/NES/NesMemoryManager.cpp | 20 +--------- Core/NES/NesMemoryManager.h | 5 +-- Core/PCE/Debugger/PceDebugger.cpp | 27 +++++++------- Core/PCE/Debugger/PceDebugger.h | 2 +- Core/PCE/Debugger/PceDisUtils.cpp | 31 ++++++++++++++++ Core/PCE/Debugger/PceDisUtils.h | 2 + Core/SNES/Debugger/Cx4Debugger.cpp | 4 +- Core/SNES/Debugger/GsuDebugger.cpp | 2 +- Core/SNES/Debugger/SnesCodeDataLogger.h | 11 ------ Core/SNES/Debugger/SnesDebugger.cpp | 32 ++++++++-------- Core/SNES/Debugger/SnesDisUtils.cpp | 31 ++++++++++++++++ Core/SNES/Debugger/SnesDisUtils.h | 2 + Core/Shared/SettingTypes.h | 2 + NewUI/Config/Debugger/DebuggerConfig.cs | 7 +++- .../Debugger/Views/DebuggerOptionsView.axaml | 4 ++ NewUI/Interop/ConfigApi.cs | 2 + NewUI/Localization/resources.en.xml | 1 + NewUI/ThirdParty/DataBox/DataBox.cs | 2 +- 27 files changed, 221 insertions(+), 90 deletions(-) diff --git a/Core/Debugger/CodeDataLogger.h b/Core/Debugger/CodeDataLogger.h index ce6be2fe..120ce3b9 100644 --- a/Core/Debugger/CodeDataLogger.h +++ b/Core/Debugger/CodeDataLogger.h @@ -38,6 +38,11 @@ public: _cdlData[absoluteAddr] |= CdlFlags::Code | flags; } + void SetCode(int32_t absoluteAddr, uint8_t flags) + { + _cdlData[absoluteAddr] |= CdlFlags::Code | flags; + } + template void SetData(int32_t absoluteAddr) { diff --git a/Core/Debugger/DebugTypes.h b/Core/Debugger/DebugTypes.h index fd1f89bd..46a27abd 100644 --- a/Core/Debugger/DebugTypes.h +++ b/Core/Debugger/DebugTypes.h @@ -105,6 +105,7 @@ struct DisassemblyResult Flags = flags; CpuAddress = cpuAddress; Address.Address = -1; + Address.Type = {}; CommentLine = commentLine; } diff --git a/Core/Debugger/Disassembler.cpp b/Core/Debugger/Disassembler.cpp index 9f7512be..bd494ab7 100644 --- a/Core/Debugger/Disassembler.cpp +++ b/Core/Debugger/Disassembler.cpp @@ -111,6 +111,7 @@ vector Disassembler::Disassemble(CpuType cpuType, uint16_t ba bool disData = _settings->CheckDebuggerFlag(DebuggerFlags::DisassembleVerifiedData); bool showUnident = _settings->CheckDebuggerFlag(DebuggerFlags::ShowUnidentifiedData); bool showData = _settings->CheckDebuggerFlag(DebuggerFlags::ShowVerifiedData); + bool showJumpLabels = _settings->CheckDebuggerFlag(DebuggerFlags::ShowJumpLabels); bool inUnknownBlock = false; bool inVerifiedBlock = false; @@ -216,6 +217,9 @@ vector Disassembler::Disassemble(CpuType cpuType, uint16_t ba } else { results.push_back(DisassemblyResult(addrInfo, i)); } + } else if(showJumpLabels && cdl && (cdl->IsJumpTarget(addrInfo.Address) || cdl->IsSubEntryPoint(addrInfo.Address))) { + results.push_back(DisassemblyResult(addrInfo, i, LineFlags::Label)); + results.push_back(DisassemblyResult(addrInfo, i)); } else { results.push_back(DisassemblyResult(addrInfo, i)); } @@ -310,6 +314,7 @@ void Disassembler::GetLineData(DisassemblyResult& row, CpuType type, MemoryType case MemoryType::GbCartRam: case MemoryType::SnesSaveRam: case MemoryType::NesSaveRam: + case MemoryType::PceSaveRam: data.Flags |= (uint8_t)LineFlags::SaveRam; break; } @@ -329,7 +334,15 @@ void Disassembler::GetLineData(DisassemblyResult& row, CpuType type, MemoryType data.Flags |= LineFlags::VerifiedCode; memcpy(data.Comment, comment.c_str(), std::min((int)comment.size() + 1, 1000)); } else if(data.Flags & LineFlags::Label) { - string label = _labelManager->GetLabel(row.Address) + ":"; + string label = _labelManager->GetLabel(row.Address); + if(label.empty()) { + //Use address as the label + label = "$" + DebugUtilities::AddressToHex(type, row.CpuAddress); + if(_settings->CheckDebuggerFlag(DebuggerFlags::UseLowerCaseDisassembly)) { + std::transform(label.begin(), label.end(), label.begin(), ::tolower); + } + } + label += ":"; data.Flags |= LineFlags::VerifiedCode; memcpy(data.Text, label.c_str(), std::min((int)label.size() + 1, 1000)); } else { diff --git a/Core/Gameboy/Debugger/GameboyDisUtils.cpp b/Core/Gameboy/Debugger/GameboyDisUtils.cpp index d11fe584..4f5ac239 100644 --- a/Core/Gameboy/Debugger/GameboyDisUtils.cpp +++ b/Core/Gameboy/Debugger/GameboyDisUtils.cpp @@ -248,6 +248,43 @@ bool GameboyDisUtils::IsConditionalJump(uint8_t opCode) } } + +CdlFlags::CdlFlags GameboyDisUtils::GetOpFlags(uint8_t opCode, uint16_t pc, uint16_t prevPc) +{ + switch(opCode) { + case 0xC4: //CALL NZ,a16 + case 0xC7: //RST 00H + case 0xCD: //CALL a16 + case 0xCC: //CALL Z,a16 + case 0xCF: //RST 08H + case 0xD4: //CALL NC,a16 + case 0xD7: //RST 10H + case 0xDC: //CALL C,a16 + case 0xDF: //RST 18H + case 0xE7: //RST 20H + case 0xEF: //RST 28H + case 0xF7: //RST 30H + case 0xFF: //RST 38H + return CdlFlags::SubEntryPoint; + + case 0x18: //JR r8 + case 0xC3: //JP a16 + case 0xE9: //JP (HL) + case 0x20: //JR NZ,r8 + case 0x28: //JR Z,r8 + case 0x30: //JR NC,r8 + case 0x38: //JR C,r8 + case 0xC2: //JP NZ,a16 + case 0xCA: //JP Z,a16 + case 0xD2: //JP NC,a16 + case 0xDA: //JP C,a16 + return pc != prevPc + GameboyDisUtils::GetOpSize(opCode) ? CdlFlags::JumpTarget : CdlFlags::None; + + default: + return CdlFlags::None; + } +} + string GameboyDisUtils::GetOpTemplate(uint8_t op, bool prefixed) { return prefixed ? _cbTemplate[op] : _opTemplate[op]; diff --git a/Core/Gameboy/Debugger/GameboyDisUtils.h b/Core/Gameboy/Debugger/GameboyDisUtils.h index 450aaaea..36a1694c 100644 --- a/Core/Gameboy/Debugger/GameboyDisUtils.h +++ b/Core/Gameboy/Debugger/GameboyDisUtils.h @@ -1,5 +1,6 @@ #pragma once #include "stdafx.h" +#include "Debugger/DebugTypes.h" class DisassemblyInfo; class LabelManager; @@ -16,5 +17,6 @@ public: static bool IsReturnInstruction(uint8_t opCode); static bool IsUnconditionalJump(uint8_t opCode); static bool IsConditionalJump(uint8_t opCode); + static CdlFlags::CdlFlags GetOpFlags(uint8_t opCode, uint16_t pc, uint16_t prevPc); static string GetOpTemplate(uint8_t op, bool prefixed); }; diff --git a/Core/Gameboy/Debugger/GbDebugger.cpp b/Core/Gameboy/Debugger/GbDebugger.cpp index 6a286526..d94281ba 100644 --- a/Core/Gameboy/Debugger/GbDebugger.cpp +++ b/Core/Gameboy/Debugger/GbDebugger.cpp @@ -90,11 +90,7 @@ void GbDebugger::ProcessInstruction() if(addressInfo.Address >= 0) { if(addressInfo.Type == MemoryType::GbPrgRom) { - if(GameboyDisUtils::IsJumpToSub(_prevOpCode)) { - _codeDataLogger->SetCode(addressInfo.Address); - } else { - _codeDataLogger->SetCode(addressInfo.Address); - } + _codeDataLogger->SetCode(addressInfo.Address, GameboyDisUtils::GetOpFlags(_prevOpCode, pc, _prevProgramCounter)); } _disassembler->BuildCache(addressInfo, 0, CpuType::Gameboy); } @@ -263,6 +259,10 @@ void GbDebugger::ProcessInterrupt(uint32_t originalPc, uint32_t currentPc, bool AddressInfo ret = _gameboy->GetAbsoluteAddress(originalPc); AddressInfo dest = _gameboy->GetAbsoluteAddress(currentPc); + if(dest.Type == MemoryType::GbPrgRom && dest.Address >= 0) { + _codeDataLogger->SetCode(dest.Address, CdlFlags::SubEntryPoint); + } + _debugger->InternalProcessInterrupt( CpuType::Gameboy, *this, *_step.get(), src, _prevProgramCounter, dest, currentPc, ret, originalPc, forNmi diff --git a/Core/NES/Debugger/NesDebugger.cpp b/Core/NES/Debugger/NesDebugger.cpp index 9e4cc03f..8545d2df 100644 --- a/Core/NES/Debugger/NesDebugger.cpp +++ b/Core/NES/Debugger/NesDebugger.cpp @@ -97,26 +97,21 @@ void NesDebugger::Reset() void NesDebugger::ProcessInstruction() { NesCpuState& state = _cpu->GetState(); - uint16_t addr = state.PC; - uint8_t value = _memoryManager->DebugRead(addr); - AddressInfo addressInfo = _mapper->GetAbsoluteAddress(addr); - MemoryOperationInfo operation(addr, value, MemoryOperationType::ExecOpCode, MemoryType::NesMemory); + uint16_t pc = state.PC; + uint8_t opCode = _memoryManager->DebugRead(pc); + AddressInfo addressInfo = _mapper->GetAbsoluteAddress(pc); + MemoryOperationInfo operation(pc, opCode, MemoryOperationType::ExecOpCode, MemoryType::NesMemory); bool needDisassemble = _traceLogger->IsEnabled() || _settings->CheckDebuggerFlag(DebuggerFlags::NesDebuggerEnabled); if(addressInfo.Address >= 0) { if(addressInfo.Type == MemoryType::NesPrgRom) { - if(NesDisUtils::IsJumpToSub(_prevOpCode)) { - _codeDataLogger->SetCode(addressInfo.Address); - } else { - _codeDataLogger->SetCode(addressInfo.Address); - } + _codeDataLogger->SetCode(addressInfo.Address, NesDisUtils::GetOpFlags(_prevOpCode, pc, _prevProgramCounter)); } if(needDisassemble) { _disassembler->BuildCache(addressInfo, 0, CpuType::Nes); } } - uint32_t pc = state.PC; if(NesDisUtils::IsJumpToSub(_prevOpCode)) { //JSR uint8_t opSize = NesDisUtils::GetOpSize(_prevOpCode); @@ -134,15 +129,15 @@ void NesDebugger::ProcessInstruction() _step->Break(BreakSource::CpuStep); } - _prevOpCode = value; + _prevOpCode = opCode; _prevProgramCounter = pc; _step->ProcessCpuExec(); if(_settings->CheckDebuggerFlag(DebuggerFlags::NesDebuggerEnabled)) { - if(value == 0x00 && _settings->CheckDebuggerFlag(DebuggerFlags::NesBreakOnBrk)) { + if(opCode == 0x00 && _settings->CheckDebuggerFlag(DebuggerFlags::NesBreakOnBrk)) { _step->Break(BreakSource::BreakOnBrk); - } else if(_settings->CheckDebuggerFlag(DebuggerFlags::NesBreakOnUnofficialOpCode) && NesDisUtils::IsOpUnofficial(value)) { + } else if(_settings->CheckDebuggerFlag(DebuggerFlags::NesBreakOnUnofficialOpCode) && NesDisUtils::IsOpUnofficial(opCode)) { _step->Break(BreakSource::BreakOnUnofficialOpCode); } } @@ -278,7 +273,11 @@ void NesDebugger::ProcessInterrupt(uint32_t originalPc, uint32_t currentPc, bool AddressInfo src = _mapper->GetAbsoluteAddress(_prevProgramCounter); AddressInfo ret = _mapper->GetAbsoluteAddress(originalPc); AddressInfo dest = _mapper->GetAbsoluteAddress(currentPc); - + + if(dest.Type == MemoryType::NesPrgRom && dest.Address >= 0) { + _codeDataLogger->SetCode(dest.Address, CdlFlags::SubEntryPoint); + } + _debugger->InternalProcessInterrupt( CpuType::Nes, *this, *_step.get(), src, _prevProgramCounter, dest, currentPc, ret, originalPc, forNmi diff --git a/Core/NES/Debugger/NesDisUtils.cpp b/Core/NES/Debugger/NesDisUtils.cpp index e063a89d..ff88ca17 100644 --- a/Core/NES/Debugger/NesDisUtils.cpp +++ b/Core/NES/Debugger/NesDisUtils.cpp @@ -236,6 +236,7 @@ bool NesDisUtils::IsOpUnofficial(uint8_t opCode) bool NesDisUtils::IsUnconditionalJump(uint8_t opCode) { switch(opCode) { + case 0x00: //BRK case 0x20: //JSR case 0x40: //RTI case 0x4C: //JMP (Absolute) @@ -266,6 +267,30 @@ bool NesDisUtils::IsConditionalJump(uint8_t opCode) } } +CdlFlags::CdlFlags NesDisUtils::GetOpFlags(uint8_t opCode, uint16_t pc, uint16_t prevPc) +{ + switch(opCode) { + case 0x00: //BRK + case 0x20: //JSR + return CdlFlags::SubEntryPoint; + + case 0x10: //BPL + case 0x30: //BMI + case 0x4C: //JMP (Absolute) + case 0x50: //BVC + case 0x6C: //JMP (Indirect) + case 0x70: //BVS + case 0x90: //BCC + case 0xB0: //BCS + case 0xD0: //BNE + case 0xF0: //BEQ + return pc != prevPc + NesDisUtils::GetOpSize(opCode) ? CdlFlags::JumpTarget : CdlFlags::None; + + default: + return CdlFlags::None; + } +} + bool NesDisUtils::IsJumpToSub(uint8_t opCode) { return opCode == 0x20 || opCode == 0x00; //JSR, BRK diff --git a/Core/NES/Debugger/NesDisUtils.h b/Core/NES/Debugger/NesDisUtils.h index 60357c31..8eefa94c 100644 --- a/Core/NES/Debugger/NesDisUtils.h +++ b/Core/NES/Debugger/NesDisUtils.h @@ -1,5 +1,6 @@ #pragma once #include "stdafx.h" +#include "Debugger/DebugTypes.h" class DisassemblyInfo; class LabelManager; @@ -24,6 +25,7 @@ public: static bool IsOpUnofficial(uint8_t opCode); static bool IsUnconditionalJump(uint8_t opCode); static bool IsConditionalJump(uint8_t opCode); + static CdlFlags::CdlFlags GetOpFlags(uint8_t opCode, uint16_t pc, uint16_t prevPc); static bool IsJumpToSub(uint8_t opCode); static bool IsReturnInstruction(uint8_t opCode); }; diff --git a/Core/NES/NesMemoryManager.cpp b/Core/NES/NesMemoryManager.cpp index f3976a6a..2a7b092d 100644 --- a/Core/NES/NesMemoryManager.cpp +++ b/Core/NES/NesMemoryManager.cpp @@ -95,25 +95,9 @@ uint8_t* NesMemoryManager::GetInternalRAM() return _internalRAM; } -uint8_t NesMemoryManager::DebugRead(uint16_t addr, bool disableSideEffects) +uint8_t NesMemoryManager::DebugRead(uint16_t addr) { - uint8_t value = 0x00; - if(addr <= 0x1FFF) { - value = _ramReadHandlers[addr]->ReadRam(addr); - } else { - INesMemoryHandler* handler = _ramReadHandlers[addr]; - if(handler) { - if(disableSideEffects) { - value = handler->PeekRam(addr); - } else { - value = handler->ReadRam(addr); - } - } else { - //Fake open bus - value = addr >> 8; - } - } - + uint8_t value = _ramReadHandlers[addr]->PeekRam(addr); if(_cheatManager->HasCheats()) { _cheatManager->ApplyCheat(addr, value); } diff --git a/Core/NES/NesMemoryManager.h b/Core/NES/NesMemoryManager.h index 2b2bb68a..e0f4f700 100644 --- a/Core/NES/NesMemoryManager.h +++ b/Core/NES/NesMemoryManager.h @@ -49,15 +49,12 @@ class NesMemoryManager : public ISerializable void RegisterWriteHandler(INesMemoryHandler* handler, uint32_t start, uint32_t end); void UnregisterIODevice(INesMemoryHandler* handler); - uint8_t DebugRead(uint16_t addr, bool disableSideEffects = true); + uint8_t DebugRead(uint16_t addr); uint16_t DebugReadWord(uint16_t addr); void DebugWrite(uint16_t addr, uint8_t value, bool disableSideEffects = true); uint8_t* GetInternalRAM(); - uint8_t DebugReadVram(uint16_t addr); - void DebugWriteVram(uint16_t addr, uint8_t value); - uint8_t Read(uint16_t addr, MemoryOperationType operationType = MemoryOperationType::Read); void Write(uint16_t addr, uint8_t value, MemoryOperationType operationType); diff --git a/Core/PCE/Debugger/PceDebugger.cpp b/Core/PCE/Debugger/PceDebugger.cpp index 6ec18e7f..aed6277f 100644 --- a/Core/PCE/Debugger/PceDebugger.cpp +++ b/Core/PCE/Debugger/PceDebugger.cpp @@ -76,32 +76,27 @@ void PceDebugger::Reset() { _enableBreakOnUninitRead = true; _callstackManager.reset(new CallstackManager(_debugger)); - _prevOpCode = 0xFF; + _prevOpCode = 0x01; } void PceDebugger::ProcessInstruction() { PceCpuState& state = _cpu->GetState(); - uint16_t addr = state.PC; - uint8_t value = _memoryManager->DebugRead(addr); - AddressInfo addressInfo = _memoryManager->GetAbsoluteAddress(addr); - MemoryOperationInfo operation(addr, value, MemoryOperationType::ExecOpCode, MemoryType::PceMemory); + uint16_t pc = state.PC; + uint8_t opCode = _memoryManager->DebugRead(pc); + AddressInfo addressInfo = _memoryManager->GetAbsoluteAddress(pc); + MemoryOperationInfo operation(pc, opCode, MemoryOperationType::ExecOpCode, MemoryType::PceMemory); bool needDisassemble = _traceLogger->IsEnabled() || _settings->CheckDebuggerFlag(DebuggerFlags::PceDebuggerEnabled); if(addressInfo.Address >= 0) { if(addressInfo.Type == MemoryType::PcePrgRom) { - if(PceDisUtils::IsJumpToSub(_prevOpCode)) { - _codeDataLogger->SetCode(addressInfo.Address); - } else { - _codeDataLogger->SetCode(addressInfo.Address); - } + _codeDataLogger->SetCode(addressInfo.Address, PceDisUtils::GetOpFlags(_prevOpCode, pc, _prevProgramCounter)); } if(needDisassemble) { _disassembler->BuildCache(addressInfo, 0, CpuType::Pce); } } - uint32_t pc = state.PC; if(PceDisUtils::IsJumpToSub(_prevOpCode)) { //JSR uint8_t opSize = PceDisUtils::GetOpSize(_prevOpCode); @@ -119,15 +114,15 @@ void PceDebugger::ProcessInstruction() _step->Break(BreakSource::CpuStep); } - _prevOpCode = value; + _prevOpCode = opCode; _prevProgramCounter = pc; _step->ProcessCpuExec(); if(_settings->CheckDebuggerFlag(DebuggerFlags::PceDebuggerEnabled)) { - if(value == 0x00 && _settings->CheckDebuggerFlag(DebuggerFlags::PceBreakOnBrk)) { + if(opCode == 0x00 && _settings->CheckDebuggerFlag(DebuggerFlags::PceBreakOnBrk)) { _step->Break(BreakSource::BreakOnBrk); - } else if(_settings->CheckDebuggerFlag(DebuggerFlags::PceBreakOnUnofficialOpCode) && PceDisUtils::IsOpUnofficial(value)) { + } else if(_settings->CheckDebuggerFlag(DebuggerFlags::PceBreakOnUnofficialOpCode) && PceDisUtils::IsOpUnofficial(opCode)) { _step->Break(BreakSource::BreakOnUnofficialOpCode); } } @@ -254,6 +249,10 @@ void PceDebugger::ProcessInterrupt(uint32_t originalPc, uint32_t currentPc, bool AddressInfo ret = _memoryManager->GetAbsoluteAddress(originalPc); AddressInfo dest = _memoryManager->GetAbsoluteAddress(currentPc); + if(dest.Type == MemoryType::PcePrgRom && dest.Address >= 0) { + _codeDataLogger->SetCode(dest.Address, CdlFlags::SubEntryPoint); + } + _debugger->InternalProcessInterrupt( CpuType::Pce, *this, *_step.get(), src, _prevProgramCounter, dest, currentPc, ret, originalPc, forNmi diff --git a/Core/PCE/Debugger/PceDebugger.h b/Core/PCE/Debugger/PceDebugger.h index c693a74f..bcfb727f 100644 --- a/Core/PCE/Debugger/PceDebugger.h +++ b/Core/PCE/Debugger/PceDebugger.h @@ -50,7 +50,7 @@ class PceDebugger final : public IDebugger unique_ptr _ppuTools; bool _enableBreakOnUninitRead = false; - uint8_t _prevOpCode = 0xFF; + uint8_t _prevOpCode = 0x01; uint32_t _prevProgramCounter = 0; unique_ptr _dummyCpu; diff --git a/Core/PCE/Debugger/PceDisUtils.cpp b/Core/PCE/Debugger/PceDisUtils.cpp index f2d38df0..68887312 100644 --- a/Core/PCE/Debugger/PceDisUtils.cpp +++ b/Core/PCE/Debugger/PceDisUtils.cpp @@ -275,6 +275,37 @@ bool PceDisUtils::IsConditionalJump(uint8_t opCode) } } +CdlFlags::CdlFlags PceDisUtils::GetOpFlags(uint8_t opCode, uint16_t pc, uint16_t prevPc) +{ + switch(opCode) { + case 0x00: //BRK + case 0x20: //JSR + case 0x44: //BSR + return CdlFlags::SubEntryPoint; + + case 0x10: //BPL + case 0x30: //BMI + case 0x4C: //JMP (Absolute) + case 0x50: //BVC + case 0x6C: //JMP (Indirect) + case 0x70: //BVS + case 0x7C: //JMP (Absolute,X) + case 0x80: //BRA + case 0x90: //BCC + case 0xB0: //BCS + case 0xD0: //BNE + case 0xF0: //BEQ + case 0x0F: case 0x1F: case 0x2F: case 0x3F: //BBR + case 0x4F: case 0x5F: case 0x6F: case 0x7F: //BBR + case 0x8F: case 0x9F: case 0xAF: case 0xBF: //BBS + case 0xCF: case 0xDF: case 0xEF: case 0xFF: //BBS + return pc != prevPc + PceDisUtils::GetOpSize(opCode) ? CdlFlags::JumpTarget : CdlFlags::None; + + default: + return CdlFlags::None; + } +} + bool PceDisUtils::IsJumpToSub(uint8_t opCode) { return opCode == 0x20 || opCode == 0x44 || opCode == 0x00; //JSR, BSR, BRK diff --git a/Core/PCE/Debugger/PceDisUtils.h b/Core/PCE/Debugger/PceDisUtils.h index 4c6b5173..667dbb25 100644 --- a/Core/PCE/Debugger/PceDisUtils.h +++ b/Core/PCE/Debugger/PceDisUtils.h @@ -1,5 +1,6 @@ #pragma once #include "stdafx.h" +#include "Debugger/DebugTypes.h" class DisassemblyInfo; class LabelManager; @@ -25,5 +26,6 @@ public: static bool IsConditionalJump(uint8_t opCode); static bool IsJumpToSub(uint8_t opCode); static bool IsReturnInstruction(uint8_t opCode); + static CdlFlags::CdlFlags GetOpFlags(uint8_t opCode, uint16_t pc, uint16_t prevPc); static bool IsOpUnofficial(uint8_t opCode); }; diff --git a/Core/SNES/Debugger/Cx4Debugger.cpp b/Core/SNES/Debugger/Cx4Debugger.cpp index e06f4ed1..ad81d02e 100644 --- a/Core/SNES/Debugger/Cx4Debugger.cpp +++ b/Core/SNES/Debugger/Cx4Debugger.cpp @@ -50,8 +50,8 @@ void Cx4Debugger::ProcessInstruction() MemoryOperationInfo operation(addr, value, MemoryOperationType::ExecOpCode, MemoryType::Cx4Memory); if(addressInfo.Type == MemoryType::SnesPrgRom) { - _codeDataLogger->SetSnesCode(addressInfo.Address); - _codeDataLogger->SetSnesCode(addressInfo.Address + 1); + _codeDataLogger->SetCode(addressInfo.Address); + _codeDataLogger->SetCode(addressInfo.Address + 1); } if(_settings->CheckDebuggerFlag(DebuggerFlags::Cx4DebuggerEnabled)) { diff --git a/Core/SNES/Debugger/GsuDebugger.cpp b/Core/SNES/Debugger/GsuDebugger.cpp index dc52fc37..bebddf42 100644 --- a/Core/SNES/Debugger/GsuDebugger.cpp +++ b/Core/SNES/Debugger/GsuDebugger.cpp @@ -50,7 +50,7 @@ void GsuDebugger::ProcessInstruction() MemoryOperationInfo operation(addr, state.ProgramReadBuffer, MemoryOperationType::ExecOpCode, MemoryType::GsuMemory); if(addressInfo.Type == MemoryType::SnesPrgRom) { - _codeDataLogger->SetSnesCode(addressInfo.Address); + _codeDataLogger->SetCode(addressInfo.Address); } if(_settings->CheckDebuggerFlag(DebuggerFlags::GsuDebuggerEnabled)) { diff --git a/Core/SNES/Debugger/SnesCodeDataLogger.h b/Core/SNES/Debugger/SnesCodeDataLogger.h index 05c18f32..5bda1a2d 100644 --- a/Core/SNES/Debugger/SnesCodeDataLogger.h +++ b/Core/SNES/Debugger/SnesCodeDataLogger.h @@ -34,17 +34,6 @@ private: public: using CodeDataLogger::CodeDataLogger; - void SetSnesCode(int32_t absoluteAddr, uint8_t flags) - { - _cdlData[absoluteAddr] |= CdlFlags::Code | flags; - } - - template - void SetSnesCode(int32_t absoluteAddr) - { - _cdlData[absoluteAddr] |= CdlFlags::Code | flags; - } - void RebuildPrgCache(Disassembler* dis) override { //TODO GSU flags diff --git a/Core/SNES/Debugger/SnesDebugger.cpp b/Core/SNES/Debugger/SnesDebugger.cpp index f3367ef0..ed5a34f1 100644 --- a/Core/SNES/Debugger/SnesDebugger.cpp +++ b/Core/SNES/Debugger/SnesDebugger.cpp @@ -123,19 +123,15 @@ void SnesDebugger::ProcessConfigChange() void SnesDebugger::ProcessInstruction() { SnesCpuState& state = GetCpuState(); - uint32_t addr = (state.K << 16) | state.PC; - AddressInfo addressInfo = _memoryMappings->GetAbsoluteAddress(addr); - uint8_t value = _memoryManager->Peek(addr); - MemoryOperationInfo operation(addr, value, MemoryOperationType::ExecOpCode, MemoryType::SnesMemory); + uint32_t pc = (state.K << 16) | state.PC; + AddressInfo addressInfo = _memoryMappings->GetAbsoluteAddress(pc); + uint8_t opCode = _memoryManager->Peek(pc); + MemoryOperationInfo operation(pc, opCode, MemoryOperationType::ExecOpCode, MemoryType::SnesMemory); if(addressInfo.Address >= 0) { uint8_t cpuFlags = state.PS & (ProcFlags::IndexMode8 | ProcFlags::MemoryMode8); if(addressInfo.Type == MemoryType::SnesPrgRom) { - uint8_t flags = CdlFlags::Code | cpuFlags; - if(SnesDisUtils::IsJumpToSub(_prevOpCode)) { - flags |= CdlFlags::SubEntryPoint; - } - _cdl->SetSnesCode(addressInfo.Address, flags); + _cdl->SetCode(addressInfo.Address, SnesDisUtils::GetOpFlags(_prevOpCode, pc, _prevProgramCounter) | cpuFlags); } if(_traceLogger->IsEnabled() || _debuggerEnabled) { _disassembler->BuildCache(addressInfo, cpuFlags, _cpuType); @@ -148,26 +144,26 @@ void SnesDebugger::ProcessInstruction() uint32_t returnPc = (_prevProgramCounter & 0xFF0000) | (((_prevProgramCounter & 0xFFFF) + opSize) & 0xFFFF); AddressInfo srcAddress = _memoryMappings->GetAbsoluteAddress(_prevProgramCounter); AddressInfo retAddress = _memoryMappings->GetAbsoluteAddress(returnPc); - _callstackManager->Push(srcAddress, _prevProgramCounter, addressInfo, addr, retAddress, returnPc, StackFrameFlags::None); + _callstackManager->Push(srcAddress, _prevProgramCounter, addressInfo, pc, retAddress, returnPc, StackFrameFlags::None); } else if(SnesDisUtils::IsReturnInstruction(_prevOpCode)) { //RTS, RTL, RTI - _callstackManager->Pop(addressInfo, addr); + _callstackManager->Pop(addressInfo, pc); } - if(_step->BreakAddress == (int32_t)addr && (SnesDisUtils::IsReturnInstruction(_prevOpCode) || _prevOpCode == 0x44 || _prevOpCode == 0x54)) { + if(_step->BreakAddress == (int32_t)pc && (SnesDisUtils::IsReturnInstruction(_prevOpCode) || _prevOpCode == 0x44 || _prevOpCode == 0x54)) { //RTS/RTL/RTI found, if we're on the expected return address, break immediately (for step over/step out) //Also used for MVN/MVP _step->Break(BreakSource::CpuStep); } - _prevOpCode = value; - _prevProgramCounter = addr; + _prevOpCode = opCode; + _prevProgramCounter = pc; _step->ProcessCpuExec(); if(_debuggerEnabled) { //Break on BRK/STP/WDM/COP - switch(value) { + switch(opCode) { case 0x00: if(_settings->CheckDebuggerFlag(DebuggerFlags::BreakOnBrk)) { _step->Break(BreakSource::BreakOnBrk); } break; case 0x02: if(_settings->CheckDebuggerFlag(DebuggerFlags::BreakOnCop)) { _step->Break(BreakSource::BreakOnCop); } break; case 0x42: if(_settings->CheckDebuggerFlag(DebuggerFlags::BreakOnWdm)) { _step->Break(BreakSource::BreakOnWdm); } break; @@ -208,7 +204,7 @@ void SnesDebugger::ProcessRead(uint32_t addr, uint8_t value, MemoryOperationType _memoryAccessCounter->ProcessMemoryExec(addressInfo, _memoryManager->GetMasterClock()); } else if(type == MemoryOperationType::ExecOperand) { if(addressInfo.Type == MemoryType::SnesPrgRom && addressInfo.Address >= 0) { - _cdl->SetSnesCode(addressInfo.Address, (state.PS & (SnesCdlFlags::IndexMode8 | SnesCdlFlags::MemoryMode8))); + _cdl->SetCode(addressInfo.Address, (state.PS & (SnesCdlFlags::IndexMode8 | SnesCdlFlags::MemoryMode8))); } if(_traceLogger->IsEnabled()) { _traceLogger->LogNonExec(operation); @@ -299,6 +295,10 @@ void SnesDebugger::ProcessInterrupt(uint32_t originalPc, uint32_t currentPc, boo AddressInfo ret = _memoryMappings->GetAbsoluteAddress(originalPc); AddressInfo dest = _memoryMappings->GetAbsoluteAddress(currentPc); + if(dest.Type == MemoryType::SnesPrgRom && dest.Address >= 0) { + _codeDataLogger->SetCode(dest.Address, CdlFlags::SubEntryPoint); + } + _debugger->InternalProcessInterrupt( _cpuType, *this, *_step.get(), src, _prevProgramCounter, dest, currentPc, ret, originalPc, forNmi diff --git a/Core/SNES/Debugger/SnesDisUtils.cpp b/Core/SNES/Debugger/SnesDisUtils.cpp index 2aa91e3d..dfb63cf1 100644 --- a/Core/SNES/Debugger/SnesDisUtils.cpp +++ b/Core/SNES/Debugger/SnesDisUtils.cpp @@ -216,6 +216,37 @@ bool SnesDisUtils::IsConditionalJump(uint8_t opCode) } } +CdlFlags::CdlFlags SnesDisUtils::GetOpFlags(uint8_t opCode, uint32_t pc, uint32_t prevPc) +{ + switch(opCode) { + case 0x00: //BRK + case 0x02: //COP + case 0x20: //JSR + case 0x22: //JSR + case 0xFC: //JSR + return CdlFlags::SubEntryPoint; + + case 0x10: //BPL + case 0x30: //BMI + case 0x50: //BVC + case 0x70: //BVS + case 0x90: //BCC + case 0xB0: //BCS + case 0xD0: //BNE + case 0xF0: //BEQ + case 0x4C: //JMP + case 0x5C: //JMP + case 0x6C: //JMP + case 0x7C: //JMP + case 0x80: //BRA + case 0xDC: //JMP + return pc != prevPc + SnesDisUtils::GetOpSize(opCode, 0) ? CdlFlags::JumpTarget : CdlFlags::None; + + default: + return CdlFlags::None; + } +} + bool SnesDisUtils::IsJumpToSub(uint8_t opCode) { return opCode == 0x20 || opCode == 0x22 || opCode == 0xFC; //JSR, JSL diff --git a/Core/SNES/Debugger/SnesDisUtils.h b/Core/SNES/Debugger/SnesDisUtils.h index fe2a3b73..473f7d85 100644 --- a/Core/SNES/Debugger/SnesDisUtils.h +++ b/Core/SNES/Debugger/SnesDisUtils.h @@ -1,5 +1,6 @@ #pragma once #include "stdafx.h" +#include "Debugger/DebugTypes.h" class DisassemblyInfo; class SnesConsole; @@ -26,6 +27,7 @@ public: static uint8_t GetOpSize(uint8_t opCode, uint8_t flags); static bool IsUnconditionalJump(uint8_t opCode); static bool IsConditionalJump(uint8_t opCode); + static CdlFlags::CdlFlags GetOpFlags(uint8_t opCode, uint32_t pc, uint32_t prevPc); static bool IsJumpToSub(uint8_t opCode); static bool IsReturnInstruction(uint8_t opCode); static int32_t GetEffectiveAddress(DisassemblyInfo &info, SnesConsole* console, SnesCpuState &state, CpuType type); diff --git a/Core/Shared/SettingTypes.h b/Core/Shared/SettingTypes.h index a6e903b0..a5331163 100644 --- a/Core/Shared/SettingTypes.h +++ b/Core/Shared/SettingTypes.h @@ -769,6 +769,8 @@ enum class DebuggerFlags : uint64_t BreakOnStp = (1 << 3), BreakOnUninitRead = (1 << 4), + ShowJumpLabels = (1 << 5), + ShowVerifiedData = (1 << 8), DisassembleVerifiedData = (1 << 9), diff --git a/NewUI/Config/Debugger/DebuggerConfig.cs b/NewUI/Config/Debugger/DebuggerConfig.cs index 5bc68124..6fcfde99 100644 --- a/NewUI/Config/Debugger/DebuggerConfig.cs +++ b/NewUI/Config/Debugger/DebuggerConfig.cs @@ -17,6 +17,8 @@ namespace Mesen.Config [Reactive] public bool ShowByteCode { get; set; } = false; [Reactive] public bool UseLowerCaseDisassembly { get; set; } = false; + + [Reactive] public bool ShowJumpLabels { get; set; } = false; [Reactive] public SnesDebuggerConfig Snes { get; set; } = new(); [Reactive] public NesDebuggerConfig Nes { get; set; } = new(); @@ -47,6 +49,7 @@ namespace Mesen.Config [Reactive] public CodeDisplayMode UnidentifiedBlockDisplay { get; set; } = CodeDisplayMode.Hide; [Reactive] public CodeDisplayMode VerifiedDataDisplay { get; set; } = CodeDisplayMode.Hide; + //TODO remove? [Reactive] public bool UseAltSpcOpNames { get; set; } = false; [Reactive] public int BreakOnValue { get; set; } = 0; @@ -56,8 +59,6 @@ namespace Mesen.Config [Reactive] public bool ShowSelectionLength { get; set; } = false; [Reactive] public WatchFormatStyle WatchFormat { get; set; } = WatchFormatStyle.Hex; - [Reactive] public bool ShowCommentsInLabelList { get; set; } = true; - [Reactive] public Color CodeOpcodeColor { get; set; } = Color.FromRgb(22, 37, 37); [Reactive] public Color CodeLabelDefinitionColor { get; set; } = Colors.Blue; [Reactive] public Color CodeImmediateColor { get; set; } = Colors.Chocolate; @@ -86,6 +87,8 @@ namespace Mesen.Config Pce.ApplyConfig(); ConfigApi.SetDebuggerFlag(DebuggerFlags.BreakOnUninitRead, BreakOnUninitRead); + + ConfigApi.SetDebuggerFlag(DebuggerFlags.ShowJumpLabels, ShowJumpLabels); ConfigApi.SetDebuggerFlag(DebuggerFlags.ShowUnidentifiedData, UnidentifiedBlockDisplay == CodeDisplayMode.Show); ConfigApi.SetDebuggerFlag(DebuggerFlags.DisassembleUnidentifiedData, UnidentifiedBlockDisplay == CodeDisplayMode.Disassemble); diff --git a/NewUI/Debugger/Views/DebuggerOptionsView.axaml b/NewUI/Debugger/Views/DebuggerOptionsView.axaml index 22a09eaf..c67d46c5 100644 --- a/NewUI/Debugger/Views/DebuggerOptionsView.axaml +++ b/NewUI/Debugger/Views/DebuggerOptionsView.axaml @@ -43,6 +43,10 @@ IsChecked="{CompiledBinding Config.ShowByteCode}" Content="{l:Translate chkShowByteCode}" /> + Unidentified blocks: Show byte code Use lower case + Show jump/sub labels Break on... BRK diff --git a/NewUI/ThirdParty/DataBox/DataBox.cs b/NewUI/ThirdParty/DataBox/DataBox.cs index b4c39a55..5d7ad982 100644 --- a/NewUI/ThirdParty/DataBox/DataBox.cs +++ b/NewUI/ThirdParty/DataBox/DataBox.cs @@ -74,7 +74,7 @@ public class DataBox : TemplatedControl AvaloniaProperty.Register(nameof(VerticalGridLinesBrush)); private IEnumerable _items = Array.Empty(); - private ISelectionModel _selection = new SelectionModel(); + private ISelectionModel? _selection = new SelectionModel(); private AvaloniaList _columns; private ScrollViewer? _headersPresenterScrollViewer;