The ZX Spectrum Reverse Engineering and Clone Desgin Blog


A site dedicated to the reverse engineering of the ZX Spectrum and related projects.

< 46 of 68 >

Implementing the ULA Contention Model

Jul 15, 2007

First a summary. As discussed previously, the Spectrum ULA applies a special contention pattern to the second T-state (T2) of an IO instruction. This pattern is different to that used to avoid video memory contention.

EDIT: Nov 2009 - This was later found to be false. Both memory and IO contention use the same CPU WAIT timing. See Memory Contention Revised and Snow

The ULA is trying to make sure that the fourth T-state (T3) of an IO instruction for one of its ports, executes during the two cycles in which it is not busy with the video. The ULA first notices that the Z80 is acting on one of its ports during the instructions second T-state, and it is this T-state that it delays. If the memory contention model were used, T2 would be delayed until the ULA was no longer busy and not T3.

The ULA knows this of course, and so it delays T2 until two cycles before it knows it will become free. The remaining two T-states then execute uncontended, so that T3 (the 4th) executes when the the ULA is no longer busy.

The two contention timings are show below, along with two examples of ULA IO Port execution:

MEM WAIT                                
IO WAIT                                
ULA IO1    T1  T2  ---------> T2  TW  T3   
ULA IO2    T1  T2  TW  T3 

From the above diagram, we can see that:

  1. MEMWAIT = HC2 • HC3
  2. IOWAIT = HC2 • HC3

The rules governing which WAIT needs to be applied are:

  1. For memory access between addresses 0x4000 and 0x7FFF, apply MEMWAIT during the memory access T-states
  2. For IO ports between addresses 0x4000 and 0x7FFF, apply IOWAIT whilst the port address is active on the address bus
  3. For IO port with A0 reset, apply IOWAIT at T2 and then no further contention at TW and T3

The choice between MEMWAIT and IOWAIT can be made depending on whether the Z80 MREQ control signal is active or not.

Address range 0x4000 to 0x7FFF = ADDR16 = A14 • A15

ZXIO = A0IORQ   (ULA port access)

As IORQ goes low for T2, TW and T3, we detect the initial high to low transient of ZXIO and use that to create a single cycle wide ZXIO-T2

Contention should be appled whenever ADDR16 or ZXIO-T2 are low. However, ZXIO-T2 going high should disable all contention until the end of the current IO instruction (when IORQ and thus ZXIO) return to high.

The wait generation schematic and modifications to the CPU control schematic can be found in schematics version 1.11.