The floating bus explained!
technical report - rev 1.06 (apr 25 2002)
|1.||The floating bus on the 48K and 128K|
Due to the resistors which decouple the two dedicated buses inside the Spectrum, when the Z80 reads from an unattached port (such as 0xFF) it actually reads the data currently present on the ULA bus, which may happen to be a byte being transferred by the ULA from video memory for the screen rendering. If the ULA is building the border, then its data bus is idle (0xFF), otherwise we are perfectly able to predict whether it is reading a bitmap byte, an attribute or again it's idle. This "nice" effect goes under the name of floating bus. Unfortunately some programs do rely on the exact behaviour of the floating bus, so we can't simply forget about it; notable examples are Arkanoid (first edition), Cobra, Sidewize, Duet and DigiSynth.
In the next table we show the locations which are read by the ULA with their respective times (T-STATES), both in the 128K and in the 48K. Remember that during a port read, the Z80 fetches the input byte from the bus in the last cycle of the I/O transaction (i.e. T4).
The ULA reads a whole row of pixels and attributes using 16 x 8T cycles, the first of which starts at 14368 on the 128K and 14347 on the 48K. The screen bytes are fetched during the first 4T of each cycle (order: bitmap, attribute, bitmap+1, attribute+1), while in the last 4T the bus is idle (0xFF). After that 128T, the ULA is busy drawing the border and it does not read the video memory, so it leaves the bus idle for the remaining 228-128 = 100T (or 224-128 = 96T on the 48K). Then, the second row of pixels is started to be read at 14368+228 = 14596T (or 14347+224 = 14571T on the 48K) with the same scheme, and so on until the 192th row is finished.
The floating bus test program.
Click here to download the latest version of the test program (TAP).
With simple modifications, this tool is suitable to study other effects too.
|2.||The snow effect|
Although the ULA is usually hyper-efficient to halt the Z80 even when not needed, sometimes it forgets to apply contention when it really should. Try the following program:
DI LD A, 0x40 LD I, A EI RETYou will see random dots and patterns appearing on the screen, a nice visual effect called the snow effect which has been used as a "special fx" in the game Vectron.
Technically speaking, this happens because when the I register falls in the range 0x40-0x7F then the ULA gets confused by the memory refresh cycles of the Z80 (performed during each instruction fetch), and it doesn't apply contention to take precedence as usual. Under this circumstance, the IR address put on the bus by the CPU interferes with the video memory address generated by the ULA (who wants to read the videoram to draw the screen), with the result that the RAM chip which contains the display file perceives a mixture of the two addresses. Therefore the ULA reads the data from an unexpected memory location (which still belongs to videoram), and a wrong pattern is displayed on the screen.
In detail, the address which is actually read by the ULA is the following:
A15-A8 = A15-A8 of the ULA address A7-A0 = the R register of the Z80Remember that the attribute and bitmap bytes for a given screen cell (e.g. addresses 0x4000 and 0x5800) are stored at the same row but a different column in videoram. Since the clash alters the row address only, the ULA always reads matching attribute/bitmap couples - it simply displays the pattern in the wrong cell. This rule applies both to the 48K and 128K Spectrum models.
At the moment it's not 100% clear to us what happens inside the ULA in terms of circuitry logic and which determines the snow effect.