Ever asked how the vertical and horizontal sync are realized in detail and how it matches to video standard ?
This is not very exactly explained in the ZX81 ROM listing.
Lets start with the VSYNC pulse. It's duration is more or less 6 horizontal lines, about 384 microseconds. But for now we count only lines.
So it's now 6.
Code: Select all
0277: [0277] D3 FF OUT ($FF),A ; end the TV frame synchronization pulse.
0279: [0279] 2A 0C 40 LD HL,($400C) ; (12) set HL to the Display File from D_FILE
027C: [027C] CB FC SET 7,H ; (8) set bit 15 to address the echo display.
027E: [027E] CD 92 02 CALL L0292 ; (17) routine DISPLAY-3 displays the top set
; of blank lines.
VSYNC is ended with OUT ($FF),A and next the top margin lines are printed. 55 for UK version.
So the line counter is now at 61.
Code: Select all
0074: [0074] 2A 0C 40 LD HL,($400C) ; (16) fetch start of Display File from D_FILE
; points to the HALT at beginning.
0077: [0077] CB FC SET 7,H ; (8) point to upper 32K 'echo display file'
0079: [0079] 76 HALT ; (1) HALT synchronizes with NMI.
007A: [007A] D3 FD OUT ($FD),A ; (11) Stop the NMI generator.
007C: [007C] DD E9 JP (IX) ; (8) forward to L0281 (after top) or L028F
After 55 margin lines the T-State SYNC is initiated from the NMI routine as well, after continue with picture generation.
So line counter is now at 62.
Code: Select all
0281: [0281] ED 5F L0281: LD A,R ; (9) Harmless Nonsensical Timing or something
; very clever?
0283: [0283] 01 01 19 LD BC,$1901 ; (10) 25 lines, 1 scanline in first.
0286: [0286] 3E F5 LD A,$F5 ; (7) This value will be loaded into R and
; ensures that the cycle starts at the right
; part of the display - after 32nd character
; position.
0288: [0288] CD B5 02 CALL L02B5 ; (17) routine DISPLAY-5 completes the current
; blank line and then generates the display of
; the live picture using INT interrupts
; The final interrupt returns to the next
; address.
So the video generation is continued. The picture normally contains 24 rows with 8 scanlines per row, so 192 lines in TV world. But it completes the current line and BC register is loaded with one more scanline ($1901 instead of $1808). So in fact 193 lines are displayed ! And it ends with an additional INT ACK because the routine at $0038 checks end of display AFTER displaying 193 lines and the first margin line appears with the next NMI which extends 193,1 lines to 194. And by the way, thats why an collapsed DFILE consists of 25 NEWLINE instead of 24 or an expanded DFILE starts with a NEWLINE character as well.
Line counter is now at 256.
Code: Select all
028B: [028B] 2B L028B: DEC HL ; point HL to the last NEWLINE/HALT.
028C: [028C] CD 92 02 CALL L0292 ; routine DISPLAY-3 displays the bottom set of
; blank lines.
; ---
;; R-IX-2
028F: [028F] C3 29 02 L028F: JP L0229 ; JUMP back to DISPLAY-1
Now again 55 (bottom margin) lines are generated plus again 1 T-State SYNC line (not really needed but used).
So line counter is now at 312.
After a new FRAME begins with VSYNC.
Well in fact the TV display is divided a bit more complex. Normally the picture has 25 full frames which are devided into two half frames, called odd and even frame. The position of the frames are coded with more complex VSYNC pulses, normally it is not just one longe pulse like from the ZX80 or ZX81. So the standard give 25 pictures interlaced with 625 lines, divided into two frames with 312,5 lines. This is a difference but the TV's are tolerant enough to take the signal, resulting in a little bit faster frame rate. The deviation is 0,16%.
The duration of 1 line is 64us (microseconds) which matches 1 second after 25 "full" frames: 64us*625*25 = 1 second
Now lets take a look at the horizontal lines.
This is even not very well explained in the ROMs how 1 line matches exactly 64us (207 clock cycles).
In fact it is only 63,7 us and exactly one clock cycle is missing. 208 clock cycles would give exactly 64us at 3.25 MHz speed. So this is a deviation of 0,5% which can be handled by the TVs but I ask myself if it wouldn't have been possible by Sinclair to realize a 208 clock cycle display.
But let's start with the INT ($38), during active picture generation (the 192 lines, 24 rows).
Code: Select all
0038: [0038] 0D L0038: DEC C ; (4) decrement C - the scan line counter.
0039: [0039] C2 45 00 JP NZ,L0045 ; (10/10) JUMP forward if not zero to SCAN-LINE
003C: [003C] E1 POP HL ; (10) point to start of next row in display
; file.
003D: [003D] 05 DEC B ; (4) decrement the row counter. (4)
003E: [003E] C8 RET Z ; (11/5) return when picture complete to L028B
; with interrupts disabled.
003F: [003F] CB D9 SET 3,C ; (8) Load the scan line counter with eight.
; Note. LD C,$08 is 7 clock cycles which
; is way too fast.
; ->
;; WAIT-INT
0041: [0041] ED 4F L0041: LD R,A ; (9) Load R with initial rising value $DD.
0043: [0043] FB EI ; (4) Enable Interrupts. [ R is now $DE ].
0044: [0044] E9 JP (HL) ; (4) jump to the echo display file in upper
; memory and execute characters $00 - $3F
; as NOP instructions. The video hardware
; is able to read these characters and,
; with the I register is able to convert
; the character bitmaps in this ROM into a
; line of bytes. Eventually the NEWLINE/HALT
; will be encountered before R reaches $FF.
; It is however the transition from $FF to
; $80 that triggers the next interrupt.
; [ The Refresh register is now $DF ]
; ---
;; SCAN-LINE
0045: [0045] D1 L0045: POP DE ; (10) discard the address after NEWLINE as the
; same text line has to be done again
; eight times.
0046: [0046] C8 RET Z ; (5) Harmless Nonsensical Timing.
; (condition never met)
0047: [0047] 18 F8 JR L0041 ; (12) back to WAIT-INT
It takes 58 cycles after INT ACK to start with video code execution. R Register is $DE (not $DF like stated) and interrupt occurs when R Register is 00 !.
So the 32 characters are executed first. After 32 characters R is still $FE so the following HALT is executed anyway and an additional NOP !
So it is in fact 33 characters which are executed plus one additional NOP caused from the HALT instruction.
After the NOP the interrupt acknowledge take place.
Code: Select all
;; WAIT-INT
0041: [0041] ED 4F L0041: LD R,A ; (9) Load R with initial rising value $DD.
0043: [0043] FB EI ; (4) Enable Interrupts. [ R is now $DE ].
0044: [0044] E9 JP (HL) ; (4) jump to the echo display file in upper
; memory and execute characters $00 - $3F
; as NOP instructions. The video hardware
; is able to read these characters and,
; with the I register is able to convert
; the character bitmaps in this ROM into a
; line of bytes. Eventually the NEWLINE/HALT
; will be encountered before R reaches $FF.
; It is however the transition from $FF to
; $80 that triggers the next interrupt.
; [ The Refresh register is now $DF ]
So the comment in line 0043 is quite imprecise. R is not $DE in fact it is $DD and incremented before the next refrehs begins (probably R register is incremented or loaded with LD R,A command during the (following) M1 cycle).
So we have now 34 characters to execute (32 chars + HALT/NEWLINE + NOP) = 34*4=136 cycles.
So 58 cycles to start up, all in all now 194 cycles.
An interrupt acknowlede is following, this is an M1 cycle with two additional wait states, so 6 cycles instead of 4 cycles.
Now we have exactly 200 cycles.
What now happens depends a bit on the interrupt mode, we are using IM1 which is exactly a shortcut to RST $38.
A restart instruction is stated with 11 cycles while it is overlapping the INT ACK cycle. In fact the next M1 cycle starts 7 clock cycles after the INT ACK.
So we have additional 7 clock cycles after INT ACK which include 2 normal write cycles (writing PC to stack).
Don't know what the hell the CPU does in the 1 remaining additional clock cycle as there are enough cycles in the INT ACK to load the PC register. Maybe a small break before the exhausting and urgent INT service routine.