diff --git a/Core/APU.cpp b/Core/APU.cpp index 0c509411..02dc26aa 100644 --- a/Core/APU.cpp +++ b/Core/APU.cpp @@ -135,6 +135,13 @@ void APU::Run() while(_previousCycle < _currentCycle) { _previousCycle += _frameCounter->Run(cyclesToRun); + //Reload counters set by writes to 4003/4008/400B/400F after running the frame counter to allow the length counter to be clocked first + //This fixes the test "len_reload_timing" (tests 4 & 5) + _squareChannel[0]->ReloadCounter(); + _squareChannel[1]->ReloadCounter(); + _noiseChannel->ReloadCounter(); + _triangleChannel->ReloadCounter(); + _squareChannel[0]->Run(_previousCycle); _squareChannel[1]->Run(_previousCycle); _noiseChannel->Run(_previousCycle); diff --git a/Core/ApuLengthCounter.h b/Core/ApuLengthCounter.h index b4c75875..a498fede 100644 --- a/Core/ApuLengthCounter.h +++ b/Core/ApuLengthCounter.h @@ -13,7 +13,9 @@ private: protected: bool _lengthCounterHalt; uint8_t _lengthCounter; - + uint8_t _lengthCounterReloadValue; + uint8_t _lengthCounterPreviousValue; + void InitializeLengthCounter(bool haltFlag) { SetRunFlag(); @@ -23,7 +25,9 @@ protected: void LoadLengthCounter(uint8_t value) { if(_enabled) { - _lengthCounter = _lcLookupTable[value]; + _lengthCounterReloadValue = _lcLookupTable[value]; + _lengthCounterPreviousValue = _lengthCounter; + SetRunFlag(); } } @@ -86,6 +90,16 @@ public: BaseApuChannel::Run(targetCycle); } + void ReloadCounter() + { + if(_lengthCounterReloadValue) { + if(_lengthCounter == _lengthCounterPreviousValue) { + _lengthCounter = _lengthCounterReloadValue; + } + _lengthCounterReloadValue = 0; + } + } + void TickLengthCounter() { if(_lengthCounter > 0 && !_lengthCounterHalt) {