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"
|
#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;
|
||||||
|
}
|
17
Core/APU.h
17
Core/APU.h
|
@ -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,13 +66,15 @@ class APU : public Snapshotable, public IMemoryHandler
|
||||||
|
|
||||||
__forceinline static void ExecStatic()
|
__forceinline static void ExecStatic()
|
||||||
{
|
{
|
||||||
if(EmulationSettings::GetOverclockRate(true) == 100) {
|
if(APU::_apuEnabled) {
|
||||||
Instance->Exec();
|
if(EmulationSettings::GetOverclockRate() == 100 || !EmulationSettings::GetOverclockAdjustApu()) {
|
||||||
} else {
|
|
||||||
Instance->_cyclesNeeded += 1.0 / ((double)EmulationSettings::GetOverclockRate(true) / 100.0);
|
|
||||||
while(Instance->_cyclesNeeded >= 1.0) {
|
|
||||||
Instance->Exec();
|
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 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();
|
||||||
};
|
};
|
|
@ -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,13 +20,15 @@ protected:
|
||||||
public:
|
public:
|
||||||
void Clock()
|
void Clock()
|
||||||
{
|
{
|
||||||
if(EmulationSettings::GetOverclockRate(true) == 100) {
|
if(APU::IsApuEnabled()) {
|
||||||
ClockAudio();
|
if(EmulationSettings::GetOverclockRate() == 100 || !EmulationSettings::GetOverclockAdjustApu()) {
|
||||||
} else {
|
|
||||||
_clocksNeeded += 1.0 / ((double)EmulationSettings::GetOverclockRate(true) / 100);
|
|
||||||
while(_clocksNeeded >= 1.0) {
|
|
||||||
ClockAudio();
|
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::_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;
|
||||||
|
|
||||||
|
|
|
@ -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 _effectiveOverclockRate;
|
||||||
return _effectiveOverclockRateSound;
|
|
||||||
} else if(!forApu) {
|
|
||||||
return _effectiveOverclockRate;
|
|
||||||
} else {
|
|
||||||
return 100;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool GetOverclockAdjustApu()
|
static bool GetOverclockAdjustApu()
|
||||||
|
|
25
Core/PPU.cpp
25
Core/PPU.cpp
|
@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -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) {
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
Loading…
Add table
Reference in a new issue