Old English Fonts

Date: 198x
Type: Program
Platform(s): TS 2068
Tags: Font

This program is an interactive “Old English” decorative font compositor that lets users type characters rendered as large, multi-row glyphs on screen. Each keystroke maps to a unique font glyph drawn across three or four display rows using custom character sets, with the active character set selected by POKEing addresses 23606–23607 to redirect the UDG/font pointer to one of several machine code font tables loaded separately as a CODE block at address 61559. The program supports uppercase letters A–Z, lowercase a–z, digits 0–9, and several punctuation marks, each rendered 1–3 columns wide. Editing features include single-character delete (DELETE key, code 12), full-line erase (CAPS SHIFT 5, code 8), screen clear (EDIT, code 7), new line (ENTER, code 13), and two COPY-triggered print routines via RANDOMIZE USR 23296. A companion section (lines 1603–1625) provides an oversized six-column-wide font mode accessible via the “(” key.


Program Analysis

Program Structure

The program is divided into several functional zones:

  1. Lines 5–16: Subroutines that select a font table by POKEing system variables 23606–23607, then position the print cursor via PRINT AT L,C; and RETURN.
  2. Lines 25–33: Menu display and mode-select loop; pressing p jumps to the typing compositor at line 300 (which falls through to line 330 via missing intermediate lines).
  3. Lines 330–1500: The main compositor loop. Initializes row (L) and column (C) cursors, then polls INKEY$ for each supported character and dispatches to the appropriate font subroutine and glyph print block.
  4. Lines 1603–1625: An alternate “wide” mode (6 columns per glyph) entered by pressing ( at line 365, with its own scan loop.
  5. Lines 9030–9990: Bootstrap and save lines: LOAD "OldEng C" CODE 61559,3808 loads the machine code font data, then RUN starts the program. SAVE lines persist both BASIC and the CODE block.

Font Table Switching via POKEs

The most technically notable feature is the use of system variables at addresses 23606 and 23607, which together form a two-byte pointer that the ROM uses to locate the user-defined graphics (UDG) character bitmaps. By POKEing different values into this pair, the program redirects the character renderer to one of several font tables embedded in the machine code block at address 61559 (near the top of 64K RAM). The subroutines and their target addresses are:

LinePOKE 23606POKE 23607Computed AddressUsed For
1006015360Default/reset font
1121625064216Lowercase f–x font
1218425365208 (approx)Lowercase y–z and punctuation font
1511923961303 (approx)Digit 1–0 font
168724161783 (approx)Wide-glyph / apostrophe font
615224262104 (approx)Uppercase A–J font
710424562824 (approx)Uppercase K–S font
8824863496 (approx)Uppercase T–Z and lowercase a–e font

Each computed address equals PEEK(23607)*256 + PEEK(23606). Because characters from code 32 upward are printed normally but rendered via the redirected UDG pointer math, the actual on-screen glyphs come from the loaded CODE block rather than the ROM character set.

Glyph Layout and Cursor Management

Each “letter” occupies a cell 3–4 rows tall and 1–3 (or 6, in wide mode) columns wide. After a font subroutine sets the pointer and positions the cursor, the calling line prints strings of remapped characters at AT L,C, AT L+1,C, AT L+2,C, and sometimes AT L+PI,C (effectively AT L+3,C since INT(PI)=3). The column counter C is then incremented by the glyph width. Using PI instead of 3 is a minor memory/token optimization — a floating-point literal 3 occupies the same token space, but PI is a single keyword token.

Line and Column Wraparound

Several boundary conditions are managed around column 29–31:

  • C=29: Triple beep warning (line 950).
  • C=30: Double beep (line 960).
  • C=31: Short beep (line 970).
  • C>31: Advance L by 4, reset C to 0, multi-beep fanfare (line 980).
  • ENTER (code 13): Manual new line advance (line 990).

Editing Commands

Key / CodeLineAction
DELETE (code 12)1000Erases 4 rows at column C-1, decrements C
EDIT (code 7)1010CLS and restart compositor
CAPS SHIFT 5 (code 8)1020Erases current row (columns 0 onward), resets C=0
STOP keyword361RANDOMIZE USR 23296 (COPY to printer), then CLS restart
NOT keyword362RANDOMIZE USR 23296 (COPY to printer), then partial restart

The use of RANDOMIZE USR 23296 calls the ROM COPY routine that sends the screen contents to a ZX Printer.

Notable Bugs and Anomalies

  • Line 500 typo: The “N” branch prints ";>=";... (note >= instead of <= as in the “D” branch at line 400). This is likely a copy-paste error causing a slightly wrong glyph segment.
  • Line 1020 dead code: LET L=L is a no-op. The subsequent GO TO 360 is preceded by REM deletes line, but the GO TO before the REM still executes correctly — the REM text is just documentation squeezed onto the same line.
  • Line 520 / 610: The “P” and “Y” uppercase branches use AT L+PI,C to print a fourth glyph row, making these characters taller than most others. This is intentional for letters with descenders.
  • Missing line 300: The menu at line 33 says GO TO 300, but no line 300 exists; execution falls through to line 330 automatically, which is the intended behavior.
  • Line 860: The “x” lowercase branch references "{" in a PRINT string. On the TS2068, { outside a string is the ON ERR keyword token, but inside a string literal it is a literal brace character — this is fine as printed output.

Key BASIC Idioms

  • PAUSE NOT PI (lines 360, 1603): NOT PI evaluates to 0, so PAUSE 0 waits indefinitely for a key — a standard fast-loop idiom rather than a timed pause.
  • CODE INKEY$=32 etc.: Using CODE on INKEY$ to test control/special keys by ASCII value avoids entering unprintable characters into the listing.
  • All font subroutines share the same structure (POKE pair + optional PRINT AT L,C; + RETURN), keeping the calling lines uniform.

Content

Appears On

Library tape of the Indiana Sinclair Timex User’s Group.

Related Products

Related Articles

Related Content

Image Gallery

Old English Fonts

Source Code

    5 GO SUB 10: GO TO 25
    6 POKE 23606,152: POKE 23607,242: PRINT AT L,C;: RETURN 
    7 POKE 23606,104: POKE 23607,245: PRINT AT L,C;: RETURN 
    8 POKE 23606,8: POKE 23607,248: PRINT AT L,C;: RETURN 
   10 POKE 23606,0: POKE 23607,60: RETURN 
   11 POKE 23606,216: POKE 23607,250: RETURN 
   12 POKE 23606,184: POKE 23607,253: RETURN 
   15 POKE 23606,119: POKE 23607,239: RETURN 
   16 POKE 23606,87: POKE 23607,241: PRINT AT L,c;: RETURN 
   25 PRINT INK 4;AT 1,7;"OLD ENGLISH FONTS": PRINT INK 2;AT 2,11;"  MENU  "
   26 PRINT AT 4,2;"DEFINED FONTS .......A - Z";AT 5,23;"a - z";AT 6,23;"1 - 0";AT 7,20;"""?,.:;'$"
   27 PRINT "  SPACE ...........SPACE BAR"'"  DELETE ONE FONT ... DELETE"'"  DELETE LINE..........C/S 5"'"  START OVER AGAIN......EDIT"'"  NEW LINE.............ENTER"
   28 PRINT "  RETURN TO BASIC..........a"'"  TO TYPE..................p"
   29 PRINT ' INK 4;"  COPY - NEW............STOP"' INK 4;"  COPY - REPEAT..........NOT"
   30 PRINT #1; INK 2;"   INPUT   p/a "
   32 PAUSE 0
   33 IF INKEY$="p" THEN GO TO 300
  330 CLS 
  340 LET L=1: LET C=0
  360 PAUSE NOT PI
  361 IF INKEY$=" STOP " THEN RANDOMIZE USR 23296: GO TO 330
  362 IF INKEY$="NOT " THEN RANDOMIZE USR 23296: GO TO 340
  365 IF INKEY$="(" THEN GO TO 1600
  370 IF INKEY$="A" THEN GO SUB 6: PRINT " !""";AT L+1,C;"#$%";AT L+2,C;"&'(": LET C=C+3
  380 IF INKEY$="B" THEN GO SUB 6: PRINT ")*+";AT L+1,C;",-.";AT L+2,C;"/01": LET C=C+3
  390 IF INKEY$="C" THEN GO SUB 6: PRINT "234";AT L+1,C;"567";AT L+2,C;"89:": LET C=C+3
  400 IF INKEY$="D" THEN GO SUB 6: PRINT ";<=";AT L+1,C;">?@";AT L+2,C;"ABC": LET C=C+3
  410 IF INKEY$="E" THEN GO SUB 6: PRINT "DEF";AT L+1,C;"GHI";AT L+2,C;"JKL": LET C=C+3
  420 IF INKEY$="F" THEN GO SUB 6: PRINT "MNO";AT L+1,C;"PQR";AT L+2,C;"STU": LET C=C+3
  430 IF INKEY$="G" THEN GO SUB 6: PRINT "VWX";AT L+1,C;"YZ[";AT L+2,C;"\]^": LET C=C+3
  440 IF INKEY$="H" THEN GO SUB 6: PRINT "_`a";AT L+1,C;"bcd";AT L+2,C;"efg": LET C=C+3
  450 IF INKEY$="I" THEN GO SUB 6: PRINT "hij";AT L+1,C;"klm";AT L+2,C;"nop": LET C=C+3
  460 IF INKEY$="J" THEN GO SUB 6: PRINT "qrs";AT L+1,C;"tuv";AT L+2,C;"wxy": LET C=C+3
  470 IF INKEY$="K" THEN GO SUB 7: PRINT " !""";AT L+1,C;"#$%";AT L+2,C;"&'(": LET C=C+3
  480 IF INKEY$="L" THEN GO SUB 7: PRINT ")*+";AT L+1,C;",-.";AT L+2,C;"/01": LET C=C+3
  490 IF INKEY$="M" THEN GO SUB 7: PRINT "234";AT L+1,C;"567";AT L+2,C;"89:": LET C=C+3
  500 IF INKEY$="N" THEN GO SUB 7: PRINT ";>=";AT L+1,C;">?@";AT L+2,C;"ABC": LET C=C+3
  510 IF INKEY$="O" THEN GO SUB 7: PRINT "DEF";AT L+1,C;"GHI";AT L+2,C;"JKL": LET C=C+3
  520 IF INKEY$="P" THEN GO SUB 7: PRINT "MNO";AT L+1,C;"PQR";AT L+2,C;"STU";AT L+PI,C;"VWX": LET C=C+3
  530 IF INKEY$="Q" THEN GO SUB 7: PRINT "YZ[";AT L+1,C;"\]^";AT L+2,C;"_`a": LET C=C+3
  540 IF INKEY$="R" THEN GO SUB 7: PRINT "bcd";AT L+1,C;"efg";AT L+2,C;"hij": LET C=C+3
  550 IF INKEY$="S" THEN GO SUB 7: PRINT "klm";AT L+1,C;"nop";AT L+2,C;"qrs": LET C=C+3
  560 IF INKEY$="T" THEN GO SUB 8: PRINT " !""";AT L+1,C;"#$%";AT L+2,C;"&'(": LET C=C+3
  570 IF INKEY$="U" THEN GO SUB 8: PRINT ")*+";AT L+1,C;",-.";AT L+2,C;"/01": LET C=C+3
  580 IF INKEY$="V" THEN GO SUB 8: PRINT "234";AT L+1,C;"567";AT L+2,C;"89:": LET C=C+3
  590 IF INKEY$="W" THEN GO SUB 8: PRINT ";<=";AT L+1,C;">?@";AT L+2,C;"ABC": LET C=C+3
  600 IF INKEY$="X" THEN GO SUB 8: PRINT "DEF";AT L+1,C;"GHI";AT L+2,C;"JKL": LET C=C+3
  610 IF INKEY$="Y" THEN GO SUB 8: PRINT "MNO";AT L+1,C;"PQR";AT L+2,C;"STU";AT L+PI,C;"VWX": LET C=C+3
  620 IF INKEY$="Z" THEN GO SUB 8: PRINT "YZ[";AT L+1,C;"\]^";AT L+2,C;"_`a": LET C=C+3
  630 IF INKEY$="a" THEN GO SUB 8: PRINT AT L+1,C;"bc";AT L+2,C;"de": LET C=C+2
  640 IF INKEY$="b" THEN GO SUB 8: PRINT "fg";AT L+1,C;"hi";AT L+2,C;"jk": LET C=C+2
  650 IF INKEY$="c" THEN GO SUB 8: PRINT AT L+1,C;"lm";AT L+2,C;"no": LET C=C+2
  660 IF INKEY$="d" THEN GO SUB 8: PRINT "pq";AT L+1,C;"rs";AT L+2,C;"tu": LET C=C+2
  670 IF INKEY$="e" THEN GO SUB 8: PRINT AT L+1,C;"vw";AT L+2,C;"xy": LET C=C+2
  680 IF INKEY$="f" THEN GO SUB 11: PRINT AT L,C;" !";AT L+1,C;"""#";AT L+2,C;"$%": LET C=C+2
  690 IF INKEY$="g" THEN GO SUB 11: PRINT AT L+1,C;"&'";AT L+2,C;"()";AT L+PI,C;"*+": LET C=C+2
  700 IF INKEY$="h" THEN GO SUB 11: PRINT AT L,C;",-";AT L+1,C;"./";AT L+2,C;"01": LET C=C+2
  710 IF INKEY$="i" THEN GO SUB 11: PRINT AT L,C;"2";AT L+1,C;"3";AT L+2,C;"4": LET C=C+1
  720 IF INKEY$="j" THEN GO SUB 11: PRINT AT L,C;"2";AT L+1,C;"5";AT L+2,C;"67";AT L+PI,C;"89": LET C=C+2
  730 IF INKEY$="k" THEN GO SUB 11: PRINT AT L,C;":;";AT L+1,C;"<=";AT L+2,C;">?": LET C=C+2
  740 IF INKEY$="l" THEN GO SUB 11: PRINT AT L,C;"@";AT L+1,C;"A";AT L+2,C;"B": LET C=C+1
  750 IF INKEY$="m" THEN GO SUB 11: PRINT AT L+1,C;"CD";AT L+2,C;"EF": LET C=C+2
  760 IF INKEY$="n" THEN GO SUB 11: PRINT AT L+1,C;"GH";AT L+2,C;"IJ": LET C=C+2
  770 IF INKEY$="o" THEN GO SUB 11: PRINT AT L+1,C;"KL";AT L+2,C;"MN": LET C=C+2
  780 IF INKEY$="p" THEN GO SUB 11: PRINT AT L+1,C;"OP";AT L+2,C;"QR";AT L+PI,C;"ST": LET C=C+2
  790 IF INKEY$="q" THEN GO SUB 11: PRINT AT L+1,C;"UV";AT L+2,C;"WX";AT L+PI,C+1;"Y": LET C=C+2
  800 IF INKEY$="r" THEN GO SUB 11: PRINT AT L+1,C;"Z[";AT L+2,C;"\]": LET C=C+2
  810 IF INKEY$="s" THEN GO SUB 11: PRINT AT L+1,C;"^_";AT L+2,C;"`a": LET C=C+2
  820 IF INKEY$="t" THEN GO SUB 11: PRINT AT L,C;"b";AT L+1,C;"c";AT L+2,C;"d": LET C=C+1
  830 IF INKEY$="u" THEN GO SUB 11: PRINT AT L+1,C;"ef";AT L+2,C;"gh": LET C=C+2
  840 IF INKEY$="v" THEN GO SUB 11: PRINT AT L,C;"ij";AT L+1,C;"kl";AT L+2,C;"mn": LET C=C+2
  850 IF INKEY$="w" THEN GO SUB 11: PRINT AT L,C+1;"op";AT L+1,C;"qrs";AT L+2,C;"tuv": LET C=C+3
  860 IF INKEY$="x" THEN GO SUB 11: PRINT AT L+1,C;"wx";AT L+2,C;"yz";AT L+PI,C;"{": LET C=C+2
  870 IF INKEY$="y" THEN GO SUB 12: PRINT AT L+1,C;" !";AT L+2,C;"""#";AT L+PI,C;"$%": LET C=C+2
  880 IF INKEY$="z" THEN GO SUB 12: PRINT AT L+1,C;"&'";AT L+2,C;"()": LET C=C+2
  890 IF INKEY$="?" THEN GO SUB 12: PRINT AT L,C;"*+";AT L+1,C;",-";AT L+2,C;"./": LET C=C+2
  900 IF INKEY$=":" THEN GO SUB 12: PRINT AT L+1,C;"0";AT L+2,C;"0": LET C=C+1
  910 IF INKEY$=";" THEN GO SUB 12: PRINT AT L+1,C;"0";AT L+2,C;"2": LET C=C+1
  920 IF INKEY$="," THEN GO SUB 12: PRINT AT L+2,C;"2": LET C=C+1
  930 IF INKEY$="." THEN GO SUB 12: PRINT AT L+2,C;"3": LET C=C+1
  940 IF CODE INKEY$=32 THEN LET C=C+1: BEEP .2,20
  950 IF C=29 THEN BEEP .2,12: BEEP .2,12: BEEP .2,12
  960 IF C=30 THEN BEEP .2,10: BEEP .2,10
  970 IF C=31 THEN BEEP 0,1
  980 IF C>31 THEN LET L=L+4: LET C=0: BEEP 0,1: BEEP .2,20: BEEP .2,20: BEEP .2,20: BEEP .2,20: BEEP .2,20: BEEP .2,20: BEEP .2,20: BEEP .2,20
  990 IF CODE INKEY$=13 THEN LET L=L+4: LET C=0: BEEP 1,0
 1000 IF CODE INKEY$=12 THEN GO SUB 10: PRINT AT L,C-1;" ";AT L+1,C-1;" ";AT L+2,C-1;" ";AT L+PI,C-1;" ": LET C=C-1
 1010 IF CODE INKEY$=7 THEN CLS : GO TO 340
 1020 IF CODE INKEY$=8 THEN GO SUB 10: PRINT AT L,0,,,,,,,,: LET L=L: LET C=0: GO TO 360: REM deletes line
 1025 IF INKEY$="1" THEN GO SUB 15: PRINT AT L,C;" ";AT L+1,C;"!";AT L+2,C;"""": LET C=C+1
 1030 IF INKEY$="2" THEN GO SUB 15: PRINT AT L,C;"#$";AT L+1,C;"%&";AT L+2,C;"'(": LET C=C+2
 1035 IF INKEY$="3" THEN GO SUB 15: PRINT AT L,C;")*";AT L+1,C;"+,";AT L+2,C;"-.": LET C=C+2
 1040 IF INKEY$="4" THEN GO SUB 15: PRINT AT L,C;"/0";AT L+1,C;"12";AT L+2,C;"34": LET C=C+2
 1045 IF INKEY$="5" THEN GO SUB 15: PRINT AT L,C;"56";AT L+1,C;"78";AT L+2,C;"9:": LET C=C+2
 1050 IF INKEY$="6" THEN GO SUB 15: PRINT AT L,C;";<";AT L+1,C;"=>";AT L+2,C;"?@": LET C=C+2
 1055 IF INKEY$="7" THEN GO SUB 15: PRINT AT L,C;"AB";AT L+1,C;"CD";AT L+2,C;"EF": LET C=C+2
 1057 IF INKEY$="8" THEN GO SUB 15: PRINT AT L,C;"GH";AT L+1,C;"IJ";AT L+2,C;"KL": LET C=C+2
 1060 IF INKEY$="9" THEN GO SUB 15: PRINT AT L,C;"MN";AT L+1,C;"OP";AT L+2,C;"QR": LET C=C+2
 1065 IF INKEY$="0" THEN GO SUB 15: PRINT AT L,C;"ST";AT L+1,C;"UV";AT L+2,C;"WX": LET C=C+2
 1070 IF INKEY$="$" THEN GO SUB 15: PRINT AT L,C;"Y";AT L+1,C;"Z";AT L+2,C;"[": LET C=C+1
 1080 IF INKEY$="'" THEN GO SUB 16: PRINT "#": LET C=C+1
 1085 IF INKEY$="""" THEN GO SUB 16: PRINT "##": LET C=C+2
 1500 GO TO 360
 1603 PAUSE NOT PI
 1605 IF INKEY$="A" THEN GO SUB 16: PRINT "$%&'()";AT L+1,C;"*+,-./";AT L+2,C;"012345": LET C=C+6: GO TO 360
 1610 IF INKEY$="Z" THEN GO SUB 16: PRINT "6789:;";AT L+1,C;"<=>?@A";AT L+2,C;"BCDEFG": LET C=C+6: GO TO 360
 1615 IF INKEY$="C" THEN GO SUB 16: PRINT " ";AT L+1,C;"!";AT L+2,C;"""": LET C=C+1: GO TO 360
 1625 GO TO 1603
 9030 LOAD "OldEng C"CODE 61559,3808
 9040 RUN 
 9990 SAVE "OldEng" LINE 9030: SAVE "OldEng C"CODE 61559,3808

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

People

No people associated with this content.

Scroll to Top