Routerman & Ultra
Hey Routerman, I just stumbled upon a classic NES glitch where the sprite flickers every 32āÆms because the CPU and PPU are fighting over the same memory bus. Think itās a subtle timing race. Want to trace the data path and see where the anomaly really originates?
Yeah, that flicker is a classic busācontention loop. The CPU and PPU are literally waving at each other for that same 16ābit bus, and the 32āÆms window just lines up with the Vāblank cycle. Letās map the path: the sprite data lives in the OAM, but the PPU pulls data from name tables during rendering, while the CPU tries to write to those same tables. The arbitration hardware hands control to whoeverās request is active, but in this case the timing gets out of sync. If we line up the bus requests against the PPU scanlines, weāll see a repeated overlap every 32āÆms. So, start by checking the cycle count at the start of each Vāblank, then trace the CPUās memory writes to the VRAM during that interval. That should reveal whether the glitch is a subtle race or just a timing slip of the bus logic. Ready to dive into the cycle diagram?
Nice breakdown, Routerman. Letās grab a cycle counter, hook the bus logger, and plot the writes in a timeline. Iāll line up the scanlines and see where the overlap spikes. If itās a race, we can tweak the CPU delay to squash it. If itās a timing slip, maybe a tweak to the PPU clock phase. Time to crunch some data. Ready when you are.
Sounds good. I'll fire up the cycle counter, start the bus logger, and pull the first snapshot of the timeline. Let me know when you see the spike so we can pin down whether itās a pure bus fight or just a phase slip. Weāll tweak the delay and see if the flicker stopsāhappy to dive deeper if the data says itās a subtle timing slip. Let's get that plot.
Got the snapshot, Routerman. The spike lines up right on the Vāblank boundary, exactly 32āÆms apart. Looks like a pure bus fight ā the PPU pulls the same 16ābit word the CPU is trying to write. Iāll add a small delay to the CPU write cycle and reācapture. If the flicker disappears, weāve confirmed itās a contention race. If not, weāll need to adjust the PPU phase. Letās run the tweak and see what the data tells us.
Great, the timing matches the Vāblank slot. Adding a microādelay to the CPU write should give the bus a breathing room. If the flicker clears, weāve nailed it as a classic contention race. If it persists, weāll have to look at the PPUās scanline cycle alignment. Keep me posted on the next capture. Let's see if the bus just needs a polite āwaitā before it pulls the same word.
Nice, a microādelay is the classic āwaitā trick. If the flicker clears, weāve nailed a pure bus race. If not, weāll sync the PPUās scanline phase instead. Hit me back with the next capture.Nice, a microādelay is the classic āwaitā trick. If the flicker clears, weāve nailed a pure bus race. If not, weāll sync the PPUās scanline phase instead. Hit me back with the next capture.
Hit it. The microādelay should be a few hundred nanosecondsājust enough to let the PPU finish the read before the CPU writes. If the flicker disappears, we can call it a race. If it stays, weāll shift the PPU clock by one scanline phase and reālog. Letās see what the new timeline looks like.
Got it, throwing in a 200āns buffer now. Watch the logāif the flicker goes dark weāve nailed the contention. If it stays, weāll push the PPU clock one scanline ahead and reācapture. Letās see the updated timeline.
Log shows the flicker is goneānice! The 200āns buffer let the PPU finish its read before the CPU writes, so it was a clean contention race. No need to shift the PPU clock now. Great work, weāve got the culprit nailed. If any other hiccups pop up, let me know.