Debugger: Fixed PPU breakpoint issues

This commit is contained in:
Sour 2022-01-08 20:36:47 -05:00
parent 9316f8a0b2
commit 7cbe3139f9
14 changed files with 78 additions and 54 deletions

View file

@ -3,15 +3,15 @@
#include "DebugTypes.h"
#include "DebugUtilities.h"
bool Breakpoint::Matches(uint32_t memoryAddr, AddressInfo &info)
bool Breakpoint::Matches(MemoryOperationInfo& operation, AddressInfo &info)
{
if(DebugUtilities::IsPpuMemory(_memoryType) != DebugUtilities::IsPpuMemory(info.Type)) {
//Don't break on a PPU breakpoint if the operation is for a CPU, or vice versa
return false;
}
if(DebugUtilities::IsRelativeMemory(_memoryType)) {
return (int32_t)memoryAddr >= _startAddr && (int32_t)memoryAddr <= _endAddr;
if(operation.MemType == _memoryType && DebugUtilities::IsRelativeMemory(_memoryType)) {
return (int32_t)operation.Address >= _startAddr && (int32_t)operation.Address <= _endAddr;
} else if(_memoryType == info.Type) {
return info.Address >= _startAddr && info.Address <= _endAddr;
}

View file

@ -7,11 +7,12 @@ struct AddressInfo;
enum class BreakpointType;
enum class BreakpointTypeFlags;
enum class BreakpointCategory;
struct MemoryOperationInfo;
class Breakpoint
{
public:
bool Matches(uint32_t memoryAddr, AddressInfo &info);
bool Matches(MemoryOperationInfo &opInfo, AddressInfo &info);
bool HasBreakpointType(BreakpointType type);
string GetCondition();
bool HasCondition();

View file

@ -58,18 +58,23 @@ void BreakpointManager::SetBreakpoints(Breakpoint breakpoints[], uint32_t count)
BreakpointType BreakpointManager::GetBreakpointType(MemoryOperationType type)
{
switch(type) {
default:
case MemoryOperationType::ExecOperand:
case MemoryOperationType::ExecOpCode:
return BreakpointType::Execute;
case MemoryOperationType::DmaRead:
case MemoryOperationType::Read:
case MemoryOperationType::DummyRead:
case MemoryOperationType::PpuRenderingRead:
return BreakpointType::Read;
case MemoryOperationType::DmaWrite:
case MemoryOperationType::Write:
case MemoryOperationType::DummyWrite:
return BreakpointType::Write;
default:
throw std::runtime_error("Unsupported memory operation type");
}
}
@ -85,7 +90,7 @@ int BreakpointManager::InternalCheckBreakpoint(MemoryOperationInfo operationInfo
EvalResultType resultType;
vector<Breakpoint> &breakpoints = _breakpoints[(int)type];
for(size_t i = 0; i < breakpoints.size(); i++) {
if(breakpoints[i].Matches(operationInfo.Address, address)) {
if(breakpoints[i].Matches(operationInfo, address)) {
if(!breakpoints[i].HasCondition() || _bpExpEval->Evaluate(_rpnList[(int)type][i], state, resultType, operationInfo)) {
if(breakpoints[i].IsMarked()) {
_eventManager->AddEvent(DebugEventType::Breakpoint, operationInfo, breakpoints[i].GetId());

View file

@ -15,6 +15,23 @@ struct MemoryOperationInfo
uint32_t Address;
int32_t Value;
MemoryOperationType Type;
SnesMemoryType MemType;
MemoryOperationInfo()
{
Address = 0;
Value = 0;
Type = (MemoryOperationType)0;
MemType = (SnesMemoryType)0;
}
MemoryOperationInfo(uint32_t addr, int32_t val, MemoryOperationType opType, SnesMemoryType memType)
{
Address = addr;
Value = val;
Type = opType;
MemType = memType;
}
};
enum class BreakpointTypeFlags
@ -295,6 +312,16 @@ struct StepRequest
HasRequest = (StepCount != -1 || PpuStepCount != -1 || BreakAddress != -1 || BreakScanline != INT32_MIN);
}
__forceinline void ProcessCpuExec(BreakSource* source = nullptr)
{
if(StepCount > 0) {
StepCount--;
if(StepCount == 0 && source) {
*source = BreakSource::CpuStep;
}
}
}
bool HasScanlineBreakRequest()
{
return BreakScanline != INT32_MIN;

View file

@ -313,7 +313,7 @@ void Debugger::ProcessEvent(EventType type)
int32_t Debugger::EvaluateExpression(string expression, CpuType cpuType, EvalResultType &resultType, bool useCache)
{
MemoryOperationInfo operationInfo { 0, 0, MemoryOperationType::Read };
MemoryOperationInfo operationInfo { 0, 0, MemoryOperationType::Read, SnesMemoryType::Register };
BaseState& state = _debuggers[(int)cpuType].Debugger->GetState();
if(useCache) {
return _debuggers[(int)cpuType].Evaluator->Evaluate(expression, state, resultType, operationInfo);

View file

@ -71,7 +71,7 @@ void GbDebugger::Reset()
void GbDebugger::ProcessRead(uint32_t addr, uint8_t value, MemoryOperationType type)
{
AddressInfo addressInfo = _gameboy->GetAbsoluteAddress(addr);
MemoryOperationInfo operation { addr, value, type };
MemoryOperationInfo operation(addr, value, type, SnesMemoryType::GameboyMemory);
BreakSource breakSource = BreakSource::Unspecified;
GbCpuState& state = _cpu->GetState();
@ -131,9 +131,7 @@ void GbDebugger::ProcessRead(uint32_t addr, uint8_t value, MemoryOperationType t
_prevOpCode = value;
_prevProgramCounter = pc;
if(_step->StepCount > 0) {
_step->StepCount--;
}
_step->ProcessCpuExec(&breakSource);
_memoryAccessCounter->ProcessMemoryExec(addressInfo, _emu->GetMasterClock());
} else if(type == MemoryOperationType::ExecOperand) {
@ -182,7 +180,7 @@ void GbDebugger::ProcessRead(uint32_t addr, uint8_t value, MemoryOperationType t
void GbDebugger::ProcessWrite(uint32_t addr, uint8_t value, MemoryOperationType type)
{
AddressInfo addressInfo = _gameboy->GetAbsoluteAddress(addr);
MemoryOperationInfo operation { addr, value, type };
MemoryOperationInfo operation(addr, value, type, SnesMemoryType::GameboyMemory);
_debugger->ProcessBreakConditions(false, GetBreakpointManager(), operation, addressInfo);
if(addressInfo.Type == SnesMemoryType::GbWorkRam || addressInfo.Type == SnesMemoryType::GbCartRam || addressInfo.Type == SnesMemoryType::GbHighRam) {
@ -245,7 +243,7 @@ void GbDebugger::ProcessInterrupt(uint32_t originalPc, uint32_t currentPc, bool
void GbDebugger::ProcessPpuRead(uint16_t addr, uint8_t value, SnesMemoryType memoryType)
{
MemoryOperationInfo operation { addr, value, MemoryOperationType::Read };
MemoryOperationInfo operation(addr, value, MemoryOperationType::Read, memoryType);
AddressInfo addressInfo { addr, memoryType };
_debugger->ProcessBreakConditions(false, _breakpointManager.get(), operation, addressInfo);
_memoryAccessCounter->ProcessMemoryRead(addressInfo, _gameboy->GetMasterClock());
@ -253,7 +251,7 @@ void GbDebugger::ProcessPpuRead(uint16_t addr, uint8_t value, SnesMemoryType mem
void GbDebugger::ProcessPpuWrite(uint16_t addr, uint8_t value, SnesMemoryType memoryType)
{
MemoryOperationInfo operation { addr, value, MemoryOperationType::Write };
MemoryOperationInfo operation(addr, value, MemoryOperationType::Write, memoryType);
AddressInfo addressInfo { addr, memoryType };
_debugger->ProcessBreakConditions(false, _breakpointManager.get(), operation, addressInfo);
_memoryAccessCounter->ProcessMemoryWrite(addressInfo, _gameboy->GetMasterClock());

View file

@ -67,7 +67,7 @@ void NesDebugger::Reset()
void NesDebugger::ProcessRead(uint32_t addr, uint8_t value, MemoryOperationType type)
{
AddressInfo addressInfo = _mapper->GetAbsoluteAddress(addr);
MemoryOperationInfo operation = { addr, value, type };
MemoryOperationInfo operation(addr, value, type, SnesMemoryType::NesMemory);
NesCpuState& state = _cpu->GetState();
BreakSource breakSource = BreakSource::Unspecified;
@ -112,14 +112,13 @@ void NesDebugger::ProcessRead(uint32_t addr, uint8_t value, MemoryOperationType
if(_step->BreakAddress == (int32_t)pc && (_prevOpCode == 0x60 || _prevOpCode == 0x40)) {
//RTS/RTI found, if we're on the expected return address, break immediately (for step over/step out)
_step->StepCount = 0;
breakSource = BreakSource::CpuStep;
}
_prevOpCode = value;
_prevProgramCounter = pc;
if(_step->StepCount > 0) {
_step->StepCount--;
}
_step->ProcessCpuExec(&breakSource);
if(_settings->CheckDebuggerFlag(DebuggerFlags::NesDebuggerEnabled)) {
if(value == 0x00 && _settings->CheckDebuggerFlag(DebuggerFlags::NesBreakOnBrk)) {
@ -176,7 +175,7 @@ void NesDebugger::ProcessRead(uint32_t addr, uint8_t value, MemoryOperationType
void NesDebugger::ProcessWrite(uint32_t addr, uint8_t value, MemoryOperationType type)
{
AddressInfo addressInfo = _mapper->GetAbsoluteAddress(addr);
MemoryOperationInfo operation = { addr, value, type };
MemoryOperationInfo operation(addr, value, type, SnesMemoryType::NesMemory);
if(addressInfo.Address >= 0 && (addressInfo.Type == SnesMemoryType::WorkRam || addressInfo.Type == SnesMemoryType::SaveRam)) {
_disassembler->InvalidateCache(addressInfo, CpuType::Nes);
}
@ -234,7 +233,7 @@ void NesDebugger::ProcessInterrupt(uint32_t originalPc, uint32_t currentPc, bool
void NesDebugger::ProcessPpuRead(uint16_t addr, uint8_t value, SnesMemoryType memoryType)
{
MemoryOperationInfo operation { addr, value, MemoryOperationType::Read };
MemoryOperationInfo operation(addr, value, MemoryOperationType::Read, memoryType);
AddressInfo addressInfo { addr, memoryType };
if(DebugUtilities::IsRelativeMemory(memoryType)) {
_mapper->GetPpuAbsoluteAddress(addr, addressInfo);
@ -245,7 +244,7 @@ void NesDebugger::ProcessPpuRead(uint16_t addr, uint8_t value, SnesMemoryType me
void NesDebugger::ProcessPpuWrite(uint16_t addr, uint8_t value, SnesMemoryType memoryType)
{
MemoryOperationInfo operation { addr, value, MemoryOperationType::Write };
MemoryOperationInfo operation(addr, value, MemoryOperationType::Write, memoryType);
AddressInfo addressInfo { addr, memoryType };
if(DebugUtilities::IsRelativeMemory(memoryType)) {
_mapper->GetPpuAbsoluteAddress(addr, addressInfo);

View file

@ -377,7 +377,7 @@ template<class T> uint8_t NesPpu<T>::ReadRam(uint16_t addr)
if((_ppuBusAddress & 0x3FFF) >= 0x3F00 && !_console->GetNesConfig().DisablePaletteRead) {
returnValue = ReadPaletteRam(_ppuBusAddress) | (_openBus & 0xC0);
_emu->ProcessPpuRead<CpuType::Nes>(_ppuBusAddress & 0x1F, returnValue, SnesMemoryType::NesPaletteRam);
_emu->ProcessPpuRead<CpuType::Nes>(_ppuBusAddress, returnValue, SnesMemoryType::NesPpuMemory);
openBusMask = 0xC0;
} else {
openBusMask = 0x00;
@ -462,7 +462,7 @@ template<class T> void NesPpu<T>::WriteRam(uint16_t addr, uint8_t value)
case PPURegisters::VideoMemoryData:
if((_ppuBusAddress & 0x3FFF) >= 0x3F00) {
WritePaletteRam(_ppuBusAddress, value);
_emu->ProcessPpuWrite<CpuType::Nes>(_ppuBusAddress & 0x1F, value, SnesMemoryType::NesPaletteRam);
_emu->ProcessPpuWrite<CpuType::Nes>(_ppuBusAddress, value, SnesMemoryType::NesPpuMemory);
} else {
if(_scanline >= 240 || !IsRenderingEnabled()) {
_mapper->WriteVram(_ppuBusAddress & 0x3FFF, value);

View file

@ -91,7 +91,7 @@ void CpuDebugger::Reset()
void CpuDebugger::ProcessRead(uint32_t addr, uint8_t value, MemoryOperationType type)
{
AddressInfo addressInfo = _memoryMappings->GetAbsoluteAddress(addr);
MemoryOperationInfo operation = { addr, value, type };
MemoryOperationInfo operation(addr, value, type, SnesMemoryType::CpuMemory);
CpuState& state = GetCpuState();
BreakSource breakSource = BreakSource::Unspecified;
@ -135,14 +135,13 @@ void CpuDebugger::ProcessRead(uint32_t addr, uint8_t value, MemoryOperationType
if(_step->BreakAddress == (int32_t)pc && (_prevOpCode == 0x60 || _prevOpCode == 0x40 || _prevOpCode == 0x6B || _prevOpCode == 0x44 || _prevOpCode == 0x54)) {
//RTS/RTL/RTI found, if we're on the expected return address, break immediately (for step over/step out)
_step->StepCount = 0;
breakSource = BreakSource::CpuStep;
}
_prevOpCode = value;
_prevProgramCounter = pc;
if(_step->StepCount > 0) {
_step->StepCount--;
}
_step->ProcessCpuExec(&breakSource);
if(_settings->CheckDebuggerFlag(DebuggerFlags::CpuDebuggerEnabled)) {
if(value == 0x00 || value == 0x02 || value == 0x42 || value == 0xDB) {
@ -200,7 +199,7 @@ void CpuDebugger::ProcessRead(uint32_t addr, uint8_t value, MemoryOperationType
void CpuDebugger::ProcessWrite(uint32_t addr, uint8_t value, MemoryOperationType type)
{
AddressInfo addressInfo = _memoryMappings->GetAbsoluteAddress(addr);
MemoryOperationInfo operation = { addr, value, type };
MemoryOperationInfo operation(addr, value, type, SnesMemoryType::CpuMemory);
if(addressInfo.Address >= 0 && (addressInfo.Type == SnesMemoryType::WorkRam || addressInfo.Type == SnesMemoryType::SaveRam)) {
_disassembler->InvalidateCache(addressInfo, _cpuType);
}
@ -263,7 +262,7 @@ void CpuDebugger::ProcessInterrupt(uint32_t originalPc, uint32_t currentPc, bool
void CpuDebugger::ProcessPpuRead(uint16_t addr, uint8_t value, SnesMemoryType memoryType)
{
MemoryOperationInfo operation { addr, value, MemoryOperationType::Read };
MemoryOperationInfo operation(addr, value, MemoryOperationType::Read, memoryType);
AddressInfo addressInfo { addr, memoryType };
_debugger->ProcessBreakConditions(false, _breakpointManager.get(), operation, addressInfo);
_memoryAccessCounter->ProcessMemoryRead(addressInfo, _console->GetMasterClock());
@ -271,7 +270,7 @@ void CpuDebugger::ProcessPpuRead(uint16_t addr, uint8_t value, SnesMemoryType me
void CpuDebugger::ProcessPpuWrite(uint16_t addr, uint8_t value, SnesMemoryType memoryType)
{
MemoryOperationInfo operation { addr, value, MemoryOperationType::Write };
MemoryOperationInfo operation(addr, value, MemoryOperationType::Write, memoryType);
AddressInfo addressInfo { addr, memoryType };
_debugger->ProcessBreakConditions(false, _breakpointManager.get(), operation, addressInfo);
_memoryAccessCounter->ProcessMemoryWrite(addressInfo, _console->GetMasterClock());

View file

@ -46,7 +46,7 @@ void Cx4Debugger::ProcessRead(uint32_t addr, uint8_t value, MemoryOperationType
addr = (state.Cache.Address[state.Cache.Page] + (state.PC * 2)) & 0xFFFFFF;
AddressInfo addressInfo = _cx4->GetMemoryMappings()->GetAbsoluteAddress(addr);
MemoryOperationInfo operation { (uint32_t)addr, value, type };
MemoryOperationInfo operation(addr, value, type, SnesMemoryType::Cx4Memory);
if(type == MemoryOperationType::ExecOpCode) {
AddressInfo opCodeHighAddr = _cx4->GetMemoryMappings()->GetAbsoluteAddress(addr + 1);
@ -66,10 +66,8 @@ void Cx4Debugger::ProcessRead(uint32_t addr, uint8_t value, MemoryOperationType
_prevProgramCounter = addr;
if(_step->StepCount > 0) {
_step->StepCount--;
}
_step->ProcessCpuExec();
_memoryAccessCounter->ProcessMemoryExec(addressInfo, _memoryManager->GetMasterClock());
_memoryAccessCounter->ProcessMemoryExec(opCodeHighAddr, _memoryManager->GetMasterClock());
} else {
@ -88,7 +86,7 @@ void Cx4Debugger::ProcessRead(uint32_t addr, uint8_t value, MemoryOperationType
void Cx4Debugger::ProcessWrite(uint32_t addr, uint8_t value, MemoryOperationType type)
{
AddressInfo addressInfo = _cx4->GetMemoryMappings()->GetAbsoluteAddress(addr);
MemoryOperationInfo operation { (uint32_t)addr, value, type };
MemoryOperationInfo operation(addr, value, type, SnesMemoryType::Cx4Memory);
_debugger->ProcessBreakConditions(_step->StepCount == 0, GetBreakpointManager(), operation, addressInfo);
_memoryAccessCounter->ProcessMemoryWrite(addressInfo, _memoryManager->GetMasterClock());
if(_traceLogger->IsEnabled()) {

View file

@ -48,7 +48,7 @@ void GsuDebugger::ProcessRead(uint32_t addr, uint8_t value, MemoryOperationType
}
AddressInfo addressInfo = _gsu->GetMemoryMappings()->GetAbsoluteAddress(addr);
MemoryOperationInfo operation { addr, value, type };
MemoryOperationInfo operation(addr, value, type, SnesMemoryType::GsuMemory);
if(type == MemoryOperationType::ExecOpCode) {
if(addressInfo.Type == SnesMemoryType::PrgRom) {
@ -70,9 +70,8 @@ void GsuDebugger::ProcessRead(uint32_t addr, uint8_t value, MemoryOperationType
_prevOpCode = value;
_prevProgramCounter = addr;
if(_step->StepCount > 0) {
_step->StepCount--;
}
_step->ProcessCpuExec();
_memoryAccessCounter->ProcessMemoryExec(addressInfo, _memoryManager->GetMasterClock());
} else {
if(addressInfo.Type == SnesMemoryType::PrgRom) {
@ -90,7 +89,7 @@ void GsuDebugger::ProcessRead(uint32_t addr, uint8_t value, MemoryOperationType
void GsuDebugger::ProcessWrite(uint32_t addr, uint8_t value, MemoryOperationType type)
{
AddressInfo addressInfo = _gsu->GetMemoryMappings()->GetAbsoluteAddress(addr);
MemoryOperationInfo operation { addr, value, type };
MemoryOperationInfo operation(addr, value, type, SnesMemoryType::GsuMemory);
_debugger->ProcessBreakConditions(false, GetBreakpointManager(), operation, addressInfo);
if(_traceLogger->IsEnabled()) {

View file

@ -38,7 +38,7 @@ void NecDspDebugger::Reset()
void NecDspDebugger::ProcessRead(uint32_t addr, uint8_t value, MemoryOperationType type)
{
AddressInfo addressInfo = { (int32_t)addr, type == MemoryOperationType::ExecOpCode ? SnesMemoryType::DspProgramRom : SnesMemoryType::DspDataRom };
MemoryOperationInfo operation { (uint32_t)addr, value, type };
MemoryOperationInfo operation(addr, value, type, SnesMemoryType::NecDspMemory);
if(type == MemoryOperationType::ExecOpCode) {
if(_traceLogger->IsEnabled() || _settings->CheckDebuggerFlag(DebuggerFlags::NecDspDebuggerEnabled)) {
@ -51,10 +51,7 @@ void NecDspDebugger::ProcessRead(uint32_t addr, uint8_t value, MemoryOperationTy
}
_prevProgramCounter = addr;
if(_step->StepCount > 0) {
_step->StepCount--;
}
_step->ProcessCpuExec();
}
_debugger->ProcessBreakConditions(_step->StepCount == 0, GetBreakpointManager(), operation, addressInfo);
@ -63,7 +60,7 @@ void NecDspDebugger::ProcessRead(uint32_t addr, uint8_t value, MemoryOperationTy
void NecDspDebugger::ProcessWrite(uint32_t addr, uint8_t value, MemoryOperationType type)
{
AddressInfo addressInfo { (int32_t)addr, SnesMemoryType::DspDataRam }; //Writes never affect the DSP ROM
MemoryOperationInfo operation { addr, value, type };
MemoryOperationInfo operation(addr, value, type, SnesMemoryType::NecDspMemory);
_debugger->ProcessBreakConditions(false, GetBreakpointManager(), operation, addressInfo);
if(_traceLogger->IsEnabled()) {

View file

@ -47,7 +47,7 @@ void SpcDebugger::ProcessRead(uint32_t addr, uint8_t value, MemoryOperationType
}
AddressInfo addressInfo = _spc->GetAbsoluteAddress(addr);
MemoryOperationInfo operation { addr, value, type };
MemoryOperationInfo operation(addr, value, type, SnesMemoryType::SpcMemory);
BreakSource breakSource = BreakSource::Unspecified;
if(type == MemoryOperationType::ExecOpCode) {
@ -82,9 +82,7 @@ void SpcDebugger::ProcessRead(uint32_t addr, uint8_t value, MemoryOperationType
_prevOpCode = value;
_prevProgramCounter = spcState.PC;
if(_step->StepCount > 0) {
_step->StepCount--;
}
_step->ProcessCpuExec(&breakSource);
if(_settings->CheckDebuggerFlag(DebuggerFlags::SpcDebuggerEnabled)) {
//Break on BRK/STP
@ -115,7 +113,7 @@ void SpcDebugger::ProcessRead(uint32_t addr, uint8_t value, MemoryOperationType
void SpcDebugger::ProcessWrite(uint32_t addr, uint8_t value, MemoryOperationType type)
{
AddressInfo addressInfo { (int32_t)addr, SnesMemoryType::SpcRam }; //Writes never affect the SPC ROM
MemoryOperationInfo operation { addr, value, type };
MemoryOperationInfo operation(addr, value, type, SnesMemoryType::SpcMemory);
_debugger->ProcessBreakConditions(false, GetBreakpointManager(), operation, addressInfo);
_disassembler->InvalidateCache(addressInfo, CpuType::Spc);

View file

@ -407,7 +407,9 @@ namespace Mesen.Interop
ExecOperand = 3,
DmaRead = 4,
DmaWrite = 5,
DummyRead = 6
DummyRead = 6,
DummyWrite = 7,
PpuRenderingRead = 8
}
public struct MemoryOperationInfo
@ -415,6 +417,7 @@ namespace Mesen.Interop
public UInt32 Address;
public Int32 Value;
public MemoryOperationType Type;
public SnesMemoryType MemType;
}
public enum DebugEventType