The ZX81 Video Display System - wilf rigter (last rev. 04/2005)

ZX97 with HIRES Splash Screen on Power Up
Contents
1. INTRODUCTION
2. ZX81 DISPLAY BASICS
3. SLOW MODE VIDEO
4. FASY MODE VIDEO
5. ZX81 VIDEO HARDWARE
6. ZX81 CHARACTER VIDEO HARDWARE
7. PSEUDO HIRES VIDEO HARDWARE
8.TRUE HIRES VIDEO HARDWARE
9.ZX81 CHARCTER DISPLAY TIMING
10.PSEUDO HIRES DISPLAY TIMING
11.TRUE HIRES DISPLAY TIMING
12.ZX81 SLOW MODE VIDEO ROUTINES
13. ZX81 FAST MODE VIDEO ROUTINES
14.TRUE HIRES VIDEO ROUTINES
15. PSEUDO HIRES VIDEO ROUTINE
________________________________________________________________________________________________________________________
When
fortuitous circumstances combine innovative technical ideas with an economical
design and a market opportunity, interesting things always happen. In 1980,
Sinclair was not yet a household word and he was perhaps better known for his
digital watch and calculator than his ZX80 personal computer. However
Sinclair’s market experience with the ZX80 and new low cost LSI technology gave
him a vision and an opportunity to introduce an affordable, easy to use,
mass-producible computer version of the ZX80 with floating point math and a
non-flicker display. The ZX81 was born and "the rest is history".
A
key to the economical design of the ZX81 was combining the ZX80 video system,
which uses the Z80 to do most of the work, with a small circuit that was
available for the Z80 to generate a SLOW mode display. When the ZX81 circuit was integrated into
the ULA chip, it was not only cheap to manufacture but the ZX81 video circuit
turned out to be versatile with display capabilities well beyond the designer's
original goals.
The
standard ZX81 video screen displays 24 rows of 32 characters. Every character
has height of 8 scan lines and a width of 8 pixels. The characters to be
displayed are located in a block of memory called DFILE. The set of 128 displayable
characters includes 64 normal (white on black) uppercase only letters, numbers,
symbols and graphics characters and their inverse (black on white). The ZX81
character codes CHR$ 0-63, CHR$118 and CHR$ 128-191, are non-standard (not
ASCII). A set of token codes is also used for keywords, functions and commands
but these are always expanded to the displayable characters before printing to
DFILE. The DFILE is formatted starting with the Sinclair equivalent of a
Carriage Return (CHR$ 118) followed by up to 32 CHR$ codes, this repeated 24
times and ending with a CHR$ 118. CHR$ 118 is the opcode for the Z80 HALT
instruction for reasons which will be explained later. All other character
codes are illegal and if loaded into DFILE will generally cause a system crash.
The collapsed DFILE is used in the 1K and 2K basic ZX81 to minimize screen
memory requirements. When empty a collapsed DFILE consists of just 25 CHR$ 118
codes. Each line is expanded when characters are printed to that line. When
equipped with 4K or more of memory, DFILE is initialized to the fully expanded
format with 24 lines of 32 CHR$ 00 (space) characters and 25 CHR$ 118 line
termination characters.
The
character codes are not displayed directly but rather are used as address
pointers to a ROM video pattern table. The ROM pattern bytes are addressed by a
combination of the character code in DFILE and the ZX81 hardware and are loaded
into the video shift register. Bit 7 of the character code is used by the video
hardware to invert the pixels as they are shifted out of the shift register.
The display on the screen is generated by the serial bit stream of pixels a
video shift register which turns the TV CRT electron beam on and off as it
scans the phosphor coating on the inside face of the picture tube. A fully
expanded DFILE with 24 lines of 32 characters per row and 8 pattern bytes per
character displays 6144 pattern bytes or 49152 pixels per screen.
In
the SLOW mode, the CPU is multitasking between video and program execution. About
80% of the CPU time allocated to video and keyboard service routines and only
about 20 % of CPU time is available to execute the application program. In
fact, the CPU time is divided in four distinct task blocks per TV frame as
shown in TABLE 1. Tasks are switched using a Non-Maskable-Interrupt (NMI)
generator to call a NMI service routine that controls task switching from the
asynchronous application program to the real-time video routines.
________________________________________________ | | | 1. VSYNC, frame count and keyboard - NMI off | | 2. Blank lines/application code - NMI on | | 3. VIDEO DISPLAY routine - NMI off | | 4. Blank lines/application code - NMI on | |________________________________________________| TABLE 1 SLOW MODE CPU TASK TABLE
Each
task can be described in more detail as follows:
1.
During the vertical sync interval, when no video is actually displayed, the CPU
executes a fixed length VSYNC routine which increments a FRAME counter, reads 8
rows of keyboard data together with the 50/60Hz mode bit. Any I/O read
operation with A0 low (ie FE) addresses the ULA keyboard port. It also causes
the ULA to start the vertical sync pulse by clamping the video output to the 0V
sync level and simultaneously applies a reset to the ULA 3 bit line counter
(LCNTR). After the all the keyboard data is processed (400us later), the CPU
executes an OUT FF,A (any OUT will do) which restores the ULA video output to
the normal "white level with horizontal sync pulses" and releases the
LCNTR reset. At the end of the VSYNC routine, the number of blank lines to the
start of the live display is determined from the system variable MARGIN
(50/60HZ). Then the NMI generator is turned on and the CPU registers are
switched back to the application task.
2. While
the CPU executes the application code, the CPU is interrupted every 64 us by
the NMI generator at the same time the ULA generates a horizontal sync pulse.
The NMI routine increments a blank line counter in A' and returns if there is
more time left for application code execution. When the blank line counter is
incremented to zero the NMI routine turns off the NMI generator and switches to
the VIDEO DISPLAY routine through a pointer in the IX register.
3. The
video display routine sets up the display file pointer, the row and line
counters, enables INT and JP(HL) to the start of DFILE + 32K. Each character in
the DFILE is interpreted as a NOP instruction except the N/L character, which
terminates the line. At the end of each line, the INT service routine updates
the row and line counters and returns to execute the remaining lines. After 192
lines, the video display routine ends by turning on the NMI generator and CPU switches
back to execute application code.
4. As
before, during the top blank lines, the NMI routine counts the number of blank
lines remaining. At the end of the bottom blank lines, the sequence repeats
when the NMI service routine switches back to the VSYNC routine.
In the
ZX80 compatible FAST mode, the CPU executes either the video routine or any
other program but not both, which causes the familiar flicker of the display when
switching between these tasks. When the application program is running, it is
executed using 100% of the available CPU time. Only if the application program
is Stopped (in the command mode) or waiting for a keyboard INPUT, or in PAUSE
mode is the video is displayed. The video hardware is activated in the same way
as the SLOW mode but NMI is always off. In addition, the blank lines at the top
and bottom of the screen are also generated in software making the ZX81 ROM
fully compatible with the ZX80 hardware.
The ZX81
video hardware consists of the Z80 CPU, ROM, RAM and the larger part of the
ZX81 Sinclair Logic Chip (usually called the ULA) as shown in FIG 1 with all
relevant connections including the isolation resistors R. For simplicity only
the 2K RAM is shown. The ULA contains a 6.5 MHz crystal oscillator and a
frequency divider, which generates horizontal sync pulses at the video output
and NMI pulses on the NMI output. The HSYNC and the NMI outputs can be
controlled with the following I/O operations.
1. OUT FD,A - turns off the NMI generator2. OUT FE,A - turns on the NMI generator3. IN A,FE - turns off the HSYNC generator (only if NMI is off)4. OUT FF,A - turns on the HSYNC generator
The ULA
video output switches between 3 voltage levels. It is normally at the +5V white
level for blank lines. Characters patterns are displayed as black pixels when
the level is +2.5V . The narrow horizontal sync pulses and wide vertical sync
pulses are 0V level as shown in FIG 1 waveform. These logic levels are reduced
with a resistor divider to 1V, 0.5V and 0V (UK/US) at the input of the TV RF
modulator.
white _ _____ _____ _________//__________//____ ____//_____ black _ | |__| |__| | | |<--400us-->| | sync _ |<-------64us------>|<---64us---->| |_____//____| | display line blank blank vert sync blank FIG 1 - VIDEO LEVELS
The
HSYNC pulses are 5 usec wide with 64 usec between HSYNC pulses. The VSYNC is
400 usec wide with 16.6 msec or 20 msec between VSYNC pulses. VSYNC is used to
synchronize the TV vertical oscillator and start the raster scan at the top of
the screen. This occurs when IN A,FE (used for scanning the keyboard) clamps
the video output to the SYNC level. 400us later OUT FF,A releases SYNC to
enable the 64 us HSYNC pulses. The HSYNC pulses continue to be generated
independent of the CPU until the next VSYNC.
The CPU
executes the application code during the blank lines at the top and bottom of
the screen while the NMI generator interrupts the CPU every 64 us and
increments a blank line counter to determine if it is time for the VIDEO
DISPLAY of VSYNC routines.
The
Sinclair ZX81 character display generator consists of the Z80, ROM, RAM and the
larger part of the ZX81 Sinclair Logic Chip (usually called the ULA) as shown
in FIG 2 with all relevant connections including the isolation resistors R. For
simplicity only the 2K RAM is shown.
ULA ROM Z80 2K RAM ________________ _____ _____ _____ VIDEO<-| VSHFTREG <-DATA|-----|DATA |-----|DATA |--R--|DATA | | LINECTR ->A0-2|-----|A0-2 |--R--|A0-2 |-----|A0-2 | | CHRLATCH ->A3-8|-----|A3-8 |--R--|A3-8 |-----|A3-8 | | | |A9-12|-----|A9-13|-----|A9-11| | ROMCS|-----|CE | | INT|-----|A6 | | | |_____| | | | | | RAMCS|-----------------|-----|-----|CE/OE| | A14|-----------------|A14 | |_____| | A15|-----------------|A15 | | WR|-----------------|WR | | RD|-----------------|RD | | M1|-----------------|M1 | | MREQ|-----------------|MREQ | | IORQ|-----------------|IORQ | | NMI|-----------------|NMI | | HALT|-----------------|HALT | |________________| |_____| FIG 2 ZX81 CHARACTER VIDEO DISPLAY CIRCUIT
The
pseudo hires graphics video display generator consists of the Z80 CPU, ROM, RAM
and a large part of the ZX81 Sinclair Logic Chip (usually called the ULA) as
shown in FIG 2 with all relevant connections including the isolation resistors
R. For simplicity only the 2K RAM is shown.
ULA ROM Z80 2K RAM ________________ _____ _____ _____ VIDEO<-| VSHFTREG <-DATA|-----|DATA |-----|DATA |--R--|DATA | | *LINECTR ->A0-2|-----|A0-2 |--R--|A0-2 |-----|A0-2 | | CHRLATCH ->A3-8|-----|A3-8 |--R--|A3-8 |-----|A3-8 | | | |A9-12|-----|A9-13|-----|A9-11| | ROMCS|-----|CE | | *INT|-----|A6 | | | |_____| | | | | | RAMCS|-----------------|-----|-----|CE/OE| | A14|-----------------|A14 | |_____| | A15|-----------------|A15 | | WR|-----------------|WR | | RD|-----------------|RD | | M1|-----------------|M1 | | MREQ|-----------------|MREQ | | IORQ|-----------------|IORQ | | NMI|-----------------|NMI | | HALT|-----------------|HALT | |________________| |_____| FIG 3 PSEUDO HIRES GRAPHICS DISPLAY CIRCUIT
The only
difference between pseudo hires and Sinclair character hardware is the *ULA
LCNTR and the use of the *INT input. Most pseudo hires core routines do not use
INT and the ULA LCNTR is reset to zero every horizontal line. The exception is
XTRICATOR which uses INT and makes dual use of the I register in INT mode 2 as
a part of the RST vector address when interrupted at the end of each horizontal
line and at refresh time as a ROM pattern table pointer.
The
portion of the ZX81 hardware required for true hires graphics display consists
of the Z80 CPU, the RAM, the video shift register and the sync circuit of the
ULA as shown in FIG 4 with all relevant connections. Again the 2K SRAM is shown
for simplicity but applies to larger SRAM designs as well. If a 16K RAMPACK is
used, this must be slightly modified, as will be shown later, to enable the
data outputs during RFSH time as required for this hires display method.
ULA ROM Z80 2K RAM ________________ _____ _____ _____ VIDEO<-| VSHFTREG <-DATA|-----|DATA |-----|DATA |--R--|DATA | | | |A0-12|-----|A0-15|-----|A0-10| | ROMCS|-----|CE | | | | | | | |_____| | | | | | RAMCE|-----------------|-----|-----|CE/OE| | A14|-----------------|A14 | |_____| | A15|-----------------|A15 | | WR|-----------------|WR | | RD|-----------------|RD | | M1|-----------------|M1 | | MREQ|-----------------|MREQ | | IORQ|-----------------|IORQ | | NMI|-----------------|NMI | | HALT|-----------------|HALT | |________________| |_____| FIG 5 TRUE HIRES GRAPHICS VIDEO DISPLAY CIRCUIT
With the
exception of WRX1K, which creates a miniature hires screen on a 1K ZX81, all
hires programs, need a 6K hires graphics file (HFILE). Suitable RAM for true
hires graphics can be implemented by modifying a standard 16K RAMPACK with a
couple of diodes and a resistor.
The
RAMPACK is modified to enable the data output at RFSH time by cutting the RD
and RFSH lines at the edge connector and installing 2 only 1N34A Germanium
diodes and a 4.7K pull-up resistor. Modify at your own risk!
+5V | [4.7K] 1N34A |connector RD _______|/|____|_____________ RD OF RAMPACK |\| | |connector RFSH _______|/|____| +5V_____ RFSH of RAMPACK |\| 1N34A FIG 5 RAMPACK MODIFICATION FOR TRUE HIRES
All the
Sinclair ZX81 character display hardware shown in FIG 2 is required to generate
a standard screen of 24 lines of 32 characters. The character display starts
when the last blank line at the top of the screen has occurred and the video
routine jumps to the DFILE echo above 32K. The hardware in the ZX81 ULA takes
control when any opcode is executed above 32K (A15 high and M1 low) with data
bit 6 equal to zero. The video data is loaded in these simplified steps:
1. The ULA loads the character code into a address register in the ULA
2. The ULA forces the data lines low.
3. The CPU interprets the byte as a NOP.
4. The ULA generates part of the ROM pattern table address and the Z80 CPU generates the pattern table pointer with the I register.
5. The pattern byte is loaded into the ULA shift register.
One
could say that the Dfile is literally executed with NOPs substituted for each
character code. Each NOP executes in 4 CPU clock cycles at 3.25 MHz or 8 pixels
at 6.5MHz from the ULA video shift register.
<--------CHARACTER 1-----------><--------CHARACTER 2-----------> T STATE <--T1--><--T2--><--T3--><--T4--><--T1--><--T2--><--T3--><--T4--> (ref) ___ 1___2 3___ ___5 ___ ___ ___ ___ CPU CLOCK | |___| |___| |___| |___| |___| |___| |___| |___| _ _______________ _______________ _______________ _______________ A0-A15 _X_____PC________X___I+CHR+ULA___X______PC_______X___I+CHR+ULA___X ________ NOP __________ ________ NOP __________ DATA >---|__CHR___|_____|_ROM DATA_|-----|__CHR___|_____|_ROM DATA_|-- FIG 6 ZX81 CHARACTER DISPLAY TIMING
The detailed sequence of operations for each character byte is shown in FIG 6 and described as follows:
1. Each character code (CHR$) byte in DFILE is addressed by the CPU PC, on the rising edge T2 data is loaded from DFILE into the ULA: bits 0-5 into a 6 bit ULA address latch while bit 7 is loaded into 1 bit ULA video invert latch
2. On the falling edge of T2, the ULA forces all CPU data lines to zero.
3. On the rising edge of T3 the low data lines are interpreted by the CPU as a NOP instruction.
4. During T3/4, the CPU executes the Refresh cycle and ROM address lines are generated with I register on A9-A15, the ULA 6 bit character code register on A3-A8, and the ULA modulo 8 line counter on line A0-A2.
5. On the falling edge of T4, pattern data from the ROM is loaded into ULA video shift register and 8 video pixels are shifted out at 6.5MHz
6. If character code latch bit 7 (in the ULA) equals 1, the video pixels are inverted.
7. The CPU increments the program counter and fetches the next character code.
8. This repeats until a HALT (Sinclair) is fetched.
9. HALT opcode bit 6 = 1 and is therefore executed (no NOP).
10. The ULA generates a HSYNC pulse independent of the CPU timing and the ULA LCNTR is incremented
11. The halted CPU continues to execute NOPs, incrementing register R and samples the INT input on the rising edge of each T4.
12. When A6, which is hardwired to INT, goes low during refresh time, (bit 6 of the R reg = 0), the Z80 executes the INT routine (below 32K)
13. CPU returns from INT and resumes "execution" of DFILE CHR$ codes.
14.
The process repeats 192 times and then INT routine
returns to the main video routine, turns on the NMI generator and switches back
to the application code.
All the ZX81
character display hardware shown in FIG 2 with some exceptions is required to
generate a standard screen of 192 lines of 32 pseudo hires patterns. The
display starts when the last blank line at the top of the screen has occurred
and the video routine jumps to the 6K DFILE echo above 32K. The hardware in the
ZX81 ULA takes control when any opcode is executed above 32K (A15 high and M1
low) with data bit 6 equal to zero.
The
video data is loaded in five steps:
1. The ULA loads the character code into an address register
2. The ULA forces the data lines low. 3. The CPU interprets the byte as a NOP.
3. The ULA generates part of the ROM pattern table address. The CPU generates the pattern table MSB address with the I register.
4. The quasi hires pattern byte is loaded into the ULA shift register.
Each NOP
executes in 4 CPU clock cycles at 3.25 MHz or 8 pixels at 6.5MHz from the ULA
video shift register.
<--------CHARACTER 1-----------><--------CHARACTER 2-----------> T STATE <--T1--><--T2--><--T3--><--T4--><--T1--><--T2--><--T3--><--T4--> (ref) ___ 1___2 3___ ___5 ___ ___ ___ ___ CPU CLOCK | |___| |___| |___| |___| |___| |___| |___| |___| _ _______________ _______________ _______________ _______________ A0-A15 _X_____PC________X___I+CHR+ULA___X______PC_______X___I+CHR+ULA___X ________ NOP __________ ________ NOP __________ DATA >---|__CHR___|_____|_ROM DATA_|-----|__CHR___|_____|_ROM DATA_|-- FIG 7 SINCLAIR CHARACTER DISPLAY TIMING
The
detailed sequence of operations for each character byte is as follows:
1. Each character code (CHR$) byte in DFILE is addressed by the CPU PC, on the rising edge T2 data is loaded from DFILE into the ULA: bits 0-5 into a 6 bit ULA address latch while bit 7 is loaded into 1 bit ULA video invert latch
2. On the falling edge of T2, the ULA forces all CPU data lines to zero.
3. On the rising edge of T3 the low data lines are interpreted by the CPU as a NOP instruction.
4. During T3/4, the CPU executes the Refresh cycle and ROM address lines are generated with I register on A9-A15, the ULA 6 bit character code register on A3-A8, and zero on line A0-A2.
5. On the falling edge of T4, pattern data from the ROM is loaded into ULA video shift register and 8 video pixels are shifted out at 6.5MHz
6. If character code latch bit 7 (in the ULA) equals 1, video pixels are inverted.
7. The CPU increments the program counter and fetches the next character code.
8. This repeats until a RET fetched which returns to the hires routine.
9. RET opcode bit 6 = 1 and is therefore executed (no NOP)
10. The ULA generates a HSYNC pulse independent of the CPU timing and the ULA LCNTR is incremented but the video software resets the LCNTR to zero.
11. CPU returns from the hires routine and resumes "execution" of DFILE CHR$ codes.
12. The process repeats 192 times and then hires routine ends by turning on the NMI generator and by switching back to the application code.
Although
I will use the WRX hires core routine as an example, the true hires software
developed independently by others is very similar. The true hires display
starts when the last blank line at the top of the screen has occurred, and NMI
jumps via IX to the HR video routine. HR sets up the I and R register pointers
to the hires display file (HFILE), then the HR routine jumps to the LBUF
routine echo above 32K and loads register R and points to the first NOP opcode.
The ULA loads the video shift register when any opcode is executed with A15
high and M1 low and data bit 6 equal to zero.
The
hires data is loaded in 3 steps:
1. The CPU executes each of the 4T state NOP instructions.
2. During T3/4 (refresh), the I and R registers appear on the A0-15 lines.
3. The hires byte addressed by I and R is loaded into the ULA shift register.
LBUF
consists 32 NOP opcodes, each executing in 4 CPU clock cycles. During the
second part of the opcode execution, the I and R register address the hires
byte in HFILE which the ULA loads into the video shift register. The ULA
generated ROM address for the pattern table is not used since ROMCS is not
enabled as register I (A8-15) is set up to point to the RAM based HFILE.
<---------HIRESBYTE1-----------><---------HIRESBYTE2-----------> T STATE <--T1--><--T2--><--T3--><--T4--><--T1--><--T2--><--T3--><--T4--> ___ ___ ___ ___ ___ ___ ___ ___ CPU CLOCK | |___| |___| |___| |___| |___| |___| |___| |___| _ _______________ _______________ _______________ _______________ A0-A15 _X______PC_______X______I_+_R____X______PC_______X______I_+_R____X ____________ _________ ____________ _________ DATA >---|_____NOP____|--|__HIRES__|-----|_____NOP____|--|__HIRES__|-- FIG 8 TRUE HIRES DISPLAY TIMING
The
detailed sequence of operations for each HIRES byte is as follows:
1. The first opcode of the LBUF routine, LD R,A is executed.
2. The following 32 NOPs in LBUF are sequentially executed.
3. On the rising edge of T3 of each instruction fetch, the CPU executes the NOP.
4. During T3/4, the address is generated with the R register on A0-7 and the I register on A8-A15.
5. On the falling edge of T4, a hires data byte from HFILE is loaded into ULA video shift register and 8 video pixels are shifted out at 6.5MHz
6. The CPU increments the program counter and the R register and fetches the next NOP and the next hires byte.
7. This process repeats 32 times.
8. The last opcode of LBUF, JP (IX), is executed to return to the HR routine.
9. The ULA generates a horizontal sync pulse.
10. The HLINE routine increment the I/R register pair by 32 and jumps back to the 32 NOP LBUF routine echo above 32K.
11. The process repeats 192 times.
12. The HIRES video routine may call the Sinclair character routine for the bottom line and restores the registers etc to return to the application code.
Like the
other hires routines WRX intercepts the Sinclair video by loading a new video
routine vector in the IX register.
As shown
in TABLE 1 the CPU is multitasking between the video routines and the
application program in 4 blocks of time.
0229 DISPLAY-1 DECREMENT FRAME COUNTER023E DISPLAY-2 CHECK KEYBOARD (START OF VSYNC)0277 OUT FF,A ENDS THE VSYNC PULSE0292 DISPLAY-3 SAVE THE VIDEO POINTER IN IX (0281), RETURN TO APPLICATION
0066 NMI COUNTS BLANK LINES, RETURN TO APPLICATION OR VIA JP (IX) TO 0281
0281 VIDEO-1 - SETUP DISPLAY PARAMETERS, CALL 2B5 (RETURN VIA INT)02B5 DISPLAY-5 - SETUP DISPLAY PARAMETERS, ENABLE INTERRUPT, JP (DFILE)XXXX (DFILE) - EXECUTES HALTs AND FORCED NOPs IN DFILE0038 INT - DECREMENTS ROW/LINES COUNTERS RETURN TO DFILE OR TO 028B0292 DISPLAY-3 - SAVE VIDEO POINTER (028F)
0066 NMI COUNTS BLANK LINES, RETURN TO APPLICATION OR VIA JP (IX) TO 028F 028F VIDEO-2 JP 229 BACK TO FRAME COUNTER in BLOCK 1
The ZX81
video routines follow in fully annotated listings showing more details than IAN
LOGAN ZX81 DISASSEMBLY. Needless to say, I used Dr. Logan’s book extensively
during my research into the ZX81 video code.
NOTE:
Only code that is relevant to video is shown here.
0038 ;INT SERVICE ROUTINE DEC C ;decrement the scan line counter in register C JP NZ 0045 ;go SCAN-LINE : repeats 8 times for each DFILE character row POP HL ;point to the start of next DFILE row DEC B ;decrement the ROW counter in register B RET Z ;return to 028B SET 3,C ;load scan line counter in register C with 08 scan lines 0041 ;WAIT-INT LD R,A ;load value DD into register R EI ;enable INT JP (HL) ;execute the NOPs in DFILE 0045 ;SCAN-LINE POP DE ;discard the return address RET Z ;delay (never returns) JR 0041 ;got WAIT-INT ;---------------------------------------------------------- 0066 ;NMI SERVICE ROUTINE ;Interrupts application program every 64 usec (HSYNC) EX AF,AF' ;retrieve blank line counter in AF' INC A ;next blank line JP M 006D ;RETURN via 006D if AF' = FF (to NMI-EXIT) JR Z 006F ;JR NMI-CONT if last line006D EX AF,AF' ;save blank line counter RET ;return to application or NMI-EXIT 006F ;NMI-CONT EX AF,AF' ;retrieve main register AF PUSH AF ;now save the application program registers PUSH BC PUSH DE PUSH HL LD HL,(DFILE) ;needed only if IX=0281 and SET 7,H ;if DFILE is executed HALT ;1T state synchronization: this HALT is used with special ;hardware connected to the CPU WAIT and HALT lines and is ;released and synchronized on the falling of the NMI pulse 007A ;NMI-EXIT OUT FD,A ;turn off NMI generator JP (IX) ;to VIDEO-1 or VIDEO-2 ;--------------------------------------------------------- 0229 ;DISPLAY-1 LD HL,(FRAMES);get the system variable FRAMES DEC HL ;decrement each frame ..... LD (FRAMES),HL;save the system variable FRAMES 023E ;DISPLAY-2 CALL 02BB ;read the keyboard and load MARGIN with blank lines ..... ;also starts the VSYNC pulse0277 OUT FF,A ;stops the VSYNC pulse LD HL,(DFILE) ;(FAST VIDEO only) - point HL to first HALT for blank lines SET 7,H ;(FAST VIDEO only) - DFILE echo above 32K027E CALL 0292 0281 ;VIDEO-1 ;this vector is saved in register IX at 0292 LD A,R ;delay LD BC,1901 ;set up INT parameters for first HALT at (DFILE) LD A,F5 ;set up R register for first HALT at (DFILE) CALL 2B5 ;continue setup for DFILE display and return via INT028B ;return here from last INT DEC HL ;(FAST VIDEO only) - point HL to last HALT for blank lines CALL 292 ;save VIDEO vector in IX, calculate blank lines, POP regs 028F JP 0229 ;VIDEO-2 ;this vector is saved in register IX at 0292 0292 ;DISPLAY-3 POP IX ;IX=0281 or 028F to vestor to VIDEO-1 or VIDEO-2 LD C,(IY+56) ;load number of blank lines from MARGIN (1F in 60 Hz option) BIT 7,(IY+59) ;test FAST/SLOW bit JR Z,2A9 ;(FAST VIDEO) branches to generate blank lines LD A,C ;C=(MARGIN)=1F for 60 Hz NEG ; INC A ; EX AF,AF'