diff --git a/Core/NES/NesCpu.cpp b/Core/NES/NesCpu.cpp index 78dbd4b3..2d0bdf6e 100644 --- a/Core/NES/NesCpu.cpp +++ b/Core/NES/NesCpu.cpp @@ -356,17 +356,28 @@ void NesCpu::ProcessPendingDma(uint16_t readAddress) //The exact specifics of where the CPU reads instead aren't known yet - so just disable read side-effects entirely on PAL bool isNtscInputBehavior = _console->GetRegion() != ConsoleRegion::Pal; - //"If this cycle is a read, hijack the read, discard the value, and prevent all other actions that occur on this cycle (PC not incremented, etc)" + //On Famicom, each dummy/idle read to 4016/4017 is intepreted as a read of the joypad registers + //On NES (or AV Famicom), only the first dummy/idle read causes side effects (e.g only a single bit is lost) + bool isNesBehavior = _console->GetNesConfig().ConsoleType != NesConsoleType::Hvc001; + bool skipDummyReads = !isNtscInputBehavior || (isNesBehavior && (readAddress == 0x4016 || readAddress == 0x4017)); + + _needHalt = false; + StartCpuCycle(true); - if(isNtscInputBehavior && !skipFirstInputClock) { + if(_abortDmcDma && isNesBehavior && (readAddress == 0x4016 || readAddress == 0x4017)) { + //Skip halt cycle dummy read on 4016/4017 + //The DMA was aborted, and the CPU will read 4016/4017 next + //If 4016/4017 is read here, the controllers will see 2 separate reads + //even though they would only see a single read on hardware (except the original Famicom) + } else if(isNtscInputBehavior && !skipFirstInputClock) { _memoryManager->Read(readAddress, MemoryOperationType::DmaRead); } EndCpuCycle(true); - _needHalt = false; if(_abortDmcDma) { _dmcDmaRunning = false; _abortDmcDma = false; + _needDummyRead = false; return; } @@ -374,17 +385,12 @@ void NesCpu::ProcessPendingDma(uint16_t readAddress) uint8_t spriteReadAddr = 0; uint8_t readValue = 0; - //On Famicom, each dummy/idle read to 4016/4017 is intepreted as a read of the joypad registers - //On NES (or AV Famicom), only the first dummy/idle read causes side effects (e.g only a single bit is lost) - NesConsoleType type = _console->GetNesConfig().ConsoleType; - bool isNesBehavior = type != NesConsoleType::Hvc001; - bool skipDummyReads = !isNtscInputBehavior || (isNesBehavior && (readAddress == 0x4016 || readAddress == 0x4017)); - auto processCycle = [this] { //Sprite DMA cycles count as halt/dummy cycles for the DMC DMA when both run at the same time if(_abortDmcDma) { _dmcDmaRunning = false; _abortDmcDma = false; + _needDummyRead = false; _needHalt = false; } else if(_needHalt) { _needHalt = false;