Parallel 1000 is a ZX81/TS1000 printer driver installation utility that configures and relocates a Z80 machine code parallel printer driver to one of four memory locations: above RAMTOP, below system variables (address 8192), at the line 1 REM statement, or at a user-specified address. The program validates the relocation address against key system boundaries, checking that it falls between 8192 and 32767 and avoids the system variable area (15784–17325). It calculates high and low bytes of the target address using integer division and POKEs them into memory at addresses 17127 and 17128, then activates the driver via USR calls to fixed offsets (17161 or 17157). Entry points for LCOPY, LLIST, CLRBUF, and LPRINT functions are reported as USR expressions relative to the BASE address, with offsets of 167, 325, 560, and 171 respectively. The REM statements at lines 1 and 3 contain the actual Z80 machine code payload embedded in the BASIC program.
Program Analysis
Program Structure
The program is organized into several functional blocks:
- Lines 1 and 3 (REM blocks) — contain the embedded Z80 machine code for the parallel printer driver, stored as raw bytes within REM statement payloads.
- Lines 1000–1110 — user interface for linefeed control code configuration and relocation mode selection.
- Lines 1210–1280 — custom address entry and validation loop.
- Lines 1300–1450 — handlers for the three preset relocation modes (below system variables, at REM, above RAMTOP).
- Lines 1560–1600 — address patching: writes LRAM and HRAM into the machine code at addresses 17127 and 17128.
- Lines 1700–1799 — output section reporting BASE and entry point addresses, then activating the driver via USR.
- Lines 1800–1820 — subroutine decomposing RAM into high/low byte variables.
- Lines 9000–9020 — diagnostic loop printing memory contents from 16626 to 16652.
Machine Code Embedding
The Z80 printer driver is embedded directly in the two REM statements at lines 1 and 3. This is a standard technique for storing machine code in BASIC programs: the bytes following the REM token are never interpreted by the BASIC interpreter and can hold arbitrary binary data. The driver is activated by calling USR 17161 or USR 17157 at lines 1785 and 1791, which are fixed absolute addresses pointing into or near the REM data area.
Relocation Modes
The program supports four relocation destinations, selected by single-character input:
| Key | Destination | BASE value |
|---|---|---|
| R | Above RAMTOP | PEEK(16388)+256*PEEK(16389)+1 |
| V | Below system variables | 8192 |
| T | At line 1 REM | 16521 (hardcoded as BASE) |
| E | User-specified address | User input, validated |
RAMTOP is read from system variables at addresses 16388–16389 using the standard high/low byte formula. For the “above RAMTOP” mode, the program enforces an upper limit of 32138 (code cannot run above 32767, and a margin is added), stopping with an error message if RAMTOP is too high.
Address Validation
For the user-specified (“E”) mode, the input address is checked against multiple boundaries. Addresses below 8192 or above 32767 are rejected outright. Addresses in the range 15784–17324 are also rejected, as this encompasses the system variable area. The validation loop at lines 1210–1280 re-prompts on any invalid entry, printing the offending value with an “IS AN INVALID RELOCATION ADDRESS” message before looping back to line 1225.
Address Patching Mechanism
The subroutine at lines 1800–1820 decomposes the RAM variable into HRAM (high byte, via INT(RAM/256)) and LRAM (low byte, via RAM - HRAM*256). These are then POKEd into specific locations within the machine code (addresses 17127 and 17128), effectively self-modifying the driver’s internal jump or load address so it operates correctly at the chosen relocation target. This is a classic position-dependent patching approach rather than fully position-independent code.
Entry Point Reporting
After relocation, the program prints the USR call addresses for four driver entry points, all expressed as BASE + offset:
LCOPYat BASE+167LLISTat BASE+325CLRBUFat BASE+560LPRINTat BASE+171
These offsets are fixed constants baked into the listing, implying the machine code layout is fixed-size and the entry points are at known positions within it.
Linefeed Control
Lines 1000–1007 ask whether the printer needs a separate linefeed control code. If the user enters “N”, execution continues normally. If “Y”, the program skips the POKE at line 1007. The POKE at line 1007 writes 201 (the Z80 RET opcode) to address 16524, which is within the system variable / ROM call area, presumably disabling or short-circuiting a linefeed-generating routine within the driver.
Activation and Cleanup
At lines 1785 and 1791, the driver is activated by USR 17161 and USR 17157 respectively. When the “T” (REM) mode is chosen, the NEW command at line 1796 is skipped (branching to line 1799 STOP), since the driver lives in the REM area and a NEW would destroy it. For all other modes, NEW is called to clear BASIC memory, leaving only the relocated machine code resident.
Diagnostic Routine
Lines 9000–9020 provide a simple memory inspection loop, PRINTing the address and byte value for each location from 16626 to 16652. This range covers part of the system variables / driver patching area and appears to be a debugging aid left in the final listing.
Notable Idioms and Anomalies
- The use of
PAUSE 180at line 1775 gives the user approximately six seconds to read the entry point information before the screen is potentially modified. - Line 1790 is a bare
REMwith no content, serving as a label target for the GOTO at line 1782 — a common ZX81 BASIC technique to annotate branch targets. - The
B$="Z"assignment at line 1050 is set but never referenced again in the visible BASIC code, suggesting it may be a remnant of an earlier version or used within the machine code context. - The variable
Lassigned fromUSRcalls at lines 1785 and 1791 captures the return value of the machine code routine but is never used, which is normal when USR is called purely for its side effects.
Content
Source Code
1 REM LN PEEK PILN [E]RNDY~~LN STR$ PITAN FASTVAL NEWZ#▞ 5[M]RND,,LN [E]RND#PEEK 3 AT LPRINT TAN <=3 ACS #C RAND TAN 4EEEEEEEEEE678UZCDYWXFHEJVGIKLMNOPQRSTINKEY$ PI########################5B )▛INKEY$ :▞,#Y X4 CLEAR<$4 PRINT TAN RNDEXP )LN PAUSE RNDLN DIM PI#LN [+]RND7# RETURN#4 RUN LN BINKEY$ 7# ▌COS / GOSUB LN [E]RNDLN [,,]RNDTAN ▞-/ OR LN PAUSE RNDE£RND7 FAST FOR E:RND GOSUB # FOR LPRINT #LN [+]RND71C▛# RETURN#4 POKE / PRINT LN BINKEY$ TAN :£TAN 5#RND# RETURN#COS LN TO INKEY$ #7#Y LN PEEK INKEY$ 7.#[M]C-# RETURN#C* RETURN#C" RETURNRNDK#LN [+]RND/ STOP/USR ; LN BINKEY$ 7/INT 77777...../LN PRINT LN **INKEY$ 4~~Y LN [+]RNDY█LN PEEK INKEY$ LET FASTSTR$ LN #,,~~#LN [+]RND▀# NEW█C PRINT Y LN [+]RNDSGN LPRINT /[C] RETURN#SABS RETURN[Z]KEXP /[L]LN PAUSE RND/[L]▘ THENINKEY$ ▝TAN ▘ THENINKEY$ ~~[R]TAN #7#7 FASTLN PIPI:▌5 IF INKEY$ #LN [+]RNDF$4 SAVE LPRINT TAN 08863 5SPI6OPI▘▖ 5 PLOT INKEY$ ,,Q06MPIVAL EOPI#7#76OPIVAL LPRINT 6QPIEKPILN #PILN [2]PIAT $4**TAN RUN INKEY$ RNDPI~~ (B CONT ▀# ~~ ▘ FOR 6KPILN RETURNINKEY$ EKPI FOR LN [-]PITAN #[W]**""#[X]TAN # # VAL EQPI6#PIY~~ PRINT LET XC1 PRINT EMPIOE#PI6#PI FOR EQPI;6#PI FASTAT LN [A]PIC LPRINT S TO LET FOR E#PI FOR ZLN [H]PI AT TAN 5 PLOT INKEY$ #LEN 0#TAN C▝K▀LN #PITAN EKPILN #PITAN #J##J#<;6KPITAN E£RND7▞▀:4Q 7$4 IF 7▌4 POKE E£RND7LN INPUT PITAN Y$PEEK 3 FAST56( STOP STOPF#[O]C▝/ RUN LPRINT TAN ▘#E£RND7TAN 6:RNDY/MURNDTAN
3 REM ## LN KINKEY$ TAN ▘[,,]RNDE SCROLLPI[R] GOSUB PI FASTAT -X<>5Z#<># <>7<># <>7STR$ #7# FOR ,, FOR #F#SGN +4 CONT GOSUB # SCROLLPI5[,,]RND▘#▝ GOSUB [K]TAN RND[1]RND[5]INKEY$ :INKEY$ +INKEY$ 2INKEY$ CINKEY$ FINKEY$ PINKEY$ #INKEY$ #INKEY$ )INKEY$ #INKEY$ #INKEY$ █INKEY$ [,,]INKEY$ [0]INKEY$ [7]INKEY$ [C]PI[Q]INKEY$ [N]INKEY$ [Y]INKEY$ INT INKEY$ USR INKEY$ OR INKEY$ FASTINKEY$ REM INKEY$ INPUT INKEY$ COPYPI▝PI▒PI:PI>PI;PI2PI5PI8PIBPI#PI#PI#PI#PI#PI#PI#PI#PI#PI#PI#PI▙PI["]PI[(]PI[*]PI[7]PI[B]PI[E]#▞PISQR RND[~~]RND[$]RND[>]RND PLOT
1000 CLS
1001 PRINT "DOES YOUR PRINTER REQUIRE A"
1002 PRINT "SEPARATE LINEFEED CONTROL CODE"
1003 PRINT "FOR PROPER OPERATION(Y,N)?"
1004 INPUT A$
1005 IF A$="Y" THEN GOTO 1008
1006 IF A$<>"N" THEN GOTO 1000
1007 POKE 16524,201
1008 CLS
1009 PRINT "DO YOU WANT THE PRINTER"
1010 PRINT "DRIVER TO EXECUTE:"
1015 PRINT
1020 PRINT "ABOVE RAMTOP(R) OR"
1030 PRINT "BELOW SYSTEM VARIABLES(V) OR"
1040 PRINT "AT 1 REM(T) OR"
1045 PRINT "ALMOST ANYWHERE ELSE(E)?"
1050 LET B$="Z"
1060 INPUT A$
1070 IF A$="R" THEN GOTO 1400
1080 IF A$="V" THEN GOTO 1300
1090 IF A$="T" THEN GOTO 1350
1095 IF A$="E" THEN GOTO 1220
1100 PRINT "PLEASE ENTER R, V, T, OR E."
1110 GOTO 1060
1210 PRINT
1212 PRINT RAM;" IS AN INVALID"
1215 PRINT "RELOCATION ADDRESS."
1220 PRINT
1225 PRINT "ENTER RELOCATION ADDRESS?"
1230 INPUT RAM
1240 IF RAM<8192 THEN GOTO 1210
1250 IF RAM>32767 THEN GOTO 1210
1260 IF RAM<15784 THEN GOTO 1570
1270 IF RAM<17325 THEN GOTO 1210
1280 GOTO 1570
1300 LET RAM=8192
1310 GOTO 1570
1350 LET BASE=16521
1360 GOTO 1700
1400 LET RAM=PEEK (16388)+256*PEEK 16389
1410 IF RAM<32139 THEN GOTO 1560
1415 PRINT
1420 PRINT "Z80 MACHINE CODE CANNOT EXECUTE"
1430 PRINT "ABOVE 32767. RAMTOP MUST BE"
1440 PRINT "BELOW 32139."
1450 STOP
1560 LET RAM=RAM+1
1570 GOSUB 1800
1580 LET BASE=RAM
1590 POKE 17127,LRAM
1600 POKE 17128,HRAM
1700 CLS
1705 PRINT "THE PRINTER DRIVER WILL BE"
1710 PRINT "LOCATED AT ";BASE
1715 PRINT
1720 PRINT "THE ENTRY ADDRESSES ARE:"
1725 PRINT
1730 PRINT "LCOPY = USR(";BASE+167;")"
1740 PRINT "LLIST = USR(";BASE+325;")"
1750 PRINT "CLRBUF= USR(";BASE+560;")"
1760 PRINT "LPRINT= USR(";BASE+171;")"
1765 PRINT
1770 PRINT "IF YOUR PRINTER IS CONNECTED"
1771 PRINT "A COPY OF THIS WILL BE PRINTED."
1775 PAUSE 180
1776 PRINT
1777 PRINT "PLEASE FOLLOW THE REMAINDER"
1778 PRINT "OF THE INSTRUCTIONS TO USE"
1779 PRINT
1780 PRINT "THE BYTE-BACK PRINTER DRIVER"
1782 IF A$="T" THEN GOTO 1790
1785 LET L=USR 17161
1790 REM
1791 LET L=USR 17157
1795 IF A$="T" THEN GOTO 1799
1796 NEW
1799 STOP
1800 LET HRAM=INT (RAM/256)
1810 LET LRAM=RAM-HRAM*256
1820 RETURN
9000 FOR I=16626 TO 16652
9010 PRINT I,PEEK I
9020 NEXT I
Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.
