Relocatable AERCO Driver V4

This BASIC program is a configuration and management utility for the AERCO Relocatable Centronics Print Driver, a 800-byte machine code block that is loaded into high RAM (default base address 64000) to provide printer output support. The program allows the user to customize the driver for eight different dot-matrix printers—including the Seikosha GP-100, Prowriter 8510, Star Gemini, Epson models, Olivetti PR2300, Seikosha 250, and MT Spirit 80—by POKEing printer-specific escape-code sequences and control bytes into the machine code block at calculated offsets from the base address. A key design feature is that the driver remains relocatable (loadable at any base address) until it is activated via RANDOMIZE USR, after which its internal addresses are fixed. The program also manages linefeed auto-switching, print width, a COPY screen-dump function, tape backup and verification, and includes a multi-page help system. Control bytes for features such as line width and linefeed are stored at fixed offsets (BASE+4 and BASE+5), and printer-type configuration data is written to offset regions TA (BASE+388), TG (BASE+405), and TT (BASE+440) using DATA statements and FOR/NEXT POKE loops.


Program Analysis

Program Structure

The program is organized into high-numbered line ranges, all above 8000, making it suitable for appending to a user’s own BASIC program. The major functional sections are:

  1. Lines 8000–8038: Entry point and REMs including fairware notice and author contact.
  2. Lines 8090–8212: Tape load, backup, and verify routines.
  3. Lines 8900–8954: Initialization — computes all key offsets from the base address B into named variables.
  4. Lines 9000–9150: Main menu — displays options and dispatches on keypress.
  5. Lines 9220–9236: Linefeed toggle and width input handlers.
  6. Lines 9400–9498: Printer type configuration routines (types 1–8) using DATA and POKE.
  7. Lines 9500–9692: Test menu — exercises LPRINT, LLIST, and two COPY variants including a graphics pattern generator.
  8. Lines 9700–9798: Multi-page help system with menu-driven pagination.
  9. Lines 9900–9920: Save and verify routine, with a guard check to prevent saving a driver that has already been activated.

Machine Code Driver Interface

The program does not contain machine code directly; instead it loads a separate 800-byte binary file (RADRIVER) and configures it by POKEing values at well-defined offsets from the base address B (default 64000). All offset variables are computed once at line 8910–8912:

VariableOffsetPurpose
TABASE+388Initialization escape sequence bytes
TGBASE+405Graphics/bit-image escape sequence
TTBASE+440Tab/line termination sequence
L1–L7VariousJump targets and control flow patches inside the MC
c1BASE+450Standard COPY entry point
c2BASE+612Olivetti PR2300-specific COPY entry point
BASE+4Print width (stored as width−1)
BASE+5Linefeed switch (10 = ON, 0 = OFF)

The relocatability guard is implemented by checking PEEK 64040 and PEEK 64041 for values 8 and 0 respectively (lines 8204, 9902). Once the driver is activated with RANDOMIZE USR BASE, these bytes change, and the program refuses to save or back up the now-fixed driver, printing an error message instead.

Printer Type Configuration

Eight printer types are supported. Each type handler POKEs a sequence of bytes read from DATA statements into the TA, TG, and TT regions, followed by individual POKEs to L1L5 for internal jump address bytes. The two DATA lines used are:

  • Line 9438: For types 3, 4, and 8 (Star Gemini / Epson family): 3,27,51,16,4,27,75,0,1,2,27,64
  • Line 9498: For type 2 (Prowriter 8510, also used as default init): 6,27,84,49,54,27,62,6,27,83,48,50,53,54,4,27,60,27,65
  • Line 9478: For type 7 (Seikosha 250): 3,27,76,2,8,27,16,0,111,27,71,1,0,3,27,76,3

Types 4 and 8 reuse the type 3 subroutine (GO SUB 9435) and then patch a single byte at TA+3 to differentiate them (24 for type 4, 21 for type 8). The Olivetti PR2300 (types 5 and 6) shares most configuration with type 2 but additionally writes to L6 (BASE+586) and L7 (BASE+587) to set zoom or normal mode.

Key BASIC Idioms and Techniques

  • Keypress debounce: The idiom at lines 9110–9114 (and mirrored at 9791–9793) first waits for the previously-seen key to be released, then waits for any new keypress — preventing key repeat and double-firing.
  • Lowercase normalization: Line 9116 converts lowercase input to uppercase using CHR$ (CODE k$-32) when k$>"`" (i.e., ASCII > 96), avoiding duplicate IF branches for each letter.
  • RESTORE before READ in loops: Each printer-type routine calls RESTORE to its own DATA line before reading, ensuring correct data is used regardless of prior READ state.
  • Paginated help: The help system (lines 9700–9798) uses a ret variable to track which help page to display next, with GO TO ret via a shared input-check subroutine at line 9790. This implements a simple state machine for multi-page display.
  • Input validation loop: The width input at lines 9231–9233 iterates over each character of the input string to confirm all are digits before calling VAL, avoiding a crash on non-numeric input.

Graphics Test Pattern

The COPY test routine at lines 9680–9692 generates a geometric test image before printing. It draws two families of diagonal lines using DRAW OVER 1 (XOR mode) to create a crossed pattern, then adds a border rectangle and a series of concentric circles (CIRCLE 127,87,i for i from 20 to 70 in steps of 10). This provides a visually rich but programmatically compact screen to verify the printer’s bit-image graphics capability.

Bugs and Anomalies

  • Line 8114 uses lowercase q$ instead of the uppercase Q$ used in line 8110 and 8112. On most Sinclair BASIC interpreters, variable names are case-sensitive for string variables, so q$ and Q$ are distinct variables. The value entered by the user is stored in Q$, so the test at 8114 against q$ (which is empty) will always be false. The program falls through to line 8116 regardless of input, but since 8112 handles “Y”/”y” first and 8116 loops back, the only practical effect is that “n”/”N” is not caught at 8114 and instead loops back through 8116 to re-prompt — a minor but real bug.
  • Line 9415 is defined as a shared “update type indicator” stub but is also the fall-through target from lines that GO TO 9415 after configuration. Since line 9416 (GO TO 9100) is immediately after and also goes to the main menu, line 9416 is redundant dead code.
  • The test menu at line 9515 uses INPUT Q$ without LINE, meaning single-character entry requires ENTER to be pressed, making the UX inconsistent with the main menu’s direct INKEY$ approach.

Content

Appears On

Related Products

Customizable printer driver for parallel (Centronics) printers. While it was written for the CP-68 parallel printer interface, it does work...
Connect to parallel (Centronics) printers. Print in either the printer’s native font or the TS 2068 display font.

Related Articles

Related Content

Image Gallery

Source Code

 8000 LET B=64000: LET BASE=B: GO TO 8900
 8010 REM RELOCATABLE AERCO
 8014 REM CENTRONICS PRINT DRIVER
 8016 REM VERSION 4T (7-26-85)
 8018 
 8020 REM **A FAIRWARE PROGRAM**
 8022 REM **COPYING IS WELCOME**
 8024 
 8026 REM IF YOU LIKE THIS            PROGRAM, PLEASE SEND $5.00      TO THE AUTHOR:
 8028 
 8030 REM  JACK DOHANY
 8032 REM  325 O'CONNOR ST.
 8034 REM  MENLO PARK, CA  94025
 8036 REM  (415) 321-7684
 8038 
 8040 
 8090 CLS : PRINT "**RELOCATABLE AERCO DRIVER  V4**": RETURN 
 8100 REM LOAD MC
 8101 CLEAR 63999
 8102 BORDER 0: PAPER 0: INK 7: GO SUB 8090: PRINT AT 10,0;"LOADING 800-BYTE DRIVER CODE"'" AT LOC 64000 FOR CUSTOMIZING."
 8104 LOAD "RADRIVER"CODE 64000
 8106 LET B=64000: LET BASE=B
 8108 GO SUB 8090
 8110 INPUT "MAKE BACKUP? (Y/N): ";Q$: IF Q$="" THEN GO TO 8110
 8112 IF Q$="Y" OR Q$="y" THEN GO TO 8200
 8114 IF q$="n" OR q$="N" THEN GO TO 8900
 8116 GO TO 8110
 8200 REM BACKUP
 8204 IF PEEK 64040<>8 OR PEEK 64041<>0 THEN GO TO 9920
 8208 GO SUB 8090: PRINT AT 10,0;"MAKING TWO-PART BACKUP": SAVE "RALOADER" LINE 8100: BEEP .1,10: SAVE "RADRIVER"CODE 64000,800
 8210 GO SUB 8090: PRINT AT 10,0;"REWIND and PLAY to VERIFY"''"or BREAK and RUN."
 8212 VERIFY "": VERIFY ""CODE : GO TO 8108
 8900 REM INITIALIZE
 8905 LET k$=""
 8906 LET L$="OFF": IF PEEK (B+5)=10 THEN LET L$="ON "
 8908 LET width=1+PEEK (B+4)
 8910 LET TA=B+388: LET TG=B+405: LET TT=B+440
 8912 LET l1=b+456: LET l2=b+480: LET l3=b+492: LET l4=b+494: LET l5=b+500: LET l6=b+586: LET l7=b+587
 8914 LET c1=b+450: LET c2=b+612
 8920 GO SUB 9490: LET typ=2
 8954 GO TO 9000
 9000 REM MAIN MENU
 9050 CLS : PRINT TAB 6;"*** MAIN MENU ***"
 9052 PRINT '"H: HELP (INSTRUCTIONS)"''"W: SET WIDTH";TAB 20;"-NOW ";width;'"L: LINEFEED SWITCH";TAB 20;"-NOW": GO SUB 9226
 9060 PRINT "S: SAVE CUSTOMIZED DRIVER"'"T: TEST CUSTOMIZED DRIVER"'"Q: QUIT"
 9070 PRINT AT 10,5;" TO CUSTOMISE DRIVER "'"PLEASE SELECT YOUR PRINTER TYPE:"''" 1: Seikosha GP100"'" 2: Prowriter 8510"'" 3: Star Gemini, older Epsons"'" 4: Newer Epsons"'" 5: Olivetti PR2300 Zoom"'" 6: Olivetti PR2300 Normal"'" 7: Seikosha 250"
 9073 PRINT " 8: MT Spirit 80"
 9074 PRINT AT 12+typ,1; INVERSE 1;typ
 9100 PRINT #1;AT 1,4;"** Please press a key ** "
 9110 IF k$=INKEY$ THEN GO TO 9110
 9112 IF INKEY$="" THEN GO TO 9112
 9114 LET k$=INKEY$: BEEP .01,25
 9116 IF k$>"`" THEN LET k$=CHR$ (CODE k$-32)
 9120 IF K$="H" THEN GO TO 9700
 9122 IF k$="W" THEN GO TO 9230
 9124 IF k$="L" THEN GO TO 9220
 9128 IF k$="S" THEN GO TO 9900
 9130 IF K$="T" THEN GO TO 9500
 9132 IF k$="Q" THEN CLS : PRINT AT 10,9;" OK TO RUN ": STOP 
 9134 IF k$="1" THEN GO TO 9410
 9135 IF k$="2" THEN GO TO 9420
 9136 IF k$="3" THEN GO TO 9430
 9137 IF k$="4" THEN GO TO 9440
 9138 IF k$="5" THEN GO TO 9450
 9139 IF k$="6" THEN GO TO 9460
 9140 IF k$="7" THEN GO TO 9470
 9141 IF k$="8" THEN GO TO 9480
 9150 GO TO 9110
 9220 IF PEEK (b+5)=0 THEN POKE b+5,10: GO TO 9224
 9222 POKE b+5,0
 9224 GO SUB 9226: GO TO 9110
 9226 LET L$="OFF": IF PEEK (b+5)=10 THEN LET L$="ON "
 9228 PRINT AT 5,25; INVERSE 1;L$: RETURN 
 9230 INPUT "WIDTH: "; LINE q$: IF q$="" THEN GO TO 9100
 9231 FOR i=1 TO LEN q$
 9232 IF q$(i)<"0" OR q$(i)>"9" THEN GO TO 9230
 9233 NEXT i
 9235 IF VAL q$<2 OR VAL q$>255 THEN GO TO 9230
 9236 LET width=VAL q$: POKE b+4,width-1: PRINT AT 4,25;width;"   ": GO TO 9100
 9400 REM TYPES
 9402 LET copy=c1: RETURN 
 9404 LET copy=c2: RETURN 
 9410 REM type 1
 9412 GO SUB 9402: POKE TA,1: POKE TA+1,8: POKE TG,0: POKE TT,1: POKE TT+1,15: POKE L1,25: POKE L2,64: POKE L3,251: POKE L4,11: POKE L5,11
 9415 PRINT AT 12+typ,1;typ: LET typ=CODE k$-48: PRINT AT 12+typ,1; INVERSE 1;typ: GO TO 9100
 9416 GO TO 9100
 9420 REM type 2
 9422 GO SUB 9490: GO TO 9415
 9430 REM type 3
 9432 GO SUB 9435: GO TO 9415
 9435 GO SUB 9402: RESTORE 9438: FOR i=TA TO TA+3: READ by: POKE i,by: NEXT i: FOR i=TG TO TG+4: READ by: POKE i,by: NEXT i: FOR i=TT TO TT+2: READ by: POKE i,by: NEXT i
 9436 POKE L1,24: POKE L2,1: POKE L3,35: POKE L4,195: POKE L5,35: RETURN 
 9438 DATA 3,27,51,16,4,27,75,0,1,2,27,64
 9440 REM type 4
 9442 GO SUB 9435: POKE TA+3,24
 9446 GO TO 9415
 9450 REM type 5
 9452 GO SUB 9404: POKE L6,27: POKE L7,47: GO TO 9415
 9460 REM type 6
 9462 GO SUB 9404: POKE L6,0: POKE L7,0: GO TO 9415
 9470 REM type 7
 9471 GO SUB 9402
 9472 RESTORE 9478: FOR i=TA TO TA+3: READ by: POKE i,by: NEXT i: FOR i=TG TO TG+8: READ by: POKE i,by: NEXT i: FOR i=TT TO TT+3: READ by: POKE i,by: NEXT i
 9474 POKE L1,24: POKE L2,128: POKE L3,59: POKE L4,251: POKE L5,59
 9476 GO TO 9415
 9478 DATA 3,27,76,2,8,27,16,0,111,27,71,1,0,3,27,76,3
 9480 REM TYPE 8
 9482 GO SUB 9435: POKE TA+3,21
 9484 GO TO 9415
 9490 REM initialize (type 2)
 9491 GO SUB 9402
 9493 RESTORE 9498: FOR i=TA TO TA+6: READ by: POKE i,by: NEXT i: FOR i=TG TO TG+6: READ by: POKE i,by: NEXT i: FOR i=TT TO TT+4: READ by: POKE i,by: NEXT i
 9494 POKE L1,24: POKE L2,128: POKE L3,59: POKE L4,251: POKE L5,59
 9495 RETURN 
 9498 DATA 6,27,84,49,54,27,62,6,27,83,48,50,53,54,4,27,60,27,65
 9500 REM TEST
 9510 CLS : PRINT TAB 10;"** TEST **"''"1: LPRINT"''"2: LLIST"''"3: COPY (to T/S 2040)"''"4: COPY (RANDOMIZE USR ";copy;")"''"0: RETURN TO MAIN MENU"
 9512 PRINT '"NOTE: TESTING WILL TURN THE"'"DRIVER ON AND MAKE IT NO LONGER"'"RELOCATABLE."
 9515 INPUT Q$: IF Q$="" THEN GO TO 9515
 9520 IF Q$="0" THEN GO TO 9000
 9522 IF Q$="1" OR Q$="2" OR Q$="4" THEN RANDOMIZE USR BASE
 9523 IF Q$="1" THEN GO TO 9610
 9524 IF Q$="2" THEN GO TO 9620
 9525 IF Q$="3" THEN GO TO 9630
 9526 IF Q$="4" THEN GO TO 9640
 9530 GO TO 9515
 9610 REM LPRINT
 9612 CLS : LET Q$="This is a test."+CHR$ 13+"Linefeed Switch is "+L$+"."+CHR$ 13+"End of test."
 9614 PRINT q$: LPRINT q$
 9616 PAUSE 200: GO TO 9500
 9620 REM LLIST
 9624 LLIST 9700: GO TO 9500
 9630 REM COPY 2040
 9632 GO SUB 9680: COPY : GO TO 9616
 9640 REM COPY AERCO
 9644 GO SUB 9680: RANDOMIZE USR copy: PAUSE 200: GO TO 9500
 9680 CLS : FOR f=0 TO 174 STEP 2: PLOT 0,f: DRAW OVER 1;f,174-f: PLOT 255,f: DRAW OVER 1;-f,174-f: NEXT f
 9682 FOR f=0 TO 174 STEP 2: PLOT 0,f: DRAW OVER 1;174-f,-f: PLOT 255,f: DRAW OVER 1;-174+f,-f: NEXT f
 9690 PLOT 0,0: DRAW 0,175: DRAW 255,0: DRAW 0,-175: DRAW -255,0: FOR i=20 TO 70 STEP 10: CIRCLE 127,87,i: NEXT i
 9692 RETURN 
 9700 REM HELP
 9701 LET q$="": GO SUB 8090
 9702 PRINT '"PLEASE FOLLOW THIS SEQUENCE:"''"1. CUSTOMIZE DRIVER."'"2. SAVE IT."'"3. THEN TEST IT."
 9703 PRINT '"TO USE YOUR CUSTOMIZED DRIVER,"'"SIMPLY LOAD IT TO ANY REASONABLE"'"BASE ADDRESS WITH THIS COMMAND:"''"LOAD ""NAME"" CODE base"''"WHERE base IS THE BASE ADDRESS"'"OF YOUR CHOICE."''"THEN TURN THE DRIVER ON WITH:"''"RANDOMISE USR base"
 9704 LET ret=9705: GO TO 9790
 9705 PRINT '"The driver is 800 bytes long."''"The driver will work with either"'"ROM, 2068 or Spectrum."''"NOTE: THE CUSTOMIZED DRIVER IS"'"RELOCATABLE, BUT ONLY UNTIL IT"'"HAS BEEN TURNED ON."
 9706 PRINT '"THE DRIVER MAY BE TURNED ON AND"'"OFF REPEATEDLY, BUT TURNING IT"'"OFF DOES NOT RESTORE ITS"'"RELOCATABILITY."
 9707 LET ret=9708: GO TO 9790
 9708 PRINT '"The print driver shouldn't be"'"turned on until after it's been"'"CUSTOMIZED and SAVED from"'"the MENU."
 9709 PRINT '"You can then leave it where it"'"is (64000-64799) or load it to"'"another base address with:"''"CLEAR base-1           e.g.62999"'"LOAD ""NAME"" CODE base  e.g.63000"
 9710 PRINT '"To turn the driver ON:"''"RANDOMIZE USR base     e.g.63000"''"Note that the driver is now at"'"64000, so you'd turn it on with"'"RANDOMIZE USR 64000"
 9714 LET RET=9720: GO TO 9790
 9720 PRINT '"   IMPORTANT DRIVER CONTROLS:   "''"POKE (BASE+4),WIDTH-1"''"POKE (BASE+5),10 = LINEFEED ON"'"POKE (BASE+5),0  = LINEFEED OFF"
 9722 PRINT '"RANDOMIZE USR BASE = TURN ON"''"RANDOMIZE USR (BASE+2)= TURN OFF"
 9724 PRINT '"RANDOMIZE USR (BASE+450) = COPY"'"(EXCEPT PR2300 PRINTER)"
 9730 LET RET=9731: GO TO 9790
 9731 PRINT '"The OLIVETTI PR2300 printer"'"uses a unique copy function:"''"TO SET NORMAL MODE:"'"POKE (base+586),0"'"POKE (base+587),0"
 9732 PRINT '"TO SET ZOOM MODE:"'"POKE (base+586),27"'"POKE (base+587),47"''"TO COPY SCREEN TO PR2300:"'"RANDOMIZE USR (base+612)"
 9735 LET RET=9736: GO TO 9790
 9736 PRINT '"The menu can be used to set the"'"two print parameters:"'"WIDTH and LINEFEED SWITCH."
 9737 PRINT '"These can also be changed"'"directly as follows:"''"TO SET WIDTH:"'"POKE base+4, width-1"
 9738 PRINT ''"TO TURN LINEFEED SWITCH ON/OFF:"'"POKE base+5, 10 (ON) or 0 (OFF)"
 9739 PRINT ''"EXAMPLE: say the driver is"'"loaded at 60000 and you want the"'"printing width to be 80 columns:"'"POKE 60004,79 will do it."
 9740 LET RET=9742: GO TO 9790
 9742 PRINT '"NOTE: If the Auto-Linefeed DIP"'"switch on your printer is OFF"'"then the driver's linefeed"'"switch should be ON, and vice-"'"versa."
 9743 PRINT ''"NOTE RE COPY FUNCTION:"'"If your printer doesn't have"'"BIT-IMAGE GRAPHICS CAPABILITY,"'"then it cannot copy the screen."
 9744 PRINT '"If your dot-matrix printer is"'"not among the types listed, you"'"can try various types."'"For further assistance, contact"'"AERCO (512)451-5874"
 9746 LET ret=9748: GO TO 9790
 9748 PRINT '"For further help in using the"'"Relocatable Print Driver, call"'"or write:"''"Jack Dohany (415) 321-7684"'"325 O'Connor St"'"Menlo Park, CA 94025"
 9749 PRINT '"Note that Version 5 is now being"'"worked on. Features:"'". Set Left Margin"'". Set Lines Per Page"'". Word Wrap"'". Constant Relocatability"''"Enquire re price/availability."     
 9750 LET RET=9700: GO TO 9790
 9790 PRINT #1;AT 0,0;"menu  copy(2040)  ENT=next pg"
 9791 IF q$=INKEY$ THEN GO TO 9791
 9792 IF INKEY$="" THEN GO TO 9792
 9793 LET q$=INKEY$
 9795 IF q$="c" OR q$="C" THEN COPY : GO TO 9790
 9796 IF q$=CHR$ 13 THEN GO SUB 8090: GO TO ret
 9797 IF q$="M" OR q$="m" THEN GO TO 9000
 9798 GO TO 9790
 9900 REM SAVE
 9902 IF PEEK 64040<>8 OR PEEK 64041<>0 THEN GO TO 9920
 9905 INPUT "FILE NAME: ";f$: IF f$="" THEN GO TO 9905
 9906 SAVE f$CODE 64000,800
 9908 INPUT "VERIFY? (y/n): ";q$: IF q$="" THEN GO TO 9908
 9910 IF q$="y" OR q$="Y" THEN VERIFY ""CODE : GO TO 9000
 9912 IF q$="n" OR q$="N" THEN GO TO 9000
 9914 GO TO 9908
 9920 CLS : PRINT AT 10,0;"DRIVER HAS BEEN TURNED ON AND IS"'"NO LONGER RELOCATABLE."''"PLEASE RELOAD ORIGINAL DRIVER,"'"CUSTOMIZE, SAVE, AND RELOAD": STOP 

Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.

Scroll to Top