The ZX Spectrum Reverse Engineering and Clone Desgin Blog


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

< 62 of 68 >

The Harlequin Dynamic Memory Control

Feb 20, 2008

Replicating the ZX Spectum dynamic memory control signal timings exactly is not necessary for the Harlequin, so long as the timing adheres to the dynamic memory tolerances as given in the specification. In order to ensure compatibility with the ZX Spectrum in terms of the floating bus, we will need to ensure that the display and attribute bytes are available on the databus before the falling edge of CLK3.5.

Video Access

By taking the ZX Spectrum's memory timings and adjusting them slightly to relate to the Harlequin clock signals, maintaining approximate timing margins, we can produce the following timing sequence:


The first byte fetch, when AL1 goes low, is used to initiate a RAS cycle that spans both the display byte read, and the attribute byte read. The display byte row address is placed on the bus at the falling edge of AL1, so we delay RAS until the next falling edge of CLK14 to allow sufficient time for the address on the bus to stabilise. The NEC 4116 datasheet says that a minimum of 0us (tASR) must pass between a stable address on the bus and RAS going low. By delaying RAS, we ensure that the address is stable.

Next we must send CAS low. This is aligned to the next rising edge of CLK14 to allow enough time between the RAS and CAS signals for the column address to be placed on the bus and stabilise.

According the the specifications, the row address must be held for approximately 20ns after RAS goes low (tRAH), so we must wait at least this long before swapping to the column address. The address multiplexor can be switched to the column address shortly after RAS goes low by selecting on RAS that has been delayed by a few series gates.

During a RAS cycle we put CAS low twice: once to latch the display byte column address and fetch the byte, and a second time to latch the attribute byte column address and fetch the byte. This is known as a page mode read cycle, and it provides a faster access with lower power dissipation than a normal read cycle. Towards the end of this cycle RAS goes high, however this occurs earlier than CAS to allow a sufficient RAS pre-charge time before the next RAS. Once RAS is high the row address is incremented and the cycle may begin again.

Considering the timing diagram above, we see that:

vCAS = HC0 • CLK7

vRAS = HC0 • AL1   [Note: Must be delayed until falling edge of CLK14.]

Note that nothing in these equations stops the signals from being generated continuously, when they should only be generated while AL1 or AL2 are low.

vCAS = (HC0 • CLK7) + (AL1 • AL2)

vRAS = (HC0 • AL1) + (AL1 • AL2)    [Note: Must be delayed until falling edge of CLK14.]

Currently the video address counter is incremented with outlatch, but this occurs during AL1 of the second fetch cycle, which unfortunately is after the second RAS has begun, and thus is too late to advance the row address as required. Instead we can use the end of the RAS cycle to increment the address, as it is safe to do so between this point and the next RAS cycle. As the Video Address clock is incremented on a falling edge, we have:

Videoclk = NOT (vRAS) = vRAS

That's the video access taken care of, and now to give the CPU access to the dynamic memory.

CPU Access

The Z80 CPU generates control signals that are appropriate for interfacing with dynamic memories as the Z80 was designed at a time when static memory was expensive and dynamic memory the norm. This means that our CPU RAS and CAS generation can be relatively simple, and certainly much simpler than that for our video access.

During a Z80 memory access the required address is placed on the address bus followed by MREQ going low. Shortly afterwards RD may go low, or WR a cycle or so later.

This simple Z80 control sequence allows us to generate RAS from MREQ, and CAS from RD or WR. Note, we only want to generate the control signals when the Z80 is accessing the lower 16K RAM (0x4000 - 0x7FFF).

cRAS = MREQ + A14 + A15 = RAM16


There are however a couple of small timing issues.

As RD follows MREQ very closely, any CAS generated from it would follow RAS very closely, so we must delay CAS in this case.

Secondly, MREQ goes low just over halfway through T-state T1 of a memory read or write cycle, just after the falling edge of the clock. Under a contended memory access the video circuit releases the hold on the CPU clock half way through cycle 7 of 8 (during the fourth byte fetch of the two pairs). The CPU clock will go low at the end of this 7th cycle, and MREQ very shortly after that. The video circuit will have only just handed the address bus back to the CPU and its vCAS will have only just gone high, so a CPU RAS generated from MREQ at this point will go low during this moment of instability.

It would be advisable therefore to delay cRAS for a moment, and to make sure that cCAS always follows cRAS by considering it along with RD and WR.

cRAS = RAM16

cCAS = cRAS + (RDWR)

Clocking vRAS, cRAS and cCAS through D-type flip-flops clocked on the falling edge of CLK14 introduces a 36ns delay, which is insignificant as far as the Z80 is concerned, but is ample time for the address bus and other signals to stabilise once the video circuit has finished with them.

Next a look at the address bus and multiplexers....