Debugger: SNES - Added new "break on..." options

Invalid vram/oam/cgram access, controller read while auto-read is running
This commit is contained in:
Sour 2025-03-27 21:30:38 +09:00
parent ad548465c6
commit 2d96724b28
12 changed files with 51 additions and 13 deletions

View file

@ -343,6 +343,9 @@ enum class BreakSource
GbaNopLoad,
GbaUnalignedMemoryAccess,
SnesInvalidPpuAccess,
SnesReadDuringAutoJoy,
BreakOnUndefinedOpCode
};

View file

@ -805,6 +805,8 @@ bool Debugger::IsBreakOptionEnabled(BreakSource src)
case BreakSource::PceBreakOnInvalidVramAddress: return cfg.PceBreakOnInvalidVramAddress;
case BreakSource::GbaInvalidOpCode: return cfg.GbaBreakOnInvalidOpCode;
case BreakSource::GbaUnalignedMemoryAccess: return cfg.GbaBreakOnUnalignedMemAccess;
case BreakSource::SnesInvalidPpuAccess: return cfg.SnesBreakOnInvalidPpuAccess;
case BreakSource::SnesReadDuringAutoJoy: return cfg.SnesBreakOnReadDuringAutoJoy;
}
return true;
}

View file

@ -17,6 +17,7 @@ InternalRegisters::InternalRegisters()
void InternalRegisters::Initialize(SnesConsole* console)
{
_emu = console->GetEmulator();
_cpu = console->GetCpu();
_aluMulDiv.Initialize(_cpu);
_console = console;
@ -160,8 +161,7 @@ uint8_t InternalRegisters::ReadControllerData(uint8_t port, bool getMsb)
}
if(_autoReadActive) {
//TODO add a break option for this?
_console->GetEmulator()->DebugLog("[Input] Read input during auto-read - results may be invalid.");
_emu->BreakIfDebugging(CpuType::Snes, BreakSource::SnesReadDuringAutoJoy);
}
return value;

View file

@ -14,6 +14,7 @@ class SnesControlManager;
class InternalRegisters final : public ISerializable
{
private:
Emulator* _emu = nullptr;
SnesConsole* _console = nullptr;
SnesCpu* _cpu = nullptr;
SnesPpu* _ppu = nullptr;
@ -62,6 +63,7 @@ public:
bool IsVerticalIrqEnabled() { return _state.EnableVerticalIrq; }
bool IsHorizontalIrqEnabled() { return _state.EnableHorizontalIrq; }
bool IsNmiEnabled() { return _state.EnableNmi; }
bool IsAutoReadActive() { return _autoReadActive; }
bool IsFastRomEnabled() { return _state.EnableFastRom; }
uint16_t GetHorizontalTimer() { return _state.HorizontalTimer; }
uint16_t GetVerticalTimer() { return _state.VerticalTimer; }

View file

@ -88,6 +88,9 @@ void SnesControlManager::UpdateControlDevices()
uint8_t SnesControlManager::Read(uint16_t addr, bool forAutoRead)
{
if(!forAutoRead) {
if(_console->GetInternalRegisters()->IsAutoReadActive()) {
_emu->BreakIfDebugging(CpuType::Snes, BreakSource::SnesReadDuringAutoJoy);
}
_console->GetInternalRegisters()->ProcessAutoJoypad();
SetInputReadFlag();
}

View file

@ -6,7 +6,6 @@
#include "SNES/Spc.h"
#include "SNES/InternalRegisters.h"
#include "SNES/SnesControlManager.h"
#include "SNES/InternalRegisters.h"
#include "SNES/SnesDmaController.h"
#include "SNES/Debugger/SnesPpuTools.h"
#include "Debugger/Debugger.h"
@ -1624,12 +1623,20 @@ bool SnesPpu::IsDoubleWidth()
bool SnesPpu::CanAccessCgram()
{
return _scanline >= _nmiScanline || _scanline == 0 || _state.ForcedBlank || _memoryManager->GetHClock() < 88 || _memoryManager->GetHClock() >= 1096;
bool allowAccess = _scanline >= _nmiScanline || _scanline == 0 || _state.ForcedBlank || _memoryManager->GetHClock() < 88 || _memoryManager->GetHClock() >= 1096;
if(!allowAccess) {
_emu->BreakIfDebugging(CpuType::Snes, BreakSource::SnesInvalidPpuAccess);
}
return allowAccess;
}
bool SnesPpu::CanAccessVram()
{
return _scanline >= _nmiScanline || _state.ForcedBlank;
bool allowAccess = _scanline >= _nmiScanline || _state.ForcedBlank;
if(!allowAccess) {
_emu->BreakIfDebugging(CpuType::Snes, BreakSource::SnesInvalidPpuAccess);
}
return allowAccess;
}
void SnesPpu::SetLocationLatchRequest(uint16_t x, uint16_t y)
@ -1672,6 +1679,7 @@ uint16_t SnesPpu::GetOamAddress()
if(_state.ForcedBlank || _scanline >= _vblankStartScanline) {
return _state.InternalOamAddress;
} else {
_emu->BreakIfDebugging(CpuType::Snes, BreakSource::SnesInvalidPpuAccess);
if(_memoryManager->GetHClock() <= 255 * 4) {
return _oamEvaluationIndex << 2;
} else {

View file

@ -800,6 +800,8 @@ struct DebugConfig
bool SnesBreakOnCop = false;
bool SnesBreakOnWdm = false;
bool SnesBreakOnStp = false;
bool SnesBreakOnInvalidPpuAccess = false;
bool SnesBreakOnReadDuringAutoJoy = false;
bool SnesUseAltSpcOpNames = false;
bool SnesIgnoreDspReadWrites = false;

View file

@ -61,6 +61,8 @@ namespace Mesen.Config
SnesBreakOnCop = Debugger.Snes.BreakOnCop,
SnesBreakOnWdm = Debugger.Snes.BreakOnWdm,
SnesBreakOnStp = Debugger.Snes.BreakOnStp,
SnesBreakOnInvalidPpuAccess = Debugger.Snes.BreakOnInvalidPpuAccess,
SnesBreakOnReadDuringAutoJoy = Debugger.Snes.BreakOnReadDuringAutoJoy,
SnesUseAltSpcOpNames = Debugger.Snes.UseAltSpcOpNames,
SnesIgnoreDspReadWrites = Debugger.Snes.IgnoreDspReadWrites,
@ -127,6 +129,8 @@ namespace Mesen.Config
[MarshalAs(UnmanagedType.I1)] public bool SnesBreakOnCop;
[MarshalAs(UnmanagedType.I1)] public bool SnesBreakOnWdm;
[MarshalAs(UnmanagedType.I1)] public bool SnesBreakOnStp;
[MarshalAs(UnmanagedType.I1)] public bool SnesBreakOnInvalidPpuAccess;
[MarshalAs(UnmanagedType.I1)] public bool SnesBreakOnReadDuringAutoJoy;
[MarshalAs(UnmanagedType.I1)] public bool SnesUseAltSpcOpNames;
[MarshalAs(UnmanagedType.I1)] public bool SnesIgnoreDspReadWrites;

View file

@ -1,10 +1,4 @@
using Avalonia;
using Avalonia.Media;
using Mesen.Debugger;
using Mesen.Interop;
using ReactiveUI.Fody.Helpers;
using System.Reactive.Linq;
using System.Reactive;
using ReactiveUI.Fody.Helpers;
using Mesen.ViewModels;
namespace Mesen.Config
@ -15,6 +9,8 @@ namespace Mesen.Config
[Reactive] public bool BreakOnCop { get; set; } = false;
[Reactive] public bool BreakOnWdm { get; set; } = false;
[Reactive] public bool BreakOnStp { get; set; } = false;
[Reactive] public bool BreakOnInvalidPpuAccess { get; set; } = false;
[Reactive] public bool BreakOnReadDuringAutoJoy { get; set; } = false;
[Reactive] public bool UseAltSpcOpNames { get; set; } = false;
[Reactive] public bool IgnoreDspReadWrites { get; set; } = true;

View file

@ -91,6 +91,15 @@
IsChecked="{Binding Config.Snes.BreakOnStp}"
Content="{l:Translate chkBreakOnStp}"
/>
<Rectangle Stroke="#AAA" Height="1" StrokeThickness="1" HorizontalAlignment="Stretch" Margin="0 2" />
<CheckBox
IsChecked="{Binding Config.Snes.BreakOnInvalidPpuAccess}"
Content="{l:Translate chkBreakOnInvalidPpuAccess}"
/>
<CheckBox
IsChecked="{Binding Config.Snes.BreakOnReadDuringAutoJoy}"
Content="{l:Translate chkBreakOnReadDuringAutoJoy}"
/>
</StackPanel>
<StackPanel IsVisible="{Binding IsGameboy}">
<CheckBox

View file

@ -1547,6 +1547,7 @@ namespace Mesen.Interop
BreakOnCop,
BreakOnWdm,
BreakOnStp,
BreakOnUninitMemoryRead,
GbInvalidOamAccess,
@ -1574,7 +1575,10 @@ namespace Mesen.Interop
GbaInvalidOpCode,
GbaNopLoad,
GbaUnalignedMemoryAccess,
SnesInvalidPpuAccess,
SnesReadDuringAutoJoy,
BreakOnUndefinedOpCode
}

View file

@ -1349,6 +1349,8 @@
<Control ID="chkBreakOnCop">COP</Control>
<Control ID="chkBreakOnWdm">WDM</Control>
<Control ID="chkBreakOnStp">STP</Control>
<Control ID="chkBreakOnInvalidPpuAccess">Invalid PPU memory access</Control>
<Control ID="chkBreakOnReadDuringAutoJoy">Controller read during auto-read</Control>
<Control ID="chkBreakOnUninitRead">Uninitialized memory read</Control>
<Control ID="chkBreakOnOpen">Debugger opened</Control>
<Control ID="chkBreakOnPowerCycleReset">Power/reset</Control>
@ -2965,6 +2967,9 @@ E
<Value ID="GbaInvalidOpCode">Invalid instruction</Value>
<Value ID="GbaUnalignedMemoryAccess">Unaligned memory access</Value>
<Value ID="SnesReadDuringAutoJoy">Controller read during auto-read</Value>
<Value ID="SnesInvalidPpuAccess">Invalid PPU memory access</Value>
<Value ID="BreakOnUndefinedOpCode">Undefined OP</Value>
</Enum>
<Enum ID="MemoryOperationType">