--- title: "Power Print" id: 72099 type: "computer_media" slug: "power-print" url: "http://localhost/computer_media/power-print/" markdown_url: "http://localhost/computer_media/power-print.md" published_at: "2026-10-21T05:34:33+00:00" modified_at: "2026-10-21T05:34:33+00:00" author: "David Anderson" featured_image: url: "http://localhost/wp-content/uploads/2026/10/pprint-1.png" excerpt: "Configuration program that builds a relocatable printer driver with correct LLISTings, margins, tab stops, text and graphics screen dumps, and an interrupt-driven print spooler." post_tag: - name: "Downloadable" slug: "downloadable" taxonomy: "post_tag" url: "http://localhost/tag/downloadable/" - name: "McBrine Computer Products" slug: "mcbrine-computer-products" taxonomy: "post_tag" url: "http://localhost/tag/mcbrine-computer-products/" - name: "TS 2068" slug: "ts2068" taxonomy: "post_tag" url: "http://localhost/tag/ts2068/" model: - name: "Timex/Sinclair 2068" slug: "ts-2068" taxonomy: "model" url: "http://localhost/model/ts-2068/" indiv: - name: "William McBrine" slug: "william-mcbrine" taxonomy: "indiv" url: "http://localhost/indiv/william-mcbrine/" genre: - name: "Printer" slug: "printer" taxonomy: "genre" url: "http://localhost/type/printer/" media_type: "Program" programmers: - name: "William McBrine" slug: "william-mcbrine" taxonomy: "indiv" url: "http://localhost/indiv/william-mcbrine/" download_url: "https://archive.org/download/timex-sinclair-software-archive/Power%20Print%20%281988%29%28McBrine%2C%20William%29%28TS2068%29%28US%29%28Program%29.zip" tsrun_member: "Power Print (1988)(McBrine, William)(TS2068)(US)(Program)/Power Print (1988)(McBrine, William)(TS2068)(US)(Program).tap" mediadate: "1988" producer_company: - id: 11084 title: "McBrine Computer Products" type: "company" url: "http://localhost/company/mcbrine-computer-products/" images: - url: "http://localhost/wp-content/uploads/2026/10/pprint-1.png" - url: "http://localhost/wp-content/uploads/2026/10/pprint-2.png" related_products: - id: 13619 title: "Power Print" type: "product" url: "http://localhost/product/power-print/" media_type_tags: "Printer" license: false --- # Power Print 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.B1` and `pprint.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 32768` to relocate and link the chosen modules. It reports the start and length and saves the result from 36488 as `outp.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 variables `a` to `f` to 10–15, so `VAL` of 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 `VIDMOD` system 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 `REM`med 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 : RUN ```