PrintScreen is a utility that uses machine code routines, entered via BASIC, to send the screen contents to a printer through a Memopak interface. The program first lists itself (line 10), then prints characters 0–191 while skipping the range 64–127 (line 30 filters these out using an AND mask), and finally calls machine code at USR 16528 and USR 16840 to perform the actual screen dump. The REM line 0 encodes the machine code routine directly in its token stream, a well-known ZX81 technique for embedding binary data in a BASIC listing. Lines 1–8 display a decorative banner explaining the utility and its invocation method (RAND USR 16528).
Program Analysis
Program Structure
The program is organized into two distinct regions: a set of REM lines that carry the machine code payload and a short BASIC driver that exercises and saves the routine.
| Line(s) | Purpose |
|---|---|
| 0 (first) | Machine code embedded in REM token stream |
| 1, 0, 0, 0, 0, 0, 7, 8 | Decorative banner / documentation REMs |
| 10 | LIST 1 — lists the program from line 1 |
| 20–40 | Loops through characters 0–191, printing those outside 64–127 |
| 50 | Calls machine code at USR 16528 and USR 16840 |
| 60 | STOP |
| 70 | SAVE "PRTSC[R]" |
| 80 | RUN |
Machine Code Embedding in REM
The first REM at line 0 contains the machine code routine for the print-screen function. This is the classic ZX81 technique of storing binary data inside a REM statement: the interpreter never executes the body of a REM, so arbitrary bytes — including Z80 opcodes — can be stored there safely. The entry point is at address 16528 (the start of RAM, 16514 + 14 bytes of system variables), and a secondary entry or helper routine sits at 16840. The RAND USR 16528 invocation documented in the banner calls directly into this embedded routine.
Character Filter in Line 30
Line 30 uses the idiom CHR$ N AND (N<64 OR N>127). On the ZX81, the boolean expressions N<64 and N>127 evaluate to 1 (true) or 0 (false). When the condition is false (i.e., N is in 64–127, the alphabetic and keyword range), the AND forces the argument to CHR$ to zero, printing CHR$ 0 (a space) instead. This neatly sidesteps characters that would otherwise invoke BASIC keywords or produce unwanted token output during the display pass.
USR Call Chain in Line 50
Line 50 reads:
RAND (USR 16528 + USR 16840 + USR 16528)
Each USR call jumps to the machine code, executes it, and returns a value (typically the BC register pair). The results are added together and passed to RAND, which simply discards the value — the entire expression is evaluated for its side effects (the three print-screen calls). Calling USR 16528 twice suggests the routine may need to be invoked more than once to complete a full 192-line screen dump, with USR 16840 handling a mid-point or secondary pass.
Multiple Identical REM Lines at Line 0
Several REMs share line number 0. On the ZX81, duplicate line numbers are legal; the system stores each as a separate record in the program area and LIST displays them in sequence. This is exploited here to pack the decorative banner into lines that sort before line 1 yet after the machine code REM. LIST 1 at line 10 deliberately skips line 0 entirely, presenting only the human-readable banner to the user.
SAVE and RUN Lines
Line 70 saves the program under the name PRTSC (the [R] escape represents the letter R in the zmakebas encoding, giving the filename a trailing R). Line 80’s RUN restarts the program after saving, providing a convenient loop for repeated use without manual re-entry.
Notable Techniques Summary
- Machine code stored in a
REMstatement at the start of RAM (address 16528). - Boolean arithmetic used as a character mask in
CHR$ N AND condition. - Three
USRcalls chained inside a single arithmetic expression, results discarded viaRAND. - Duplicate line-0 REMs used to layer machine code below the human-readable banner.
LIST 1used to suppress the machine code REM from normal display.
Content
Image Gallery
Source Code
0 REM .INKEY$ ▒.#> \,,.# ▝ █5▙RND▞▛#LN PD7( RAND LN [D]RNDY.LN PDYM#PDE£RND▞-VAL 7 FAST5[,,]RND▞▌#LN PD7( RAND LPRINT ▞4VAL #ACS #4" FAST5[?]RNDACS [Y]LN POKE RND/"ACS [Z] FAST5[?]RNDACS RETURNLN POKE RND LPRINT 7AT ( TO Y\~~LN PDY$LN PDAT LN #?K[I]([V]TAN 5 SAVE 1W#)▒ ;( CLEARLN [Q]INKEY$ ACS # FOR CODE ASN \~~LN ""INKEY$ ( PRINT LN [5]INKEY$ LN [M]INKEY$ ACS # FOR CODE ASN \~~LN ""INKEY$ ( PRINT LN [5]INKEY$ LN [M]INKEY$ ACS # FOR CODE ASN \~~LN ""INKEY$ ( PRINT LN [5]INKEY$ LN [M]INKEY$ ACS # FOR CODE ASN \~~LN ""INKEY$ ( PRINT LN [5]INKEY$ LN [M]INKEY$ ACS # FOR CODE ASN \~~LN ""INKEY$ ( PRINT LN [5]INKEY$ LN [M]INKEY$ ACS # FOR CODE ASN \~~LN ""INKEY$ ( PRINT LN [5]INKEY$ LN [M]INKEY$ ACS # FOR CODE ASN \~~LN ""INKEY$ ( PRINT LN [5]INKEY$ LN [M]INKEY$ ACS # FOR CODE ASN \~~LN ""INKEY$ ( PRINT LN [5]INKEY$ LPRINT TAN ACS COPYTAN ACS RUN TAN ACS LOAD TAN ACS SCROLLTAN ACS TO TAN ACS NOT TAN ACS INT TAN ACS SIN TAN 5[?]RNDACS #C▝ INPUT COPY PRINT LN PD LET #PDSGN LPRINT /▘SGN FASTSTR$ [J])[,,]INKEY$ ▞▒TAN FOR <<<7TAN **E£RND:-▞47#LEN █#( RAND 7$4 NEXT TAN ********
1 REM ▛▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▜
0 REM ▌ P.MCMULLIN,1985 ▐
0 REM ▛\~~\~~\~~\~~\~~\~~\~~\~~\~~\~~\~~\~~\~~\~~\~~\~~\~~\~~\~~▜
0 REM ▌ RAND USR 16528 = ▐
0 REM ▌ PRINT SCREEN ▐
0 REM ▛\~~\~~\~~\~~\~~\~~\~~\~~\~~\~~\~~\~~\~~\~~\~~\~~\~~\~~\~~▜
7 REM ▌MEMOPAK I/F VERSION▐
8 REM ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀
10 LIST 1
20 FOR N=0 TO 191
30 PRINT CHR$ N AND (N<64 OR N>127);
40 NEXT N
50 RAND (USR 16528+USR 16840+USR 16528)
60 STOP
70 SAVE "PRTSC[R]"
80 RUN
Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.