If you are restoring a ZX Design retro computer, put a finger on the ULA. If it is cold and the screen is white, the ULA is dead. If it is hot and the screen is flickering vertical lines, the lower RAM (attached to the ULA) is dead.
To the naive observer, slowing the CPU down 30% to draw the screen is a flaw. To the systems engineer, it is genius.
The Problem: DRAM requires refresh every 2ms. The Z80 has an internal refresh counter, but on a contended bus, it might miss cycles. The ULA Solution: During the 224 visible scanlines (48 lines of border, 192 of active video), the ULA seizes the bus for exactly 1 cycle out of every 4. This ensures: If you are restoring a ZX Design retro
Design Lesson: The ULA does not fight the Z80; it rides it. The Z80’s /MREQ signal is ignored during contention. This is a masterclass in asynchronous-to-synchronous bridging using minimal logic.
module ula( input clk_14M, input nRST, inout [7:0] data_bus, input [15:0] address, output nWAIT, output nINT, output composite_video );
// Video timing counters & sync generation... // Memory contention logic... // Keyboard scan on IOREQ & A0 low... endmoduleDesign Lesson: The ULA does not fight the
The Spectrum ULA maps the keyboard to port 0xFE. It reads 5 rows of keys (Shift, Z–M, etc.) via IN instructions. The Spectrum ULA maps the keyboard to port 0xFE
Design steps:
Bonus: Add a simpler design variant – use a modern microcontroller to scan keys and send serial data to the main CPU, but that misses the ULA’s charm.
Without a working ULA, debugging is hard. Build incrementally:
Common pitfalls: