Program for designing fonts for use with Pixel Print.
This package contains three interrelated BASIC programs: a loader/menu (lines 1–9999 of the first program), a font designer utility called FONT-D, and an SG-10 dot-matrix printer font downloader called FONT-S. The loader uses a 12-byte Z80 machine code routine POKEd into address 32000 to perform an LDIR block copy (opcodes 17, 0, 64, 33, 232, 128, 1, 0, 27, 237, 176, 201), transferring 6912 bytes of screen data from address 33000 to the display file at 16384. FONT-S implements an 8×11 pixel grid editor that uses a two-dimensional array V(8,11) and a 240-entry font table A$(240,14), packing column bit-patterns into bytes for Epson ESC/P download commands (ESC & and ESC :). The TS2068-specific STICK function handles joystick input alongside keyboard controls, and ON ERR/RESET blocks provide tape error recovery. Font library management stores character data at fixed memory addresses (37139 onward) with a count stored at 37199–37200, allowing multiple fonts to be saved and loaded as individual CODE blocks.
Program Analysis
Program Structure
The listing contains three distinct programs concatenated together:
- Loader/Splash (lines 1–9999, first block): Displays a title screen by block-copying a logo image with machine code, then chains to FONT-D.
- FONT-D (lines 1–9999, second block): Font library manager with LOAD/SAVE/VERIFY routines for a “Char-Lib” tape archive.
- FONT-S (lines 1–9999, third block): The interactive pixel-print font designer and Epson SG-10 printer downloader.
Machine Code Usage
The loader at line 2 POKEs 12 bytes into address 32000 and executes them with RANDOMIZE USR 32000. The byte sequence disassembles as a standard Z80 LDIR block copy:
| Address | Bytes | Instruction | Purpose |
|---|---|---|---|
| 32000 | 17, 0, 64 | LD DE,16384 | Destination: display file |
| 32003 | 33, 232, 128 | LD HL,33000 | Source: loaded logo data |
| 32006 | 1, 0, 27 | LD BC,6912 | Byte count: full screen + attributes |
| 32009 | 237, 176 | LDIR | Block copy |
| 32011 | 201 | RET | Return to BASIC |
Line 3 then re-POKEs bytes 32001–32005 to redirect the same routine to copy a different memory region before re-executing it, reusing the stub for a second display operation. FONT-D also calls RANDOMIZE USR 34512 and RANDOMIZE USR 34303, which invoke separately loaded machine code beyond the BASIC listing.
FONT-S: Grid Editor Logic
The character editor uses a DIM v(8,11) array representing an 8-row by 11-column pixel grid. Navigation is handled by lines 80–180, with the cursor position tracked in variables R (row, 2–9) and C (column, 1–11). Pressing “1” (k=49) sets a pixel and prints UDG \a (a filled block shaped by POKEs in line 9990); pressing “0” (k=48) clears it. The PLOT and PLOT INVERSE 1 calls mirror the grid state into the small preview box drawn in the top-right of the screen.
Bit-Packing and Printer Download
At line 200, each column of the 8×11 grid is packed into a single byte by summing row values as powers of two:
M(C) = V(8,C) + V(7,C)*2 + V(6,C)*4 + ... + V(1,C)*128
Lines 210–265 auto-detect the start column (SC) and end column (EC) of the non-zero region to trim whitespace. The control byte M0 at line 270 encodes descender flag, start column, and end column into a single byte: 128*D + 16*SC + EC.
Download to the Epson SG-10 (line 340–370) uses standard ESC/P sequences:
ESC : 0 0 0— copy ROM characters to RAMESC & 0 [data]— define custom characterESC % 1 0— select user-defined character set
The POKE 23728,1 call suppresses output through a ZPRINT-80 driver intercept, routing subsequent LPRINT commands directly to the printer rather than through any screen-capture layer.
TS2068-Specific Features
FONT-S uses the STICK function at lines 7–11 for joystick input. Joystick directions map to key codes: up=55 (“7”), down=54 (“6”), right=56 (“8”), left=53 (“5”), fire=toggles a pixel. The ON ERR/RESET idiom at lines 8000 and 8100 provides structured tape-error handling not available in standard Spectrum BASIC.
Font Library Memory Map
FONT-D manages a library with a fixed memory layout:
| Address | Contents |
|---|---|
| 37139 | Start of Char-Lib CODE block (452 bytes) |
| 37169–37170 | Pointer to font load address (plib) |
| 37199–37200 | Font count (clib), low/high byte |
| 37359 + i*10 | Font name string for font i (10 bytes) |
| 39000 + 1000*i | Font data CODE block for font i (768 bytes) |
Notable Bugs and Anomalies
- Line 2030 contains the misspelling
"Saveing"in the progress message — this appears in the printed output on screen. - Line 120 sets
LET k=13after placing a “0” pixel but does not advanceC, whereas line 110 explicitly incrementsC. Clearing a pixel therefore does not advance the cursor automatically. - Lines 130–160 contain wrap-around logic gated on variable
W, but the wrap toggle message at line 9030 always prints “Wrap is Off” and only conditionally appends"n "(intended to show “On”) — the “On” state message is effectively truncated to an incomplete string. - Line 9989 is a self-documenting stub instructing the user to remove it and configure their printer driver;
STOPthere prevents accidental execution without setup. - The
SAVE "FONT-S" LINE 9989at the end auto-starts at the stub/warning line rather than the main menu, reinforcing the requirement for user customization before use.
Content
Image Gallery
Source Code
1 REM *********************** Pixel Print FONT Utility Package * by Lemke Software Development 2144 White Oak Wichita, Ks. 67207 ********************************
2 DATA 17,0,64,33,232,128,1,0,27,237,176,201: PAPER 1: INK 1: BORDER 1: CLS : LOAD ""CODE 33000: FOR j=0 TO 11: READ a: POKE 32000+j,a: NEXT j: RANDOMIZE USR 32000
3 POKE 32001,232: POKE 32002,128: POKE 32004,0: POKE 32005,64: PAUSE 100: INK 7
4 CLS : PRINT AT 2,0;"
"
5 PRINT AT 5,0;"This tape contains 2 separate programs that work with FONTS... FONT DESIGNER: FONT-D use this to browse the font library, modify or create new FONTS. SG-10 FONT DL: FONT-S use this as an example of FULL SIZE PRINTER FONT DESIGN and DOWN LOADING"
6 PRINT #0;AT 0,0;" Press Any key to LOAD FONT-D.": PAUSE 0: PAPER 7: INK 0: BORDER 7: CLS : RANDOMIZE USR 32000: LOAD ""
9999 SAVE "FONT PKG" LINE 1: SAVE "LSD LOGO"CODE 33000,6912
10 REM *********************** PIXEL-PRINT "the Desktop Publisher" * by S D Lemke 1987 Lemke Software Development 2144 White Oak Wichita, Ks. 67207 ********************************
20 REM Font Builder Utility ********************************
30 CLS : RANDOMIZE USR 34512
1000 CLS : PRINT AT 6,0;" Press ENTER to LOAD a Library. ": PAUSE 0: IF CODE INKEY$=13 THEN GO SUB 8010: GO TO 1020
1010 GO TO 30
1020 LOAD "Char-Lib"CODE 37139,452: LET clib=PEEK 37199+256*PEEK 37200: IF clib=0 THEN GO TO 30
1030 FOR i=1 TO clib: BEEP .01,20: PRINT AT 16,0;" Loading No. ";i;" of ";clib;" fonts.": LOAD ""CODE : NEXT i: GO TO 30
2000 CLS : PRINT AT 10,0;"Press ENTER to SAVE the Library.": PAUSE 0: IF CODE INKEY$=13 THEN GO TO 2020
2010 GO TO 30
2020 LET clib=PEEK 37199+256*PEEK 37200: IF clib=0 THEN PRINT ''"Library Empty. Save Terminated!": FOR i=1 TO 10: BEEP .01,20: PAUSE 30: NEXT i: GO TO 30
2030 SAVE "Char-Lib"CODE 37139,452: FOR i=1 TO clib: BEEP .01,20: PRINT AT 16,0;" Saveing No. ";i;" of ";clib;" fonts.": LET a$="": FOR j=(37359+i*10) TO (37368+i*10): LET a$=a$+CHR$ PEEK j: NEXT j: SAVE a$CODE (39000+1000*i),768: NEXT i
2040 CLS : GO SUB 8000: VERIFY "Char-Lib"CODE
2050 FOR i=1 TO clib: BEEP .01,20: PRINT AT 16,0;" Verifying No. ";i;" of ";clib;" fonts.": VERIFY ""CODE : NEXT i: GO TO 30
3000 CLS : PRINT AT 10,0;" Press ENTER to LOAD a FONT. ": PAUSE 0: IF CODE INKEY$=13 THEN GO TO 3020
3010 GO TO 30
3020 GO SUB 8010: LET plib=PEEK 37169+256*PEEK 37170: LOAD ""CODE plib,768: GO TO 30
8000 PRINT AT 10,0;" Rewind your tape and PLAY to VERIFY your SAVE. "
8010 PRINT '" IF a LOAD ERROR occurs then: TYPE RUN (ENTER) ": RETURN
9000 LOAD "FONT-D"CODE
9100 CLEAR 28990: PAPER 1: BORDER 1: INK 7: CLS
9200 RANDOMIZE USR 34303
9300 STOP
9999 SAVE "FONT-D" LINE 9000: SAVE "FONT-D"CODE 30000,7139
1 REM *********************** SG-10 Download Character Set * by S D Lemke Lemke Software Development 2144 White Oak Wichita, Ks. 67207 ********************************
5 IF KB THEN PAUSE 0: LET k=CODE INKEY$: RETURN
6 PAUSE 3
7 LET JS=|(1,1): IF JS=1 OR JS=5 OR JS=9 THEN LET K=55: RETURN
8 LET JS=|(1,1): IF JS=2 OR JS=6 OR JS=10 THEN LET K=54: RETURN
9 LET JS=|(1,1): IF JS=8 THEN LET K=56: RETURN
10 LET JS=|(1,1): IF JS=4 THEN LET K=53: RETURN
11 LET JS=|(2,1): IF JS=1 THEN LET K=48+1-V(R-1,C): RETURN
12 IF CODE INKEY$=226 THEN LET k=226: RETURN
13 GO TO 7
15 REM GRID
20 FOR x=4 TO 101 STEP 16: PLOT x,160: DRAW 0,-64: NEXT x: FOR y=160 TO 96 STEP -8: PLOT 4,y: DRAW 96,0: NEXT y: PLOT 120,171: DRAW 18,0: DRAW 0,-13: DRAW -18,0: DRAW 0,13
30 PRINT AT 11,1;"1 3 5 7 9 B";AT 3,15;"ASCII Code:___";AT 5,15;"Descender:_";AT 8,15;"Start Column:_";AT 9,15;"End Column:__": RETURN
35 REM Define Font
40 CLS : GO SUB 20: INPUT "DL Replacement for: ";C$: LET CNT=CODE C$: LET A$(CNT,1)=C$: LET A$(CNT,2)=C$: PRINT AT 3,26;CODE C$;TAB 31
50 INPUT "Is this a Descender (Y/N)? ";C$: LET D=0: IF C$="n" OR C$="N" THEN LET D=1
60 PRINT AT 5,25;D: PRINT #0;AT 0,0;"Define your Character... Press "" STOP "" when complete."
70 LET R=2: LET C=1: DIM v(8,11)
80 PRINT AT R,C; FLASH 1; OVER 1;" ": GO SUB 5
90 PRINT AT R,C; FLASH 0; OVER 1;" "
100 IF k=226 THEN GO TO 190
110 IF k=49 THEN PRINT AT R,C;"a": LET V(R-1,C)=1: PLOT 123+c,170-r: LET C=C+1: LET k=13: GO TO 90
120 IF k=48 THEN PRINT AT R,C;"_": LET V(R-1,C)=0: PLOT INVERSE 1;123+c,170-r: LET k=13: GO TO 90
130 IF k=56 THEN LET C=C+1: IF C>11 THEN LET C=11: IF W THEN LET C=1: LET R=R+1: IF R>9 THEN LET R=9: LET C=11
140 IF k=53 THEN LET C=C-1: IF C<1 THEN LET C=1: IF W THEN LET C=11: LET R=R-1: IF R<2 THEN LET R=2: LET C=1
150 IF k=54 THEN LET R=R+1: IF R>9 THEN LET R=9: IF W THEN LET R=2: LET C=C+1: IF C>11 THEN LET C=11: LET R=9
160 IF k=55 THEN LET R=R-1: IF R<2 THEN LET R=2: IF W THEN LET R=9: LET C=C-1: IF C<1 THEN LET C=1: LET R=2
170 IF k=13 THEN LET C=C+1: IF C>11 THEN LET C=1: LET R=R+1: IF R>9 THEN LET R=9: LET C=11
180 GO TO 80
190 PRINT AT 13,8;" WORKING "
200 DIM M(11): FOR C=1 TO 11: LET M(C)=V(8,C)+V(7,C)*2+V(6,C)*4+V(5,C)*8+V(4,C)*16+V(3,C)*32+V(2,C)*64+V(1,C)*128: NEXT C
210 FOR C=1 TO 7: IF M(C)<>0 THEN GO TO 230
220 NEXT C: LET C=1
230 LET SC=C-1: PRINT AT 8,28;SC;TAB 31
240 FOR C=11 TO 4 STEP -1: IF M(C)<>0 THEN GO TO 260
250 NEXT C: LET C=11
260 IF C<11 THEN LET C=C+1
265 LET EC=C: PRINT AT 9,26;EC;TAB 31
270 LET M0=128*D+16*SC+EC
280 PRINT AT 14,0;M0,,;: FOR C=1 TO 11: PRINT M(C),;: NEXT c
290 LET A$(CNT,3)=CHR$ M0
300 FOR C=1 TO 11: LET A$(CNT,3+C)=CHR$ M(C): NEXT C
310 PAUSE 60: GO TO 40
330 REM Down Load
335 REM NOTE; the POKE in the next line tells ZPRINT-80 that the following commands are printer commands... and are not printed.
340 PRINT #0;" DOWNLOADing Font to printer. ": POKE 23728,1: LPRINT CHR$ 27;CHR$ 58;CHR$ 0;CHR$ 0;CHR$ 0: FOR C=1 TO 240: IF A$(C,1)=" " THEN GO TO 360
350 LPRINT CHR$ 27;CHR$ 38;CHR$ 0;: FOR I=1 TO 14: LPRINT a$(C,I);: NEXT I: LPRINT
360 NEXT c
370 LPRINT CHR$ 27;CHR$ 37;CHR$ 1;CHR$ 0: POKE 23728,0: LPRINT "A B C D E F G H I J K L M N O P Q R S T U V W X Y Z"
380 LPRINT "a b c d e f g h i j k l m n o p q r s t u v w x y z"
390 LPRINT "0 1 2 3 4 5 6 7 8 9"
400 GO TO 9991
8000 ON ERR RESET : ON ERR GO TO 8010: INPUT "File to LOAD? "; LINE C$: LOAD C$ DATA a$(): GO TO 9991
8010 BEEP .05,20: PRINT #0;"LOAD ERROR...... Try again!": GO TO 9991
8100 ON ERR RESET : ON ERR GO TO 8110: INPUT "File to SAVE? "; LINE C$: SAVE C$ DATA a$(): PRINT #0;"REWIND tape and Play to VERIFY.": VERIFY C$ DATA A$(): GO TO 9991
8110 BEEP .05,20: PRINT #0;"VERIFY ERROR...... Try again!": GO TO 9991
9000 IF C$="8" THEN ON ERR RESET : STOP
9010 IF C$="7" THEN LET KB=1: BEEP .05,20: PRINT AT 20,8;"KEYBOARD is On ": GO TO 9991
9020 IF C$="6" THEN LET KB=0: BEEP .05,20: PRINT AT 20,8;"KEYBOARD is Off": GO TO 9991
9030 IF C$="5" THEN LET W=NOT W: BEEP .05,20: PRINT AT 20,8;"Wrap is Off": IF W THEN PRINT AT 20,17;"n "
9035 IF C$="5" THEN GO TO 9991
9040 IF C$="4" THEN GO TO 340
9050 IF C$="3" THEN GO TO 8000
9060 IF C$="2" THEN GO TO 8100
9070 IF C$="1" THEN GO TO 40
9989 BEEP .01,40: CLS : PRINT "Remove this line and modify the next line to LOAD and initializeyour printer driver. This exampleis set to use the ZPRINT-80 HI code...": STOP
9990 LOAD ""CODE : RANDOMIZE USR 64000: DIM a$(240,14): LET W=0: LET KB=1: POKE USR "A",0: POKE USR "A"+7,0: FOR C=1 TO 6: POKE USR "A"+C,126: NEXT C: LET cnt=0
9991 ON ERR RESET : PAUSE 60
9992 CLS : PRINT AT 5,3;"Printer Font Downloader";''';"PRESS: 1 to CREATE Font 2 to SAVE Font 3 to LOAD Font 4 to DOWNLOAD Font 5 to toggle WRAP 6 for JOYSTICK 7 for KEYBOARD 8 to STOP"
9993 PAUSE 0: LET C$=INKEY$: IF C$<"1" OR C$>"8" THEN BEEP .05,1: GO TO 9993
9994 ON ERR GO TO 9992
9995 GO TO 9000
9997 DIM a$(240,14): POKE USR "A",0: POKE USR "A"+7,0: FOR C=1 TO 6: POKE USR "A"+C,126: NEXT C: LET cnt=0: GO TO 40
9998 STOP
9999 SAVE "FONT-S" LINE 9989
Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.