Overclocking: Changed APU behavior when adding extra lines before/after NMI (helps reduce overclocking-related issues)

This commit is contained in:
Souryo 2017-04-29 21:39:57 -04:00
parent aab1c25a2b
commit cf8c98f384
8 changed files with 71 additions and 24 deletions

View file

@ -11,6 +11,7 @@
#include "MemoryManager.h" #include "MemoryManager.h"
APU* APU::Instance = nullptr; APU* APU::Instance = nullptr;
bool APU::_apuEnabled = true;
APU::APU(MemoryManager* memoryManager) APU::APU(MemoryManager* memoryManager)
{ {
@ -20,6 +21,8 @@ APU::APU(MemoryManager* memoryManager)
_nesModel = NesModel::Auto; _nesModel = NesModel::Auto;
_apuEnabled = true;
_mixer.reset(new SoundMixer()); _mixer.reset(new SoundMixer());
_squareChannel[0].reset(new SquareChannel(AudioChannel::Square1, _mixer.get(), true)); _squareChannel[0].reset(new SquareChannel(AudioChannel::Square1, _mixer.get(), true));
@ -202,6 +205,7 @@ void APU::EndFrame()
void APU::Reset(bool softReset) void APU::Reset(bool softReset)
{ {
_apuEnabled = true;
_cyclesNeeded = 0; _cyclesNeeded = 0;
_currentCycle = 0; _currentCycle = 0;
_previousCycle = 0; _previousCycle = 0;
@ -237,3 +241,17 @@ void APU::AddExpansionAudioDelta(AudioChannel channel, int16_t delta)
{ {
Instance->_mixer->AddDelta(channel, Instance->_currentCycle, 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;
}

View file

@ -20,6 +20,7 @@ class APU : public Snapshotable, public IMemoryHandler
{ {
private: private:
static APU* Instance; static APU* Instance;
static bool _apuEnabled;
uint32_t _previousCycle; uint32_t _previousCycle;
uint32_t _currentCycle; uint32_t _currentCycle;
@ -65,18 +66,22 @@ class APU : public Snapshotable, public IMemoryHandler
__forceinline static void ExecStatic() __forceinline static void ExecStatic()
{ {
if(EmulationSettings::GetOverclockRate(true) == 100) { if(APU::_apuEnabled) {
if(EmulationSettings::GetOverclockRate() == 100 || !EmulationSettings::GetOverclockAdjustApu()) {
Instance->Exec(); Instance->Exec();
} else { } else {
Instance->_cyclesNeeded += 1.0 / ((double)EmulationSettings::GetOverclockRate(true) / 100.0); Instance->_cyclesNeeded += 1.0 / ((double)EmulationSettings::GetOverclockRate() / 100.0);
while(Instance->_cyclesNeeded >= 1.0) { while(Instance->_cyclesNeeded >= 1.0) {
Instance->Exec(); Instance->Exec();
Instance->_cyclesNeeded--; Instance->_cyclesNeeded--;
} }
} }
} }
}
static void StaticRun(); static void StaticRun();
static void AddExpansionAudioDelta(AudioChannel channel, int16_t delta); static void AddExpansionAudioDelta(AudioChannel channel, int16_t delta);
static void SetApuStatus(bool enabled);
static bool IsApuEnabled();
}; };

View file

@ -2,6 +2,7 @@
#include "stdafx.h" #include "stdafx.h"
#include "Snapshotable.h" #include "Snapshotable.h"
#include "EmulationSettings.h" #include "EmulationSettings.h"
#include "APU.h"
class BaseExpansionAudio : public Snapshotable class BaseExpansionAudio : public Snapshotable
{ {
@ -19,14 +20,16 @@ protected:
public: public:
void Clock() void Clock()
{ {
if(EmulationSettings::GetOverclockRate(true) == 100) { if(APU::IsApuEnabled()) {
if(EmulationSettings::GetOverclockRate() == 100 || !EmulationSettings::GetOverclockAdjustApu()) {
ClockAudio(); ClockAudio();
} else { } else {
_clocksNeeded += 1.0 / ((double)EmulationSettings::GetOverclockRate(true) / 100); _clocksNeeded += 1.0 / ((double)EmulationSettings::GetOverclockRate() / 100);
while(_clocksNeeded >= 1.0) { while(_clocksNeeded >= 1.0) {
ClockAudio(); ClockAudio();
_clocksNeeded--; _clocksNeeded--;
} }
} }
} }
}
}; };

View file

@ -43,7 +43,6 @@ uint32_t EmulationSettings::_extraScanlinesBeforeNmi = 0;
uint32_t EmulationSettings::_extraScanlinesAfterNmi = 0; uint32_t EmulationSettings::_extraScanlinesAfterNmi = 0;
uint32_t EmulationSettings::_ppuScanlineCount = 262; uint32_t EmulationSettings::_ppuScanlineCount = 262;
double EmulationSettings::_effectiveOverclockRate = 100; double EmulationSettings::_effectiveOverclockRate = 100;
double EmulationSettings::_effectiveOverclockRateSound = 100;
bool EmulationSettings::_overclockAdjustApu = true; bool EmulationSettings::_overclockAdjustApu = true;
bool EmulationSettings::_disableOverclocking = false; bool EmulationSettings::_disableOverclocking = false;

View file

@ -677,13 +677,12 @@ public:
static void UpdateEffectiveOverclockRate() static void UpdateEffectiveOverclockRate()
{ {
if(_disableOverclocking) { if(_disableOverclocking) {
_effectiveOverclockRateSound = 100;
_effectiveOverclockRate = 100; _effectiveOverclockRate = 100;
} else { } else {
_effectiveOverclockRateSound = _overclockRate * (double)(1 + (double)(_extraScanlinesBeforeNmi + _extraScanlinesAfterNmi) / _ppuScanlineCount);
_effectiveOverclockRate = _overclockRate; _effectiveOverclockRate = _overclockRate;
} }
_hasOverclock = _effectiveOverclockRate != 100; _hasOverclock = _effectiveOverclockRate != 100;
_audioSettingsChanged = true;
} }
static void SetPpuScanlineCount(uint32_t scanlineCount) static void SetPpuScanlineCount(uint32_t scanlineCount)
@ -708,15 +707,9 @@ public:
return _hasOverclock; 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; return _effectiveOverclockRate;
} else {
return 100;
}
} }
static bool GetOverclockAdjustApu() static bool GetOverclockAdjustApu()

View file

@ -1,6 +1,7 @@
#include "stdafx.h" #include "stdafx.h"
#include "PPU.h" #include "PPU.h"
#include "CPU.h" #include "CPU.h"
#include "APU.h"
#include "EmulationSettings.h" #include "EmulationSettings.h"
#include "VideoDecoder.h" #include "VideoDecoder.h"
#include "Debugger.h" #include "Debugger.h"
@ -109,16 +110,22 @@ void PPU::SetNesModel(NesModel model)
case NesModel::NTSC: case NesModel::NTSC:
_nmiScanline = 241; _nmiScanline = 241;
_vblankEnd = 260; _vblankEnd = 260;
_standardNmiScanline = 241;
_standardVblankEnd = 260;
EmulationSettings::SetPpuScanlineCount(262); EmulationSettings::SetPpuScanlineCount(262);
break; break;
case NesModel::PAL: case NesModel::PAL:
_nmiScanline = 241; _nmiScanline = 241;
_vblankEnd = 310; _vblankEnd = 310;
_standardNmiScanline = 241;
_standardVblankEnd = 310;
EmulationSettings::SetPpuScanlineCount(312); EmulationSettings::SetPpuScanlineCount(312);
break; break;
case NesModel::Dendy: case NesModel::Dendy:
_nmiScanline = 291; _nmiScanline = 291;
_vblankEnd = 310; _vblankEnd = 310;
_standardNmiScanline = 291;
_standardVblankEnd = 310;
EmulationSettings::SetPpuScanlineCount(312); EmulationSettings::SetPpuScanlineCount(312);
break; 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() void PPU::Exec()
{ {
if(_cycle > 339) { if(_cycle > 339) {
@ -1012,6 +1033,8 @@ void PPU::Exec()
Debugger::ProcessPpuCycle(); Debugger::ProcessPpuCycle();
UpdateApuStatus();
//Cycle = 0 //Cycle = 0
if(_scanline == -1) { if(_scanline == -1) {
_statusFlags.SpriteOverflow = false; _statusFlags.SpriteOverflow = false;
@ -1137,5 +1160,7 @@ void PPU::StreamState(bool saving)
} }
_lastUpdatedPixel = -1; _lastUpdatedPixel = -1;
UpdateApuStatus();
} }
} }

View file

@ -48,6 +48,8 @@ class PPU : public IMemoryHandler, public Snapshotable
uint16_t *_outputBuffers[2]; uint16_t *_outputBuffers[2];
NesModel _nesModel; NesModel _nesModel;
uint16_t _standardVblankEnd;
uint16_t _standardNmiScanline;
uint16_t _vblankEnd; uint16_t _vblankEnd;
uint16_t _nmiScanline; uint16_t _nmiScanline;
@ -137,6 +139,8 @@ class PPU : public IMemoryHandler, public Snapshotable
void UpdateGrayscaleAndIntensifyBits(); void UpdateGrayscaleAndIntensifyBits();
virtual void SendFrame(); virtual void SendFrame();
void UpdateApuStatus();
PPURegisters GetRegisterID(uint16_t addr) PPURegisters GetRegisterID(uint16_t addr)
{ {
if(addr == 0x4014) { if(addr == 0x4014) {

View file

@ -166,7 +166,7 @@ void SoundMixer::UpdateRates(bool forceUpdate)
{ {
uint32_t newRate = CPU::GetClockRate(_model); uint32_t newRate = CPU::GetClockRate(_model);
if(!EmulationSettings::GetOverclockAdjustApu()) { 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) { if(_clockRate != newRate || forceUpdate) {