Bus fixes: Reading of CPU MMIO registers does not update MDR
[lsnes.git] / bsnes-patches / v085 / 0027-Bus-fixes-Do-not-update-MDR-on-read-from-CPU-MMIO-sp.patch
blob3f5dca61601ccee61359dc490edcd78c08c6d6b2
1 From 4cfbbeadc3abe3e3911f7f59ce57b715edc76563 Mon Sep 17 00:00:00 2001
2 From: Ilari Liusvaara <ilariliusvaara@welho.com>
3 Date: Wed, 25 Oct 2017 14:18:34 +0300
4 Subject: [PATCH 27/27] Bus fixes: Do not update MDR on read from CPU MMIO
5 space
7 Also, updates the controller read timings to be more accurate.
8 ---
9 snes/config/config.cpp | 1 +
10 snes/config/config.hpp | 1 +
11 snes/cpu/cpu.cpp | 2 +
12 snes/cpu/memory/memory.cpp | 26 ++++++++-
13 snes/cpu/mmio/mmio.cpp | 14 +++--
14 snes/cpu/timing/joypad.cpp | 132 +++++++++++++++++++++++++++++++++++++++------
15 snes/cpu/timing/timing.cpp | 11 ++--
16 snes/cpu/timing/timing.hpp | 3 +-
17 snes/snes.hpp | 1 +
18 9 files changed, 166 insertions(+), 25 deletions(-)
20 diff --git a/snes/config/config.cpp b/snes/config/config.cpp
21 index 19831370..8dcfd7e8 100755
22 --- a/snes/config/config.cpp
23 +++ b/snes/config/config.cpp
24 @@ -15,6 +15,7 @@ Configuration::Configuration() {
25 cpu.pal_frequency = 21281370;
26 cpu.wram_init_value = 0x55;
27 cpu.alt_poll_timings = false;
28 + cpu.bus_fixes = false;
30 smp.ntsc_frequency = 24607104; //32040.5 * 768
31 smp.pal_frequency = 24607104;
32 diff --git a/snes/config/config.hpp b/snes/config/config.hpp
33 index 68fe0bde..d8577e39 100755
34 --- a/snes/config/config.hpp
35 +++ b/snes/config/config.hpp
36 @@ -14,6 +14,7 @@ struct Configuration {
37 unsigned pal_frequency;
38 unsigned wram_init_value;
39 bool alt_poll_timings;
40 + bool bus_fixes;
41 } cpu;
43 struct SMP {
44 diff --git a/snes/cpu/cpu.cpp b/snes/cpu/cpu.cpp
45 index e11fc882..5e8e3137 100755
46 --- a/snes/cpu/cpu.cpp
47 +++ b/snes/cpu/cpu.cpp
48 @@ -1,5 +1,7 @@
49 #include <snes/snes.hpp>
50 #include <cstdio>
51 +#include <iostream>
52 +#include <cassert>
54 #define CPU_CPP
55 namespace SNES {
56 diff --git a/snes/cpu/memory/memory.cpp b/snes/cpu/memory/memory.cpp
57 index 31f82c31..df439c22 100755
58 --- a/snes/cpu/memory/memory.cpp
59 +++ b/snes/cpu/memory/memory.cpp
60 @@ -14,10 +14,32 @@ uint8 CPU::op_read(uint32 addr, bool exec) {
61 status.clock_count = speed(addr);
62 dma_edge();
63 add_clocks(status.clock_count - 4);
64 - regs.mdr = bus.read(addr, exec);
65 + //MDR presents the state held by parasitic capacitance of the external bus.
66 + //This bus is not affected by reads from CPU-internal registers, only if
67 + //some external device responds. SDD1 does hook some of these addresses, but
68 + //passes read straight through, as expected (as the CPU probably won't
69 + //monitor if external device responds, even if it broadcasts a read).
70 + //
71 + //We use 4000-43FF as CPU register range, and not 4000-437F it likely is
72 + //for quickness of checking. This will only affect things if some device
73 + //tries to map the 4380-43FF range (that device will still work correctly,
74 + //but openbus in that range won't).
75 + //
76 + //This was discovered while investigating why one Super Metroid glitch
77 + //worked on emulator but crashed on real console.
78 + //
79 + //a word fetch from 2f4017 AND 0xfffc results in 2f3c and a word fetch from
80 + //2f4210 AND 0x7f7f results in 2f22. This also extends to long fetches
81 + //by arguments. E.g. long argument fetch from 94420F with 2F already on
82 + //the bus AND 0x7f7fff results in 2f222f.
83 + //
84 + //The reason for masking some bits in above explanation was to ignore some
85 + //known bits in those registers (bits 7 of 4210 and 4211, bits 0&1 of 4017).
86 + uint8_t tmp = bus.read(addr, exec);
87 + if(!config.cpu.bus_fixes || (addr & 0x40FC00) != 0x004000) regs.mdr = tmp;
88 add_clocks(4);
89 alu_edge();
90 - return regs.mdr;
91 + return tmp;
94 void CPU::op_write(uint32 addr, uint8 data) {
95 diff --git a/snes/cpu/mmio/mmio.cpp b/snes/cpu/mmio/mmio.cpp
96 index 30048c19..be2990a3 100755
97 --- a/snes/cpu/mmio/mmio.cpp
98 +++ b/snes/cpu/mmio/mmio.cpp
99 @@ -33,9 +33,17 @@ void CPU::mmio_w2183(uint8 data) {
100 //strobing $4016.d0 affects both controller port latches.
101 //$4017 bit 0 writes are ignored.
102 void CPU::mmio_w4016(uint8 data) {
103 - if(data&1) interface->notifyLatched();
104 - input.port1->latch(data & 1);
105 - input.port2->latch(data & 1);
106 + //Only consider autoassert if both busfix and auto flags are set.
107 + auto auto_asserted = (status.auto_joypad_counter & 384) == 384;
108 + //Bit 6 of status.auto_joypad_counter follows "manual" latch.
109 + auto oldstatus = auto_asserted || (status.auto_joypad_counter & 64) != 0;
110 + status.auto_joypad_counter &= ~64;
111 + status.auto_joypad_counter |= (data & 1) << 6;
112 + auto newstatus = auto_asserted || (status.auto_joypad_counter & 64) != 0;
113 + //If !oldstatus and newstatus, signal latch.
114 + if(!oldstatus && newstatus) interface->notifyLatched();
115 + input.port1->latch(newstatus);
116 + input.port2->latch(newstatus);
119 //JOYSER0
120 diff --git a/snes/cpu/timing/joypad.cpp b/snes/cpu/timing/joypad.cpp
121 index afca7504..b60be020 100755
122 --- a/snes/cpu/timing/joypad.cpp
123 +++ b/snes/cpu/timing/joypad.cpp
124 @@ -3,11 +3,14 @@
125 //called every 256 clocks; see CPU::add_clocks()
126 void CPU::step_auto_joypad_poll() {
127 if(vcounter() >= (ppu.overscan() == false ? 225 : 240)) {
128 + auto cycle = status.auto_joypad_counter & 63;
129 //cache enable state at first iteration
130 - if(status.auto_joypad_counter == 0) status.auto_joypad_latch = status.auto_joypad_poll;
131 - status.auto_joypad_active = status.auto_joypad_counter <= 15;
132 + if(cycle == 0) status.auto_joypad_latch = status.auto_joypad_poll;
133 + status.auto_joypad_active = cycle <= 15;
134 if(status.auto_joypad_active && status.auto_joypad_latch) {
135 - if(status.auto_joypad_counter == 0) {
136 + if(cycle == 0) {
137 + if(status.auto_joypad_counter & 128)
138 + std::cerr << "step_auto_joypad_poll(): bus fixes set (counter=" << status.auto_joypad_counter << ")???" << std::endl;
139 if(dma_trace_fn) dma_trace_fn("-- Start automatic polling --");
140 interface->notifyLatched();
141 input.port1->latch(1);
142 @@ -23,7 +26,7 @@ void CPU::step_auto_joypad_poll() {
143 status.joy2 = (status.joy2 << 1) | (bool)(port1 & 1);
144 status.joy3 = (status.joy3 << 1) | (bool)(port0 & 2);
145 status.joy4 = (status.joy4 << 1) | (bool)(port1 & 2);
146 - if(status.auto_joypad_counter == 15) {
147 + if(cycle == 15) {
148 char buf[512];
149 sprintf(buf, "-- End automatic polling [%04x %04x %04x %04x] --",
150 status.joy1, status.joy2, status.joy3, status.joy4);
151 @@ -31,32 +34,129 @@ void CPU::step_auto_joypad_poll() {
155 - status.auto_joypad_counter++;
156 + //Only bits 0-5 are supposed to increment.
157 + if(cycle < 60)
158 + status.auto_joypad_counter++;
162 //called every 128 clocks; see CPU::add_clocks()
163 -void CPU::step_auto_joypad_poll_NEW(bool polarity) {
164 - if(status.auto_joypad_counter > 0 && status.auto_joypad_counter <= 34) {
165 +void CPU::step_auto_joypad_poll_NEW2(bool polarity) {
166 + //Poll starts on multiple of 128 mod 256 clocks (polarity=false) on first
167 + //vblank scanline. If autopoller is off, mark as done for the frame.
168 + if(vcounter() >= (ppu.overscan() == false ? 225 : 240) && !polarity &&
169 + (status.auto_joypad_counter & 63) == 0) {
170 + if(!(status.auto_joypad_counter & 128))
171 + std::cerr << "step_auto_joypad_poll_NEW2(): bus fixes clear???" << std::endl;
172 + //Preserve high bits of autopoll counter.
173 + auto x = status.auto_joypad_counter & ~63;
174 + status.auto_joypad_counter = x | (status.auto_joypad_poll ? 1 : 36);
175 + status.auto_joypad_latch = status.auto_joypad_poll;
177 + //Abuse bit 6 of counter for "manual" poll flag. Bit 7 is supposed to be
178 + //always set.
179 + auto cycle = status.auto_joypad_counter & 63;
180 + auto old_latchstate = (status.auto_joypad_counter & 320) != 0;
181 + //If not enabled... This is not latched, as autopoll can be aborted.
182 + if(!status.auto_joypad_poll && cycle > 0 && cycle < 36) {
183 + if(dma_trace_fn) dma_trace_fn("-- Automatic polling ABORTED --");
184 + status.auto_joypad_counter += (36 - cycle);
185 + status.auto_joypad_active = false;
186 + status.auto_joypad_latch = false;
187 + //Release autopoll latch.
188 + status.auto_joypad_counter &= ~256; //Autopoll clears latch.
189 + auto new_latchstate = (status.auto_joypad_counter & 320) != 0;
190 + if(old_latchstate && !new_latchstate) {
191 + input.port1->latch(0);
192 + input.port2->latch(0);
194 + return;
196 + //On cycle #1, latch is asserted (unless latch is already high, in this
197 + //case the autopoller is supposed to force latch high too).
198 + if(cycle == 1) {
199 + if(dma_trace_fn) dma_trace_fn("-- Start automatic polling --");
200 + //Assert autopoll latch.
201 + status.auto_joypad_counter |= 256;
202 + auto new_latchstate = (status.auto_joypad_counter & 320) != 0;
203 + if(!old_latchstate && new_latchstate) {
204 + interface->notifyLatched();
205 + input.port1->latch(1);
206 + input.port2->latch(1);
209 + //On cycle #2, busy is asserted and controllers are cleared.
210 + if(cycle == 2) {
211 + status.joy1 = 0;
212 + status.joy2 = 0;
213 + status.joy3 = 0;
214 + status.joy4 = 0;
215 + status.auto_joypad_active = true;
217 + //Then, on cycle #3, latch is deasserted, unless "manual" latch forces
218 + //real latch high.
219 + if(cycle == 3) {
220 + //Release autopoll latch.
221 + status.auto_joypad_counter &= ~256;
222 + auto new_latchstate = (status.auto_joypad_counter & 320) != 0;
223 + if(old_latchstate && !new_latchstate) {
224 + input.port1->latch(0);
225 + input.port2->latch(0);
228 + //Then on cycles #4, #6, #8, ..., #34, a bit is shifted. Also, clock would
229 + //go low, but we can not emulate that.
230 + if(cycle >= 4 && cycle <= 34 && cycle % 2 == 0) {
231 + uint2 port0 = input.port1->data();
232 + uint2 port1 = input.port2->data();
233 + status.joy1 = (status.joy1 << 1) | (bool)(port0 & 1);
234 + status.joy2 = (status.joy2 << 1) | (bool)(port1 & 1);
235 + status.joy3 = (status.joy3 << 1) | (bool)(port0 & 2);
236 + status.joy4 = (status.joy4 << 1) | (bool)(port1 & 2);
238 + //Then on cycles #5, #7, #9, ..., #35, clock drops high, But we can not
239 + //emulate that.
240 + //Then on cycle #35, busy flag is deasserted and poll is complete.
241 + if(cycle == 35) {
242 + status.auto_joypad_active = false;
243 + char buf[512];
244 + sprintf(buf, "-- End automatic polling [%04x %04x %04x %04x] --",
245 + status.joy1, status.joy2, status.joy3, status.joy4);
246 + if(dma_trace_fn) dma_trace_fn(buf);
248 + //The entiere train is 35 cycles.
249 + if(cycle > 0 && cycle < 36) {
250 + status.auto_joypad_counter++;
255 +//called every 128 clocks; see CPU::add_clocks()
256 +void CPU::step_auto_joypad_poll_NEW(bool polarity, bool new2) {
257 + if(new2) return step_auto_joypad_poll_NEW2(polarity);
258 + auto cycle = status.auto_joypad_counter & 63;
259 + if(cycle > 0 && cycle <= 34) {
260 if(!status.auto_joypad_latch) {
261 //FIXME: Is this right, busy flag goes on even if not enabled???
262 - if(status.auto_joypad_counter == 1)
263 + if(cycle == 1)
264 status.auto_joypad_active = true;
265 - if(status.auto_joypad_counter == 34)
266 + if(cycle == 34)
267 status.auto_joypad_active = false;
268 } else {
269 - if(status.auto_joypad_counter == 1) {
270 + if(cycle == 1) {
271 + if(status.auto_joypad_counter & 128)
272 + std::cerr << "step_auto_joypad_poll_NEW(): bus fixes set???" << std::endl;
273 if(dma_trace_fn) dma_trace_fn("-- Start automatic polling --");
274 status.auto_joypad_active = true;
275 interface->notifyLatched();
276 input.port1->latch(1);
277 input.port2->latch(1);
279 - if(status.auto_joypad_counter == 3) {
280 + if(cycle == 3) {
281 input.port1->latch(0);
282 input.port2->latch(0);
284 - if((status.auto_joypad_counter & 1) != 0 && status.auto_joypad_counter != 1) {
285 + if((cycle & 1) != 0 && cycle != 1) {
286 uint2 port0 = input.port1->data();
287 uint2 port1 = input.port2->data();
289 @@ -65,7 +165,7 @@ void CPU::step_auto_joypad_poll_NEW(bool polarity) {
290 status.joy3 = (status.joy3 << 1) | (bool)(port0 & 2);
291 status.joy4 = (status.joy4 << 1) | (bool)(port1 & 2);
293 - if(status.auto_joypad_counter == 34) {
294 + if(cycle == 34) {
295 status.auto_joypad_active = false;
296 char buf[512];
297 sprintf(buf, "-- End automatic polling [%04x %04x %04x %04x] --",
298 @@ -75,9 +175,11 @@ void CPU::step_auto_joypad_poll_NEW(bool polarity) {
300 status.auto_joypad_counter++;
302 - if(vcounter() >= (ppu.overscan() == false ? 225 : 240) && status.auto_joypad_counter == 0 && !polarity) {
303 + if(vcounter() >= (ppu.overscan() == false ? 225 : 240) && cycle == 0 && !polarity) {
304 + //Preserve high bits of autopoller counter.
305 + auto x = status.auto_joypad_counter & ~63;
306 status.auto_joypad_latch = status.auto_joypad_poll;
307 - status.auto_joypad_counter = 1;
308 + status.auto_joypad_counter = x | 1;
312 diff --git a/snes/cpu/timing/timing.cpp b/snes/cpu/timing/timing.cpp
313 index d7cf24f3..ef81d891 100755
314 --- a/snes/cpu/timing/timing.cpp
315 +++ b/snes/cpu/timing/timing.cpp
316 @@ -17,12 +17,12 @@ void CPU::add_clocks(unsigned clocks) {
318 step(clocks);
320 - if(config.cpu.alt_poll_timings) {
321 + if(config.cpu.alt_poll_timings || config.cpu.bus_fixes) {
322 bool opolarity = (status.auto_joypad_clock & 128);
323 status.auto_joypad_clock = (status.auto_joypad_clock + clocks) & 0xFF;
324 bool npolarity = (status.auto_joypad_clock & 128);
325 if(opolarity != npolarity)
326 - step_auto_joypad_poll_NEW(opolarity);
327 + step_auto_joypad_poll_NEW(opolarity, config.cpu.bus_fixes);
328 } else {
329 status.auto_joypad_clock += clocks;
330 if(status.auto_joypad_clock >= 256) {
331 @@ -53,7 +53,8 @@ void CPU::scanline() {
332 status.hdma_init_position = (cpu_version == 1 ? 12 + 8 - dma_counter() : 12 + dma_counter());
333 status.hdma_init_triggered = false;
335 - status.auto_joypad_counter = 0;
336 + //Only clear the low 6 bits (counter).
337 + status.auto_joypad_counter &= ~63;
340 //DRAM refresh occurs once every scanline
341 @@ -200,7 +201,9 @@ void CPU::timing_reset() {
343 status.auto_joypad_active = false;
344 status.auto_joypad_latch = false;
345 - status.auto_joypad_counter = 0;
346 + //Set bit 7 of joypad counter if bus fixes are active (for combined
347 + //latch behavior).
348 + status.auto_joypad_counter = config.cpu.bus_fixes ? 128 : 0;
349 status.auto_joypad_clock = 0;
352 diff --git a/snes/cpu/timing/timing.hpp b/snes/cpu/timing/timing.hpp
353 index bf15a727..8be2b830 100755
354 --- a/snes/cpu/timing/timing.hpp
355 +++ b/snes/cpu/timing/timing.hpp
356 @@ -22,4 +22,5 @@ alwaysinline bool irq_test();
358 //joypad.cpp
359 void step_auto_joypad_poll();
360 -void step_auto_joypad_poll_NEW(bool polarity);
361 +void step_auto_joypad_poll_NEW(bool polarity, bool new2);
362 +void step_auto_joypad_poll_NEW2(bool polarity);
363 diff --git a/snes/snes.hpp b/snes/snes.hpp
364 index 3a65e360..961842b3 100755
365 --- a/snes/snes.hpp
366 +++ b/snes/snes.hpp
367 @@ -3,6 +3,7 @@
368 #define BSNES_SUPPORTS_ADV_BREAKPOINTS
369 #define BSNES_SUPPORTS_ADV_BREAKPOINTS_PPU
370 #define BSNES_SUPPORTS_ALT_TIMINGS
371 +#define BSNES_SUPPORTS_BUS_FIXES
372 #define BSNES_SUPPORTS_TRACE_SA1
373 #define BSNES_SUPPORTS_DMA_TRACE
376 2.15.0.rc1