Overclocking: Changed APU behavior when adding extra lines before/after NMI (helps reduce overclocking-related issues)
This commit is contained in:
parent
aab1c25a2b
commit
cf8c98f384
8 changed files with 71 additions and 24 deletions
18
Core/APU.cpp
18
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;
|
||||
}
|
17
Core/APU.h
17
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();
|
||||
};
|
|
@ -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--;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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()
|
||||
|
|
25
Core/PPU.cpp
25
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();
|
||||
}
|
||||
}
|
|
@ -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) {
|
||||
|
|
|
@ -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) {
|
||||
|
|
Loading…
Add table
Reference in a new issue