From cf8c98f3840f6f1459a90218a251b03c5446b701 Mon Sep 17 00:00:00 2001 From: Souryo Date: Sat, 29 Apr 2017 21:39:57 -0400 Subject: [PATCH] Overclocking: Changed APU behavior when adding extra lines before/after NMI (helps reduce overclocking-related issues) --- Core/APU.cpp | 18 ++++++++++++++++++ Core/APU.h | 17 +++++++++++------ Core/BaseExpansionAudio.h | 15 +++++++++------ Core/EmulationSettings.cpp | 1 - Core/EmulationSettings.h | 13 +++---------- Core/PPU.cpp | 25 +++++++++++++++++++++++++ Core/PPU.h | 4 ++++ Core/SoundMixer.cpp | 2 +- 8 files changed, 71 insertions(+), 24 deletions(-) diff --git a/Core/APU.cpp b/Core/APU.cpp index 1830dfe0..73ee64dc 100644 --- a/Core/APU.cpp +++ b/Core/APU.cpp @@ -11,6 +11,7 @@ #include "MemoryManager.h" APU* APU::Instance = nullptr; +bool APU::_apuEnabled = true; APU::APU(MemoryManager* memoryManager) { @@ -20,6 +21,8 @@ APU::APU(MemoryManager* memoryManager) _nesModel = NesModel::Auto; + _apuEnabled = true; + _mixer.reset(new SoundMixer()); _squareChannel[0].reset(new SquareChannel(AudioChannel::Square1, _mixer.get(), true)); @@ -202,6 +205,7 @@ void APU::EndFrame() void APU::Reset(bool softReset) { + _apuEnabled = true; _cyclesNeeded = 0; _currentCycle = 0; _previousCycle = 0; @@ -236,4 +240,18 @@ void APU::StreamState(bool saving) void APU::AddExpansionAudioDelta(AudioChannel channel, int16_t delta) { Instance->_mixer->AddDelta(channel, Instance->_currentCycle, delta); +} + +void APU::SetApuStatus(bool enabled) +{ + _apuEnabled = enabled; +} + +bool APU::IsApuEnabled() +{ + //Adding extra lines before/after NMI temporarely turns off the APU + //This appears to result in less side-effects than spreading out the APU's + //load over the entire PPU frame, like what was done before. + //This is most likely due to the timing of the Frame Counter & DMC IRQs. + return _apuEnabled; } \ No newline at end of file diff --git a/Core/APU.h b/Core/APU.h index cdefe9db..e8833200 100644 --- a/Core/APU.h +++ b/Core/APU.h @@ -20,6 +20,7 @@ class APU : public Snapshotable, public IMemoryHandler { private: static APU* Instance; + static bool _apuEnabled; uint32_t _previousCycle; uint32_t _currentCycle; @@ -65,13 +66,15 @@ class APU : public Snapshotable, public IMemoryHandler __forceinline static void ExecStatic() { - if(EmulationSettings::GetOverclockRate(true) == 100) { - Instance->Exec(); - } else { - Instance->_cyclesNeeded += 1.0 / ((double)EmulationSettings::GetOverclockRate(true) / 100.0); - while(Instance->_cyclesNeeded >= 1.0) { + if(APU::_apuEnabled) { + if(EmulationSettings::GetOverclockRate() == 100 || !EmulationSettings::GetOverclockAdjustApu()) { Instance->Exec(); - Instance->_cyclesNeeded--; + } else { + Instance->_cyclesNeeded += 1.0 / ((double)EmulationSettings::GetOverclockRate() / 100.0); + while(Instance->_cyclesNeeded >= 1.0) { + Instance->Exec(); + Instance->_cyclesNeeded--; + } } } } @@ -79,4 +82,6 @@ class APU : public Snapshotable, public IMemoryHandler static void StaticRun(); static void AddExpansionAudioDelta(AudioChannel channel, int16_t delta); + static void SetApuStatus(bool enabled); + static bool IsApuEnabled(); }; \ No newline at end of file diff --git a/Core/BaseExpansionAudio.h b/Core/BaseExpansionAudio.h index 5d58da8e..437a86af 100644 --- a/Core/BaseExpansionAudio.h +++ b/Core/BaseExpansionAudio.h @@ -2,6 +2,7 @@ #include "stdafx.h" #include "Snapshotable.h" #include "EmulationSettings.h" +#include "APU.h" class BaseExpansionAudio : public Snapshotable { @@ -19,13 +20,15 @@ protected: public: void Clock() { - if(EmulationSettings::GetOverclockRate(true) == 100) { - ClockAudio(); - } else { - _clocksNeeded += 1.0 / ((double)EmulationSettings::GetOverclockRate(true) / 100); - while(_clocksNeeded >= 1.0) { + if(APU::IsApuEnabled()) { + if(EmulationSettings::GetOverclockRate() == 100 || !EmulationSettings::GetOverclockAdjustApu()) { ClockAudio(); - _clocksNeeded--; + } else { + _clocksNeeded += 1.0 / ((double)EmulationSettings::GetOverclockRate() / 100); + while(_clocksNeeded >= 1.0) { + ClockAudio(); + _clocksNeeded--; + } } } } diff --git a/Core/EmulationSettings.cpp b/Core/EmulationSettings.cpp index b008792a..47c21580 100644 --- a/Core/EmulationSettings.cpp +++ b/Core/EmulationSettings.cpp @@ -43,7 +43,6 @@ uint32_t EmulationSettings::_extraScanlinesBeforeNmi = 0; uint32_t EmulationSettings::_extraScanlinesAfterNmi = 0; uint32_t EmulationSettings::_ppuScanlineCount = 262; double EmulationSettings::_effectiveOverclockRate = 100; -double EmulationSettings::_effectiveOverclockRateSound = 100; bool EmulationSettings::_overclockAdjustApu = true; bool EmulationSettings::_disableOverclocking = false; diff --git a/Core/EmulationSettings.h b/Core/EmulationSettings.h index 51e29190..0d93ec45 100644 --- a/Core/EmulationSettings.h +++ b/Core/EmulationSettings.h @@ -677,13 +677,12 @@ public: static void UpdateEffectiveOverclockRate() { if(_disableOverclocking) { - _effectiveOverclockRateSound = 100; _effectiveOverclockRate = 100; } else { - _effectiveOverclockRateSound = _overclockRate * (double)(1 + (double)(_extraScanlinesBeforeNmi + _extraScanlinesAfterNmi) / _ppuScanlineCount); _effectiveOverclockRate = _overclockRate; } _hasOverclock = _effectiveOverclockRate != 100; + _audioSettingsChanged = true; } static void SetPpuScanlineCount(uint32_t scanlineCount) @@ -708,15 +707,9 @@ public: return _hasOverclock; } - static double GetOverclockRate(bool forApu = false, bool forSoundMixer = false) + static double GetOverclockRate() { - if(forApu && _overclockAdjustApu || forSoundMixer) { - return _effectiveOverclockRateSound; - } else if(!forApu) { - return _effectiveOverclockRate; - } else { - return 100; - } + return _effectiveOverclockRate; } static bool GetOverclockAdjustApu() diff --git a/Core/PPU.cpp b/Core/PPU.cpp index 8b31c986..316e1089 100644 --- a/Core/PPU.cpp +++ b/Core/PPU.cpp @@ -1,6 +1,7 @@ #include "stdafx.h" #include "PPU.h" #include "CPU.h" +#include "APU.h" #include "EmulationSettings.h" #include "VideoDecoder.h" #include "Debugger.h" @@ -109,16 +110,22 @@ void PPU::SetNesModel(NesModel model) case NesModel::NTSC: _nmiScanline = 241; _vblankEnd = 260; + _standardNmiScanline = 241; + _standardVblankEnd = 260; EmulationSettings::SetPpuScanlineCount(262); break; case NesModel::PAL: _nmiScanline = 241; _vblankEnd = 310; + _standardNmiScanline = 241; + _standardVblankEnd = 310; EmulationSettings::SetPpuScanlineCount(312); break; case NesModel::Dendy: _nmiScanline = 291; _vblankEnd = 310; + _standardNmiScanline = 291; + _standardVblankEnd = 310; EmulationSettings::SetPpuScanlineCount(312); break; } @@ -1000,6 +1007,20 @@ void PPU::TriggerNmi() } } +void PPU::UpdateApuStatus() +{ + APU::SetApuStatus(true); + if(_scanline > 240) { + if(_scanline > _standardVblankEnd) { + //Disable APU for extra lines after NMI + APU::SetApuStatus(false); + } else if(_scanline < _standardNmiScanline) { + //Disable APU for extra lines before NMI + APU::SetApuStatus(false); + } + } +} + void PPU::Exec() { if(_cycle > 339) { @@ -1011,6 +1032,8 @@ void PPU::Exec() } Debugger::ProcessPpuCycle(); + + UpdateApuStatus(); //Cycle = 0 if(_scanline == -1) { @@ -1137,5 +1160,7 @@ void PPU::StreamState(bool saving) } _lastUpdatedPixel = -1; + + UpdateApuStatus(); } } \ No newline at end of file diff --git a/Core/PPU.h b/Core/PPU.h index 08fa2c9f..5dd58185 100644 --- a/Core/PPU.h +++ b/Core/PPU.h @@ -48,6 +48,8 @@ class PPU : public IMemoryHandler, public Snapshotable uint16_t *_outputBuffers[2]; NesModel _nesModel; + uint16_t _standardVblankEnd; + uint16_t _standardNmiScanline; uint16_t _vblankEnd; uint16_t _nmiScanline; @@ -137,6 +139,8 @@ class PPU : public IMemoryHandler, public Snapshotable void UpdateGrayscaleAndIntensifyBits(); virtual void SendFrame(); + void UpdateApuStatus(); + PPURegisters GetRegisterID(uint16_t addr) { if(addr == 0x4014) { diff --git a/Core/SoundMixer.cpp b/Core/SoundMixer.cpp index 841048e2..e16c2c29 100644 --- a/Core/SoundMixer.cpp +++ b/Core/SoundMixer.cpp @@ -166,7 +166,7 @@ void SoundMixer::UpdateRates(bool forceUpdate) { uint32_t newRate = CPU::GetClockRate(_model); if(!EmulationSettings::GetOverclockAdjustApu()) { - newRate = (uint32_t)(newRate * (double)EmulationSettings::GetOverclockRate(false, true) / 100); + newRate = (uint32_t)(newRate * (double)EmulationSettings::GetOverclockRate() / 100); } if(_clockRate != newRate || forceUpdate) {