This program is a BASIC loader and menu shell for a machine code drawing application called “DRAW,” converted from a Spectrum original (published in Your Computer, June 1984) to the Timex/Sinclair 2068. The BASIC sets up system variables via POKE, loads the machine code block at address 30000 (2610 bytes), and enters a tight loop at line 40 that repeatedly calls a machine code routine at USR 31967 to handle user input and drawing. Subroutines at lines 1000–1210 handle saving/loading screen data and overlaying text, while the circle-drawing subroutine at lines 3000–3130 computes a parametric circle in BASIC using SIN/COS, calling USR 31526 to execute each DRAW step in machine code. Line 9000 provides a SAVE routine to re-save both the BASIC loader and the machine code block.
Program Structure
The program is organised as a thin BASIC shell around a substantial machine code block. Execution flows as follows:
- Lines 10–30: Initialisation — set border/paper/ink via POKEs to system variables,
CLEAR 29999to protect the machine code area, thenLOAD "DRAW" CODEto bring in 2610 bytes at address 30000. - Line 30:
RANDOMIZE USR 30017— one-shot machine code initialisation entry point. - Line 40:
GO SUB USR 31967: GO TO 40— the main event loop; the machine code routine handles input and calls back into BASIC subroutines as needed. - Lines 1000–1210: BASIC subroutines for saving a screenshot (
SAVE … SCREEN$), loading a screenshot, and printing text onto the drawing. - Lines 3000–3130: A parametric circle-drawing subroutine, selectable with or without recentring (flag
F). - Line 9000: Development utility to re-save both the BASIC program and the machine code block.
Machine Code Interface
Three distinct machine code entry points are visible in the BASIC:
| Address | Role |
|---|---|
30017 | Redraw/refresh the screen or reset display state; called after most user-visible operations. |
31967 | Main interactive loop entry — reads joystick/keyboard and dispatches to BASIC subroutines via GO SUB USR. |
31526 | Execute a single DRAW step using delta coordinates held in BASIC variables X, IX, Y, IY; the REM comments on lines 3100 and 3120 document the intended arguments. |
31176 | Render the text string held in A$ onto the screen. |
The pattern RANDOMIZE USR addr is the standard idiom for calling machine code while discarding any return value; the Z80 routine returns 0 in BC, which RANDOMIZE accepts without error.
The GO SUB USR 31967 idiom (line 40) is less common: the machine code routine must itself execute a Z80 RET that maps to a BASIC RETURN, causing the BASIC interpreter to treat execution as if a GOSUB had returned, then GO TO 40 re-enters it. This gives the machine code full control while still allowing it to invoke BASIC subroutines.
Memory Map and POKEs
Lines 10 and 20 configure both Spectrum system variables and custom machine code parameters:
| Address | Value | Purpose |
|---|---|---|
23693 | 7 | System variable ATTR P — permanent attribute (white paper, white ink) |
23694 | 0 | System variable MASK P |
23697 | 0 | System variable P FLAG |
32578 | 128 | Machine code variable: current X position (low byte) |
32579 | 88 | Machine code variable: current Y position |
32582 | 1 | Machine code flag (likely draw colour/mode) |
32583 | 1 | Machine code flag |
23681 | 0 | System variable COORDS X (reset graphics cursor) |
Parametric Circle Subroutine (Lines 3000–3130)
The circle routine demonstrates an interesting BASIC/machine-code hybrid approach. It computes the circle radius from two stored points (current position and an “input” point read from addresses 32578–32581), then steps around the circumference using COS and SIN:
R = SQR((CX-IX)²+(CY-IY)²)— Euclidean radius in screen pixels.- Step size
Sis chosen adaptively:2*INT(INT(PI*SQR(R)+0.5)/2)+2— this rounds up to the nearest even integer, ensuring the loop closes cleanly. It is clamped to 252 to avoid excessively long loops for large circles. - Each vertex is passed to the machine code DRAW routine at USR 31526 as a delta from the previous point (
X-IX,Y-IY), matching the Spectrum’s nativeDRAW dx,dysemantics. - Lines 3000 and 3010 set flag
F: whenF=1(entered via line 3010), the centre is moved to the previous input point before drawing, enabling concentric or chained circles.
Text Overlay (Lines 1200–1210)
Line 1200 uses an INPUT AT 0,0; PAPER 6; INK 0; prompt that dynamically calculates the maximum number of characters that fit on the remaining canvas width: INT((256 - PEEK 32578)/8 / PEEK 23728). Here PEEK 32578 gives the current X pixel position and PEEK 23728 is the system variable DF SZ (lower screen size). The trailing PRINT ; after the INPUT anchors the cursor, and then USR 31176 renders A$ using the machine code text renderer.
The REM A$ at the end of line 1200 is a documentation comment; in Sinclair BASIC a REM following a colon is never executed, so it serves purely as an in-line note to indicate that A$ is the operative variable.
Save/Load Subroutines
Lines 1000 and 1100 validate the filename (1–10 characters) before performing SAVE/LOAD … SCREEN$ operations. The validation loop IF NOT LEN A$ OR LEN A$>10 THEN GO TO 1000 re-prompts on empty or over-length names. After each save or load, RANDOMIZE USR 30017 is called to refresh the display from the machine code side.
Development Save Line
Line 9000 re-saves the full package: SAVE "specdraw" LINE 1 stores the BASIC with auto-run at line 1, followed by SAVE "DRAW" CODE 30000,2610 to dump exactly the 2610-byte machine code block. The subsequent STOP prevents accidental fall-through.
Content
Source Code
1 REM spectrum draw ---- from YOUR COMPUTER June 1984 converted to T/S2068 by F. Chrysler.
10 POKE 23693,7: POKE 23694,0: POKE 23697,0: BORDER 0: CLEAR 29999: LOAD "DRAW"CODE : CLS
20 POKE 32583,1: POKE 32582,1: POKE 23681,0: POKE 32578,128: POKE 32579,88
30 RANDOMIZE USR 30017
40 GO SUB USR 31967: GO TO 40
1000 INPUT "Name ? "; LINE A$: IF NOT LEN A$ OR LEN A$>10 THEN GO TO 1000
1010 SAVE A$ SCREEN$ : RANDOMIZE USR 30017: RETURN
1100 INPUT "Name ? "; LINE A$: LOAD A$SCREEN$ : RANDOMIZE USR 30017: RETURN
1200 RANDOMIZE USR 30017: INPUT AT 0,0; PAPER 6; INK 0;"Text (max. ";INT ((256-PEEK 32578)/8/PEEK 23728);")",, LINE A$: PRINT ;: RANDOMIZE USR 31176: REM A$
1210 RANDOMIZE USR 30017: RETURN
3000 LET F=0: GO TO 3020
3010 LET F=1
3020 LET CX=PEEK 32578: LET CY=PEEK 32579: LET IX=PEEK 32580: LET IY=PEEK 32581: LET R=SQR ((CX-IX)*(CX-IX)+(CY-IY)*(CY-IY))
3030 IF F THEN LET CX=IX: LET CY=IY
3050 LET IX=CX+R: LET IY=CY: POKE 32584,IX-256*INT (IX/255): POKE 32585,128+INT (IX/255): POKE 32586,IY: POKE 32587,128
3060 LET S=2*INT (INT (PI*SQR R+.5)/2)+2: IF S>252 THEN LET S=252
3070 FOR N=0 TO 2*PI STEP PI/S
3080 LET X=INT (.5+CX+R*COS N)
3090 LET Y=INT (.5+CY+R*SIN N)
3100 RANDOMIZE USR 31526: REM X-IX,Y-IY
3110 LET IY=Y: LET IX=X: NEXT N
3120 RANDOMIZE USR 31526: REM CX+R-IX,CY-IY
3130 RANDOMIZE USR 30017: RETURN
9000 SAVE "specdraw" LINE 1: SAVE "DRAW"CODE 30000,2610: STOP
Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.
