diff --git a/Core/APU.cpp b/Core/APU.cpp index fb4e38dc..729fd040 100644 --- a/Core/APU.cpp +++ b/Core/APU.cpp @@ -131,7 +131,7 @@ void APU::Run() //-When a DMC or FrameCounter interrupt needs to be fired int32_t cyclesToRun = _currentCycle - _previousCycle; - while(_previousCycle < _currentCycle) { + while(cyclesToRun > 0) { _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 diff --git a/Core/CPU.h b/Core/CPU.h index 684607bd..6b0ced9c 100644 --- a/Core/CPU.h +++ b/Core/CPU.h @@ -148,22 +148,24 @@ private: void MemoryWrite(uint16_t addr, uint8_t value) { - if(_dmcCounter == 4) { - _dmcCounter = 3; - } - - while(_dmcDmaRunning) { - IncCycleCount(); - } - _cpuWrite = true;; _writeAddr = addr; IncCycleCount(); + while(_dmcDmaRunning) { + IncCycleCount(); + } _memoryManager->Write(addr, value); + + //DMA DMC might have started after a write to $4015, stall CPU if needed + while (_dmcDmaRunning) { + IncCycleCount(); + } _cpuWrite = false; + } uint8_t MemoryRead(uint16_t addr, MemoryOperationType operationType = MemoryOperationType::Read) { + IncCycleCount(); while(_dmcDmaRunning) { //Stall CPU until we can process a DMC read if((addr != 0x4016 && addr != 0x4017 && (_cycleCount & 0x01)) || _dmcCounter == 1) { @@ -175,7 +177,6 @@ private: } IncCycleCount(); } - IncCycleCount(); uint8_t value = _memoryManager->Read(addr, operationType); return value; } diff --git a/Core/DeltaModulationChannel.cpp b/Core/DeltaModulationChannel.cpp index 37135e1a..36fa8fa6 100644 --- a/Core/DeltaModulationChannel.cpp +++ b/Core/DeltaModulationChannel.cpp @@ -34,6 +34,9 @@ void DeltaModulationChannel::Reset(bool softReset) //Not sure if this is accurate, but it seems to make things better rather than worse (for dpcmletterbox) //"On the real thing, I think the power-on value is 428 (or the equivalent at least - it uses a linear feedback shift register), though only the even/oddness should matter for this test." _period = (GetNesModel() == NesModel::NTSC ? _dmcPeriodLookupTableNtsc : _dmcPeriodLookupTablePal)[0] - 1; + + //Make sure the DMC doesn't tick on the first cycle - this is part of what keeps Sprite/DMC DMA tests working while fixing dmc_pitch. + _timer = _period; } void DeltaModulationChannel::InitSample() @@ -163,7 +166,6 @@ void DeltaModulationChannel::WriteRAM(uint16_t addr, uint8_t value) case 1: //4011 _outputLevel = value & 0x7F; - _shiftRegister = value & 0x7F; //4011 applies new output right away, not on the timer's reload. This fixes bad DMC sound when playing through 4011. AddOutput(_outputLevel);