Parallel 1000

Products: Parallel 1000
Date: 1985
Type: Cassette
Platform(s): TS 1000
Tags: Printer

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:

  1. 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.
  2. Lines 1000–1110 — user interface for linefeed control code configuration and relocation mode selection.
  3. Lines 1210–1280 — custom address entry and validation loop.
  4. Lines 1300–1450 — handlers for the three preset relocation modes (below system variables, at REM, above RAMTOP).
  5. Lines 1560–1600 — address patching: writes LRAM and HRAM into the machine code at addresses 17127 and 17128.
  6. Lines 1700–1799 — output section reporting BASE and entry point addresses, then activating the driver via USR.
  7. Lines 1800–1820 — subroutine decomposing RAM into high/low byte variables.
  8. 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:

KeyDestinationBASE value
RAbove RAMTOPPEEK(16388)+256*PEEK(16389)+1
VBelow system variables8192
TAt line 1 REM16521 (hardcoded as BASE)
EUser-specified addressUser 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:

  • LCOPY at BASE+167
  • LLIST at BASE+325
  • CLRBUF at BASE+560
  • LPRINT at 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 180 at 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 REM with 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 L assigned from USR calls 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

Appears On

Related Products

Interface to Centronics parallel interface printers. Driver translates Timex/Sinclair code to 80 column ASCII and sends printer via USR calls...

Related Articles

Related Content

Image Gallery

Parallel 1000

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.

People

No people associated with this content.

Scroll to Top