diff --git a/bsnes/sfc/cpu/cpu.hpp b/bsnes/sfc/cpu/cpu.hpp index 5542b053..54db38c8 100644 --- a/bsnes/sfc/cpu/cpu.hpp +++ b/bsnes/sfc/cpu/cpu.hpp @@ -122,6 +122,9 @@ private: uint2 autoJoypadPort0 = 0; uint2 autoJoypadPort1 = 0; + + bool cpuLatch = false; + bool autoJoypadLatch = false; } status; struct IO { diff --git a/bsnes/sfc/cpu/io.cpp b/bsnes/sfc/cpu/io.cpp index 440085f5..a4d9a5ec 100644 --- a/bsnes/sfc/cpu/io.cpp +++ b/bsnes/sfc/cpu/io.cpp @@ -130,18 +130,20 @@ auto CPU::writeCPU(uint addr, uint8 data) -> void { //bit 0 is shared between JOYSER0 and JOYSER1: //strobing $4016.d0 affects both controller port latches. //$4017 bit 0 writes are ignored. - controllerPort1.device->latch(data & 1); - controllerPort2.device->latch(data & 1); + status.cpuLatch = data & 1; + controllerPort1.device->latch(status.autoJoypadLatch | status.cpuLatch); + controllerPort2.device->latch(status.autoJoypadLatch | status.cpuLatch); return; case 0x4200: //NMITIMEN io.autoJoypadPoll = data & 1; - if(status.autoJoypadCounter < 2) { + if(status.autoJoypadCounter == 0) { // allow controller latches during this time - controllerPort1.device->latch(io.autoJoypadPoll); - controllerPort2.device->latch(io.autoJoypadPoll); - }else if (!io.autoJoypadPoll) { - status.autoJoypadCounter = 33; // Disable auto-joypad read + status.autoJoypadLatch = io.autoJoypadPoll; + controllerPort1.device->latch(status.autoJoypadLatch | status.cpuLatch); + controllerPort2.device->latch(status.autoJoypadLatch | status.cpuLatch); + } else if (!io.autoJoypadPoll && status.autoJoypadCounter >= 2) { + status.autoJoypadCounter = 33; } nmitimenUpdate(data); diff --git a/bsnes/sfc/cpu/serialization.cpp b/bsnes/sfc/cpu/serialization.cpp index 556e9a04..edeff5c9 100644 --- a/bsnes/sfc/cpu/serialization.cpp +++ b/bsnes/sfc/cpu/serialization.cpp @@ -48,6 +48,9 @@ auto CPU::serialize(serializer& s) -> void { s.integer(status.autoJoypadPort0); s.integer(status.autoJoypadPort1); + s.boolean(status.cpuLatch); + s.boolean(status.autoJoypadLatch); + s.integer(io.wramAddress); s.boolean(io.hirqEnable); diff --git a/bsnes/sfc/cpu/timing.cpp b/bsnes/sfc/cpu/timing.cpp index 2273bac6..a325fa05 100644 --- a/bsnes/sfc/cpu/timing.cpp +++ b/bsnes/sfc/cpu/timing.cpp @@ -214,15 +214,9 @@ auto CPU::joypadEdge() -> void { if(status.autoJoypadCounter == 0) { //latch controller states on the first polling cycle - controllerPort1.device->latch(io.autoJoypadPoll); - controllerPort2.device->latch(io.autoJoypadPoll); - } - - if(status.autoJoypadCounter == 1) { - //release latch and begin reading on the second cycle - controllerPort1.device->latch(0); - controllerPort2.device->latch(0); - + status.autoJoypadLatch = io.autoJoypadPoll; + controllerPort1.device->latch(status.autoJoypadLatch | status.cpuLatch); + controllerPort2.device->latch(status.autoJoypadLatch | status.cpuLatch); if(io.autoJoypadPoll) { //shift registers are cleared to zero at start of auto-joypad polling io.joy1 = 0; @@ -232,13 +226,20 @@ auto CPU::joypadEdge() -> void { } } - if(status.autoJoypadCounter >= 2) { - if (!io.autoJoypadPoll) { - // if auto-joypad polling is disabled at this point skip the rest of the polling - status.autoJoypadCounter = 33; - return; - } + if(status.autoJoypadCounter == 1) { + //release latch and begin reading on the second cycle + status.autoJoypadLatch = 0; + controllerPort1.device->latch(status.autoJoypadLatch | status.cpuLatch); + controllerPort2.device->latch(status.autoJoypadLatch | status.cpuLatch); + } + if(status.autoJoypadCounter != 1 && !io.autoJoypadPoll) { + // if auto-joypad polling is disabled at this point skip the rest of the polling + status.autoJoypadCounter = 33; + return; + } + + if(status.autoJoypadCounter >= 2) { //sixteen bits are shifted into joy{1-4}, one bit per 256 clocks //the bits are read on one 128-clock cycle and written on the next if ((status.autoJoypadCounter & 1) == 0) {