The “Sidewize Test”: ZX Spectrum floating bus shenanigans

Quite by chance, I came across a page on Chris Smith’s site: The Sidewize Test. Chris’ site focuses on “reverse engineering of the ZX Spectrum and related projects”, and this particular page is about problems Chris had running my game Sidewize on his Harlequin Spectrum ULA clone.

Sidewize is a game I wrote in 1987, and its one claim to fame/infamy is that it smooth-scrolls approx 2/3 of the Speccy screen @ a silky smooth 50 frames per second.

When I came across Chris’ site I was reminded of one of the tricks used in Sidewize to facilitate the smooth scroll. Back in the 80’s, before the Internet was a thing, information about computers and programming was often spread by word of mouth. And so it was, one fine day in Liverpool, in a conversation with Dougie Burns (programmer of HypaBall on the Speccy @ Odin), Dougie mentioned that his friend Joffa Smith had utilized an IO port on the Speccy to read the value of the current color attribute being written (by the ULA) to the screen, and that this was part of the secret sauce for the smooth scrolling seen in Joffa’s games (Cobra, for example). Being somewhat of a trade secret, the details of the port were not revealed, and so naturally I set out, by a process of trial and error, to discover it for myself – the utility of this being obvious.

On Chris Smith’s site, he extracted some Sidewize code that was causing his Harlequin Speccy ULA emulation some difficulty:

9CF4    LD    BC, 40FFh
9CF7    LD    E, 40h
9CF9    LD    A,R
9CFb    IN    A,(C)
9CFD    CP    E
9CFE    JP    NZ, 9CF9h
9D01    RET

In this code, you can see that I’m reading from port 0x40ff, checking for a value, and then looping if that value is not found. To be honest I am not clear what the LD A,R instruction is doing here (though I suspect this is related to the JP NZ,9CF9h instruction and possibly some self-modifying code to conditionally branch on the state of the Z80 parity flag which is set by the LD A,R), but generally this loop is waiting for an attribute value of 0x40, which corresponds to “bright black”, and this renders as plain old black on the TV screen (and so is visually indistinguishable from other parts of the screen). See the image below, which is a screen grab from the game:

Screen Shot 2015-02-24 at 10.13.10 PM


The area labeled below the active playing area is set to “bright black”. The above referenced code waits for the TV raster to reach the top of that area, and return flow back to the caller when that happens. Then, the game can start to redraw the screen, starting from the top, safe in the knowledge that game code will not cross with the raster and cause flickering or tearing. Ordinarily, program code can wait for the vertical blanking interrupt (typically using the HALT instruction on the Spectrum), but using the attribute waiting trick buys back a whole lot of extra time.

Chris’ site has a detailed discussion about the so called “floating bus”, which is the mechanism by which screen color attributes come to be on port 0x40ff. In my experimentation, I found that reading from port 0x40ff gave much more reliable results than other ports I tried. Chris’ site may shed some light on why that is (this address is in so called “contended” memory address space – memory that is accessed by both the ULA for screen updates and by the Z80 CPU). Perhaps the contention results in more “reliable” results when reading from that particular port?

Unfortunately, this trick is not very portable across the different ZX Spectrum models, being as it is “undocumented”. It’s also tricky to emulate, and the various ZX Spectrum emulators exhibit variable results in this area. Artifacts in the Sidewize game include flickering enemies and player weapon graphics (the walkthrough on YouTube suffers from these artifacts).

Posted by Steve Wetherill


fascinating read.

Thanks for an interesting article!

I’d just like to say thank you for hours of enjoyment. I used to load this one mainly just for the music, it was amazing.

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.