In the pages of the ZX81 manual, we find a Basic subroutine to draw a line between any two specified points (see Listing 1). However, I found this routine to be exceedingly slow, especially when I wanted to draw several lines on the screen and had to wait several agonizing minutes to get them. The only solution was to translate the Basic subroutine into Z80 machine language.
This was a fairly straightforward task as the Basic routine did not employ any complex mathematical functions or operations beyond ABS, SGN, subtraction and addition. I was able to find the address of the PLOT/UNPLOT routine in the 8K Basic ROM through the use of Bob Maunder’s book, The ZX81 Companion. To plot a point on the screen, the C and B registers of the processor are loaded with the X and Y coordinates of the point to be plotted, respectively, and a call is made to the PLOT/UNPLOT routine at address BB2h. Location 4030h (16432d), T-ADDR in the system variables listed on p. 173 of the ZX81 manual, controls the color (black or white) of the plotted point, thus making the routine at BB2h selectively either PLOT or UNPLOT. A value of 0 in T-ADDR UNPLOTS, 4Bh PLOTS. This is demonstrated in the section of Line Draw at address 41A0h. I also wanted to make the Line Draw routine very user friendly and completely usable by the person who has either no knowledge of machine language at all or a severe phobia of PEEKs and POKEs. So, I added a short section of code to read out the values of five control variables from the variable storage section of the Basic interpreter (see Listing 3, at addresses 4082h through 40A5h).
To enter the Line Draw program, first type in the short Basic monitor program in Listing 2 (including the big REM statement) that we will use to enter, edit, and review the machine code for Line Draw. After entering the program just as it is shown, type LIST 10 so that the REM statement is scrolled off the screen and will not crash the system. The monitor that I am using here is developed out of my experience in working with the Apple II computer. I had found a monitor program that was easy to use and all around nifty. As a result I decided that the ZX81 should have that type of program, so I wrote a version for the ZX81 in Basic.
Enter the monitor program in Listing 2 and then type RUN. Every line after the prompt symbol (=) starts with a 4-digit hexadecimal address. The next character (the command character) may be either a G, meaning GOTO, or start executing the machine language program at the preceding address; an L, meaning LIST the contents of eight consective memory locations starting at the preceding address; or a :, which deposits the following eight, 2-digit, hexadecimal values, separated by one space, into consecutive memory locations starting with the specified address. Some examples are given in Listing 4. This monitor program will be helpful in entering and debugging machine language programs other than just Line Draw, so you might want to save a version on tape.
Listing 1. Line-Draw Program in Basic.
1000 LET U=C-A
1005 REM U SHOWS HOW MANY STEPS ALONG WE NEED TO GO
1010 LET V=D-B
1015 REM V SHOWS HOW MANY STEPS UP
1020 LET D1X=SGN U
1030 LET D1Y=SGN V
1035 REM (D1X,D1Y) IS A SINGLE STEP IN A DIAGONAL DIRECTION
1040 LET D2X=SGN U
1050 LET D2Y=0
1055 REM (D2X,D2Y) IS A SINGLE STEP LEFT OR RIGHT
1060 LET M=ABS U
1070 LET N=ABS V
1080 IF M>N THEN GOTO 1130
1090 LET D2X=0
1100 LET D2Y=SGN V
1105 REM NOW (D2X,D2Y) IS A SINGLE STEP UP OR DOWN
1110 LET M=ABS V
1120 LET N=ABS U
1130 REM M IS THE LARGER OF ABS U AND ABS V, N IS THE SMALLER
1140 LET S=INT (M/2)
1145 REM WE WANT TO MOVE FROM (A,B) TO (C,D) IN M STEPS USING N UP-DOWN OR RIGHT-LEFT STEPS D2, AND M-N DIAGONAL STEPS D1, DISTRIBUTED AS EVENLY AS POSSIBLE
1150 FOR I=0 TO M
1160 PLOT A,B
1170 LET S=S+N
1180 IF S<M THEN GOTO 1230
1190 LET S=S-M
1200 LET A=A+D1X
1210 LET B=B+D1Y
1215 REM A DIAGONAL STEP
1220 GOTO 1250
1230 LET A=A+D2X
1240 LET B=B+D2Y
1245 REM AN UP-DOWN OR RIGHT-LEFT STEP
1250 NEXT I
1260 RETURN
Listing 1 is from ZX81 BASIC Programming (1st ed., 1980), p. 121, and is provided for use as a subroutine in User written programs only.
Listing 2. A ZX Monitor Program.
1 REM 1234567890ADCDEF1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF
10 IF PEEK 16442=4 THEN CLS
20 LET C=0
30 PRINT
40 PRINT ">>";
50 INPUT A$
60 PRINT A$;
70 FOR A=1 TO 4
80 LET C=C+16**(4-A)*(CODE A$(A TO A)-28)
90 NEXT A
100 LET Q$=A$(5 TO 5)
110 GOTO (Q$=":")*200+(Q$="L")*300+(Q$="G")*400
200 FOR D=6 TO LEN A$ STEP 3
210 POKE INT (C+((D-6)/3)),(16*(CODE A$(D TO D)-28))+CODE A$(D+1 TO D+1)-28
220 NEXT D
230 GOTO 10
300 PRINT "(";C;")"
310 PRINT " ";
320 PRINT A$(1 TO 4);":";
330 FOR F=C TO C+7
340 LET R=PEEK F
350 LET M=INT (R/16)
360 PRINT CHR$ (M+28);CHR$ (R-M*16+28);" ";
370 NEXT F
380 GOTO 10
400 PRINT "(BC=";USR C;")";
410 GOTO 10
Listing 3. Assembly Language Line-Draw Program.
4082H: DD 21 3C 40 LD IX,VA ;LOAD VARIABLES FROM
2A 10 40 LD HL,(VARS) ;AREA IN MEMORY AND
06 05 LD B,05 ;STORE IN SINGLE-BYTE
408BH: 23 INC HL ;RESERVED LOCATIONS
7E LD A,(HL) ;SEE VARIABLE MAP AT
D6 80 SUB 80H ;END OF THIS LISTING
23 INC HL
16 00 LD D,00
4092H: 5E LD E,(HL)
CB FB SET 7,E
4095H: CB 23 SLA E
CB 12 RL D
3D DEC A
20 F9 JR NZ,4095H
DD 72 00 LD (IX+0),D
DD 23 INC IX
40A1H: 23 INC HL
23 INC HL
23 INC HL
23 INC HL
23 INC HL
10 E4 DJNZ,408BH
3A 3C 40 LD A,(VA) ;LET U=C-A
47 LD B,A
3A 3E 40 LD A,(VC)
40AEH: 90 SUB B
32 50 40 LD (VU),A
3A 3D 40 LD A,(VB) ;LET V=D-B
47 LD B,A
3A 3F 40 LD A,(VD)
90 SUB B
32 41 40 LD (VV),A
3A 50 40 LD A,(VU) ;LET D1X=SGN U
40C0H: CD 88 41 CALL 4188H
32 44 40 LD (VD1X),A
32 46 40 LD (VD2X),A ;LET D2X=SGN U
3A 41 40 LD A,(VV) ;LET D1Y=SGN V
CD 88 41 CALL 4188H
32 45 40 LD (VD1Y),A
3E 00 LD A,00 ;LET D2Y=0
32 47 40 LD (VD2Y),A
40D7H: 3A 50 40 LD A,(VU) ;LET M=ABS U
CD 98 41 CALL 4198H
32 42 40 LD (VM),A
3A 41 40 LD A,(VV) ;LET N=ABS V
CD 98 41 CALL 9841H
32 43 40 LD (VN),A
3A 42 40 LD A,(VM) ;IF M>N THEN GOTO LINE
47 LD B,A ;NUMBER 1130
40EDH: 3A 43 40 LD A,(VN)
B8 CP B
38 1C JR C,410FH
3A 41 40 LD A,(VV)
CD 88 41 CALL 4188H
32 47 40 LD (VD2Y),A ;LET D2Y=SGN V
3E 00 LD A,00 ;LET D2X=0
32 46 40 LD (VD2X),A
3A 43 40 LD A,(VN) ;LET M=ABS V
47 LD B,A ;LET N=ABS U
3A 42 40 LD A,(VM) ;(IN EFFECT, EXCHANGE M&N)
32 43 40 LD (VN),A
78 LD A,B
32 42 40 LD (VM),A
410FH: 3A 42 40 LD A,(VM) ;LINE NUMBER 1130
CB 3F SRL A ;LET S=(M/2)
32 48 40 LD (VS),A
3E 00 LD A,00 ;FOR I=0 TO M
32 49 40 LD (VI),A
411CH: ED 4B 3C 40 LD BC,(VA) ;PLOT A,B
ED 43 36 40 LD (COORDS),BC
CD A0 41 CALL 41A0H
3A 43 40 LD A,(VN) ;LET S=S+N
47 LD B,A
3A 48 40 LD A,(VS)
80 ADD A,B
32 48 40 LD (VS),A
3A 42 40 LD A,(VM) ;IF S<M THEN GOTO 1230
47 LD B,A
3A 48 40 LD A,(VS)
B8 CP B
38 1C JR C,4158H
90 SUB B ;LET S=S-M
32 48 40 LD (VS),A
3A 3C 40 LD A,(VA) ;LET A=A+D1X
47 LD B,A
3A 44 40 LD A,(VD1X)
80 ADD A,B
32 3C 40 LD (VA),A
3A 3D 40 LD A,(VB) ;LET B=B+D1Y
47 LD B,A
3A 45 40 LD A,(VD1Y)
80 ADD A,B
32 3D 40 LD (VB),A
18 16 JR 416EH ;GOTO 1250
4158H: 3A 3C 40 LD A,(VA) ;LET A=A+D2X
47 LD B,A
3A 46 40 LD A,(VD2X)
80 ADD A,B
4160H: 32 3C 40 LD (VA),A
3A 3D 40 LD A,(VB) ;LET B=B+D2Y
47 LD B,A
3A 47 40 LD A,(VD2Y)
416AH: 80 ADD A,B
32 3D 40 LD (VB),A
416EH: 3A 42 40 LD A,(VM) ;LINE NUMBER 1250
47 LD B,A ;NEXT I
3A 49 40 LD A,(VI)
3C INC A
32 49 40 LD (VI),A
B8 CP B
DA 1C 41 JP C,411CH
C9 RET ;RETURN TO CALLING PROGRAM
4188H: FE 00 CP 00H ;SIGNUM (SGN) SUBROUTINE
20 01 JR NZ,418DH ;CALL WITH ARGUMENT IN A
C9 RET ;REGISTER
418DH: FA 93 41 JP M,4193H ;LEAVES RESULT IN A REG.
3E 01 LD A,01H
C9 RET
4192H: 3E FF LD A,FFH
C9 RET
4198H: CB 7F BIT 7,A ;ABSOLUTE VALUE (ABS) ROUTINE
28 03 JR Z,419FH ;CALL SAME WAY AS SIGNUM (ABOVE)
2F CPL
C6 01 ADD A,01H
419FH: C9 RET
41A0H: 3A 40 40 LD A,(VPL) ;PLOT ROUTINE
FE 00 CP 00H ;SETS UP COLOR VARIABLE
28 02 JR Z,41A9H ;AND MAKE MONITOR CALL
3E 4B LD A,4BH ;TO BB2H
41A9H: 32 30 40 LD (4030H),A
CD B2 0B CALL BB2H
C9 RET
Now that you know how to use the monitor program, you may proceed to type in the entire listing of Line Draw as shown in Listing 5 using the deposit (:) command. It may take you until midnight, but do not despair because the results will be well worth the time and trouble. When you are finished, type ENTER to exit from the monitor, and SAVE the program at least twice, due to the sometimes unpredictability of the Sinclair SAVE, and type in the additional test lines as shown in Listing 6.
Now comes the moment of truth. Type RUN 1000. If no line appears on your screen almost immediately from the bottom left-hand corner to the top right-hand corner, or worse yet, your system crashes, you must reLOAD from tape, reenter the monitor by typing RUN, and carefully recheck your coding. It is helpful to have a friend to dictate the listing while you look at the screen otherwise you are constantly losing your place. If, however, the program does work successfully, especially the first time, you are eligible for the award for BEST-TYPER-OF-THE-YEAR. Now carefully delete each line of the Basic monitor program (remember never to type LIST, only LIST 10) all the way to line 1060 starting with line 10 by typing in the line number followed by ENTER. Now carefully SAVE this final version at least twice. To use this final version of Line Draw, all you do is set aside five variables (i.e., A-E) in your Basic program and set them to zero with the LET statement at the very top of your program (i.e., line 10). Do not declare any other variables before these five in order that Line Draw will be able to correctly find them. When you wish to plot a line during the course of your program, simply set the first two control variables (A and B) to the X and Y coordinates of the first endpoint of the desired line, the second two variables (C and D) to the coordinates of the second endpoint and the fifth variable (E) to 0 if you want to unplot the line, or to 1 to plot the line. Super simple, super fast. Some additional program examples to try with Line Draw are found in Listing 7.
```pre
Listing 4. Example Lists, GOTOs, and Deposits for ZX Monitor.
))4082L (16514d) List out 8 consecutive memory locations
beginning with address 4082h. As shown,
location 4082h would hold the value AAh,
4083h holds BBh, etc. The list command
also displays the decimal equivalent of
the specified address, in this case 16514d.
This is useful when calling your machine
program from a Basic program using the
USR() function, i.e.,
LET L=USR(16514).
))4082G (BC=0001) GOTO location 4082h and start executing
the machine language program there. The
GOTO command also displays the contents of
the BC register pair in the Z80 processor,
which is what is left in the USR variable
after calling from a Basic program.
))4082:22 33 44 55 Deposit the following 2-digit hexadecimal
values separated by one space into
consecutive memory locations beginning
with the specified address 4082h.
))4082L (16514d) If we now do another LIST command, we can
22 33 44 55 EE FF 00 11 examine our changes.
You are now ready to have some fun on your
own with more examples.
Listing 5. ZX Monitor Deposit Commands for Entering Line-Draw.
4082:DD 21 3C 40 2A 10 40 06
408A:05 23 7E D6 80 23 16 00
4092:5E CB FB CB 23 CB 12 3D
409A:20 F9 DD 72 00 DD 23 23
40A2:23 23 23 10 E4 3A 3C 40
40AA:47 3A 3E 40 90 32 50 40
40B2:3A 3D 40 47 3A 3F 40 90
40BA:32 41 40 3A 50 40 CD 88
40C2:41 32 44 40 32 46 40 3A
40CA:41 40 CD 88 41 32 45 40
40D2:3E 00 32 47 40 3A 50 40
40DA:CD 98 41 32 42 40 3A 41
40E2:40 CD 98 41 32 43 40 3A
40EA:42 40 47 3A 43 40 B8 38
40F2:1C 3A 41 40 CD 88 41 32
40FA:47 40 3E 00 32 46 40 3A
4102:43 40 47 3A 42 40 32 43
410A:40 78 32 42 40 3A 42 40
4112:CB 3F 32 48 40 3E 00 32
411A:49 40 ED 4B 3C 40 ED 43
4122:36 40 CD A0 41 3A 43 40
412A:47 3A 48 40 80 32 48 40
4132:3A 42 40 47 3A 48 40 B8
413A:38 1C 90 32 48 40 3A 3C
4142:40 47 3A 44 40 80 32 3C
414A:40 3A 3D 40 47 3A 45 40
4152:80 32 3D 40 18 16 3A 3C
415A:40 47 3A 46 40 80 32 3C
4162:40 3A 3D 40 47 3A 47 40
416A:80 32 3D 40 3A 42 40 47
4172:3A 49 40 3C 32 49 40 B8
417A:DA 1C 41 C9
4188:FE 00 20 01 C9 FA 93 41
4190:3E 01 C9 3E FF C9
4198:CB 7F 28 03 2F C6 01 C9
41A0:3A 40 40 FE 00 28 02 3E
41A8:4B 32 30 40 CD B2 0B C9
Listing 6. Additional Basic Lines for Testing Line Draw.
1000 LET A 0 (1st X coordinate)
1010 LET B 0 (1st Y coordinate)
1020 LET C 63 (2nd X coordinate)
1030 LET D 43 (2nd Y coordinate)
1040 LET E 1 (Set plot to black)
1050 LET L USR 16514 (Call machine routine to draw line from A,B to C,D)
1060 STOP (Done)
RUN 1000
(A line should immediately appear on the screen from 0,0 to 63,43)
Listing 7. Additional Example Programs for Line-Draw.
10 REM ASTERISK
20 LET A=0
30 LET B=0
40 LET C=0
50 LET D=0
60 LET E=1
70 FOR Y=0 TO 43 STEP 5
80 LET A=0
90 LET B=Y
100 LET C=63
110 LET D=43-Y
120 LET L=USR 16514
130 NEXT Y
140 FOR X=0 TO 63 STEP 5
150 LET A=X
160 LET B=0
170 LET C=63-X
180 LET D=43
190 LET L=USR 16514
200 NEXT X
10 REM SHAPE-DRAW
20 LET A=0
30 LET B=0
40 LET C=0
50 LET D=0
60 LET E=0
70 LET A$=" (SEE EXPLANATORY TEXT) "
80 FOR X=1 TO LEN A$ STEP 10
90 LET A=VAL A$(X TO X+1)
100 LET B=VAL A$(X+2 TO X+3)
110 LET C=VAL A$(X+4 TO X+5)
120 LET D=VAL A$(X+6 TO X+7)
130 LET E=0
140 IF A$(X+8)="P" THEN LET E=1
150 LET L=USR 16514
160 NEXT X
Note: The Shape Draw program draws a shape on the screen given endpoints of lines that define the shape desired coded into the text of the variable A$. For each line to be drawn, the endpoints are specified and PLOT/UNPLOT is selected by the letters P or U respectively. For example, to draw a box on the screen the following data could be put in A$: “00001000P 10001010P 10100010P 00100000P”.
Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.