Machine Timing
Frame geometry, where the interrupt falls, and when the ULA holds the bus. The figures here matter to cycle-exact work: raster splits, multiplexed sprites, and anything that has to land on a particular scanline.
Counters
The ULA runs two counters off a 7 MHz pixel clock: hc across a scanline and vc down the frame. One CPU T-state is two pixel clocks. A line is hc_max + 1 pixel clocks; a frame is vc_max + 1 lines.
| Timing | Line (T) | Lines | Frame (T) | /INT at |
|---|---|---|---|---|
| 48K | 224 | 312 | 69888 | vc 0, hc 116 |
| 128K / +2 grey | 228 | 311 | 70908 | vc 1, hc 128 |
| +2A / +3 | 228 | 311 | 70908 | vc 1, hc 126 |
| Pentagon | 224 | 320 | 71680 | vc 319, hc 439 |
/INT is held for 32 pixel clocks, 16 T-states, on every variant. An instruction still running when the 16 T-states end misses the interrupt.
The +2A and +3 differ from the 128K only in where the interrupt falls, two pixel clocks earlier.
A 48K frame is 224 × 312 = 69888 T-states, so at 3.5 MHz it lasts 69888 ÷ 3 500 000 = 19.97 ms.
Next timing selection
The Next takes its ULA timing from two registers:
- Nextreg
$03bits[6:4], the machine timing. Bit 2 selects Pentagon; otherwise bit 1 selects the 128K family, and within that bit 0 selects +3 over 128K; with neither, 48K. - Nextreg
$05, the 50/60 Hz bit. 60 Hz shortens the frame to 264 lines and moves/INTtovc0. The line length does not change, so a 60 Hz 48K frame is 224 × 264 = 59136 T-states and a 60 Hz 128K frame is 228 × 264 = 60192.
Pentagon has no 60 Hz variant.
Changing either selects a new timing profile as a whole: frame length, interrupt position, contention pattern and the raster counter’s origin move together. A change takes effect from the next frame boundary.
First active line
The 256 × 192 display does not start on the same scanline in every profile. The origin for the raster counter and the line interrupt is scanline 64 at 50 Hz, 40 at 60 Hz, and 80 on Pentagon.
Line interrupt
The line interrupt fires late in the scanline, at hc 379 on the 128K family and 371 on the 48K and Pentagon. It lasts a single 7 MHz tick, so a program polling for it tests for the beam having passed it, not for equality: at two pixel clocks per T-state, a test for equality can step over it.
Memory contention
While the ULA fetches display data it holds the bus, and a CPU access to contended memory in that time is delayed.
The delay repeats every 8 T-states:
| Machine | Delay at each T-state of the 8 |
|---|---|
| 48K, 128K, +2 | 6, 5, 4, 3, 2, 1, 0, 0 |
| +2A, +3 | 1, 0, 7, 6, 5, 4, 3, 2 |
On the 48K an access arriving at the first T-state of the 8 waits 6 T-states, and one arriving at the seventh waits none. On the +3 an access at the third T-state waits 7.
On the 48K, 128K and +2 the T-states an instruction spends with a contended address on the bus, between its reads and writes, are contended too. The +2A and +3 contend only the reads and writes.
Contention applies only:
- on lines 64 to 255,
- for the 128 T-states of each line in which the ULA reads RAM,
- starting 60 T-states into the line on the 48K and Pentagon, and 64 on the 128K family.
The rest of the line, and the top and bottom border and the vertical blank, are uncontended.
On the 48K the contended range is $4000–$7FFF. On the 128K and +2, banks 1, 3, 5 and 7 are contended, wherever they are paged. On the +2A and +3, banks 4 to 7 are contended.
On the Next, contention follows the machine timing nextreg $03 selects: the 48K or 128K pattern under 48K or 128K timing, the +2A/+3 pattern under +3 timing, and none under Pentagon timing. The Next resets into +3 timing, and the boot ROM sets it.
Nextreg $08 bit 6 disables contention. With it set the machine runs without ULA delays.
I/O contention
On the 48K, 128K and +2, a port access is contended when A0 = 0: the ULA port. The +2A and +3 contend no port access.
On the Next under 48K or 128K timing, the contended ports are the ULA port, $7FFD, and the ULA+ ports $BF3B and $FF3B. $1FFD is not contended. Under +3 or Pentagon timing no port access is contended.
CPU speed
Nextreg $07 selects 3.5, 7, 14 or 28 MHz. The CPU’s clock multiplies and the ULA’s does not, so the number of instructions between two raster positions changes and the raster positions do not.
At 7 MHz a 48K-timed line holds 2 × 224 = 448 CPU T-states.
At 28 MHz the memory inserts one wait state per read, as the hardware does, so 28 MHz is slower than four times 7 MHz. The zxnDMA’s reads take the same wait.
Reading $07 back returns two values in one byte: bits[5:4] are the actual speed and bits[1:0] the programmed one. The actual speed resets to 3.5 MHz whatever the programmed one holds, so a read straight after a reset does not return what was written. Enabling the expansion bus also holds the actual speed at 3.5 MHz, whatever is programmed, and the CPU is contended at that speed.
Known differences
- I/O contention on the classic machines ignores the high byte of the port. Hardware contends an
A0 = 1access when the port address itself falls in contended memory; Bizmuth’s 48K and 128K treat every odd port as uncontended. The Next follows the hardware.
See also
- Z80N Instructions: the extended opcodes’ cycle counts.
- Next Registers:
$03,$05,$07and$08in context.