Debugger: Added "Show jump labels" option

This commit is contained in:
Sour 2022-06-26 14:44:59 -04:00
parent b887e2b5f2
commit 5414afdbb4
27 changed files with 221 additions and 90 deletions

View file

@ -38,6 +38,11 @@ public:
_cdlData[absoluteAddr] |= CdlFlags::Code | flags;
}
void SetCode(int32_t absoluteAddr, uint8_t flags)
{
_cdlData[absoluteAddr] |= CdlFlags::Code | flags;
}
template<uint8_t flags = 0>
void SetData(int32_t absoluteAddr)
{

View file

@ -105,6 +105,7 @@ struct DisassemblyResult
Flags = flags;
CpuAddress = cpuAddress;
Address.Address = -1;
Address.Type = {};
CommentLine = commentLine;
}

View file

@ -111,6 +111,7 @@ vector<DisassemblyResult> 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<DisassemblyResult> 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>((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>((int)label.size() + 1, 1000));
} else {

View file

@ -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];

View file

@ -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);
};

View file

@ -90,11 +90,7 @@ void GbDebugger::ProcessInstruction()
if(addressInfo.Address >= 0) {
if(addressInfo.Type == MemoryType::GbPrgRom) {
if(GameboyDisUtils::IsJumpToSub(_prevOpCode)) {
_codeDataLogger->SetCode<CdlFlags::SubEntryPoint>(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

View file

@ -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<CdlFlags::SubEntryPoint>(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

View file

@ -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

View file

@ -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);
};

View file

@ -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<CpuType::Nes>()) {
_cheatManager->ApplyCheat<CpuType::Nes>(addr, value);
}

View file

@ -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);

View file

@ -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<CdlFlags::SubEntryPoint>(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

View file

@ -50,7 +50,7 @@ class PceDebugger final : public IDebugger
unique_ptr<PceVdcTools> _ppuTools;
bool _enableBreakOnUninitRead = false;
uint8_t _prevOpCode = 0xFF;
uint8_t _prevOpCode = 0x01;
uint32_t _prevProgramCounter = 0;
unique_ptr<DummyPceCpu> _dummyCpu;

View file

@ -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

View file

@ -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);
};

View file

@ -50,8 +50,8 @@ void Cx4Debugger::ProcessInstruction()
MemoryOperationInfo operation(addr, value, MemoryOperationType::ExecOpCode, MemoryType::Cx4Memory);
if(addressInfo.Type == MemoryType::SnesPrgRom) {
_codeDataLogger->SetSnesCode<SnesCdlFlags::Cx4>(addressInfo.Address);
_codeDataLogger->SetSnesCode<SnesCdlFlags::Cx4>(addressInfo.Address + 1);
_codeDataLogger->SetCode<SnesCdlFlags::Cx4>(addressInfo.Address);
_codeDataLogger->SetCode<SnesCdlFlags::Cx4>(addressInfo.Address + 1);
}
if(_settings->CheckDebuggerFlag(DebuggerFlags::Cx4DebuggerEnabled)) {

View file

@ -50,7 +50,7 @@ void GsuDebugger::ProcessInstruction()
MemoryOperationInfo operation(addr, state.ProgramReadBuffer, MemoryOperationType::ExecOpCode, MemoryType::GsuMemory);
if(addressInfo.Type == MemoryType::SnesPrgRom) {
_codeDataLogger->SetSnesCode<SnesCdlFlags::Gsu>(addressInfo.Address);
_codeDataLogger->SetCode<SnesCdlFlags::Gsu>(addressInfo.Address);
}
if(_settings->CheckDebuggerFlag(DebuggerFlags::GsuDebuggerEnabled)) {

View file

@ -34,17 +34,6 @@ private:
public:
using CodeDataLogger::CodeDataLogger;
void SetSnesCode(int32_t absoluteAddr, uint8_t flags)
{
_cdlData[absoluteAddr] |= CdlFlags::Code | flags;
}
template<uint8_t flags>
void SetSnesCode(int32_t absoluteAddr)
{
_cdlData[absoluteAddr] |= CdlFlags::Code | flags;
}
void RebuildPrgCache(Disassembler* dis) override
{
//TODO GSU flags

View file

@ -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

View file

@ -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

View file

@ -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);

View file

@ -769,6 +769,8 @@ enum class DebuggerFlags : uint64_t
BreakOnStp = (1 << 3),
BreakOnUninitRead = (1 << 4),
ShowJumpLabels = (1 << 5),
ShowVerifiedData = (1 << 8),
DisassembleVerifiedData = (1 << 9),

View file

@ -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);

View file

@ -43,6 +43,10 @@
IsChecked="{CompiledBinding Config.ShowByteCode}"
Content="{l:Translate chkShowByteCode}"
/>
<CheckBox
IsChecked="{CompiledBinding Config.ShowJumpLabels}"
Content="{l:Translate chkShowJumpLabels}"
/>
<CheckBox
IsChecked="{CompiledBinding Config.UseLowerCaseDisassembly}"
Content="{l:Translate chkUseLowerCaseDisassembly}"

View file

@ -57,6 +57,8 @@ namespace Mesen.Interop
BreakOnStp = (1 << 3),
BreakOnUninitRead = (1 << 4),
ShowJumpLabels = (1 << 5),
ShowVerifiedData = (1 << 8),
DisassembleVerifiedData = (1 << 9),

View file

@ -962,6 +962,7 @@
<Control ID="lblUnidentifiedBlock">Unidentified blocks:</Control>
<Control ID="chkShowByteCode">Show byte code</Control>
<Control ID="chkUseLowerCaseDisassembly">Use lower case</Control>
<Control ID="chkShowJumpLabels">Show jump/sub labels</Control>
<Control ID="lblBreakOptions">Break on...</Control>
<Control ID="chkBreakOnBrk">BRK</Control>

View file

@ -74,7 +74,7 @@ public class DataBox : TemplatedControl
AvaloniaProperty.Register<DataBox, IBrush>(nameof(VerticalGridLinesBrush));
private IEnumerable _items = Array.Empty<object?>();
private ISelectionModel _selection = new SelectionModel<object?>();
private ISelectionModel? _selection = new SelectionModel<object?>();
private AvaloniaList<DataBoxColumn> _columns;
private ScrollViewer? _headersPresenterScrollViewer;