From 40c456dadd79cb2c94379fda8b41a4d0ba051ad1 Mon Sep 17 00:00:00 2001
From: Ilari Liusvaara <ilari.liusvaara@elisanet.fi>
Date: Sat, 7 Dec 2013 23:32:44 +0200
Subject: [PATCH 14/21] Support alternate (more accurate) poll timings

---
 snes/config/config.cpp     |  1 +
 snes/config/config.hpp     |  1 +
 snes/cpu/timing/joypad.cpp | 40 ++++++++++++++++++++++++++++++++++++++++
 snes/cpu/timing/timing.cpp | 16 ++++++++++++----
 snes/cpu/timing/timing.hpp |  1 +
 snes/snes.hpp              |  1 +
 6 files changed, 56 insertions(+), 4 deletions(-)

diff --git a/snes/config/config.cpp b/snes/config/config.cpp
index 701af94..206daae 100755
--- a/snes/config/config.cpp
+++ b/snes/config/config.cpp
@@ -13,6 +13,7 @@ Configuration::Configuration() {
   cpu.ntsc_frequency  = 21477272;  //315 / 88 * 6000000
   cpu.pal_frequency   = 21281370;
   cpu.wram_init_value = 0x55;
+  cpu.alt_poll_timings = false;
 
   smp.ntsc_frequency = 24607104;   //32040.5 * 768
   smp.pal_frequency  = 24607104;
diff --git a/snes/config/config.hpp b/snes/config/config.hpp
index 1f4d037..dabde59 100755
--- a/snes/config/config.hpp
+++ b/snes/config/config.hpp
@@ -10,6 +10,7 @@ struct Configuration {
     unsigned ntsc_frequency;
     unsigned pal_frequency;
     unsigned wram_init_value;
+    bool alt_poll_timings;
   } cpu;
 
   struct SMP {
diff --git a/snes/cpu/timing/joypad.cpp b/snes/cpu/timing/joypad.cpp
index 6a98de0..ae8e94f 100755
--- a/snes/cpu/timing/joypad.cpp
+++ b/snes/cpu/timing/joypad.cpp
@@ -29,4 +29,44 @@ void CPU::step_auto_joypad_poll() {
   }
 }
 
+//called every 128 clocks; see CPU::add_clocks()
+void CPU::step_auto_joypad_poll_NEW(bool polarity) {
+  if(status.auto_joypad_counter > 0 && status.auto_joypad_counter <= 34) {
+    if(!status.auto_joypad_latch) {
+      //FIXME: Is this right, busy flag goes on even if not enabled???
+      if(status.auto_joypad_counter == 1)
+        status.auto_joypad_active = true;
+      if(status.auto_joypad_counter == 34)
+        status.auto_joypad_active = false;
+    } else {
+      if(status.auto_joypad_counter == 1) {
+        status.auto_joypad_active = true;
+        input.port1->latch(1);
+        input.port2->latch(1);
+      }
+      if(status.auto_joypad_counter == 3) {
+        input.port1->latch(0);
+        input.port2->latch(0);
+      }
+      if((status.auto_joypad_counter & 1) != 0 &&  status.auto_joypad_counter != 1) {
+        uint2 port0 = input.port1->data();
+        uint2 port1 = input.port2->data();
+
+        status.joy1 = (status.joy1 << 1) | (bool)(port0 & 1);
+        status.joy2 = (status.joy2 << 1) | (bool)(port1 & 1);
+        status.joy3 = (status.joy3 << 1) | (bool)(port0 & 2);
+        status.joy4 = (status.joy4 << 1) | (bool)(port1 & 2);
+      }
+      if(status.auto_joypad_counter == 34)
+        status.auto_joypad_active = false;
+    }
+    status.auto_joypad_counter++;
+  }
+  if(vcounter() >= (ppu.overscan() == false ? 225 : 240) && status.auto_joypad_counter == 0 && !polarity) {
+    status.auto_joypad_latch = status.auto_joypad_poll;
+    status.auto_joypad_counter = 1;
+  }
+}
+
+
 #endif
diff --git a/snes/cpu/timing/timing.cpp b/snes/cpu/timing/timing.cpp
index f1378f0..d7cf24f 100755
--- a/snes/cpu/timing/timing.cpp
+++ b/snes/cpu/timing/timing.cpp
@@ -17,10 +17,18 @@ void CPU::add_clocks(unsigned clocks) {
 
   step(clocks);
 
-  status.auto_joypad_clock += clocks;
-  if(status.auto_joypad_clock >= 256) {
-    status.auto_joypad_clock -= 256;
-    step_auto_joypad_poll();
+  if(config.cpu.alt_poll_timings) {
+    bool opolarity = (status.auto_joypad_clock & 128);
+    status.auto_joypad_clock = (status.auto_joypad_clock + clocks) & 0xFF;
+    bool npolarity = (status.auto_joypad_clock & 128);
+    if(opolarity != npolarity)
+      step_auto_joypad_poll_NEW(opolarity);
+  } else {
+    status.auto_joypad_clock += clocks;
+    if(status.auto_joypad_clock >= 256) {
+      status.auto_joypad_clock -= 256;
+      step_auto_joypad_poll();
+    }
   }
 
   if(status.dram_refreshed == false && hcounter() >= status.dram_refresh_position) {
diff --git a/snes/cpu/timing/timing.hpp b/snes/cpu/timing/timing.hpp
index 6c225da..bf15a72 100755
--- a/snes/cpu/timing/timing.hpp
+++ b/snes/cpu/timing/timing.hpp
@@ -22,3 +22,4 @@ alwaysinline bool irq_test();
 
 //joypad.cpp
 void step_auto_joypad_poll();
+void step_auto_joypad_poll_NEW(bool polarity);
diff --git a/snes/snes.hpp b/snes/snes.hpp
index 37ed1fe..4e3ba64 100755
--- a/snes/snes.hpp
+++ b/snes/snes.hpp
@@ -1,6 +1,7 @@
 #ifndef SNES_HPP
 #define SNES_HPP
 #define BSNES_SUPPORTS_ADV_BREAKPOINTS
+#define BSNES_SUPPORTS_ALT_TIMINGS
 
 namespace SNES {
   namespace Info {
-- 
2.0.0

