This program implements a scrolling starfield game on the ZX81/TS1000, using machine code routines embedded in the REM statement at line 1 to perform fast screen scrolling in four directions. The machine code, called via USR at addresses 16514–16588, manipulates the display file directly using Z80 block-move instructions (LDIR/LDDR) and fills vacated rows or columns with spaces (0x80 in ZX81 display format). The BASIC layer handles keyboard input (keys 0, Q, Z, 8 for right, up, down, left scrolling), prints a randomised starfield background, and maintains a status bar at row 22 showing FUEL, COORDS, and ENEMY values. Screen attributes are temporarily modified via POKEs to 16418 (the ZX81’s RAMTOP-adjacent system variable controlling the display) to suppress scroll during the status bar setup.
Program Analysis
Program Structure
The program is organised into four logical sections:
- Line 1 (REM): Houses the Z80 machine code payload — four separate routines for scrolling the display in each cardinal direction.
- Lines 5–60 (Main loop): Calls the initialisation subroutine, then enters a polling loop reading
INKEY$and dispatching to the appropriate machine code routine viaUSR, then calls the star-spawning subroutine. - Lines 100–107 (Initialisation): Fills the screen with spaces and random inverse-dot characters to create a starfield, then draws a status bar at row 22.
- Lines 200–204 (Star spawning): Adds a new star character (
%.— inverse dot) at the leading edge of the scroll direction after each move.
Machine Code Routines
The REM data at line 1 contains four Z80 routines. Their entry points (relative to the start of the display file pointer at address 16396) are called from BASIC via USR:
| Key | Direction | USR Address | Z80 Technique |
|---|---|---|---|
| 0 | Right (scroll left) | 16588 | Uses LD HL,(16396), adjusts with display offset, LDIR block copy, fills right column |
| Q | Up | 16538 | LDDR-based block move, fills bottom row with 0x80 (ZX81 space) |
| Z | Down | 16514 | Loop over rows filling with 0x80, reverse direction copy |
| 8 | Left (scroll right) | 16567 | Similar to right-scroll but using LDIR with adjusted pointer |
Each routine terminates with C9 (RET), returning control cleanly to BASIC. The byte 0x80 is the ZX81’s display-file encoding for a space character, used to blank the newly exposed row or column after scrolling.
Display File Manipulation
The routines reference address 16396 (0x400C), which is the ZX81 system variable D_FILE — the pointer to the display file. By reading this dynamically, the code remains position-independent with respect to where BASIC has placed the display file in RAM. The constant offset 0x0043 (67 decimal) appears in the scroll routines, corresponding to the 33-byte width of a ZX81 display row (32 characters + 1 newline byte), used to advance or retract the HL/DE register pairs between rows.
The scroll loop uses DJNZ with B=0x16 (22 decimal) to iterate over the 22 printable rows of the ZX81 display.
Key BASIC Idioms
LET Z=USR 16588— the return value of the machine code is discarded into a dummy variable; this is a standard ZX81 idiom for callingUSRwithout needing the result.PRINT AT A,INT (RND*32);"%."— prints an inverse dot at a random column to seed the starfield.IF D$="x" THEN ...chains (lines 25–40 and 200–203) replace aSELECT/CASEstructure absent from ZX81 BASIC.- Line 20 uses
LET D$=INKEY$rather than aPAUSE/INKEY$idiom, so the loop runs continuously even with no keypress (D$ becomes empty string, no USR call fires, but a star is still spawned at a random edge via subroutine 200’s guards).
Status Bar and SCROLL Suppression
Lines 104 and 106 POKE address 16418 to values 0 and 2 respectively. Address 16418 is DF_SZ, the display-file size variable that controls how many lines are reserved at the bottom for the lower screen. Setting it to 0 before printing the status bar prevents the display from auto-scrolling, and restoring it to 2 afterwards reinstates normal behaviour.
The status bar (line 105) displays inverse-video text reading FUEL=9872, COORDS:34,19, and ENEMY=5 — these appear to be static placeholder values rather than live game state, suggesting the program is a demonstration or early prototype.
Trailing Bytes in REM
The final bytes of the REM data (1D 1E 1F 20 21 22 23 24 25 1C) fall after the last C9 (RET) instruction and are never executed. They may represent leftover data, a lookup table, or simply padding artefacts from the original assembly process.
Anomalies and Notes
- Lines 300–301 (
SAVE/RUN) are development utilities and are never reached during normal execution. - The starfield spawning in subroutine 200 only adds a star when a key is held; with no keypress,
D$=""matches none of the conditions, so no star is drawn that cycle. This means the star density slowly decreases during inactivity. - The
GOSUB 100at line 5 is called only once, so the starfield is initialised once and then maintained incrementally by subroutine 200.
Content
Source Code
1 REM
Skip to content
Space Background
This file is part of Timex Sinclair Public Domain Library Tape 1002
. Download the collection to get this file.
This program implements a scrolling starfield game on the ZX81/TS1000, using machine code routines embedded in the REM statement at line 1 to perform fast screen scrolling in four directions. The machine code, called via USR at addresses 16514–16588, manipulates the display file directly using Z80 block-move instructions (LDIR/LDDR) and fills vacated rows or columns with spaces (0x80 in ZX81 display format). The BASIC layer handles keyboard input (keys 0, Q, Z, 8 for right, up, down, left scrolling), prints a randomised starfield background, and maintains a status bar at row 22 showing FUEL, COORDS, and ENEMY values. Screen attributes are temporarily modified via POKEs to 16418 (the ZX81’s RAMTOP-adjacent system variable controlling the display) to suppress scroll during the status bar setup.
Program Analysis
Program Structure
The program is organised into four logical sections:
- Line 1 (REM): Houses the Z80 machine code payload — four separate routines for scrolling the display in each cardinal direction.
- Lines 5–60 (Main loop): Calls the initialisation subroutine, then enters a polling loop reading
INKEY$ and dispatching to the appropriate machine code routine via USR, then calls the star-spawning subroutine.
- Lines 100–107 (Initialisation): Fills the screen with spaces and random inverse-dot characters to create a starfield, then draws a status bar at row 22.
- Lines 200–204 (Star spawning): Adds a new star character (
%. — inverse dot) at the leading edge of the scroll direction after each move.
Machine Code Routines
The REM data at line 1 contains four Z80 routines. Their entry points (relative to the start of the display file pointer at address 16396) are called from BASIC via USR:
Key Direction USR Address Z80 Technique 0 Right (scroll left) 16588 Uses LD HL,(16396), adjusts with display offset, LDIR block copy, fills right column Q Up 16538 LDDR-based block move, fills bottom row with 0x80 (ZX81 space) Z Down 16514 Loop over rows filling with 0x80, reverse direction copy 8 Left (scroll right) 16567 Similar to right-scroll but using LDIR with adjusted pointer
Each routine terminates with C9 (RET), returning control cleanly to BASIC. The byte 0x80 is the ZX81’s display-file encoding for a space character, used to blank the newly exposed row or column after scrolling.
Display File Manipulation
The routines reference address 16396 (0x400C), which is the ZX81 system variable D_FILE — the pointer to the display file. By reading this dynamically, the code remains position-independent with respect to where BASIC has placed the display file in RAM. The constant offset 0x0043 (67 decimal) appears in the scroll routines, corresponding to the 33-byte width of a ZX81 display row (32 characters + 1 newline byte), used to advance or retract the HL/DE register pairs between rows.
The scroll loop uses DJNZ with B=0x16 (22 decimal) to iterate over the 22 printable rows of the ZX81 display.
Key BASIC Idioms
LET Z=USR 16588 — the return value of the machine code is discarded into a dummy variable; this is a standard ZX81 idiom for calling USR without needing the result.
PRINT AT A,INT (RND*32);"%." — prints an inverse dot at a random column to seed the starfield.
IF D$="x" THEN ... chains (lines 25–40 and 200–203) replace a SELECT/CASE structure absent from ZX81 BASIC.
- Line 20 uses
LET D$=INKEY$ rather than a PAUSE/INKEY$ idiom, so the loop runs continuously even with no keypress (D$ becomes empty string, no USR call fires, but a star is still spawned at a random edge via subroutine 200’s guards).
Status Bar and SCROLL Suppression
Lines 104 and 106 POKE address 16418 to values 0 and 2 respectively. Address 16418 is DF_SZ, the display-file size variable that controls how many lines are reserved at the bottom for the lower screen. Setting it to 0 before printing the status bar prevents the display from auto-scrolling, and restoring it to 2 afterwards reinstates normal behaviour.
The status bar (line 105) displays inverse-video text reading FUEL=9872, COORDS:34,19, and ENEMY=5 — these appear to be static placeholder values rather than live game state, suggesting the program is a demonstration or early prototype.
Trailing Bytes in REM
The final bytes of the REM data (1D 1E 1F 20 21 22 23 24 25 1C) fall after the last C9 (RET) instruction and are never executed. They may represent leftover data, a lookup table, or simply padding artefacts from the original assembly process.
Anomalies and Notes
- Lines 300–301 (
SAVE / RUN) are development utilities and are never reached during normal execution.
- The starfield spawning in subroutine 200 only adds a star when a key is held; with no keypress,
D$="" matches none of the conditions, so no star is drawn that cycle. This means the star density slowly decreases during inactivity.
- The
GOSUB 100 at line 5 is called only once, so the starfield is initialised once and then maintained incrementally by subroutine 200.
Content
Source Code
1 REM \2A\0C\40\23\E5\11\21\00\19\D1\01\B5\02\ED\B0\EB\06\20\36\80\23\10\FB\C9\2A\10\40\11\43\00\ED\52\E5\11\21\00\ED\52\D1\01\B5\02\ED\B8\EB\06\20\2B\36\80\10\FB\C9\2A\0C\40\06\16\C5\06\20\3E\80\23\4F\7E\71\10\FA\23\C1\10\F1\C9\2A\10\40\11\43\00\ED\52\06\16\C5\06\20\3E\80\2B\4F\7E\71\10\FA\2B\C1\10\F1\C9\1D\1E\1F\20\21\22\23\24\25\1C
5 GOSUB 100
20 LET D$=INKEY$
25 IF D$="0" THEN LET Z=USR 16588
30 IF D$="Q" THEN LET Z=USR 16538
35 IF D$="Z" THEN LET Z=USR 16514
40 IF D$="8" THEN LET Z=USR 16567
50 GOSUB 200
60 GOTO 20
100 FOR A=0 TO 21
101 PRINT AT A,0;"% % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % "
102 PRINT AT A,INT (RND*32);"%."
103 NEXT A
104 POKE 16418,0
105 PRINT AT 22,0;"\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..% %F%U%E%L%=9872% %C%O%O%R%D%S%:34,19% %E%N%E%M%Y%=5% "
106 POKE 16418,2
107 RETURN
200 IF D$="0" THEN PRINT AT INT (RND*22),31;"%."
201 IF D$="Q" THEN PRINT AT 0,INT (RND*32);"%."
202 IF D$="Z" THEN PRINT AT 21,INT (RND*32);"%."
203 IF D$="8" THEN PRINT AT INT (RND*22),0;"%."
204 RETURN
300 SAVE "1009%8"
301 RUN
Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.
People
No people associated with this content.
A
Skip to content
Space Background
This file is part of Timex Sinclair Public Domain Library Tape 1002
. Download the collection to get this file.
This program implements a scrolling starfield game on the ZX81/TS1000, using machine code routines embedded in the REM statement at line 1 to perform fast screen scrolling in four directions. The machine code, called via USR at addresses 16514–16588, manipulates the display file directly using Z80 block-move instructions (LDIR/LDDR) and fills vacated rows or columns with spaces (0x80 in ZX81 display format). The BASIC layer handles keyboard input (keys 0, Q, Z, 8 for right, up, down, left scrolling), prints a randomised starfield background, and maintains a status bar at row 22 showing FUEL, COORDS, and ENEMY values. Screen attributes are temporarily modified via POKEs to 16418 (the ZX81’s RAMTOP-adjacent system variable controlling the display) to suppress scroll during the status bar setup.
Program Analysis
Program Structure
The program is organised into four logical sections:
- Line 1 (REM): Houses the Z80 machine code payload — four separate routines for scrolling the display in each cardinal direction.
- Lines 5–60 (Main loop): Calls the initialisation subroutine, then enters a polling loop reading
INKEY$ and dispatching to the appropriate machine code routine via USR, then calls the star-spawning subroutine.
- Lines 100–107 (Initialisation): Fills the screen with spaces and random inverse-dot characters to create a starfield, then draws a status bar at row 22.
- Lines 200–204 (Star spawning): Adds a new star character (
%. — inverse dot) at the leading edge of the scroll direction after each move.
Machine Code Routines
The REM data at line 1 contains four Z80 routines. Their entry points (relative to the start of the display file pointer at address 16396) are called from BASIC via USR:
Key Direction USR Address Z80 Technique 0 Right (scroll left) 16588 Uses LD HL,(16396), adjusts with display offset, LDIR block copy, fills right column Q Up 16538 LDDR-based block move, fills bottom row with 0x80 (ZX81 space) Z Down 16514 Loop over rows filling with 0x80, reverse direction copy 8 Left (scroll right) 16567 Similar to right-scroll but using LDIR with adjusted pointer
Each routine terminates with C9 (RET), returning control cleanly to BASIC. The byte 0x80 is the ZX81’s display-file encoding for a space character, used to blank the newly exposed row or column after scrolling.
Display File Manipulation
The routines reference address 16396 (0x400C), which is the ZX81 system variable D_FILE — the pointer to the display file. By reading this dynamically, the code remains position-independent with respect to where BASIC has placed the display file in RAM. The constant offset 0x0043 (67 decimal) appears in the scroll routines, corresponding to the 33-byte width of a ZX81 display row (32 characters + 1 newline byte), used to advance or retract the HL/DE register pairs between rows.
The scroll loop uses DJNZ with B=0x16 (22 decimal) to iterate over the 22 printable rows of the ZX81 display.
Key BASIC Idioms
LET Z=USR 16588 — the return value of the machine code is discarded into a dummy variable; this is a standard ZX81 idiom for calling USR without needing the result.
PRINT AT A,INT (RND*32);"%." — prints an inverse dot at a random column to seed the starfield.
IF D$="x" THEN ... chains (lines 25–40 and 200–203) replace a SELECT/CASE structure absent from ZX81 BASIC.
- Line 20 uses
LET D$=INKEY$ rather than a PAUSE/INKEY$ idiom, so the loop runs continuously even with no keypress (D$ becomes empty string, no USR call fires, but a star is still spawned at a random edge via subroutine 200’s guards).
Status Bar and SCROLL Suppression
Lines 104 and 106 POKE address 16418 to values 0 and 2 respectively. Address 16418 is DF_SZ, the display-file size variable that controls how many lines are reserved at the bottom for the lower screen. Setting it to 0 before printing the status bar prevents the display from auto-scrolling, and restoring it to 2 afterwards reinstates normal behaviour.
The status bar (line 105) displays inverse-video text reading FUEL=9872, COORDS:34,19, and ENEMY=5 — these appear to be static placeholder values rather than live game state, suggesting the program is a demonstration or early prototype.
Trailing Bytes in REM
The final bytes of the REM data (1D 1E 1F 20 21 22 23 24 25 1C) fall after the last C9 (RET) instruction and are never executed. They may represent leftover data, a lookup table, or simply padding artefacts from the original assembly process.
Anomalies and Notes
- Lines 300–301 (
SAVE / RUN) are development utilities and are never reached during normal execution.
- The starfield spawning in subroutine 200 only adds a star when a key is held; with no keypress,
D$="" matches none of the conditions, so no star is drawn that cycle. This means the star density slowly decreases during inactivity.
- The
GOSUB 100 at line 5 is called only once, so the starfield is initialised once and then maintained incrementally by subroutine 200.
Content
Source Code
1 REM \2A\0C\40\23\E5\11\21\00\19\D1\01\B5\02\ED\B0\EB\06\20\36\80\23\10\FB\C9\2A\10\40\11\43\00\ED\52\E5\11\21\00\ED\52\D1\01\B5\02\ED\B8\EB\06\20\2B\36\80\10\FB\C9\2A\0C\40\06\16\C5\06\20\3E\80\23\4F\7E\71\10\FA\23\C1\10\F1\C9\2A\10\40\11\43\00\ED\52\06\16\C5\06\20\3E\80\2B\4F\7E\71\10\FA\2B\C1\10\F1\C9\1D\1E\1F\20\21\22\23\24\25\1C
5 GOSUB 100
20 LET D$=INKEY$
25 IF D$="0" THEN LET Z=USR 16588
30 IF D$="Q" THEN LET Z=USR 16538
35 IF D$="Z" THEN LET Z=USR 16514
40 IF D$="8" THEN LET Z=USR 16567
50 GOSUB 200
60 GOTO 20
100 FOR A=0 TO 21
101 PRINT AT A,0;"% % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % "
102 PRINT AT A,INT (RND*32);"%."
103 NEXT A
104 POKE 16418,0
105 PRINT AT 22,0;"\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..% %F%U%E%L%=9872% %C%O%O%R%D%S%:34,19% %E%N%E%M%Y%=5% "
106 POKE 16418,2
107 RETURN
200 IF D$="0" THEN PRINT AT INT (RND*22),31;"%."
201 IF D$="Q" THEN PRINT AT 0,INT (RND*32);"%."
202 IF D$="Z" THEN PRINT AT 21,INT (RND*32);"%."
203 IF D$="8" THEN PRINT AT INT (RND*22),0;"%."
204 RETURN
300 SAVE "1009%8"
301 RUN
Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.
People
No people associated with this content.
C\E5
Skip to content
Space Background
This file is part of Timex Sinclair Public Domain Library Tape 1002
. Download the collection to get this file.
This program implements a scrolling starfield game on the ZX81/TS1000, using machine code routines embedded in the REM statement at line 1 to perform fast screen scrolling in four directions. The machine code, called via USR at addresses 16514–16588, manipulates the display file directly using Z80 block-move instructions (LDIR/LDDR) and fills vacated rows or columns with spaces (0x80 in ZX81 display format). The BASIC layer handles keyboard input (keys 0, Q, Z, 8 for right, up, down, left scrolling), prints a randomised starfield background, and maintains a status bar at row 22 showing FUEL, COORDS, and ENEMY values. Screen attributes are temporarily modified via POKEs to 16418 (the ZX81’s RAMTOP-adjacent system variable controlling the display) to suppress scroll during the status bar setup.
Program Analysis
Program Structure
The program is organised into four logical sections:
- Line 1 (REM): Houses the Z80 machine code payload — four separate routines for scrolling the display in each cardinal direction.
- Lines 5–60 (Main loop): Calls the initialisation subroutine, then enters a polling loop reading
INKEY$ and dispatching to the appropriate machine code routine via USR, then calls the star-spawning subroutine.
- Lines 100–107 (Initialisation): Fills the screen with spaces and random inverse-dot characters to create a starfield, then draws a status bar at row 22.
- Lines 200–204 (Star spawning): Adds a new star character (
%. — inverse dot) at the leading edge of the scroll direction after each move.
Machine Code Routines
The REM data at line 1 contains four Z80 routines. Their entry points (relative to the start of the display file pointer at address 16396) are called from BASIC via USR:
Key Direction USR Address Z80 Technique 0 Right (scroll left) 16588 Uses LD HL,(16396), adjusts with display offset, LDIR block copy, fills right column Q Up 16538 LDDR-based block move, fills bottom row with 0x80 (ZX81 space) Z Down 16514 Loop over rows filling with 0x80, reverse direction copy 8 Left (scroll right) 16567 Similar to right-scroll but using LDIR with adjusted pointer
Each routine terminates with C9 (RET), returning control cleanly to BASIC. The byte 0x80 is the ZX81’s display-file encoding for a space character, used to blank the newly exposed row or column after scrolling.
Display File Manipulation
The routines reference address 16396 (0x400C), which is the ZX81 system variable D_FILE — the pointer to the display file. By reading this dynamically, the code remains position-independent with respect to where BASIC has placed the display file in RAM. The constant offset 0x0043 (67 decimal) appears in the scroll routines, corresponding to the 33-byte width of a ZX81 display row (32 characters + 1 newline byte), used to advance or retract the HL/DE register pairs between rows.
The scroll loop uses DJNZ with B=0x16 (22 decimal) to iterate over the 22 printable rows of the ZX81 display.
Key BASIC Idioms
LET Z=USR 16588 — the return value of the machine code is discarded into a dummy variable; this is a standard ZX81 idiom for calling USR without needing the result.
PRINT AT A,INT (RND*32);"%." — prints an inverse dot at a random column to seed the starfield.
IF D$="x" THEN ... chains (lines 25–40 and 200–203) replace a SELECT/CASE structure absent from ZX81 BASIC.
- Line 20 uses
LET D$=INKEY$ rather than a PAUSE/INKEY$ idiom, so the loop runs continuously even with no keypress (D$ becomes empty string, no USR call fires, but a star is still spawned at a random edge via subroutine 200’s guards).
Status Bar and SCROLL Suppression
Lines 104 and 106 POKE address 16418 to values 0 and 2 respectively. Address 16418 is DF_SZ, the display-file size variable that controls how many lines are reserved at the bottom for the lower screen. Setting it to 0 before printing the status bar prevents the display from auto-scrolling, and restoring it to 2 afterwards reinstates normal behaviour.
The status bar (line 105) displays inverse-video text reading FUEL=9872, COORDS:34,19, and ENEMY=5 — these appear to be static placeholder values rather than live game state, suggesting the program is a demonstration or early prototype.
Trailing Bytes in REM
The final bytes of the REM data (1D 1E 1F 20 21 22 23 24 25 1C) fall after the last C9 (RET) instruction and are never executed. They may represent leftover data, a lookup table, or simply padding artefacts from the original assembly process.
Anomalies and Notes
- Lines 300–301 (
SAVE / RUN) are development utilities and are never reached during normal execution.
- The starfield spawning in subroutine 200 only adds a star when a key is held; with no keypress,
D$="" matches none of the conditions, so no star is drawn that cycle. This means the star density slowly decreases during inactivity.
- The
GOSUB 100 at line 5 is called only once, so the starfield is initialised once and then maintained incrementally by subroutine 200.
Content
Source Code
1 REM \2A\0C\40\23\E5\11\21\00\19\D1\01\B5\02\ED\B0\EB\06\20\36\80\23\10\FB\C9\2A\10\40\11\43\00\ED\52\E5\11\21\00\ED\52\D1\01\B5\02\ED\B8\EB\06\20\2B\36\80\10\FB\C9\2A\0C\40\06\16\C5\06\20\3E\80\23\4F\7E\71\10\FA\23\C1\10\F1\C9\2A\10\40\11\43\00\ED\52\06\16\C5\06\20\3E\80\2B\4F\7E\71\10\FA\2B\C1\10\F1\C9\1D\1E\1F\20\21\22\23\24\25\1C
5 GOSUB 100
20 LET D$=INKEY$
25 IF D$="0" THEN LET Z=USR 16588
30 IF D$="Q" THEN LET Z=USR 16538
35 IF D$="Z" THEN LET Z=USR 16514
40 IF D$="8" THEN LET Z=USR 16567
50 GOSUB 200
60 GOTO 20
100 FOR A=0 TO 21
101 PRINT AT A,0;"% % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % "
102 PRINT AT A,INT (RND*32);"%."
103 NEXT A
104 POKE 16418,0
105 PRINT AT 22,0;"\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..% %F%U%E%L%=9872% %C%O%O%R%D%S%:34,19% %E%N%E%M%Y%=5% "
106 POKE 16418,2
107 RETURN
200 IF D$="0" THEN PRINT AT INT (RND*22),31;"%."
201 IF D$="Q" THEN PRINT AT 0,INT (RND*32);"%."
202 IF D$="Z" THEN PRINT AT 21,INT (RND*32);"%."
203 IF D$="8" THEN PRINT AT INT (RND*22),0;"%."
204 RETURN
300 SAVE "1009%8"
301 RUN
Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.
People
No people associated with this content.
\D1 itemtype='https://schema.org/Blog' itemscope='itemscope' class="wp-singular computer_media-template-default single single-computer_media postid-57149 wp-custom-logo wp-embed-responsive wp-theme-astra wp-child-theme-astra-child ast-desktop ast-separate-container ast-left-sidebar astra-4.12.5 group-blog ast-blog-single-style-1 ast-custom-post-type ast-single-post ast-inherit-site-logo-transparent ast-hfb-header ast-full-width-primary-header ast-box-layout ast-normal-title-enabled astra-addon-4.12.4"\B5
Skip to content
Space Background
This file is part of Timex Sinclair Public Domain Library Tape 1002
. Download the collection to get this file.
This program implements a scrolling starfield game on the ZX81/TS1000, using machine code routines embedded in the REM statement at line 1 to perform fast screen scrolling in four directions. The machine code, called via USR at addresses 16514–16588, manipulates the display file directly using Z80 block-move instructions (LDIR/LDDR) and fills vacated rows or columns with spaces (0x80 in ZX81 display format). The BASIC layer handles keyboard input (keys 0, Q, Z, 8 for right, up, down, left scrolling), prints a randomised starfield background, and maintains a status bar at row 22 showing FUEL, COORDS, and ENEMY values. Screen attributes are temporarily modified via POKEs to 16418 (the ZX81’s RAMTOP-adjacent system variable controlling the display) to suppress scroll during the status bar setup.
Program Analysis
Program Structure
The program is organised into four logical sections:
- Line 1 (REM): Houses the Z80 machine code payload — four separate routines for scrolling the display in each cardinal direction.
- Lines 5–60 (Main loop): Calls the initialisation subroutine, then enters a polling loop reading
INKEY$ and dispatching to the appropriate machine code routine via USR, then calls the star-spawning subroutine.
- Lines 100–107 (Initialisation): Fills the screen with spaces and random inverse-dot characters to create a starfield, then draws a status bar at row 22.
- Lines 200–204 (Star spawning): Adds a new star character (
%. — inverse dot) at the leading edge of the scroll direction after each move.
Machine Code Routines
The REM data at line 1 contains four Z80 routines. Their entry points (relative to the start of the display file pointer at address 16396) are called from BASIC via USR:
Key Direction USR Address Z80 Technique 0 Right (scroll left) 16588 Uses LD HL,(16396), adjusts with display offset, LDIR block copy, fills right column Q Up 16538 LDDR-based block move, fills bottom row with 0x80 (ZX81 space) Z Down 16514 Loop over rows filling with 0x80, reverse direction copy 8 Left (scroll right) 16567 Similar to right-scroll but using LDIR with adjusted pointer
Each routine terminates with C9 (RET), returning control cleanly to BASIC. The byte 0x80 is the ZX81’s display-file encoding for a space character, used to blank the newly exposed row or column after scrolling.
Display File Manipulation
The routines reference address 16396 (0x400C), which is the ZX81 system variable D_FILE — the pointer to the display file. By reading this dynamically, the code remains position-independent with respect to where BASIC has placed the display file in RAM. The constant offset 0x0043 (67 decimal) appears in the scroll routines, corresponding to the 33-byte width of a ZX81 display row (32 characters + 1 newline byte), used to advance or retract the HL/DE register pairs between rows.
The scroll loop uses DJNZ with B=0x16 (22 decimal) to iterate over the 22 printable rows of the ZX81 display.
Key BASIC Idioms
LET Z=USR 16588 — the return value of the machine code is discarded into a dummy variable; this is a standard ZX81 idiom for calling USR without needing the result.
PRINT AT A,INT (RND*32);"%." — prints an inverse dot at a random column to seed the starfield.
IF D$="x" THEN ... chains (lines 25–40 and 200–203) replace a SELECT/CASE structure absent from ZX81 BASIC.
- Line 20 uses
LET D$=INKEY$ rather than a PAUSE/INKEY$ idiom, so the loop runs continuously even with no keypress (D$ becomes empty string, no USR call fires, but a star is still spawned at a random edge via subroutine 200’s guards).
Status Bar and SCROLL Suppression
Lines 104 and 106 POKE address 16418 to values 0 and 2 respectively. Address 16418 is DF_SZ, the display-file size variable that controls how many lines are reserved at the bottom for the lower screen. Setting it to 0 before printing the status bar prevents the display from auto-scrolling, and restoring it to 2 afterwards reinstates normal behaviour.
The status bar (line 105) displays inverse-video text reading FUEL=9872, COORDS:34,19, and ENEMY=5 — these appear to be static placeholder values rather than live game state, suggesting the program is a demonstration or early prototype.
Trailing Bytes in REM
The final bytes of the REM data (1D 1E 1F 20 21 22 23 24 25 1C) fall after the last C9 (RET) instruction and are never executed. They may represent leftover data, a lookup table, or simply padding artefacts from the original assembly process.
Anomalies and Notes
- Lines 300–301 (
SAVE / RUN) are development utilities and are never reached during normal execution.
- The starfield spawning in subroutine 200 only adds a star when a key is held; with no keypress,
D$="" matches none of the conditions, so no star is drawn that cycle. This means the star density slowly decreases during inactivity.
- The
GOSUB 100 at line 5 is called only once, so the starfield is initialised once and then maintained incrementally by subroutine 200.
Content
Source Code
1 REM \2A\0C\40\23\E5\11\21\00\19\D1\01\B5\02\ED\B0\EB\06\20\36\80\23\10\FB\C9\2A\10\40\11\43\00\ED\52\E5\11\21\00\ED\52\D1\01\B5\02\ED\B8\EB\06\20\2B\36\80\10\FB\C9\2A\0C\40\06\16\C5\06\20\3E\80\23\4F\7E\71\10\FA\23\C1\10\F1\C9\2A\10\40\11\43\00\ED\52\06\16\C5\06\20\3E\80\2B\4F\7E\71\10\FA\2B\C1\10\F1\C9\1D\1E\1F\20\21\22\23\24\25\1C
5 GOSUB 100
20 LET D$=INKEY$
25 IF D$="0" THEN LET Z=USR 16588
30 IF D$="Q" THEN LET Z=USR 16538
35 IF D$="Z" THEN LET Z=USR 16514
40 IF D$="8" THEN LET Z=USR 16567
50 GOSUB 200
60 GOTO 20
100 FOR A=0 TO 21
101 PRINT AT A,0;"% % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % "
102 PRINT AT A,INT (RND*32);"%."
103 NEXT A
104 POKE 16418,0
105 PRINT AT 22,0;"\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..% %F%U%E%L%=9872% %C%O%O%R%D%S%:34,19% %E%N%E%M%Y%=5% "
106 POKE 16418,2
107 RETURN
200 IF D$="0" THEN PRINT AT INT (RND*22),31;"%."
201 IF D$="Q" THEN PRINT AT 0,INT (RND*32);"%."
202 IF D$="Z" THEN PRINT AT 21,INT (RND*32);"%."
203 IF D$="8" THEN PRINT AT INT (RND*22),0;"%."
204 RETURN
300 SAVE "1009%8"
301 RUN
Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.
People
No people associated with this content.
\ED\B0\EB\FB\C9
Skip to content
Space Background
This file is part of Timex Sinclair Public Domain Library Tape 1002
. Download the collection to get this file.
This program implements a scrolling starfield game on the ZX81/TS1000, using machine code routines embedded in the REM statement at line 1 to perform fast screen scrolling in four directions. The machine code, called via USR at addresses 16514–16588, manipulates the display file directly using Z80 block-move instructions (LDIR/LDDR) and fills vacated rows or columns with spaces (0x80 in ZX81 display format). The BASIC layer handles keyboard input (keys 0, Q, Z, 8 for right, up, down, left scrolling), prints a randomised starfield background, and maintains a status bar at row 22 showing FUEL, COORDS, and ENEMY values. Screen attributes are temporarily modified via POKEs to 16418 (the ZX81’s RAMTOP-adjacent system variable controlling the display) to suppress scroll during the status bar setup.
Program Analysis
Program Structure
The program is organised into four logical sections:
- Line 1 (REM): Houses the Z80 machine code payload — four separate routines for scrolling the display in each cardinal direction.
- Lines 5–60 (Main loop): Calls the initialisation subroutine, then enters a polling loop reading
INKEY$ and dispatching to the appropriate machine code routine via USR, then calls the star-spawning subroutine.
- Lines 100–107 (Initialisation): Fills the screen with spaces and random inverse-dot characters to create a starfield, then draws a status bar at row 22.
- Lines 200–204 (Star spawning): Adds a new star character (
%. — inverse dot) at the leading edge of the scroll direction after each move.
Machine Code Routines
The REM data at line 1 contains four Z80 routines. Their entry points (relative to the start of the display file pointer at address 16396) are called from BASIC via USR:
Key Direction USR Address Z80 Technique 0 Right (scroll left) 16588 Uses LD HL,(16396), adjusts with display offset, LDIR block copy, fills right column Q Up 16538 LDDR-based block move, fills bottom row with 0x80 (ZX81 space) Z Down 16514 Loop over rows filling with 0x80, reverse direction copy 8 Left (scroll right) 16567 Similar to right-scroll but using LDIR with adjusted pointer
Each routine terminates with C9 (RET), returning control cleanly to BASIC. The byte 0x80 is the ZX81’s display-file encoding for a space character, used to blank the newly exposed row or column after scrolling.
Display File Manipulation
The routines reference address 16396 (0x400C), which is the ZX81 system variable D_FILE — the pointer to the display file. By reading this dynamically, the code remains position-independent with respect to where BASIC has placed the display file in RAM. The constant offset 0x0043 (67 decimal) appears in the scroll routines, corresponding to the 33-byte width of a ZX81 display row (32 characters + 1 newline byte), used to advance or retract the HL/DE register pairs between rows.
The scroll loop uses DJNZ with B=0x16 (22 decimal) to iterate over the 22 printable rows of the ZX81 display.
Key BASIC Idioms
LET Z=USR 16588 — the return value of the machine code is discarded into a dummy variable; this is a standard ZX81 idiom for calling USR without needing the result.
PRINT AT A,INT (RND*32);"%." — prints an inverse dot at a random column to seed the starfield.
IF D$="x" THEN ... chains (lines 25–40 and 200–203) replace a SELECT/CASE structure absent from ZX81 BASIC.
- Line 20 uses
LET D$=INKEY$ rather than a PAUSE/INKEY$ idiom, so the loop runs continuously even with no keypress (D$ becomes empty string, no USR call fires, but a star is still spawned at a random edge via subroutine 200’s guards).
Status Bar and SCROLL Suppression
Lines 104 and 106 POKE address 16418 to values 0 and 2 respectively. Address 16418 is DF_SZ, the display-file size variable that controls how many lines are reserved at the bottom for the lower screen. Setting it to 0 before printing the status bar prevents the display from auto-scrolling, and restoring it to 2 afterwards reinstates normal behaviour.
The status bar (line 105) displays inverse-video text reading FUEL=9872, COORDS:34,19, and ENEMY=5 — these appear to be static placeholder values rather than live game state, suggesting the program is a demonstration or early prototype.
Trailing Bytes in REM
The final bytes of the REM data (1D 1E 1F 20 21 22 23 24 25 1C) fall after the last C9 (RET) instruction and are never executed. They may represent leftover data, a lookup table, or simply padding artefacts from the original assembly process.
Anomalies and Notes
- Lines 300–301 (
SAVE / RUN) are development utilities and are never reached during normal execution.
- The starfield spawning in subroutine 200 only adds a star when a key is held; with no keypress,
D$="" matches none of the conditions, so no star is drawn that cycle. This means the star density slowly decreases during inactivity.
- The
GOSUB 100 at line 5 is called only once, so the starfield is initialised once and then maintained incrementally by subroutine 200.
Content
Source Code
1 REM \2A\0C\40\23\E5\11\21\00\19\D1\01\B5\02\ED\B0\EB\06\20\36\80\23\10\FB\C9\2A\10\40\11\43\00\ED\52\E5\11\21\00\ED\52\D1\01\B5\02\ED\B8\EB\06\20\2B\36\80\10\FB\C9\2A\0C\40\06\16\C5\06\20\3E\80\23\4F\7E\71\10\FA\23\C1\10\F1\C9\2A\10\40\11\43\00\ED\52\06\16\C5\06\20\3E\80\2B\4F\7E\71\10\FA\2B\C1\10\F1\C9\1D\1E\1F\20\21\22\23\24\25\1C
5 GOSUB 100
20 LET D$=INKEY$
25 IF D$="0" THEN LET Z=USR 16588
30 IF D$="Q" THEN LET Z=USR 16538
35 IF D$="Z" THEN LET Z=USR 16514
40 IF D$="8" THEN LET Z=USR 16567
50 GOSUB 200
60 GOTO 20
100 FOR A=0 TO 21
101 PRINT AT A,0;"% % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % "
102 PRINT AT A,INT (RND*32);"%."
103 NEXT A
104 POKE 16418,0
105 PRINT AT 22,0;"\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..% %F%U%E%L%=9872% %C%O%O%R%D%S%:34,19% %E%N%E%M%Y%=5% "
106 POKE 16418,2
107 RETURN
200 IF D$="0" THEN PRINT AT INT (RND*22),31;"%."
201 IF D$="Q" THEN PRINT AT 0,INT (RND*32);"%."
202 IF D$="Z" THEN PRINT AT 21,INT (RND*32);"%."
203 IF D$="8" THEN PRINT AT INT (RND*22),0;"%."
204 RETURN
300 SAVE "1009%8"
301 RUN
Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.
People
No people associated with this content.
A
Skip to content
Space Background
This file is part of Timex Sinclair Public Domain Library Tape 1002
. Download the collection to get this file.
This program implements a scrolling starfield game on the ZX81/TS1000, using machine code routines embedded in the REM statement at line 1 to perform fast screen scrolling in four directions. The machine code, called via USR at addresses 16514–16588, manipulates the display file directly using Z80 block-move instructions (LDIR/LDDR) and fills vacated rows or columns with spaces (0x80 in ZX81 display format). The BASIC layer handles keyboard input (keys 0, Q, Z, 8 for right, up, down, left scrolling), prints a randomised starfield background, and maintains a status bar at row 22 showing FUEL, COORDS, and ENEMY values. Screen attributes are temporarily modified via POKEs to 16418 (the ZX81’s RAMTOP-adjacent system variable controlling the display) to suppress scroll during the status bar setup.
Program Analysis
Program Structure
The program is organised into four logical sections:
- Line 1 (REM): Houses the Z80 machine code payload — four separate routines for scrolling the display in each cardinal direction.
- Lines 5–60 (Main loop): Calls the initialisation subroutine, then enters a polling loop reading
INKEY$ and dispatching to the appropriate machine code routine via USR, then calls the star-spawning subroutine.
- Lines 100–107 (Initialisation): Fills the screen with spaces and random inverse-dot characters to create a starfield, then draws a status bar at row 22.
- Lines 200–204 (Star spawning): Adds a new star character (
%. — inverse dot) at the leading edge of the scroll direction after each move.
Machine Code Routines
The REM data at line 1 contains four Z80 routines. Their entry points (relative to the start of the display file pointer at address 16396) are called from BASIC via USR:
Key Direction USR Address Z80 Technique 0 Right (scroll left) 16588 Uses LD HL,(16396), adjusts with display offset, LDIR block copy, fills right column Q Up 16538 LDDR-based block move, fills bottom row with 0x80 (ZX81 space) Z Down 16514 Loop over rows filling with 0x80, reverse direction copy 8 Left (scroll right) 16567 Similar to right-scroll but using LDIR with adjusted pointer
Each routine terminates with C9 (RET), returning control cleanly to BASIC. The byte 0x80 is the ZX81’s display-file encoding for a space character, used to blank the newly exposed row or column after scrolling.
Display File Manipulation
The routines reference address 16396 (0x400C), which is the ZX81 system variable D_FILE — the pointer to the display file. By reading this dynamically, the code remains position-independent with respect to where BASIC has placed the display file in RAM. The constant offset 0x0043 (67 decimal) appears in the scroll routines, corresponding to the 33-byte width of a ZX81 display row (32 characters + 1 newline byte), used to advance or retract the HL/DE register pairs between rows.
The scroll loop uses DJNZ with B=0x16 (22 decimal) to iterate over the 22 printable rows of the ZX81 display.
Key BASIC Idioms
LET Z=USR 16588 — the return value of the machine code is discarded into a dummy variable; this is a standard ZX81 idiom for calling USR without needing the result.
PRINT AT A,INT (RND*32);"%." — prints an inverse dot at a random column to seed the starfield.
IF D$="x" THEN ... chains (lines 25–40 and 200–203) replace a SELECT/CASE structure absent from ZX81 BASIC.
- Line 20 uses
LET D$=INKEY$ rather than a PAUSE/INKEY$ idiom, so the loop runs continuously even with no keypress (D$ becomes empty string, no USR call fires, but a star is still spawned at a random edge via subroutine 200’s guards).
Status Bar and SCROLL Suppression
Lines 104 and 106 POKE address 16418 to values 0 and 2 respectively. Address 16418 is DF_SZ, the display-file size variable that controls how many lines are reserved at the bottom for the lower screen. Setting it to 0 before printing the status bar prevents the display from auto-scrolling, and restoring it to 2 afterwards reinstates normal behaviour.
The status bar (line 105) displays inverse-video text reading FUEL=9872, COORDS:34,19, and ENEMY=5 — these appear to be static placeholder values rather than live game state, suggesting the program is a demonstration or early prototype.
Trailing Bytes in REM
The final bytes of the REM data (1D 1E 1F 20 21 22 23 24 25 1C) fall after the last C9 (RET) instruction and are never executed. They may represent leftover data, a lookup table, or simply padding artefacts from the original assembly process.
Anomalies and Notes
- Lines 300–301 (
SAVE / RUN) are development utilities and are never reached during normal execution.
- The starfield spawning in subroutine 200 only adds a star when a key is held; with no keypress,
D$="" matches none of the conditions, so no star is drawn that cycle. This means the star density slowly decreases during inactivity.
- The
GOSUB 100 at line 5 is called only once, so the starfield is initialised once and then maintained incrementally by subroutine 200.
Content
Source Code
1 REM \2A\0C\40\23\E5\11\21\00\19\D1\01\B5\02\ED\B0\EB\06\20\36\80\23\10\FB\C9\2A\10\40\11\43\00\ED\52\E5\11\21\00\ED\52\D1\01\B5\02\ED\B8\EB\06\20\2B\36\80\10\FB\C9\2A\0C\40\06\16\C5\06\20\3E\80\23\4F\7E\71\10\FA\23\C1\10\F1\C9\2A\10\40\11\43\00\ED\52\06\16\C5\06\20\3E\80\2B\4F\7E\71\10\FA\2B\C1\10\F1\C9\1D\1E\1F\20\21\22\23\24\25\1C
5 GOSUB 100
20 LET D$=INKEY$
25 IF D$="0" THEN LET Z=USR 16588
30 IF D$="Q" THEN LET Z=USR 16538
35 IF D$="Z" THEN LET Z=USR 16514
40 IF D$="8" THEN LET Z=USR 16567
50 GOSUB 200
60 GOTO 20
100 FOR A=0 TO 21
101 PRINT AT A,0;"% % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % "
102 PRINT AT A,INT (RND*32);"%."
103 NEXT A
104 POKE 16418,0
105 PRINT AT 22,0;"\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..% %F%U%E%L%=9872% %C%O%O%R%D%S%:34,19% %E%N%E%M%Y%=5% "
106 POKE 16418,2
107 RETURN
200 IF D$="0" THEN PRINT AT INT (RND*22),31;"%."
201 IF D$="Q" THEN PRINT AT 0,INT (RND*32);"%."
202 IF D$="Z" THEN PRINT AT 21,INT (RND*32);"%."
203 IF D$="8" THEN PRINT AT INT (RND*22),0;"%."
204 RETURN
300 SAVE "1009%8"
301 RUN
Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.
People
No people associated with this content.
\ED\E5
Skip to content
Space Background
This file is part of Timex Sinclair Public Domain Library Tape 1002
. Download the collection to get this file.
This program implements a scrolling starfield game on the ZX81/TS1000, using machine code routines embedded in the REM statement at line 1 to perform fast screen scrolling in four directions. The machine code, called via USR at addresses 16514–16588, manipulates the display file directly using Z80 block-move instructions (LDIR/LDDR) and fills vacated rows or columns with spaces (0x80 in ZX81 display format). The BASIC layer handles keyboard input (keys 0, Q, Z, 8 for right, up, down, left scrolling), prints a randomised starfield background, and maintains a status bar at row 22 showing FUEL, COORDS, and ENEMY values. Screen attributes are temporarily modified via POKEs to 16418 (the ZX81’s RAMTOP-adjacent system variable controlling the display) to suppress scroll during the status bar setup.
Program Analysis
Program Structure
The program is organised into four logical sections:
- Line 1 (REM): Houses the Z80 machine code payload — four separate routines for scrolling the display in each cardinal direction.
- Lines 5–60 (Main loop): Calls the initialisation subroutine, then enters a polling loop reading
INKEY$ and dispatching to the appropriate machine code routine via USR, then calls the star-spawning subroutine.
- Lines 100–107 (Initialisation): Fills the screen with spaces and random inverse-dot characters to create a starfield, then draws a status bar at row 22.
- Lines 200–204 (Star spawning): Adds a new star character (
%. — inverse dot) at the leading edge of the scroll direction after each move.
Machine Code Routines
The REM data at line 1 contains four Z80 routines. Their entry points (relative to the start of the display file pointer at address 16396) are called from BASIC via USR:
Key Direction USR Address Z80 Technique 0 Right (scroll left) 16588 Uses LD HL,(16396), adjusts with display offset, LDIR block copy, fills right column Q Up 16538 LDDR-based block move, fills bottom row with 0x80 (ZX81 space) Z Down 16514 Loop over rows filling with 0x80, reverse direction copy 8 Left (scroll right) 16567 Similar to right-scroll but using LDIR with adjusted pointer
Each routine terminates with C9 (RET), returning control cleanly to BASIC. The byte 0x80 is the ZX81’s display-file encoding for a space character, used to blank the newly exposed row or column after scrolling.
Display File Manipulation
The routines reference address 16396 (0x400C), which is the ZX81 system variable D_FILE — the pointer to the display file. By reading this dynamically, the code remains position-independent with respect to where BASIC has placed the display file in RAM. The constant offset 0x0043 (67 decimal) appears in the scroll routines, corresponding to the 33-byte width of a ZX81 display row (32 characters + 1 newline byte), used to advance or retract the HL/DE register pairs between rows.
The scroll loop uses DJNZ with B=0x16 (22 decimal) to iterate over the 22 printable rows of the ZX81 display.
Key BASIC Idioms
LET Z=USR 16588 — the return value of the machine code is discarded into a dummy variable; this is a standard ZX81 idiom for calling USR without needing the result.
PRINT AT A,INT (RND*32);"%." — prints an inverse dot at a random column to seed the starfield.
IF D$="x" THEN ... chains (lines 25–40 and 200–203) replace a SELECT/CASE structure absent from ZX81 BASIC.
- Line 20 uses
LET D$=INKEY$ rather than a PAUSE/INKEY$ idiom, so the loop runs continuously even with no keypress (D$ becomes empty string, no USR call fires, but a star is still spawned at a random edge via subroutine 200’s guards).
Status Bar and SCROLL Suppression
Lines 104 and 106 POKE address 16418 to values 0 and 2 respectively. Address 16418 is DF_SZ, the display-file size variable that controls how many lines are reserved at the bottom for the lower screen. Setting it to 0 before printing the status bar prevents the display from auto-scrolling, and restoring it to 2 afterwards reinstates normal behaviour.
The status bar (line 105) displays inverse-video text reading FUEL=9872, COORDS:34,19, and ENEMY=5 — these appear to be static placeholder values rather than live game state, suggesting the program is a demonstration or early prototype.
Trailing Bytes in REM
The final bytes of the REM data (1D 1E 1F 20 21 22 23 24 25 1C) fall after the last C9 (RET) instruction and are never executed. They may represent leftover data, a lookup table, or simply padding artefacts from the original assembly process.
Anomalies and Notes
- Lines 300–301 (
SAVE / RUN) are development utilities and are never reached during normal execution.
- The starfield spawning in subroutine 200 only adds a star when a key is held; with no keypress,
D$="" matches none of the conditions, so no star is drawn that cycle. This means the star density slowly decreases during inactivity.
- The
GOSUB 100 at line 5 is called only once, so the starfield is initialised once and then maintained incrementally by subroutine 200.
Content
Source Code
1 REM \2A\0C\40\23\E5\11\21\00\19\D1\01\B5\02\ED\B0\EB\06\20\36\80\23\10\FB\C9\2A\10\40\11\43\00\ED\52\E5\11\21\00\ED\52\D1\01\B5\02\ED\B8\EB\06\20\2B\36\80\10\FB\C9\2A\0C\40\06\16\C5\06\20\3E\80\23\4F\7E\71\10\FA\23\C1\10\F1\C9\2A\10\40\11\43\00\ED\52\06\16\C5\06\20\3E\80\2B\4F\7E\71\10\FA\2B\C1\10\F1\C9\1D\1E\1F\20\21\22\23\24\25\1C
5 GOSUB 100
20 LET D$=INKEY$
25 IF D$="0" THEN LET Z=USR 16588
30 IF D$="Q" THEN LET Z=USR 16538
35 IF D$="Z" THEN LET Z=USR 16514
40 IF D$="8" THEN LET Z=USR 16567
50 GOSUB 200
60 GOTO 20
100 FOR A=0 TO 21
101 PRINT AT A,0;"% % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % "
102 PRINT AT A,INT (RND*32);"%."
103 NEXT A
104 POKE 16418,0
105 PRINT AT 22,0;"\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..% %F%U%E%L%=9872% %C%O%O%R%D%S%:34,19% %E%N%E%M%Y%=5% "
106 POKE 16418,2
107 RETURN
200 IF D$="0" THEN PRINT AT INT (RND*22),31;"%."
201 IF D$="Q" THEN PRINT AT 0,INT (RND*32);"%."
202 IF D$="Z" THEN PRINT AT 21,INT (RND*32);"%."
203 IF D$="8" THEN PRINT AT INT (RND*22),0;"%."
204 RETURN
300 SAVE "1009%8"
301 RUN
Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.
People
No people associated with this content.
\ED\D1 itemtype='https://schema.org/Blog' itemscope='itemscope' class="wp-singular computer_media-template-default single single-computer_media postid-57149 wp-custom-logo wp-embed-responsive wp-theme-astra wp-child-theme-astra-child ast-desktop ast-separate-container ast-left-sidebar astra-4.12.5 group-blog ast-blog-single-style-1 ast-custom-post-type ast-single-post ast-inherit-site-logo-transparent ast-hfb-header ast-full-width-primary-header ast-box-layout ast-normal-title-enabled astra-addon-4.12.4"\B5
Skip to content
Space Background
This file is part of Timex Sinclair Public Domain Library Tape 1002
. Download the collection to get this file.
This program implements a scrolling starfield game on the ZX81/TS1000, using machine code routines embedded in the REM statement at line 1 to perform fast screen scrolling in four directions. The machine code, called via USR at addresses 16514–16588, manipulates the display file directly using Z80 block-move instructions (LDIR/LDDR) and fills vacated rows or columns with spaces (0x80 in ZX81 display format). The BASIC layer handles keyboard input (keys 0, Q, Z, 8 for right, up, down, left scrolling), prints a randomised starfield background, and maintains a status bar at row 22 showing FUEL, COORDS, and ENEMY values. Screen attributes are temporarily modified via POKEs to 16418 (the ZX81’s RAMTOP-adjacent system variable controlling the display) to suppress scroll during the status bar setup.
Program Analysis
Program Structure
The program is organised into four logical sections:
- Line 1 (REM): Houses the Z80 machine code payload — four separate routines for scrolling the display in each cardinal direction.
- Lines 5–60 (Main loop): Calls the initialisation subroutine, then enters a polling loop reading
INKEY$ and dispatching to the appropriate machine code routine via USR, then calls the star-spawning subroutine.
- Lines 100–107 (Initialisation): Fills the screen with spaces and random inverse-dot characters to create a starfield, then draws a status bar at row 22.
- Lines 200–204 (Star spawning): Adds a new star character (
%. — inverse dot) at the leading edge of the scroll direction after each move.
Machine Code Routines
The REM data at line 1 contains four Z80 routines. Their entry points (relative to the start of the display file pointer at address 16396) are called from BASIC via USR:
Key Direction USR Address Z80 Technique 0 Right (scroll left) 16588 Uses LD HL,(16396), adjusts with display offset, LDIR block copy, fills right column Q Up 16538 LDDR-based block move, fills bottom row with 0x80 (ZX81 space) Z Down 16514 Loop over rows filling with 0x80, reverse direction copy 8 Left (scroll right) 16567 Similar to right-scroll but using LDIR with adjusted pointer
Each routine terminates with C9 (RET), returning control cleanly to BASIC. The byte 0x80 is the ZX81’s display-file encoding for a space character, used to blank the newly exposed row or column after scrolling.
Display File Manipulation
The routines reference address 16396 (0x400C), which is the ZX81 system variable D_FILE — the pointer to the display file. By reading this dynamically, the code remains position-independent with respect to where BASIC has placed the display file in RAM. The constant offset 0x0043 (67 decimal) appears in the scroll routines, corresponding to the 33-byte width of a ZX81 display row (32 characters + 1 newline byte), used to advance or retract the HL/DE register pairs between rows.
The scroll loop uses DJNZ with B=0x16 (22 decimal) to iterate over the 22 printable rows of the ZX81 display.
Key BASIC Idioms
LET Z=USR 16588 — the return value of the machine code is discarded into a dummy variable; this is a standard ZX81 idiom for calling USR without needing the result.
PRINT AT A,INT (RND*32);"%." — prints an inverse dot at a random column to seed the starfield.
IF D$="x" THEN ... chains (lines 25–40 and 200–203) replace a SELECT/CASE structure absent from ZX81 BASIC.
- Line 20 uses
LET D$=INKEY$ rather than a PAUSE/INKEY$ idiom, so the loop runs continuously even with no keypress (D$ becomes empty string, no USR call fires, but a star is still spawned at a random edge via subroutine 200’s guards).
Status Bar and SCROLL Suppression
Lines 104 and 106 POKE address 16418 to values 0 and 2 respectively. Address 16418 is DF_SZ, the display-file size variable that controls how many lines are reserved at the bottom for the lower screen. Setting it to 0 before printing the status bar prevents the display from auto-scrolling, and restoring it to 2 afterwards reinstates normal behaviour.
The status bar (line 105) displays inverse-video text reading FUEL=9872, COORDS:34,19, and ENEMY=5 — these appear to be static placeholder values rather than live game state, suggesting the program is a demonstration or early prototype.
Trailing Bytes in REM
The final bytes of the REM data (1D 1E 1F 20 21 22 23 24 25 1C) fall after the last C9 (RET) instruction and are never executed. They may represent leftover data, a lookup table, or simply padding artefacts from the original assembly process.
Anomalies and Notes
- Lines 300–301 (
SAVE / RUN) are development utilities and are never reached during normal execution.
- The starfield spawning in subroutine 200 only adds a star when a key is held; with no keypress,
D$="" matches none of the conditions, so no star is drawn that cycle. This means the star density slowly decreases during inactivity.
- The
GOSUB 100 at line 5 is called only once, so the starfield is initialised once and then maintained incrementally by subroutine 200.
Content
Source Code
1 REM \2A\0C\40\23\E5\11\21\00\19\D1\01\B5\02\ED\B0\EB\06\20\36\80\23\10\FB\C9\2A\10\40\11\43\00\ED\52\E5\11\21\00\ED\52\D1\01\B5\02\ED\B8\EB\06\20\2B\36\80\10\FB\C9\2A\0C\40\06\16\C5\06\20\3E\80\23\4F\7E\71\10\FA\23\C1\10\F1\C9\2A\10\40\11\43\00\ED\52\06\16\C5\06\20\3E\80\2B\4F\7E\71\10\FA\2B\C1\10\F1\C9\1D\1E\1F\20\21\22\23\24\25\1C
5 GOSUB 100
20 LET D$=INKEY$
25 IF D$="0" THEN LET Z=USR 16588
30 IF D$="Q" THEN LET Z=USR 16538
35 IF D$="Z" THEN LET Z=USR 16514
40 IF D$="8" THEN LET Z=USR 16567
50 GOSUB 200
60 GOTO 20
100 FOR A=0 TO 21
101 PRINT AT A,0;"% % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % "
102 PRINT AT A,INT (RND*32);"%."
103 NEXT A
104 POKE 16418,0
105 PRINT AT 22,0;"\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..% %F%U%E%L%=9872% %C%O%O%R%D%S%:34,19% %E%N%E%M%Y%=5% "
106 POKE 16418,2
107 RETURN
200 IF D$="0" THEN PRINT AT INT (RND*22),31;"%."
201 IF D$="Q" THEN PRINT AT 0,INT (RND*32);"%."
202 IF D$="Z" THEN PRINT AT 21,INT (RND*32);"%."
203 IF D$="8" THEN PRINT AT INT (RND*22),0;"%."
204 RETURN
300 SAVE "1009%8"
301 RUN
Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.
People
No people associated with this content.
\ED\B8\EB
Skip to content
Space Background
This file is part of Timex Sinclair Public Domain Library Tape 1002
. Download the collection to get this file.
This program implements a scrolling starfield game on the ZX81/TS1000, using machine code routines embedded in the REM statement at line 1 to perform fast screen scrolling in four directions. The machine code, called via USR at addresses 16514–16588, manipulates the display file directly using Z80 block-move instructions (LDIR/LDDR) and fills vacated rows or columns with spaces (0x80 in ZX81 display format). The BASIC layer handles keyboard input (keys 0, Q, Z, 8 for right, up, down, left scrolling), prints a randomised starfield background, and maintains a status bar at row 22 showing FUEL, COORDS, and ENEMY values. Screen attributes are temporarily modified via POKEs to 16418 (the ZX81’s RAMTOP-adjacent system variable controlling the display) to suppress scroll during the status bar setup.
Program Analysis
Program Structure
The program is organised into four logical sections:
- Line 1 (REM): Houses the Z80 machine code payload — four separate routines for scrolling the display in each cardinal direction.
- Lines 5–60 (Main loop): Calls the initialisation subroutine, then enters a polling loop reading
INKEY$ and dispatching to the appropriate machine code routine via USR, then calls the star-spawning subroutine.
- Lines 100–107 (Initialisation): Fills the screen with spaces and random inverse-dot characters to create a starfield, then draws a status bar at row 22.
- Lines 200–204 (Star spawning): Adds a new star character (
%. — inverse dot) at the leading edge of the scroll direction after each move.
Machine Code Routines
The REM data at line 1 contains four Z80 routines. Their entry points (relative to the start of the display file pointer at address 16396) are called from BASIC via USR:
Key Direction USR Address Z80 Technique 0 Right (scroll left) 16588 Uses LD HL,(16396), adjusts with display offset, LDIR block copy, fills right column Q Up 16538 LDDR-based block move, fills bottom row with 0x80 (ZX81 space) Z Down 16514 Loop over rows filling with 0x80, reverse direction copy 8 Left (scroll right) 16567 Similar to right-scroll but using LDIR with adjusted pointer
Each routine terminates with C9 (RET), returning control cleanly to BASIC. The byte 0x80 is the ZX81’s display-file encoding for a space character, used to blank the newly exposed row or column after scrolling.
Display File Manipulation
The routines reference address 16396 (0x400C), which is the ZX81 system variable D_FILE — the pointer to the display file. By reading this dynamically, the code remains position-independent with respect to where BASIC has placed the display file in RAM. The constant offset 0x0043 (67 decimal) appears in the scroll routines, corresponding to the 33-byte width of a ZX81 display row (32 characters + 1 newline byte), used to advance or retract the HL/DE register pairs between rows.
The scroll loop uses DJNZ with B=0x16 (22 decimal) to iterate over the 22 printable rows of the ZX81 display.
Key BASIC Idioms
LET Z=USR 16588 — the return value of the machine code is discarded into a dummy variable; this is a standard ZX81 idiom for calling USR without needing the result.
PRINT AT A,INT (RND*32);"%." — prints an inverse dot at a random column to seed the starfield.
IF D$="x" THEN ... chains (lines 25–40 and 200–203) replace a SELECT/CASE structure absent from ZX81 BASIC.
- Line 20 uses
LET D$=INKEY$ rather than a PAUSE/INKEY$ idiom, so the loop runs continuously even with no keypress (D$ becomes empty string, no USR call fires, but a star is still spawned at a random edge via subroutine 200’s guards).
Status Bar and SCROLL Suppression
Lines 104 and 106 POKE address 16418 to values 0 and 2 respectively. Address 16418 is DF_SZ, the display-file size variable that controls how many lines are reserved at the bottom for the lower screen. Setting it to 0 before printing the status bar prevents the display from auto-scrolling, and restoring it to 2 afterwards reinstates normal behaviour.
The status bar (line 105) displays inverse-video text reading FUEL=9872, COORDS:34,19, and ENEMY=5 — these appear to be static placeholder values rather than live game state, suggesting the program is a demonstration or early prototype.
Trailing Bytes in REM
The final bytes of the REM data (1D 1E 1F 20 21 22 23 24 25 1C) fall after the last C9 (RET) instruction and are never executed. They may represent leftover data, a lookup table, or simply padding artefacts from the original assembly process.
Anomalies and Notes
- Lines 300–301 (
SAVE / RUN) are development utilities and are never reached during normal execution.
- The starfield spawning in subroutine 200 only adds a star when a key is held; with no keypress,
D$="" matches none of the conditions, so no star is drawn that cycle. This means the star density slowly decreases during inactivity.
- The
GOSUB 100 at line 5 is called only once, so the starfield is initialised once and then maintained incrementally by subroutine 200.
Content
Source Code
1 REM \2A\0C\40\23\E5\11\21\00\19\D1\01\B5\02\ED\B0\EB\06\20\36\80\23\10\FB\C9\2A\10\40\11\43\00\ED\52\E5\11\21\00\ED\52\D1\01\B5\02\ED\B8\EB\06\20\2B\36\80\10\FB\C9\2A\0C\40\06\16\C5\06\20\3E\80\23\4F\7E\71\10\FA\23\C1\10\F1\C9\2A\10\40\11\43\00\ED\52\06\16\C5\06\20\3E\80\2B\4F\7E\71\10\FA\2B\C1\10\F1\C9\1D\1E\1F\20\21\22\23\24\25\1C
5 GOSUB 100
20 LET D$=INKEY$
25 IF D$="0" THEN LET Z=USR 16588
30 IF D$="Q" THEN LET Z=USR 16538
35 IF D$="Z" THEN LET Z=USR 16514
40 IF D$="8" THEN LET Z=USR 16567
50 GOSUB 200
60 GOTO 20
100 FOR A=0 TO 21
101 PRINT AT A,0;"% % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % "
102 PRINT AT A,INT (RND*32);"%."
103 NEXT A
104 POKE 16418,0
105 PRINT AT 22,0;"\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..% %F%U%E%L%=9872% %C%O%O%R%D%S%:34,19% %E%N%E%M%Y%=5% "
106 POKE 16418,2
107 RETURN
200 IF D$="0" THEN PRINT AT INT (RND*22),31;"%."
201 IF D$="Q" THEN PRINT AT 0,INT (RND*32);"%."
202 IF D$="Z" THEN PRINT AT 21,INT (RND*32);"%."
203 IF D$="8" THEN PRINT AT INT (RND*22),0;"%."
204 RETURN
300 SAVE "1009%8"
301 RUN
Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.
People
No people associated with this content.
B\FB\C9
Skip to content
Space Background
This file is part of Timex Sinclair Public Domain Library Tape 1002
. Download the collection to get this file.
This program implements a scrolling starfield game on the ZX81/TS1000, using machine code routines embedded in the REM statement at line 1 to perform fast screen scrolling in four directions. The machine code, called via USR at addresses 16514–16588, manipulates the display file directly using Z80 block-move instructions (LDIR/LDDR) and fills vacated rows or columns with spaces (0x80 in ZX81 display format). The BASIC layer handles keyboard input (keys 0, Q, Z, 8 for right, up, down, left scrolling), prints a randomised starfield background, and maintains a status bar at row 22 showing FUEL, COORDS, and ENEMY values. Screen attributes are temporarily modified via POKEs to 16418 (the ZX81’s RAMTOP-adjacent system variable controlling the display) to suppress scroll during the status bar setup.
Program Analysis
Program Structure
The program is organised into four logical sections:
- Line 1 (REM): Houses the Z80 machine code payload — four separate routines for scrolling the display in each cardinal direction.
- Lines 5–60 (Main loop): Calls the initialisation subroutine, then enters a polling loop reading
INKEY$ and dispatching to the appropriate machine code routine via USR, then calls the star-spawning subroutine.
- Lines 100–107 (Initialisation): Fills the screen with spaces and random inverse-dot characters to create a starfield, then draws a status bar at row 22.
- Lines 200–204 (Star spawning): Adds a new star character (
%. — inverse dot) at the leading edge of the scroll direction after each move.
Machine Code Routines
The REM data at line 1 contains four Z80 routines. Their entry points (relative to the start of the display file pointer at address 16396) are called from BASIC via USR:
Key Direction USR Address Z80 Technique 0 Right (scroll left) 16588 Uses LD HL,(16396), adjusts with display offset, LDIR block copy, fills right column Q Up 16538 LDDR-based block move, fills bottom row with 0x80 (ZX81 space) Z Down 16514 Loop over rows filling with 0x80, reverse direction copy 8 Left (scroll right) 16567 Similar to right-scroll but using LDIR with adjusted pointer
Each routine terminates with C9 (RET), returning control cleanly to BASIC. The byte 0x80 is the ZX81’s display-file encoding for a space character, used to blank the newly exposed row or column after scrolling.
Display File Manipulation
The routines reference address 16396 (0x400C), which is the ZX81 system variable D_FILE — the pointer to the display file. By reading this dynamically, the code remains position-independent with respect to where BASIC has placed the display file in RAM. The constant offset 0x0043 (67 decimal) appears in the scroll routines, corresponding to the 33-byte width of a ZX81 display row (32 characters + 1 newline byte), used to advance or retract the HL/DE register pairs between rows.
The scroll loop uses DJNZ with B=0x16 (22 decimal) to iterate over the 22 printable rows of the ZX81 display.
Key BASIC Idioms
LET Z=USR 16588 — the return value of the machine code is discarded into a dummy variable; this is a standard ZX81 idiom for calling USR without needing the result.
PRINT AT A,INT (RND*32);"%." — prints an inverse dot at a random column to seed the starfield.
IF D$="x" THEN ... chains (lines 25–40 and 200–203) replace a SELECT/CASE structure absent from ZX81 BASIC.
- Line 20 uses
LET D$=INKEY$ rather than a PAUSE/INKEY$ idiom, so the loop runs continuously even with no keypress (D$ becomes empty string, no USR call fires, but a star is still spawned at a random edge via subroutine 200’s guards).
Status Bar and SCROLL Suppression
Lines 104 and 106 POKE address 16418 to values 0 and 2 respectively. Address 16418 is DF_SZ, the display-file size variable that controls how many lines are reserved at the bottom for the lower screen. Setting it to 0 before printing the status bar prevents the display from auto-scrolling, and restoring it to 2 afterwards reinstates normal behaviour.
The status bar (line 105) displays inverse-video text reading FUEL=9872, COORDS:34,19, and ENEMY=5 — these appear to be static placeholder values rather than live game state, suggesting the program is a demonstration or early prototype.
Trailing Bytes in REM
The final bytes of the REM data (1D 1E 1F 20 21 22 23 24 25 1C) fall after the last C9 (RET) instruction and are never executed. They may represent leftover data, a lookup table, or simply padding artefacts from the original assembly process.
Anomalies and Notes
- Lines 300–301 (
SAVE / RUN) are development utilities and are never reached during normal execution.
- The starfield spawning in subroutine 200 only adds a star when a key is held; with no keypress,
D$="" matches none of the conditions, so no star is drawn that cycle. This means the star density slowly decreases during inactivity.
- The
GOSUB 100 at line 5 is called only once, so the starfield is initialised once and then maintained incrementally by subroutine 200.
Content
Source Code
1 REM \2A\0C\40\23\E5\11\21\00\19\D1\01\B5\02\ED\B0\EB\06\20\36\80\23\10\FB\C9\2A\10\40\11\43\00\ED\52\E5\11\21\00\ED\52\D1\01\B5\02\ED\B8\EB\06\20\2B\36\80\10\FB\C9\2A\0C\40\06\16\C5\06\20\3E\80\23\4F\7E\71\10\FA\23\C1\10\F1\C9\2A\10\40\11\43\00\ED\52\06\16\C5\06\20\3E\80\2B\4F\7E\71\10\FA\2B\C1\10\F1\C9\1D\1E\1F\20\21\22\23\24\25\1C
5 GOSUB 100
20 LET D$=INKEY$
25 IF D$="0" THEN LET Z=USR 16588
30 IF D$="Q" THEN LET Z=USR 16538
35 IF D$="Z" THEN LET Z=USR 16514
40 IF D$="8" THEN LET Z=USR 16567
50 GOSUB 200
60 GOTO 20
100 FOR A=0 TO 21
101 PRINT AT A,0;"% % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % "
102 PRINT AT A,INT (RND*32);"%."
103 NEXT A
104 POKE 16418,0
105 PRINT AT 22,0;"\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..% %F%U%E%L%=9872% %C%O%O%R%D%S%:34,19% %E%N%E%M%Y%=5% "
106 POKE 16418,2
107 RETURN
200 IF D$="0" THEN PRINT AT INT (RND*22),31;"%."
201 IF D$="Q" THEN PRINT AT 0,INT (RND*32);"%."
202 IF D$="Z" THEN PRINT AT 21,INT (RND*32);"%."
203 IF D$="8" THEN PRINT AT INT (RND*22),0;"%."
204 RETURN
300 SAVE "1009%8"
301 RUN
Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.
People
No people associated with this content.
A
Skip to content
Space Background
This file is part of Timex Sinclair Public Domain Library Tape 1002
. Download the collection to get this file.
This program implements a scrolling starfield game on the ZX81/TS1000, using machine code routines embedded in the REM statement at line 1 to perform fast screen scrolling in four directions. The machine code, called via USR at addresses 16514–16588, manipulates the display file directly using Z80 block-move instructions (LDIR/LDDR) and fills vacated rows or columns with spaces (0x80 in ZX81 display format). The BASIC layer handles keyboard input (keys 0, Q, Z, 8 for right, up, down, left scrolling), prints a randomised starfield background, and maintains a status bar at row 22 showing FUEL, COORDS, and ENEMY values. Screen attributes are temporarily modified via POKEs to 16418 (the ZX81’s RAMTOP-adjacent system variable controlling the display) to suppress scroll during the status bar setup.
Program Analysis
Program Structure
The program is organised into four logical sections:
- Line 1 (REM): Houses the Z80 machine code payload — four separate routines for scrolling the display in each cardinal direction.
- Lines 5–60 (Main loop): Calls the initialisation subroutine, then enters a polling loop reading
INKEY$ and dispatching to the appropriate machine code routine via USR, then calls the star-spawning subroutine.
- Lines 100–107 (Initialisation): Fills the screen with spaces and random inverse-dot characters to create a starfield, then draws a status bar at row 22.
- Lines 200–204 (Star spawning): Adds a new star character (
%. — inverse dot) at the leading edge of the scroll direction after each move.
Machine Code Routines
The REM data at line 1 contains four Z80 routines. Their entry points (relative to the start of the display file pointer at address 16396) are called from BASIC via USR:
Key Direction USR Address Z80 Technique 0 Right (scroll left) 16588 Uses LD HL,(16396), adjusts with display offset, LDIR block copy, fills right column Q Up 16538 LDDR-based block move, fills bottom row with 0x80 (ZX81 space) Z Down 16514 Loop over rows filling with 0x80, reverse direction copy 8 Left (scroll right) 16567 Similar to right-scroll but using LDIR with adjusted pointer
Each routine terminates with C9 (RET), returning control cleanly to BASIC. The byte 0x80 is the ZX81’s display-file encoding for a space character, used to blank the newly exposed row or column after scrolling.
Display File Manipulation
The routines reference address 16396 (0x400C), which is the ZX81 system variable D_FILE — the pointer to the display file. By reading this dynamically, the code remains position-independent with respect to where BASIC has placed the display file in RAM. The constant offset 0x0043 (67 decimal) appears in the scroll routines, corresponding to the 33-byte width of a ZX81 display row (32 characters + 1 newline byte), used to advance or retract the HL/DE register pairs between rows.
The scroll loop uses DJNZ with B=0x16 (22 decimal) to iterate over the 22 printable rows of the ZX81 display.
Key BASIC Idioms
LET Z=USR 16588 — the return value of the machine code is discarded into a dummy variable; this is a standard ZX81 idiom for calling USR without needing the result.
PRINT AT A,INT (RND*32);"%." — prints an inverse dot at a random column to seed the starfield.
IF D$="x" THEN ... chains (lines 25–40 and 200–203) replace a SELECT/CASE structure absent from ZX81 BASIC.
- Line 20 uses
LET D$=INKEY$ rather than a PAUSE/INKEY$ idiom, so the loop runs continuously even with no keypress (D$ becomes empty string, no USR call fires, but a star is still spawned at a random edge via subroutine 200’s guards).
Status Bar and SCROLL Suppression
Lines 104 and 106 POKE address 16418 to values 0 and 2 respectively. Address 16418 is DF_SZ, the display-file size variable that controls how many lines are reserved at the bottom for the lower screen. Setting it to 0 before printing the status bar prevents the display from auto-scrolling, and restoring it to 2 afterwards reinstates normal behaviour.
The status bar (line 105) displays inverse-video text reading FUEL=9872, COORDS:34,19, and ENEMY=5 — these appear to be static placeholder values rather than live game state, suggesting the program is a demonstration or early prototype.
Trailing Bytes in REM
The final bytes of the REM data (1D 1E 1F 20 21 22 23 24 25 1C) fall after the last C9 (RET) instruction and are never executed. They may represent leftover data, a lookup table, or simply padding artefacts from the original assembly process.
Anomalies and Notes
- Lines 300–301 (
SAVE / RUN) are development utilities and are never reached during normal execution.
- The starfield spawning in subroutine 200 only adds a star when a key is held; with no keypress,
D$="" matches none of the conditions, so no star is drawn that cycle. This means the star density slowly decreases during inactivity.
- The
GOSUB 100 at line 5 is called only once, so the starfield is initialised once and then maintained incrementally by subroutine 200.
Content
Source Code
1 REM \2A\0C\40\23\E5\11\21\00\19\D1\01\B5\02\ED\B0\EB\06\20\36\80\23\10\FB\C9\2A\10\40\11\43\00\ED\52\E5\11\21\00\ED\52\D1\01\B5\02\ED\B8\EB\06\20\2B\36\80\10\FB\C9\2A\0C\40\06\16\C5\06\20\3E\80\23\4F\7E\71\10\FA\23\C1\10\F1\C9\2A\10\40\11\43\00\ED\52\06\16\C5\06\20\3E\80\2B\4F\7E\71\10\FA\2B\C1\10\F1\C9\1D\1E\1F\20\21\22\23\24\25\1C
5 GOSUB 100
20 LET D$=INKEY$
25 IF D$="0" THEN LET Z=USR 16588
30 IF D$="Q" THEN LET Z=USR 16538
35 IF D$="Z" THEN LET Z=USR 16514
40 IF D$="8" THEN LET Z=USR 16567
50 GOSUB 200
60 GOTO 20
100 FOR A=0 TO 21
101 PRINT AT A,0;"% % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % "
102 PRINT AT A,INT (RND*32);"%."
103 NEXT A
104 POKE 16418,0
105 PRINT AT 22,0;"\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..% %F%U%E%L%=9872% %C%O%O%R%D%S%:34,19% %E%N%E%M%Y%=5% "
106 POKE 16418,2
107 RETURN
200 IF D$="0" THEN PRINT AT INT (RND*22),31;"%."
201 IF D$="Q" THEN PRINT AT 0,INT (RND*32);"%."
202 IF D$="Z" THEN PRINT AT 21,INT (RND*32);"%."
203 IF D$="8" THEN PRINT AT INT (RND*22),0;"%."
204 RETURN
300 SAVE "1009%8"
301 RUN
Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.
People
No people associated with this content.
C\C5EFE\FA\C1\F1\C9
Skip to content
Space Background
This file is part of Timex Sinclair Public Domain Library Tape 1002
. Download the collection to get this file.
This program implements a scrolling starfield game on the ZX81/TS1000, using machine code routines embedded in the REM statement at line 1 to perform fast screen scrolling in four directions. The machine code, called via USR at addresses 16514–16588, manipulates the display file directly using Z80 block-move instructions (LDIR/LDDR) and fills vacated rows or columns with spaces (0x80 in ZX81 display format). The BASIC layer handles keyboard input (keys 0, Q, Z, 8 for right, up, down, left scrolling), prints a randomised starfield background, and maintains a status bar at row 22 showing FUEL, COORDS, and ENEMY values. Screen attributes are temporarily modified via POKEs to 16418 (the ZX81’s RAMTOP-adjacent system variable controlling the display) to suppress scroll during the status bar setup.
Program Analysis
Program Structure
The program is organised into four logical sections:
- Line 1 (REM): Houses the Z80 machine code payload — four separate routines for scrolling the display in each cardinal direction.
- Lines 5–60 (Main loop): Calls the initialisation subroutine, then enters a polling loop reading
INKEY$ and dispatching to the appropriate machine code routine via USR, then calls the star-spawning subroutine.
- Lines 100–107 (Initialisation): Fills the screen with spaces and random inverse-dot characters to create a starfield, then draws a status bar at row 22.
- Lines 200–204 (Star spawning): Adds a new star character (
%. — inverse dot) at the leading edge of the scroll direction after each move.
Machine Code Routines
The REM data at line 1 contains four Z80 routines. Their entry points (relative to the start of the display file pointer at address 16396) are called from BASIC via USR:
Key Direction USR Address Z80 Technique 0 Right (scroll left) 16588 Uses LD HL,(16396), adjusts with display offset, LDIR block copy, fills right column Q Up 16538 LDDR-based block move, fills bottom row with 0x80 (ZX81 space) Z Down 16514 Loop over rows filling with 0x80, reverse direction copy 8 Left (scroll right) 16567 Similar to right-scroll but using LDIR with adjusted pointer
Each routine terminates with C9 (RET), returning control cleanly to BASIC. The byte 0x80 is the ZX81’s display-file encoding for a space character, used to blank the newly exposed row or column after scrolling.
Display File Manipulation
The routines reference address 16396 (0x400C), which is the ZX81 system variable D_FILE — the pointer to the display file. By reading this dynamically, the code remains position-independent with respect to where BASIC has placed the display file in RAM. The constant offset 0x0043 (67 decimal) appears in the scroll routines, corresponding to the 33-byte width of a ZX81 display row (32 characters + 1 newline byte), used to advance or retract the HL/DE register pairs between rows.
The scroll loop uses DJNZ with B=0x16 (22 decimal) to iterate over the 22 printable rows of the ZX81 display.
Key BASIC Idioms
LET Z=USR 16588 — the return value of the machine code is discarded into a dummy variable; this is a standard ZX81 idiom for calling USR without needing the result.
PRINT AT A,INT (RND*32);"%." — prints an inverse dot at a random column to seed the starfield.
IF D$="x" THEN ... chains (lines 25–40 and 200–203) replace a SELECT/CASE structure absent from ZX81 BASIC.
- Line 20 uses
LET D$=INKEY$ rather than a PAUSE/INKEY$ idiom, so the loop runs continuously even with no keypress (D$ becomes empty string, no USR call fires, but a star is still spawned at a random edge via subroutine 200’s guards).
Status Bar and SCROLL Suppression
Lines 104 and 106 POKE address 16418 to values 0 and 2 respectively. Address 16418 is DF_SZ, the display-file size variable that controls how many lines are reserved at the bottom for the lower screen. Setting it to 0 before printing the status bar prevents the display from auto-scrolling, and restoring it to 2 afterwards reinstates normal behaviour.
The status bar (line 105) displays inverse-video text reading FUEL=9872, COORDS:34,19, and ENEMY=5 — these appear to be static placeholder values rather than live game state, suggesting the program is a demonstration or early prototype.
Trailing Bytes in REM
The final bytes of the REM data (1D 1E 1F 20 21 22 23 24 25 1C) fall after the last C9 (RET) instruction and are never executed. They may represent leftover data, a lookup table, or simply padding artefacts from the original assembly process.
Anomalies and Notes
- Lines 300–301 (
SAVE / RUN) are development utilities and are never reached during normal execution.
- The starfield spawning in subroutine 200 only adds a star when a key is held; with no keypress,
D$="" matches none of the conditions, so no star is drawn that cycle. This means the star density slowly decreases during inactivity.
- The
GOSUB 100 at line 5 is called only once, so the starfield is initialised once and then maintained incrementally by subroutine 200.
Content
Source Code
1 REM \2A\0C\40\23\E5\11\21\00\19\D1\01\B5\02\ED\B0\EB\06\20\36\80\23\10\FB\C9\2A\10\40\11\43\00\ED\52\E5\11\21\00\ED\52\D1\01\B5\02\ED\B8\EB\06\20\2B\36\80\10\FB\C9\2A\0C\40\06\16\C5\06\20\3E\80\23\4F\7E\71\10\FA\23\C1\10\F1\C9\2A\10\40\11\43\00\ED\52\06\16\C5\06\20\3E\80\2B\4F\7E\71\10\FA\2B\C1\10\F1\C9\1D\1E\1F\20\21\22\23\24\25\1C
5 GOSUB 100
20 LET D$=INKEY$
25 IF D$="0" THEN LET Z=USR 16588
30 IF D$="Q" THEN LET Z=USR 16538
35 IF D$="Z" THEN LET Z=USR 16514
40 IF D$="8" THEN LET Z=USR 16567
50 GOSUB 200
60 GOTO 20
100 FOR A=0 TO 21
101 PRINT AT A,0;"% % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % "
102 PRINT AT A,INT (RND*32);"%."
103 NEXT A
104 POKE 16418,0
105 PRINT AT 22,0;"\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..% %F%U%E%L%=9872% %C%O%O%R%D%S%:34,19% %E%N%E%M%Y%=5% "
106 POKE 16418,2
107 RETURN
200 IF D$="0" THEN PRINT AT INT (RND*22),31;"%."
201 IF D$="Q" THEN PRINT AT 0,INT (RND*32);"%."
202 IF D$="Z" THEN PRINT AT 21,INT (RND*32);"%."
203 IF D$="8" THEN PRINT AT INT (RND*22),0;"%."
204 RETURN
300 SAVE "1009%8"
301 RUN
Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.
People
No people associated with this content.
A
Skip to content
Space Background
This file is part of Timex Sinclair Public Domain Library Tape 1002
. Download the collection to get this file.
This program implements a scrolling starfield game on the ZX81/TS1000, using machine code routines embedded in the REM statement at line 1 to perform fast screen scrolling in four directions. The machine code, called via USR at addresses 16514–16588, manipulates the display file directly using Z80 block-move instructions (LDIR/LDDR) and fills vacated rows or columns with spaces (0x80 in ZX81 display format). The BASIC layer handles keyboard input (keys 0, Q, Z, 8 for right, up, down, left scrolling), prints a randomised starfield background, and maintains a status bar at row 22 showing FUEL, COORDS, and ENEMY values. Screen attributes are temporarily modified via POKEs to 16418 (the ZX81’s RAMTOP-adjacent system variable controlling the display) to suppress scroll during the status bar setup.
Program Analysis
Program Structure
The program is organised into four logical sections:
- Line 1 (REM): Houses the Z80 machine code payload — four separate routines for scrolling the display in each cardinal direction.
- Lines 5–60 (Main loop): Calls the initialisation subroutine, then enters a polling loop reading
INKEY$ and dispatching to the appropriate machine code routine via USR, then calls the star-spawning subroutine.
- Lines 100–107 (Initialisation): Fills the screen with spaces and random inverse-dot characters to create a starfield, then draws a status bar at row 22.
- Lines 200–204 (Star spawning): Adds a new star character (
%. — inverse dot) at the leading edge of the scroll direction after each move.
Machine Code Routines
The REM data at line 1 contains four Z80 routines. Their entry points (relative to the start of the display file pointer at address 16396) are called from BASIC via USR:
Key Direction USR Address Z80 Technique 0 Right (scroll left) 16588 Uses LD HL,(16396), adjusts with display offset, LDIR block copy, fills right column Q Up 16538 LDDR-based block move, fills bottom row with 0x80 (ZX81 space) Z Down 16514 Loop over rows filling with 0x80, reverse direction copy 8 Left (scroll right) 16567 Similar to right-scroll but using LDIR with adjusted pointer
Each routine terminates with C9 (RET), returning control cleanly to BASIC. The byte 0x80 is the ZX81’s display-file encoding for a space character, used to blank the newly exposed row or column after scrolling.
Display File Manipulation
The routines reference address 16396 (0x400C), which is the ZX81 system variable D_FILE — the pointer to the display file. By reading this dynamically, the code remains position-independent with respect to where BASIC has placed the display file in RAM. The constant offset 0x0043 (67 decimal) appears in the scroll routines, corresponding to the 33-byte width of a ZX81 display row (32 characters + 1 newline byte), used to advance or retract the HL/DE register pairs between rows.
The scroll loop uses DJNZ with B=0x16 (22 decimal) to iterate over the 22 printable rows of the ZX81 display.
Key BASIC Idioms
LET Z=USR 16588 — the return value of the machine code is discarded into a dummy variable; this is a standard ZX81 idiom for calling USR without needing the result.
PRINT AT A,INT (RND*32);"%." — prints an inverse dot at a random column to seed the starfield.
IF D$="x" THEN ... chains (lines 25–40 and 200–203) replace a SELECT/CASE structure absent from ZX81 BASIC.
- Line 20 uses
LET D$=INKEY$ rather than a PAUSE/INKEY$ idiom, so the loop runs continuously even with no keypress (D$ becomes empty string, no USR call fires, but a star is still spawned at a random edge via subroutine 200’s guards).
Status Bar and SCROLL Suppression
Lines 104 and 106 POKE address 16418 to values 0 and 2 respectively. Address 16418 is DF_SZ, the display-file size variable that controls how many lines are reserved at the bottom for the lower screen. Setting it to 0 before printing the status bar prevents the display from auto-scrolling, and restoring it to 2 afterwards reinstates normal behaviour.
The status bar (line 105) displays inverse-video text reading FUEL=9872, COORDS:34,19, and ENEMY=5 — these appear to be static placeholder values rather than live game state, suggesting the program is a demonstration or early prototype.
Trailing Bytes in REM
The final bytes of the REM data (1D 1E 1F 20 21 22 23 24 25 1C) fall after the last C9 (RET) instruction and are never executed. They may represent leftover data, a lookup table, or simply padding artefacts from the original assembly process.
Anomalies and Notes
- Lines 300–301 (
SAVE / RUN) are development utilities and are never reached during normal execution.
- The starfield spawning in subroutine 200 only adds a star when a key is held; with no keypress,
D$="" matches none of the conditions, so no star is drawn that cycle. This means the star density slowly decreases during inactivity.
- The
GOSUB 100 at line 5 is called only once, so the starfield is initialised once and then maintained incrementally by subroutine 200.
Content
Source Code
1 REM \2A\0C\40\23\E5\11\21\00\19\D1\01\B5\02\ED\B0\EB\06\20\36\80\23\10\FB\C9\2A\10\40\11\43\00\ED\52\E5\11\21\00\ED\52\D1\01\B5\02\ED\B8\EB\06\20\2B\36\80\10\FB\C9\2A\0C\40\06\16\C5\06\20\3E\80\23\4F\7E\71\10\FA\23\C1\10\F1\C9\2A\10\40\11\43\00\ED\52\06\16\C5\06\20\3E\80\2B\4F\7E\71\10\FA\2B\C1\10\F1\C9\1D\1E\1F\20\21\22\23\24\25\1C
5 GOSUB 100
20 LET D$=INKEY$
25 IF D$="0" THEN LET Z=USR 16588
30 IF D$="Q" THEN LET Z=USR 16538
35 IF D$="Z" THEN LET Z=USR 16514
40 IF D$="8" THEN LET Z=USR 16567
50 GOSUB 200
60 GOTO 20
100 FOR A=0 TO 21
101 PRINT AT A,0;"% % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % "
102 PRINT AT A,INT (RND*32);"%."
103 NEXT A
104 POKE 16418,0
105 PRINT AT 22,0;"\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..% %F%U%E%L%=9872% %C%O%O%R%D%S%:34,19% %E%N%E%M%Y%=5% "
106 POKE 16418,2
107 RETURN
200 IF D$="0" THEN PRINT AT INT (RND*22),31;"%."
201 IF D$="Q" THEN PRINT AT 0,INT (RND*32);"%."
202 IF D$="Z" THEN PRINT AT 21,INT (RND*32);"%."
203 IF D$="8" THEN PRINT AT INT (RND*22),0;"%."
204 RETURN
300 SAVE "1009%8"
301 RUN
Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.
People
No people associated with this content.
\ED\C5E
Skip to content
Space Background
This file is part of Timex Sinclair Public Domain Library Tape 1002
. Download the collection to get this file.
This program implements a scrolling starfield game on the ZX81/TS1000, using machine code routines embedded in the REM statement at line 1 to perform fast screen scrolling in four directions. The machine code, called via USR at addresses 16514–16588, manipulates the display file directly using Z80 block-move instructions (LDIR/LDDR) and fills vacated rows or columns with spaces (0x80 in ZX81 display format). The BASIC layer handles keyboard input (keys 0, Q, Z, 8 for right, up, down, left scrolling), prints a randomised starfield background, and maintains a status bar at row 22 showing FUEL, COORDS, and ENEMY values. Screen attributes are temporarily modified via POKEs to 16418 (the ZX81’s RAMTOP-adjacent system variable controlling the display) to suppress scroll during the status bar setup.
Program Analysis
Program Structure
The program is organised into four logical sections:
- Line 1 (REM): Houses the Z80 machine code payload — four separate routines for scrolling the display in each cardinal direction.
- Lines 5–60 (Main loop): Calls the initialisation subroutine, then enters a polling loop reading
INKEY$ and dispatching to the appropriate machine code routine via USR, then calls the star-spawning subroutine.
- Lines 100–107 (Initialisation): Fills the screen with spaces and random inverse-dot characters to create a starfield, then draws a status bar at row 22.
- Lines 200–204 (Star spawning): Adds a new star character (
%. — inverse dot) at the leading edge of the scroll direction after each move.
Machine Code Routines
The REM data at line 1 contains four Z80 routines. Their entry points (relative to the start of the display file pointer at address 16396) are called from BASIC via USR:
Key Direction USR Address Z80 Technique 0 Right (scroll left) 16588 Uses LD HL,(16396), adjusts with display offset, LDIR block copy, fills right column Q Up 16538 LDDR-based block move, fills bottom row with 0x80 (ZX81 space) Z Down 16514 Loop over rows filling with 0x80, reverse direction copy 8 Left (scroll right) 16567 Similar to right-scroll but using LDIR with adjusted pointer
Each routine terminates with C9 (RET), returning control cleanly to BASIC. The byte 0x80 is the ZX81’s display-file encoding for a space character, used to blank the newly exposed row or column after scrolling.
Display File Manipulation
The routines reference address 16396 (0x400C), which is the ZX81 system variable D_FILE — the pointer to the display file. By reading this dynamically, the code remains position-independent with respect to where BASIC has placed the display file in RAM. The constant offset 0x0043 (67 decimal) appears in the scroll routines, corresponding to the 33-byte width of a ZX81 display row (32 characters + 1 newline byte), used to advance or retract the HL/DE register pairs between rows.
The scroll loop uses DJNZ with B=0x16 (22 decimal) to iterate over the 22 printable rows of the ZX81 display.
Key BASIC Idioms
LET Z=USR 16588 — the return value of the machine code is discarded into a dummy variable; this is a standard ZX81 idiom for calling USR without needing the result.
PRINT AT A,INT (RND*32);"%." — prints an inverse dot at a random column to seed the starfield.
IF D$="x" THEN ... chains (lines 25–40 and 200–203) replace a SELECT/CASE structure absent from ZX81 BASIC.
- Line 20 uses
LET D$=INKEY$ rather than a PAUSE/INKEY$ idiom, so the loop runs continuously even with no keypress (D$ becomes empty string, no USR call fires, but a star is still spawned at a random edge via subroutine 200’s guards).
Status Bar and SCROLL Suppression
Lines 104 and 106 POKE address 16418 to values 0 and 2 respectively. Address 16418 is DF_SZ, the display-file size variable that controls how many lines are reserved at the bottom for the lower screen. Setting it to 0 before printing the status bar prevents the display from auto-scrolling, and restoring it to 2 afterwards reinstates normal behaviour.
The status bar (line 105) displays inverse-video text reading FUEL=9872, COORDS:34,19, and ENEMY=5 — these appear to be static placeholder values rather than live game state, suggesting the program is a demonstration or early prototype.
Trailing Bytes in REM
The final bytes of the REM data (1D 1E 1F 20 21 22 23 24 25 1C) fall after the last C9 (RET) instruction and are never executed. They may represent leftover data, a lookup table, or simply padding artefacts from the original assembly process.
Anomalies and Notes
- Lines 300–301 (
SAVE / RUN) are development utilities and are never reached during normal execution.
- The starfield spawning in subroutine 200 only adds a star when a key is held; with no keypress,
D$="" matches none of the conditions, so no star is drawn that cycle. This means the star density slowly decreases during inactivity.
- The
GOSUB 100 at line 5 is called only once, so the starfield is initialised once and then maintained incrementally by subroutine 200.
Content
Source Code
1 REM \2A\0C\40\23\E5\11\21\00\19\D1\01\B5\02\ED\B0\EB\06\20\36\80\23\10\FB\C9\2A\10\40\11\43\00\ED\52\E5\11\21\00\ED\52\D1\01\B5\02\ED\B8\EB\06\20\2B\36\80\10\FB\C9\2A\0C\40\06\16\C5\06\20\3E\80\23\4F\7E\71\10\FA\23\C1\10\F1\C9\2A\10\40\11\43\00\ED\52\06\16\C5\06\20\3E\80\2B\4F\7E\71\10\FA\2B\C1\10\F1\C9\1D\1E\1F\20\21\22\23\24\25\1C
5 GOSUB 100
20 LET D$=INKEY$
25 IF D$="0" THEN LET Z=USR 16588
30 IF D$="Q" THEN LET Z=USR 16538
35 IF D$="Z" THEN LET Z=USR 16514
40 IF D$="8" THEN LET Z=USR 16567
50 GOSUB 200
60 GOTO 20
100 FOR A=0 TO 21
101 PRINT AT A,0;"% % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % "
102 PRINT AT A,INT (RND*32);"%."
103 NEXT A
104 POKE 16418,0
105 PRINT AT 22,0;"\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..% %F%U%E%L%=9872% %C%O%O%R%D%S%:34,19% %E%N%E%M%Y%=5% "
106 POKE 16418,2
107 RETURN
200 IF D$="0" THEN PRINT AT INT (RND*22),31;"%."
201 IF D$="Q" THEN PRINT AT 0,INT (RND*32);"%."
202 IF D$="Z" THEN PRINT AT 21,INT (RND*32);"%."
203 IF D$="8" THEN PRINT AT INT (RND*22),0;"%."
204 RETURN
300 SAVE "1009%8"
301 RUN
Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.
People
No people associated with this content.
BFE\FA
Skip to content
Space Background
This file is part of Timex Sinclair Public Domain Library Tape 1002
. Download the collection to get this file.
This program implements a scrolling starfield game on the ZX81/TS1000, using machine code routines embedded in the REM statement at line 1 to perform fast screen scrolling in four directions. The machine code, called via USR at addresses 16514–16588, manipulates the display file directly using Z80 block-move instructions (LDIR/LDDR) and fills vacated rows or columns with spaces (0x80 in ZX81 display format). The BASIC layer handles keyboard input (keys 0, Q, Z, 8 for right, up, down, left scrolling), prints a randomised starfield background, and maintains a status bar at row 22 showing FUEL, COORDS, and ENEMY values. Screen attributes are temporarily modified via POKEs to 16418 (the ZX81’s RAMTOP-adjacent system variable controlling the display) to suppress scroll during the status bar setup.
Program Analysis
Program Structure
The program is organised into four logical sections:
- Line 1 (REM): Houses the Z80 machine code payload — four separate routines for scrolling the display in each cardinal direction.
- Lines 5–60 (Main loop): Calls the initialisation subroutine, then enters a polling loop reading
INKEY$ and dispatching to the appropriate machine code routine via USR, then calls the star-spawning subroutine.
- Lines 100–107 (Initialisation): Fills the screen with spaces and random inverse-dot characters to create a starfield, then draws a status bar at row 22.
- Lines 200–204 (Star spawning): Adds a new star character (
%. — inverse dot) at the leading edge of the scroll direction after each move.
Machine Code Routines
The REM data at line 1 contains four Z80 routines. Their entry points (relative to the start of the display file pointer at address 16396) are called from BASIC via USR:
Key Direction USR Address Z80 Technique 0 Right (scroll left) 16588 Uses LD HL,(16396), adjusts with display offset, LDIR block copy, fills right column Q Up 16538 LDDR-based block move, fills bottom row with 0x80 (ZX81 space) Z Down 16514 Loop over rows filling with 0x80, reverse direction copy 8 Left (scroll right) 16567 Similar to right-scroll but using LDIR with adjusted pointer
Each routine terminates with C9 (RET), returning control cleanly to BASIC. The byte 0x80 is the ZX81’s display-file encoding for a space character, used to blank the newly exposed row or column after scrolling.
Display File Manipulation
The routines reference address 16396 (0x400C), which is the ZX81 system variable D_FILE — the pointer to the display file. By reading this dynamically, the code remains position-independent with respect to where BASIC has placed the display file in RAM. The constant offset 0x0043 (67 decimal) appears in the scroll routines, corresponding to the 33-byte width of a ZX81 display row (32 characters + 1 newline byte), used to advance or retract the HL/DE register pairs between rows.
The scroll loop uses DJNZ with B=0x16 (22 decimal) to iterate over the 22 printable rows of the ZX81 display.
Key BASIC Idioms
LET Z=USR 16588 — the return value of the machine code is discarded into a dummy variable; this is a standard ZX81 idiom for calling USR without needing the result.
PRINT AT A,INT (RND*32);"%." — prints an inverse dot at a random column to seed the starfield.
IF D$="x" THEN ... chains (lines 25–40 and 200–203) replace a SELECT/CASE structure absent from ZX81 BASIC.
- Line 20 uses
LET D$=INKEY$ rather than a PAUSE/INKEY$ idiom, so the loop runs continuously even with no keypress (D$ becomes empty string, no USR call fires, but a star is still spawned at a random edge via subroutine 200’s guards).
Status Bar and SCROLL Suppression
Lines 104 and 106 POKE address 16418 to values 0 and 2 respectively. Address 16418 is DF_SZ, the display-file size variable that controls how many lines are reserved at the bottom for the lower screen. Setting it to 0 before printing the status bar prevents the display from auto-scrolling, and restoring it to 2 afterwards reinstates normal behaviour.
The status bar (line 105) displays inverse-video text reading FUEL=9872, COORDS:34,19, and ENEMY=5 — these appear to be static placeholder values rather than live game state, suggesting the program is a demonstration or early prototype.
Trailing Bytes in REM
The final bytes of the REM data (1D 1E 1F 20 21 22 23 24 25 1C) fall after the last C9 (RET) instruction and are never executed. They may represent leftover data, a lookup table, or simply padding artefacts from the original assembly process.
Anomalies and Notes
- Lines 300–301 (
SAVE / RUN) are development utilities and are never reached during normal execution.
- The starfield spawning in subroutine 200 only adds a star when a key is held; with no keypress,
D$="" matches none of the conditions, so no star is drawn that cycle. This means the star density slowly decreases during inactivity.
- The
GOSUB 100 at line 5 is called only once, so the starfield is initialised once and then maintained incrementally by subroutine 200.
Content
Source Code
1 REM \2A\0C\40\23\E5\11\21\00\19\D1\01\B5\02\ED\B0\EB\06\20\36\80\23\10\FB\C9\2A\10\40\11\43\00\ED\52\E5\11\21\00\ED\52\D1\01\B5\02\ED\B8\EB\06\20\2B\36\80\10\FB\C9\2A\0C\40\06\16\C5\06\20\3E\80\23\4F\7E\71\10\FA\23\C1\10\F1\C9\2A\10\40\11\43\00\ED\52\06\16\C5\06\20\3E\80\2B\4F\7E\71\10\FA\2B\C1\10\F1\C9\1D\1E\1F\20\21\22\23\24\25\1C
5 GOSUB 100
20 LET D$=INKEY$
25 IF D$="0" THEN LET Z=USR 16588
30 IF D$="Q" THEN LET Z=USR 16538
35 IF D$="Z" THEN LET Z=USR 16514
40 IF D$="8" THEN LET Z=USR 16567
50 GOSUB 200
60 GOTO 20
100 FOR A=0 TO 21
101 PRINT AT A,0;"% % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % "
102 PRINT AT A,INT (RND*32);"%."
103 NEXT A
104 POKE 16418,0
105 PRINT AT 22,0;"\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..% %F%U%E%L%=9872% %C%O%O%R%D%S%:34,19% %E%N%E%M%Y%=5% "
106 POKE 16418,2
107 RETURN
200 IF D$="0" THEN PRINT AT INT (RND*22),31;"%."
201 IF D$="Q" THEN PRINT AT 0,INT (RND*32);"%."
202 IF D$="Z" THEN PRINT AT 21,INT (RND*32);"%."
203 IF D$="8" THEN PRINT AT INT (RND*22),0;"%."
204 RETURN
300 SAVE "1009%8"
301 RUN
Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.
People
No people associated with this content.
B\C1\F1\C9 itemtype='https://schema.org/Blog' itemscope='itemscope' class="wp-singular computer_media-template-default single single-computer_media postid-57149 wp-custom-logo wp-embed-responsive wp-theme-astra wp-child-theme-astra-child ast-desktop ast-separate-container ast-left-sidebar astra-4.12.5 group-blog ast-blog-single-style-1 ast-custom-post-type ast-single-post ast-inherit-site-logo-transparent ast-hfb-header ast-full-width-primary-header ast-box-layout ast-normal-title-enabled astra-addon-4.12.4"D itemtype='https://schema.org/Blog' itemscope='itemscope' class="wp-singular computer_media-template-default single single-computer_media postid-57149 wp-custom-logo wp-embed-responsive wp-theme-astra wp-child-theme-astra-child ast-desktop ast-separate-container ast-left-sidebar astra-4.12.5 group-blog ast-blog-single-style-1 ast-custom-post-type ast-single-post ast-inherit-site-logo-transparent ast-hfb-header ast-full-width-primary-header ast-box-layout ast-normal-title-enabled astra-addon-4.12.4"E itemtype='https://schema.org/Blog' itemscope='itemscope' class="wp-singular computer_media-template-default single single-computer_media postid-57149 wp-custom-logo wp-embed-responsive wp-theme-astra wp-child-theme-astra-child ast-desktop ast-separate-container ast-left-sidebar astra-4.12.5 group-blog ast-blog-single-style-1 ast-custom-post-type ast-single-post ast-inherit-site-logo-transparent ast-hfb-header ast-full-width-primary-header ast-box-layout ast-normal-title-enabled astra-addon-4.12.4"F itemtype='https://schema.org/Blog' itemscope='itemscope' class="wp-singular computer_media-template-default single single-computer_media postid-57149 wp-custom-logo wp-embed-responsive wp-theme-astra wp-child-theme-astra-child ast-desktop ast-separate-container ast-left-sidebar astra-4.12.5 group-blog ast-blog-single-style-1 ast-custom-post-type ast-single-post ast-inherit-site-logo-transparent ast-hfb-header ast-full-width-primary-header ast-box-layout ast-normal-title-enabled astra-addon-4.12.4"C
5 GOSUB 100
20 LET D$=INKEY$
25 IF D$="0" THEN LET Z=USR 16588
30 IF D$="Q" THEN LET Z=USR 16538
35 IF D$="Z" THEN LET Z=USR 16514
40 IF D$="8" THEN LET Z=USR 16567
50 GOSUB 200
60 GOTO 20
100 FOR A=0 TO 21
101 PRINT AT A,0;"% % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % "
102 PRINT AT A,INT (RND*32);"%."
103 NEXT A
104 POKE 16418,0
105 PRINT AT 22,0;"\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..% %F%U%E%L%=9872% %C%O%O%R%D%S%:34,19% %E%N%E%M%Y%=5% "
106 POKE 16418,2
107 RETURN
200 IF D$="0" THEN PRINT AT INT (RND*22),31;"%."
201 IF D$="Q" THEN PRINT AT 0,INT (RND*32);"%."
202 IF D$="Z" THEN PRINT AT 21,INT (RND*32);"%."
203 IF D$="8" THEN PRINT AT INT (RND*22),0;"%."
204 RETURN
300 SAVE "1009%8"
301 RUN
Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.
