DMC: Fixed DMC DMA timing & $4011 write behavior.

Fixes dmc_pitch without breaking sprdma_and_dmc_dma tests.
This commit is contained in:
Souryo 2016-05-18 20:51:54 -04:00
parent d0cc79aeed
commit f540fc766d
3 changed files with 14 additions and 11 deletions

View File

@ -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

View File

@ -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;
}

View File

@ -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);