Builds a custom 80-column printer driver that can run at any address you choose, and includes only the parts you ask for. It translates LLIST output properly, including the TS2068-only keywords, the © and £ characters, the block graphics and UDGs. The driver supports top, bottom and left margins, a set line length, correct TAB, AT and print-comma tab stops, and printing INVERSE, BRIGHT and FLASH text as emphasized, underlined and italic. Optional modules add large and small graphics screen dumps, a text-only screen dump and an interrupt-driven print spooler. The configuration program supports Aerco, A&J, Tasman-B and Tasman-C interfaces and saves the finished code.
The title screen reads “Printer Support Program by William J McBrine III, Copyright © 1988, McBrine Computer Products.” McBrine’s two-part manual is included as text, along with its notes and corrections and an LCODE table of Epson printer control codes.
Program Analysis
Program Structure
The BASIC configuration program works on the 3720-byte machine-code package loaded at 32768. It sets options by POKEing into the package, and the final driver is assembled by machine code. The main menu at line 3000 dispatches with a computed GO SUB:
- 1. Backup Customization Program (line 200): saves
PPRINT.B1andpprint.C1, keeping any margin and character settings - 2. Produce Output File (lines 5–70, 100–150): asks for the start address, driver, spooler, interface and dump modules, then calls
USR 32768to relocate and link the chosen modules. It reports the start and length and saves the result from 36488 asoutp.C1 - 3. Set Margins, etc. (lines 300–430): translation on or off, control characters, UDG markers, margins, line length, dump margins and up to eight tab stops
- 4. Customize Characters (lines 500–550): printer codes for ©, £, the UDG marker and the 16 block graphics
- 5. Exit (
STOP)
The output code runs only at the address it was built for. You load it there with LOAD ""CODE x and start it with RANDOMIZE USR x. RANDOMIZE USR x+2 or LPRINT CHR$ 5 switches back to the TS2040 driver. With the special control characters enabled, LPRINT CHR$ 1 and CHR$ 2 give the large and small graphics dumps, CHR$ 3 the text dump and CHR$ 4 a form feed. In the finished driver, POKE 23728 turns translation on and off, and POKE 23729 sets the control-character and UDG-marker flags.
Notable Techniques
- Numeric inputs accept hexadecimal with a
#prefix. The converter at line 1000 sets variablesatofto 10–15, soVALof a single hex digit, letter or number, gives its value. - The spooler uses Z80 interrupt mode 2 with a 257-byte vector table on a 256-byte page boundary at or above 32768. It sends one character to the printer every 1/60 second while other programs run.
- The dumps check the
VIDMODsystem variable for the video mode, so the large dump and the text dump also work in the 512-pixel, 64-column mode. - The text dump reads characters back from the display, including block graphics and UDGs, and LPRINTs them. This is much faster than a graphics dump.
- Menu dispatch uses one Boolean-sum expression:
GO SUB (5 AND a$="2")+(200 AND a$="1")+….
Potential Issues
- As the notes and corrections say, driver 1 (printer-based) is no longer supported. Line 21 accepts only 2 or 3, though the menu still lists driver 1.
- Nothing checks whether the driver, jump table and spooler buffer overlap. The manual warns that an overlap is disastrous.
- The VERIFY steps the manual describes are
REMmed out in this version (lines 65, 67, 210 and 220). - The hex converter reads only the first four digits.
This copy comes from a Larken disk in the TS User Group collection (disk l-36). It was converted for tape by removing the LKDOS RANDOMIZE USR 100, OPEN #4 and PRINT #4: prefixes from the loader and save lines, and was tested in ZEsarUX.
Source Code
1 PRINT '" ' : :'''': :'''': : : : :''': :'''' :'''': :'''' : :'''': :''' : : : : : : : :'''' : : : : : : : : :''''' '''''' ''''''' ''''' ' :''''' ' ' ' ' '''' "
2 PRINT ''TAB 4;"Printer Support Program"'''TAB 14;"by"'''TAB 5;"William J McBrine III"'''TAB 7;"Copyright * 1988"'''TAB 3;"McBrine Computer Products"
3 PAUSE 300: GO TO 3000
5 CLS : LET h=0: PRINT TAB 5;" Produce Output File "
10 PRINT '"Starting address? ";: GO SUB 900: LET add=num: POKE 32770,add-256*INT (add/256): POKE 32771,INT (add/256)
20 PRINT '"Driver? 1. Printer-based"'TAB 12;"2. Computer-based"'TAB 12;"3. None"'TAB 11;"(screen dump(s) only)"
21 LET a$=INKEY$: IF a$>"3" OR a$<"2" THEN GO TO 21
22 LET drv=VAL a$: PRINT AT drv+3,12; OVER 1;" ";AT 7,0: POKE 32782,drv: IF drv=3 THEN POKE 32782,0
24 PRINT '"Use spooler (y/n)? ";
25 GO SUB 2000
26 POKE 32784,0: IF a$="Y" OR a$="y" THEN POKE 32784,1: GO SUB 100: LET h=6
27 PRINT '"Interface? 1. Aerco"'TAB 12;"2. A&J"'TAB 12;"3. Tasman-B"'TAB 12;"4. Tasman-C"
28 LET a$=INKEY$: IF a$>"4" OR a$<"1" THEN GO TO 28
29 LET int=VAL a$: PRINT AT int+h+10,12; OVER 1;" ";AT h+14,0: POKE 32783,int-1
30 PRINT '"Text dump (y/n)? ";
31 GO SUB 2000
32 POKE 32785,(a$="Y" OR a$="y")
40 PRINT '"Graphics dump (y/n)? ";
41 GO SUB 2000
42 POKE 32786,(a$="Y" OR a$="y")
49 REM do it
50 LET len=USR 32768
55 PRINT '"Start address: ";add'"Length of code: ";len''"OK to save (y/n)? ";
56 GO SUB 2000
60 IF a$="Y" OR a$="y" THEN PRINT #4: SAVE "outp.C1"CODE 36488,len
65 REM PRINT '"Verify (y/n)? ";: GO SUB 2000
67 REM IF a$="Y" OR a$="y" THEN PRINT : VERIFY "outp"CODE : PRINT '"Saved OK": PAUSE 60
70 RETURN
100 PRINT '"Jump table address? ";
105 GO SUB 901: LET tadd=num: IF tadd>=32768 THEN LET tadd=INT (tadd/256): GO TO 120
110 IF tadd>255 OR tadd<128 THEN GO TO 105
120 POKE 32777,tadd: PRINT tadd*256
130 PRINT '"Buffer start address? ";: GO SUB 900: POKE 32778,num-256*INT (num/256): POKE 32779,INT (num/256)
140 PRINT '"Buffer end address? ";: GO SUB 900: POKE 32780,num-256*INT (num/256): POKE 32781,INT (num/256)
150 RETURN
200 CLS : PRINT " Backup Customization Program "''"OK to save (y/n)? ";: GO SUB 2000: IF a$<>"Y" AND a$<>"y" THEN RETURN
210 PRINT #4: SAVE "PPRINT.B1" LINE 9999: PRINT #4: SAVE "pprint.C1"CODE 32768,3720: REM PRINT '"Verify (y/n)? ";: GO SUB 2000: IF a$<>"Y" AND a$<>"y" THEN RETURN
220 REM PRINT : VERIFY "PPRINT": VERIFY "pprintc"CODE : PRINT '"Saved OK": PAUSE 60
230 RETURN
300 CLS : PRINT TAB 6;" Set Margins, etc. "
310 PRINT '"Disable translation (y/n)? ";: GO SUB 2000: LET num=(a$="Y" OR a$="y")
320 POKE 33150,num: POKE 34072,num
330 PRINT '"Enable control chars. (y/n)? ";: GO SUB 2000: LET num=(a$="Y" OR a$="y")
340 PRINT '"Disable UDG markers (y/n)? ";: GO SUB 2000: LET num=num+(2 AND (a$="Y" OR a$="y"))
350 POKE 33155,num: POKE 34077,num
360 PRINT '"Top margin? (0) ";: LET def=0: GO SUB 890: LET num=num+1: POKE 33632,num: POKE 34715,num
370 PRINT '"Bottom margin? (0) ";: LET def=0: GO SUB 890: POKE 33635,num: POKE 34716,num
380 PRINT '"Left margin? (0) ";: LET def=0: GO SUB 890: POKE 33638,num+1: POKE 34717,num+1
390 LET lm=num: PRINT '"Line length? (";80-lm;") ";: LET def=80-lm: GO SUB 890: LET num=num+lm: POKE 33641,num: POKE 34718,num
400 PRINT '"Left mar. for large dump? (8) ";: LET def=8: GO SUB 890: LET num=num+1: POKE 35979,num
410 PRINT '"Lf. mar. for small dump? (40) ";: LET def=40: GO SUB 890: LET num=num+1: POKE 35978,num
420 PRINT '"Define new tab stops (y/n)? ";: GO SUB 2000: IF a$<>"Y" AND a$<>"y" THEN RETURN
430 PRINT '"How many (max. 8)? ";: GO SUB 900: FOR x=1 TO num: GO SUB 900: POKE 33643+x,num: POKE 34718+x,num: NEXT x: POKE 33643+x,0: POKE 34718+x,0: RETURN
500 CLS : PRINT TAB 5;" Customize Characters "
510 PRINT '"Code for ""*"" symbol? (64) ";: LET def=64: GO SUB 890: POKE 33526,num: POKE 34514,num
520 PRINT '"Code for ""`"" symbol? (195) ";: LET def=195: GO SUB 890: POKE 33558,num: POKE 34555,num
530 PRINT '"Mark for UDG's? (61) ";: LET def=61: GO SUB 890: POKE 33484,num: POKE 34472,num
540 PRINT '"Redefine graph. chars. (y/n)? ";: GO SUB 2000: IF a$<>"Y" AND a$<>"y" THEN RETURN
550 FOR x=0 TO 15: PRINT 'CHR$ (128+x);" ";128+x,: GO SUB 900: POKE 33574+x,num: POKE 34674+x,num: NEXT x: RETURN
890 INPUT LINE a$: IF a$="" THEN LET num=def: PRINT num: RETURN
895 GO SUB 910: PRINT num: RETURN
900 GO SUB 901: PRINT num: RETURN
901 INPUT LINE a$: IF a$="" THEN GO TO 901
910 IF a$(1)="#" THEN LET a$=a$(2 TO ): GO TO 1000
920 LET num=VAL a$
930 RETURN
1000 REM hex to dec
1001 LET a=10: LET b=11: LET c=12: LET d=13: LET e=14: LET f=15
1007 IF LEN a$<4 THEN FOR x=1 TO 4-LEN a$: LET a$="0"+a$: NEXT x
1010 LET num=4096*VAL a$(1)+256*VAL a$(2)+16*VAL a$(3)+VAL a$(4)
1020 RETURN
2000 LET a$=INKEY$: IF (a$<>"Y" AND a$<>"y") AND (a$<>"N" AND a$<>"n") THEN GO TO 2000
2002 PRINT a$
2005 IF INKEY$<>"" THEN GO TO 2005
2010 RETURN
3000 CLS : PRINT TAB 10;" Main Menu "''"1. Backup Customization Program"''"2. Produce Output File"''"3. Set Margins, etc."''"4. Customize Characters"''"5. Exit this Program"
3010 LET a$=INKEY$: IF a$>"5" OR a$<"1" THEN GO TO 3010
3020 IF a$="5" THEN STOP
3030 GO SUB (5 AND a$="2")+(200 AND a$="1")+(300 AND a$="3")+(500 AND a$="4"): GO TO 3000
9999 CLEAR 32767: RANDOMIZE USR 100: OPEN #4,"dd": PRINT #4: LOAD "pprint.C1"CODE : RUNNote: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.

