diff --git a/Core/Debugger/DebugTypes.h b/Core/Debugger/DebugTypes.h
index 7b922910..6e2aae07 100644
--- a/Core/Debugger/DebugTypes.h
+++ b/Core/Debugger/DebugTypes.h
@@ -343,6 +343,9 @@ enum class BreakSource
GbaNopLoad,
GbaUnalignedMemoryAccess,
+ SnesInvalidPpuAccess,
+ SnesReadDuringAutoJoy,
+
BreakOnUndefinedOpCode
};
diff --git a/Core/Debugger/Debugger.cpp b/Core/Debugger/Debugger.cpp
index bab28da0..d7584f8a 100644
--- a/Core/Debugger/Debugger.cpp
+++ b/Core/Debugger/Debugger.cpp
@@ -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;
}
diff --git a/Core/SNES/InternalRegisters.cpp b/Core/SNES/InternalRegisters.cpp
index bdc80c4a..4310d8c5 100644
--- a/Core/SNES/InternalRegisters.cpp
+++ b/Core/SNES/InternalRegisters.cpp
@@ -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;
diff --git a/Core/SNES/InternalRegisters.h b/Core/SNES/InternalRegisters.h
index d8fed135..b713a16a 100644
--- a/Core/SNES/InternalRegisters.h
+++ b/Core/SNES/InternalRegisters.h
@@ -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; }
diff --git a/Core/SNES/SnesControlManager.cpp b/Core/SNES/SnesControlManager.cpp
index 40ab2086..6a3a89dc 100644
--- a/Core/SNES/SnesControlManager.cpp
+++ b/Core/SNES/SnesControlManager.cpp
@@ -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();
}
diff --git a/Core/SNES/SnesPpu.cpp b/Core/SNES/SnesPpu.cpp
index 208dbe02..3c724521 100644
--- a/Core/SNES/SnesPpu.cpp
+++ b/Core/SNES/SnesPpu.cpp
@@ -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 {
diff --git a/Core/Shared/SettingTypes.h b/Core/Shared/SettingTypes.h
index d5166740..5f546b25 100644
--- a/Core/Shared/SettingTypes.h
+++ b/Core/Shared/SettingTypes.h
@@ -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;
diff --git a/UI/Config/Debugger/DebugConfig.cs b/UI/Config/Debugger/DebugConfig.cs
index b7e317cc..b2c1d351 100644
--- a/UI/Config/Debugger/DebugConfig.cs
+++ b/UI/Config/Debugger/DebugConfig.cs
@@ -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;
diff --git a/UI/Config/Debugger/SnesDebuggerConfig.cs b/UI/Config/Debugger/SnesDebuggerConfig.cs
index 692bffc5..e04e1222 100644
--- a/UI/Config/Debugger/SnesDebuggerConfig.cs
+++ b/UI/Config/Debugger/SnesDebuggerConfig.cs
@@ -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;
diff --git a/UI/Debugger/Views/DebuggerOptionsView.axaml b/UI/Debugger/Views/DebuggerOptionsView.axaml
index caec69e4..a09b9115 100644
--- a/UI/Debugger/Views/DebuggerOptionsView.axaml
+++ b/UI/Debugger/Views/DebuggerOptionsView.axaml
@@ -91,6 +91,15 @@
IsChecked="{Binding Config.Snes.BreakOnStp}"
Content="{l:Translate chkBreakOnStp}"
/>
+
+
+
COP
WDM
STP
+ Invalid PPU memory access
+ Controller read during auto-read
Uninitialized memory read
Debugger opened
Power/reset
@@ -2965,6 +2967,9 @@ E
Invalid instruction
Unaligned memory access
+ Controller read during auto-read
+ Invalid PPU memory access
+
Undefined OP