NOVA1000 (C) 1986 W.RIGTER
A VARIABLE DISPLAY ROUTINE
WITH MULTITASKING FEATURES
NOVA1000 is a 512 byte machine code routine which replaces the SINCLAIR video
driver and provides some powerful new display facilities. These include:
1. Increased horizontal line length with up to 34 characters per line.
2. Increased number of lines with up to 29 lines (in 50Hz mode)
3. No N/L character (CHR$ 118) required to terminate video lines.
4. Sliding display window on memory permits horizontal and vertical scrolling.
5. Rapid switching of Display files facilitates screen animations.
6. Increased execution speed with smaller screen displays for fast action.
7. View contents of large A$ string array directly
In addition to these display features, NOVA1000 includes several new system
utilities such as
1. Repeating keys.
2. 100 Hour clock/timer
3. BASIC line number trace.
A USER JUMPVECTOR allows advanced users to add more short m/c routines or
develop a multitasking system to run several longer programs concurrently.
NOVA is designed to run above RAMTOP. When loaded from tape the NOVA machine
code program is in a 0 REM line and RAND USR 16535 lowers RAMTOP and then
relocates NOVA. The accompanying BASIC program provides an example of using
the various NOVA screen modes and other features. The user program would
normally be combined with the 0 REM line and replace the NOVA BASIC demo.
A copy of the demo program NOVA2005 is found here NOVA2005.p
NOVA DISPLAY - POSITION AND SIZE
The most powerful feature of this program is the ability to create new Video
Display files located anywhere in memory. A variable number of character per
line, a variable number of lines per screen and the starting position (memory
address) of the screen are under program control.
The NOVA video routines create a window on the memory and this window can be
rapidly moved from one location to another by changing the OFFSET parameter.
The height of this window is controlled by the LINES parameter 1 to 28 lines.
Above the window is the STATUS line which displays the TIMER/CLOCK (T/C)
and the TRACE line number.
Below the window the 24th line from D-FILE may be optionally displayed. This
is the BASIC COMMAND/EDIT/INPUT line.
Like the normal screen, certain illegal character codes must be avoided.
These illegal character codes include CHR$64 to 127 and 192 to 256 with
exception of CHR$ 118 (N/L).
The ZX D-FILE display can be viewed without problems and the A$ String
Variable can be used as one large screen or multiple smaller Vfile screens.
The ZX D-FILE can be 1 to 23 lines high and 32 characters side with the 24th
D-FILE edit line optionally shown.
To view a normal D-FILE screen for BASIC listings etc, the screen location
parameter OFFSET is set to 0000. Since the normal expanded display file
contains N/L characters, the line length is 32 characters. The height of the
screen should be set for 23 and the COMMAND line turned on, to view the normal
24th edit line. For faster program execution turn off line 24 and or use fewer
displayed D-FILE lines. Maximum program speed is achieved with 1 displayed line.
The A$ VFILE can be much bigger than the screen display and the display can
be moved like a window over this string array. All normal string functions
can then directly operate on the screen. The Vfile does not require N/L characters
to delimit each displayed line and as a result the lines are 34 characters wide.
In order to view the Variable Array, the screen location parameter OFFST is set
to 1 or more determining the position of the start of the Vfile window with
respect to the start of the variable array, but how do we ensure that no portion
of memory after the end of the array displayed?
This problem of accidentally displaying data beyond the Vfile display is
overcome by the use the Screen OFfseT (SOFT) routine, which tests the length
of the array with the OFFSET value and sets this value to 0000 if the offset
is too large and would result in display of data beyond the end of the array.
In the direct edit mode or as part of a program, the SOFT routine is called
in the form RAND USR 32680 + N where N is the offset.
Horizontal scrolling is achieved by changing OFFSET by +/- 1, vertical
scrolling by changing OFFSET by +/- 34 and screens are paged by changing
OFFSET +/-(34 x LINES)
If the OFFSET parameter is poked DIRECTLY to point to any other part of
memory (ie above 32k) then the user has to ensure that this memory to be
viewed is free of illegal character codes.
The parameter LINES holds the number of lines between the top status line
and the bottom command line in the range of 1 to 26.
The normal screen or D—FILE has only 24 lines of characters that can be
viewed and any attempt to poke more into LINES may result in a system crash.
When viewing less than 22 lines, the SLOW MODE execution of BASIC and M/C
speed up inversely proportional to the number of viewable lines on the screen.
The maximum speed is attained when the value of LINES is 1 and TRACE is off
Finally the number of characters per line can be varied by inserting a N/L
character in the line. However with N/L’s scrolling is more difficult, for
example the vertical scroll must be controlled by adjusting the OFFSET with
respect to the next N/L character or 34 characters whichever is less.
The timer routine operates directly on 8 digits plus 3 : delimiters in the
STATUS line. The routine increments the least significant digits (1/60 sec per
tick) once per frame. At 59 ticks the LSD change to zero and increments the
Second digits, which at 59+1 seconds increments Minutes, which at 59+1 minutes
increments Hours up to 99 hours. A 12 or 24 hr clock can be implemented with
a short BASIC routine which resets the hours at 13hrs to 1hr or at 24hrs to
0 hr respectively.
The timer and in fact the entire status line can be transferred to the COMVAR
variable as a 32 character string with RAND USER 32677. Conversely the
COMVAR contents can be transferred to the status line with RAND USR 32674
The Communication Variable (COMVAR)is a string variable with a user defined name.
COMVAR is initialized with DIM S$(RAND USR 32671) to 32 characters and a copy of
the name, saved in the ATFR transfer byte is used to later find the variable.
The first 11 characters correspond to the TIMER/CLOCK digits and this is how the
TIMER is set up:
LET S$(1 TO 12) = ”00:00:00:00”
RAND USR 32674
To read the timer and compare against alarms, etc. you can use a string function
IF S$(USR 32761 + 1 TO 11) > “10:11:12:13” THEN GOTO ALARM1
THE NOVA FLAG
The first 3 bits in the FLAG byte at location 32625 can be poked to start and
stop various NOVA features.
The TRACE of BASIC lines numbers is a nice debug feature, which can tell you
where the BASIC program spends most of its time. FLAG Bit 0 = 1 turns on the
Repeat key causes multiple key entries when held down. This is not exactly a
typomatic routine so the speed depends on the calling program and number of
lines displayed. Still I have found it useful when a key must be recognized.
REPEAT applies to the entire keyboard. FLAG bit 1 = 1 turns on REPEAT keys.
In some cases, it is desirable to control the visibility of the bottom command
line. For example, turning off the command line speeds up program execution.
FLAG bit 2 = 1 turns the COMMAND LINE on.
These are the values that may be poked into 32625
(0) trace off, repeat off, command line off
(1) trace on , repeat off, command line off
(2) trace off, repeat on , command line off
(3) trace on , repeat on , command line off
(4) trace off, repeat off, command line on
(5) and so on to 7
The Line byte is at 32626. This byte controls the number of display
lines and therefore the speed of user BASIC or M/C programs.
It is up to five times faster than the SLOW mode and 80% as fast as the
normal video FAST mode if the number of lines is reduced to 1 and
FLAG is set to zero.
EXIT TO ZX BASIC
Exit to normal ZX video by using FAST, SLOW, SAVE, LOAD or PAUSE xxx in
a BASIC program line. When in the EDIT mode while NOVA is running EXIT to
ZX video by entering a dummy program line (e.g. 1 , N/L)
Note: It is important to remember that the NOVA timer/clock timer does not
run in when returning to ZX Video.
The user vector is a three byte address starting at 32631. Location 32631 is
initially set to C9 (RET) but can be set to JP xxxx a short user routine
which must end with RET. If the JP instruction is poked always start with the
address (32632 – LSB, 32633 – MSB before poking the C3 JP code into 32631.
MULTITASKING MACHINE CODE PROGRAMS
For advanced programmers NOVA can be revised and extended with additional
Machine Code routines. The NOVA video routine is called 120 times per second
by the NMI service routine and this provides a means to insert user routines
which run concurrently with NOVA and any other basic or M/L programs.
The user may provide 2 types of M/C routines to run concurrently with NOVA
The first type is a SHORT M/C ROUTINE and it is executed as part of the
program but must RETURN before NOVA itself returns to the BASIC (or MC)
The second type is the LONG M/C PROGRAM and this program is alternating with
the main program 60 times per second, using up 50% of the available CPU time.
SHORT USER M/C ROUTINE
The jump vector at 32631 is provided so that NOVA may be expanded to include
user supplied routines. This may take the form of a simple and short program,
which is terminated with a RET instruction. It must execute in the time
between the end of the vertical sync routine and the beginning of the active
During this time, the trace routine is also executed if enabled.
Failure to observe the time limitation may return the system to the normal
screen or sometimes cause a system crash. As pointed out, some more time is
available if the TRACE is never on at the same time as the user routine.
It is recommended that the FLAG bit 4 is tested to make a conditional
RETURN Z if FLAG bit 4 is not enabled and in this way the user and TRACE
Routine can be simultaneously controlled using POKE 32625,n or LD ($7F71),n
What can we do with such a short routine?
1. PRINTER SPOOLER - the contents of a text file may send to the printer
the current foreground program is executing.
2. Sensors may be scanned as part of a background home control or alarm
3. Voice synthesizer may be loaded with phoneme data while displaying
characters on the screen.
4. Joystick port can be read and characters entered as if keys were pressed.
5. TIMER/CLOCK and REPEAT KEY are examples of the SHORT M/C ROUTINE.
Despite the limits of available time, a SHORT M/C ROUTINE can do a lot.
LONG USER M/C ROUTINE
The time limitation of the short user routine may be overcome with a special
routine call TASKSWAP, which is itself a short user routine but controls two
or more long programs (tasks). One drawback is the need for separate M/L
stacks to save the register contents of each task waiting to be executed. The
size of the stacks depends on the number of nested CALLS and recursions.
In this version of TASKSWAP the user must reserve the stack space (usually
256 bytes) and pass the start location of the tasks to the task file.
The user can now install a second main program (must be M/L program), which
runs concurrently with the other main program (M/L or Basic) ,NOVA, and any
other short routines. This means that we can run a M/L program which passes
some jobs to a second program ( floating point calculations) but continues
with occasional checks to see if the results are available.
The set up for running alternating tasks is not a trivial problem and
presumes that the user has some knowledge of the operating system as well as
the means to generate his or her own programs.
For serious investigation of ZX multitasking, users should develop their own
utility programs to make this job easier.
A suggested first utility is TASKEDITOR, to start and stop tasks controlled
by the Timer/Clock and to pass data between tasks.
Also required is a WINDOWMANAGER, which transfers data from individual tasks
to the video window associated with that task The natural approach is to
define various starting locations within the viewable array as the start of
windows assign to each task and swap them to the screen as needed.
Details of this are discussed in the section on display size and position.
A refinement would be multiple layered windows on one screen each with it’s
own priority, size and position which show the viewable data produced by
These and other MULTITASKING UTILITIES have to wait for a future installment.
logging off: WILF R.
POKE 32625,0 TO 15-FLAGS RAND USR 32668 -START NOVA
POKE 32626,1 TO 26-LINES DIM Z$ (USR 32671) -DEFINE COMVAR (B$-Z$)
POKE 32627/28,0 TO 64K-OFFSET RAND USR 32674 -MOVE COMVAR TO STATUS
POKE 32631/3,JP VECTOR (RET) RAND USR 32677 -MOVE STATUS TO COMVAR
POKE 32634/64,”XX..X”-STATUS RAND USR 32680+N -USER FRIENDLY OFFSET
;NOVA SOURCE CODE LISTING
;COMPATIBLE WITH ARTIC ASSEMBLER
;** NEW VIDEO VECTOR **
STRT1 LD IX,VDR ;NEVER CALL VDR DIRECTLY
;** MAIN LOOP **
VDR CALL SDP ;STATUS LINE (RTC)
CALL FRM ;RTC UPDATE
CALL VDP ;VARIABLE LENGTH DFILE OR A$
;CALC BOTTOM BLANK LINES
CALL ZDP ;ZX COMMAND LINE 24 (?)
CALL RTN ;KEY REPEAT(?) AND RETURN TO BASIC
VDR1 CALL SNC ;FRAMES, KEYBOARD, VERTICAL SYNC
LD B,07 ;ALIGN SCREEN
CALL DLY ;VARIABLE DELAY ROUTINE
LD A,EC ;NUMBER OF TOP BLANK LINES
EX AF ;SAVE FOR NMI
CALL TRCE ;BASIC LINE TRACE ROUTINE
CALL USR ;DO USER ROUTINE
LD IX,VDR ;RESTORE VDR JUMP VECTOR
JP 02A4 ;EXIT TO BASIC UNTIL NEXT VDR
;** VARIABLE DELAY ROUTINE **
DLY NOP ;DELAY TIME DEPENDS ON
DLY0 NOP ;REGISTER B AND ENTRY POINT
DLY2 NOP ;
DLY3 NOP ;
DLY1 NOP ;EACH NOP = 4T STATES
DLY4 NOP ;PLUS REG B X 12T + 7T
DLYB DJNZ DLYB
;** VSYNC VIA KEY SCAN **
SNC PUSH AF ;DUMMY REGISTER PUSH TO
PUSH BC ;FORCE RETURN TO VDR (NOT BASIC)
JP 0229 ;FRAMES, KEYBOARD AND VSYNC
RTN LD A,(FLAG) ;CHECK FLAG
BIT 1,A ;FOR REPEAT BIT 1 SET
JR Z RTN1 ;EXIT IS NO REPEAT
XOR A ;REPEAT SET SO
LD (4027),A ;RESET DEBOUNCE SYSVAR
RTN1 POP IX ;SAVE RETURN ADDRESS IN REG IX
JP 02A2 ;START NMI AND RETURN TO BASIC
;** TOP OF DISPLAY SCREEM **
SDP LD B,02 ;SYNCHRONIZE WITH DISPLAY
CALL DLY ;
LD HL,RTCL ;POINT TO THE STATUS LINE
JR ZDP1 ;AND DISPLAY IT
;** MIDDLE OF DISPLAY SCREEM **
VDP LD B,29 ;SYNCRONIZE DISPLAY
CALL DLY1 ;
LD DE,(OFFST) ;FIND THE START OF THE MAIN DISPLAY
LD A,E ;IF OFFSET IS ZERO,
OR D ;
JR Z VDP1 ;THEN DISPLAY D-FILE
LD HL,(4010) ;ELSE FIND START OF VARIABLES
ADD HL,DE ;ADD THE OFFSET
LD DE,0005 ;ADD A$ HEADER LENGTH
JR VDP2 ;AND DISPLAY VFILE
VDP1 LD HL,(400C) ;LOAD DFILE START
ADD HL,DE ;DELAY
LD DE,0001 ;SKIP LEADING N/L
JR NZ VDP2 ;DELAY
VDP2 ADD HL,DE ;TRUE START OF DISPLAY
LD A,(LINES) ;CALCULATE NUMBER OF LINES
AND 1F ;
LD B,A ;SAVE IN B
RLCA ;CALCULATE BALNK LINES
ADD A,3B ;
EX AF ;SAVE IN AF’ FOR NMI
LD C,08 ;
JR ZDP2 ;GO DISPLAY MAIN SCREEN ALREADY
;** BOTTOM OF DISPLAY SCREEN **
ZDP LD B,73 ;VSYNC DELAY
CALL DLY5 ;
LD A,(FLAG) ;DISPLAY ZX COMMAND LINE 24 (?)
BIT 2,A ;
JR NZ ZDP0 ;YES, GO DISPLAY LINE 24
EX AF ;NO LINE 24 = ADD EXTRA BLANK TIME
SUB 09 ;
EX AF ;SAVE FOR NMI
ZDP0 XOR A ;START OF LINE 24 CAN BE FOUND BY
LD HL,(4010) ;START OF VAR AREA
LD DE,0021 ;32 CHARACTERS PLUS NEWLINE
SBC HL,DE ;SUBTRACT TO POINT TO START OF LINE 24
ZDP1 LD BC,0108 ;ONE ROW OR 8 HORIZONTAL LINES
ZDP2 SET 7,H ;ECHO DISPLAY ABOVE 32K
LD A,DD ;34 CHARACTERS PER LINE OR N/L (HALT WITH A6 INTERRUPT)
JP 0041 ;GO TO ZX INTERRUPT ROUTINE AND RETURN
;CONVERT LINE NUMBER IN (4007) TO DECIMAL
TRCE LD A,(FLAG) ;CHECK FLAG FOR BASIC LINE TRACE ON (?)
BIT 0,A ;
RET Z ;RETURN IF NO TRACE
LD DE,TRCL ;START OF TOP STATUS LINE
LD HL,(4007) ;BASIC LINE NUMBER
LD BC,FC18 ;DIVIDE BY 1000
CALL TR1 ;
LD BC,FF9C ;DIVIDE BY 100
CALL TR1 ;
LD BC,FFF6 ;DIVIDE BY 10
CALL TR1 ;
LD A,1C ;PLUS UNITS
ADD A,L ;
JR TR3 ;
TR1 LD A,1C ;DECIMAL CONVERSION HAS
TR2 ADD HL,BC ;VARIABLE EXECUTION TIME
INC A ;SO RUN WHILE NMI IS ON
JR C TR2 ;SUBTRACT BC UNTIL OVERFLOW
SBC HL,BC ;SUBTRACT ONE LOOP
DEC A ;ADJUST DIGIT
TR3 AND 3F ;LIMIT RESULT
LD (DE),A ;LOAD DIGIT IN TRACE FIELD
INC DE ;NEXT DIGIT
;UPDATE 100 HR TIMER
FRM LD DE,TITL-1 ;POINTER TO TIMER FIELD LEAST SIGNIFICANT DIGIT
LD HL,FRM6+1 ;POINTER TO DIGIT LIMITS AND COLON FLAG
LD B,08 ;8 DIGITS
SCF ;FIXED EXECUTION TIME BETWEEN STATUS LINE AND VDP
FRM1 LD A,(DE) ;GET DIGIT
ADC A,00 ;CARRY FLAG ADDS ONE TO DIGIT
CP (HL) ;CHECK AGAINST LIMIT
CCF ;IF LIMIT THEN RESET DIGIT TO ZERO
JR C FRM2 ;AND CARRY INCREMENTS NEXT DIGIT
LD (DE),A ;ELSE NO CARRY AND LOAD TIMER FIELD WITH DIGIT+1
JR FRM3 ;
FRM2 LD A,1C ;SET DIGIT TO ZERO
LD (DE),A ;LOAD TIMER FIELD WITH ZERO DIGIT
FRM3 DEC DE ;
DEC HL ;
BIT 7,(HL) ;TEST FOR COLON FLAG
JR Z FRM5 ;JR IF NOT COLON
DEC DE ;POINT TO NEXT DIGIT
DEC HL ;POINT TO NEXT LIMIT
FRM5 DJNZ FRM1 ;DO EIGHT TIMES
26 26 80 ; LIMIT 99: (HRS)
22 26 80 ; LIMIT 59: (MIN)
22 26 80 ; LIMIT 59: (SEC)
FRM6 22 26 ; LIMIT 59 (1/60SEC)
;INITIALIZE THE COMVAR STRING ARRAY
DIM1 XOR A ;USING DIM ?$ (USR 32671)
LD HL,(4016) ;USE CH-AD TO POINT TO NAME
LD DE,000F ;IN THE BASIC LINE
SBC HL,DE ;
LD A,(HL) ;GET NAME
LD HL,ATFR ;SAVE NAME IN ATFR
LD (HL),A ;
LD C,20 ;USR MUST RETURN 32
LD B,00 ;AS THE DIMENSION OF THE ARRAY
ULD1 CALL ALD ;LOAD DATA FROM COMVAR TO STATUS LINE
JR DLD2 ;GO TRANSFER
DLD1 CALL ALD ;LOAD DATA FROM STATUS LINE TO COMVAR
EX DE,HL ;
DLD2 LDIR ;ACTUAL TRANSFER
JR ALD1 ;
ALD LD HL,(4016) ;SAVE THE CH-ADD POINTER
EX (SP),HL ;
PUSH HL ;
LD HL,ATFR ;POINT TO COMVAR NAME
CALL 004D ;SET CH-ADD TO COMVAR NAME
CALL 111C ;LOOK UP COMVAR ADDRESS
LD DE,0006 ;SKIP COMVAR HEADER
ADD HL,DE ;
LD DE,RTCL ;POINTER TO TIMER/CLOCK FIELD
LD BC,000B ;LENGTH OF TIMER/CLOCK FIELD
ALD1 POP HL ;RESTORE CH-ADD
LD (4016),HL ;
;CHECK IF OFFSET EXCEEDS VFIEL
SOFT1 LD HL,(4016) ;SAVE CH-ADD
PUSH HL ;
RST 20 ;FIRST CHECK IF A$ EXISTS
LD HL,(4010) ;EXIT TO DFILE IF A$ WAS ERASED
LD A,(HL) ;BECAUSE OF RUN, CLEAR, ETC.
CP C6 ;
JR NZ SOFT2 ;
CALL 1300 ;NOW FIND END OF ARRAY
LD HL,0340 ;ASSUME A FULL SCREEN IS REQUIRED
EX DE,HL ;CAUSE LINES CAN BE ADJUSTED
SBC HL,DE ;ENOUGH ROOM FOR A FULL SCREEN?
JR C SOFT2 ;
CALL 12DD ;EVALUATE THE USR EXPRESSION
JR NC SOFT3 ;AND SAVE IN BC
SOFT2 LD BC,0000 ;SET BC TO ZERO
SOFT3 LD (OFFST),BC ;SAVE IN OFFSET
JR ALD1 ;
JPTBL ;START OF PROGRAM VARIABLE AREA
SPARE "12345" ;SPARE BYTES
FLAG 04 ;FLAG CONTROLS FEATURES (eg COMMAND LINE on)
LINES 18 ;NUMBER OF DISPLAYED LINES
OFFST 00 ;OFFSET FROM START OF A$ VARIABLE
00 ;OR “0000” IS DFILE
USR RET ;3 BYTE USER CALL TO SHORT ROUTINE
00 ;MUST RETURN BEFORE TIME IS UP
ATFR "Z$" ;NAME OF COMVAR (TRANSFERS DATA TO LINE 1)
RTCL "00:00:00:00" ;THESE THREE FIELDS MAKE UP STATUS LINE 1
TITL " NOVA 1000 V1.0";
TRCL " <" ;
;JUMP TABLE FOR NOVA ROUTINES
STRT JP STRT1 ;ACTIVATE NOVA VIDEO ROUTINE
DIM JP DIM1 ;INITIALIZE COMVAR NAME
ULD JP ULD1 ;MOVE COMVAR TO STATUS LINE
DLD JP DLD1 ;MOVE STATUS LINE TO COMVAR
SOFT JP SOFT1 ;TEST AND LOAD OFFSET
NOVA BASIC DEMO PROGRAM
1986 – first release of NOVA – minimal documentation
18/04/2005 – NOVA resurrected – full annotated documentation and source program
19/04/2005 – EXIT methods added and FRAMES now updates - Thanks to Siegfried Engel