Newscript

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

This program generates a custom character set font by reading the built-in ROM character data (addresses 15616–16383) and transforming individual byte values through a series of substitution rules before storing the results at address 64000. The transformation logic applies piecewise replacements to each byte — for example, value 32 becomes 48, value 64 becomes 96 — effectively widening or shifting the pixel patterns to create a bolder or enhanced typeface. System variables at 23606/23607 (CHARS low/high bytes) are then POKEd to point to the new data at 64000 (offset by 256), redirecting the ROM to use the custom font. After printing instructions and producing two hardcopy listings via COPY (one with the new font, one with the standard font at 23607=60), the program calls NEW to self-destruct, leaving only the custom character data in RAM. The font can be preserved with SAVE “text” CODE 64000,1536, which also captures the UDG area.


Program Analysis

Program Structure

The program is organised into four broad phases:

  1. Initialisation (lines 1–23): A short startup fanfare via BEEP, screen setup, a “please wait” message, and a temporary adjustment to the CHARS system variable.
  2. Font generation – printable ASCII range (lines 40–210): Iterates over ROM bytes 15616–16135 (characters 32–127, the normal printable set), applies substitution rules to each byte, and writes the result to 64000 onward.
  3. Font generation – upper range (lines 215–520): Iterates over ROM bytes 16136–16383 (the remaining character data / token characters), applies a separate but similar set of substitution rules, writing from address 64520 onward.
  4. Output and self-destruction (lines 620–860, subroutines 1000–2030): Redirects the CHARS pointer to the new data, displays instructions, produces two COPY hardcopies (one enhanced, one normal), and ends with NEW.

System Variable Manipulation

The ZX Spectrum/TS2068 system variable CHARS is a two-byte pointer at addresses 23606–23607. It normally points 256 bytes before the start of the ROM character table so that CHR$ 32 (space) maps to offset 0. The program exploits this in several ways:

Line(s)POKEEffect
2, 2323609,125 / 23607,150Temporary adjustments during generation (23609 is FLAGS2; 23607 alone shifts the font mid-run)
620–63023607,249 / 23606,0Points CHARS to 63999+1 = 64000, activating the new font (249 × 256 = 63744; +256 offset = 64000)
81023607,60Points CHARS back toward ROM standard font for the second COPY comparison

Byte-Substitution Font Transformation

The core algorithm (lines 80–210 and 220–520) reads each byte of the ROM font data with PEEK, passes it through a chain of IF comparisons, and substitutes a replacement value. This is not a mathematical transform but a hand-crafted lookup table encoded as sequential IF statements. Because multiple IFs can match the same variable in a single pass (BASIC evaluates each IF line independently), there is a subtle bug risk: a substituted value could be matched and re-substituted by a later rule on the same iteration. For example in the first loop, line 91 changes 128→192, and no later rule matches 192, so this is safe; but line 92 has a compound statement (IF b=98 THEN LET b=102: IF b=82 THEN LET b=114) where the second condition can never trigger because the first assignment changes b to 102 before evaluation — the IF b=82 clause is unreachable as written.

Memory Layout

Address rangePurpose
15616–16135ROM character bitmaps for CHR$ 32–127 (printable ASCII)
16136–16383ROM character bitmaps, upper portion
64000–64519New font data for printable ASCII range (written by first loop)
64520–64999New font data for upper range (written by second loop)
64000–65535Protected by CLEAR 63999 (line 10) so BASIC heap cannot overwrite it

Notable Techniques

  • Self-destruction via NEW: Line 860 calls NEW, which wipes the BASIC program and variables but leaves the font data above RAMTOP (set by CLEAR 63999) intact.
  • Dual hardcopy: Lines 800 and 840 each call COPY to produce a printer listing of the instructions — one with the new font active, one with the standard ROM font — for direct comparison on paper.
  • Descending BEEP scale: Subroutine 2000 plays a descending glide from note −20 to −30 as a pacing separator between instruction paragraphs.
  • Startup fanfare: Lines 3 uses five BEEP calls at pitches 0, 12, 24, 36, 48 semitones (a two-octave chromatic ascent in octave steps) as an audio cue that the program has started.
  • Zero-initialisation pass: Lines 40–60 zero all 1001 bytes from 64000 to 65000 before writing font data, ensuring unused positions default to blank rather than random RAM content.
  • Author credit: Line 650 embeds "@ m.p.biddell" in the confirmation message.

Bugs and Anomalies

  • Dead compound condition (line 92): IF b=98 THEN LET b=102: IF b=82 THEN LET b=114 — after b is set to 102, the condition b=82 is always false, so the LET b=114 branch is never executed.
  • Possible re-substitution: In the second loop, several substitution chains could theoretically cascade (e.g. 48→56 at line 243, then 56→60 at line 242 on a later iteration), but since each byte is processed exactly once per loop iteration and the IFs are on separate lines, only one substitution per byte value can fire — the risk is real but limited to values that are both a source and a target within the same pass.
  • Gap at 64520: The second loop starts writing at a=64520 (line 215), leaving bytes 64500–64519 as zeros from the initialisation pass, creating a small gap between the two font segments.

Content

Appears On

Capital Area Timex Sinclair User Group’s Library Tape.

Related Products

Related Articles

Related Content

Image Gallery

Source Code

    1 REM "CHR$ gen"
    2 POKE 23609,125
    3 BEEP .2,0: BEEP .2,12: BEEP .2,24: BEEP .2,36: BEEP .2,48
   10 CLEAR 63999
   15 PAPER 0: BORDER 0: CLS 
   20 PRINT AT 10,0; INK 7; FLASH 1; PAPER 1;"PLEASE WAIT-CREATING NEW SCRIPT"
   23 POKE 23607,150
   40 FOR j=64000 TO 65000
   50 POKE j,0
   60 NEXT j
   70 LET a=64000
   80 FOR j=15616 TO 16135
   90 LET b=(PEEK j)
   91 IF b=128 THEN LET b=b+64
   92 IF b=98 THEN LET b=102: IF b=82 THEN LET b=114
   93 IF b=70 THEN LET b=102
  101 IF b=68 THEN LET b=b+40
  105 IF b=66 THEN LET b=102
  110 IF b=64 THEN LET b=b+32
  120 IF b=32 THEN LET b=b+16
  130 IF b=16 THEN LET b=b+8
  135 IF b=8 THEN LET b=b+4
  140 IF b=4 THEN LET b=b+2
  150 IF b=2 THEN LET b=b+4
  160 IF b>255 THEN GO TO 200
  170 IF b=0 THEN GO TO 200
  180 POKE a,b
  200 LET a=a+1
  210 NEXT j
  215 LET a=64520
  220 FOR j=16136 TO 16383
  222 LET b=PEEK j
  230 IF b=120 THEN LET b=124
  231 IF b=146 THEN LET b=214
  232 IF b=84 THEN LET b=214
  233 IF b=104 THEN LET b=238
  234 IF b=96 THEN LET b=112
  235 IF b=68 THEN LET b=102
  238 IF b=64 THEN LET b=96
  240 IF b=60 THEN LET b=126
  242 IF b=56 THEN LET b=60
  243 IF b=48 THEN LET b=56
  244 IF b=40 THEN LET b=44
  245 IF b=36 THEN LET b=38
  248 IF b=34 THEN LET b=102
  250 IF b=32 THEN LET b=96
  255 IF b=28 THEN LET b=60
  260 IF b=24 THEN LET b=30
  265 IF b=16 THEN LET b=24
  270 IF b=12 THEN LET b=30
  280 IF b=4 THEN LET b=6
  500 POKE a,b
  510 LET a=a+1
  520 NEXT j
  620 POKE 23607,249
  630 POKE 23606,00
  635 PAPER 0
  636 BORDER 0
  640 CLS 
  650 PRINT AT 10,0; INK 5; PAPER 0;"CHARACTERS loaded-@ m.p.biddell"
  660 PRINT 
  670 PAUSE 200
  680 CLS 
  690 GO SUB 1000
  705 PAUSE 100
  800 COPY 
  810 POKE 23607,60
  815 CLS 
  820 GO SUB 1000
  840 COPY 
  850 PAUSE 100
  860 NEW 
 1000 PRINT INK 6;"INSTRUCTIONS-NEW CHARACTER FONT"
 1010 GO SUB 2000
 1020 PRINT INK 5;"1. After this program has self  destructed, poke 23607,249 to   turn on the new character set."
 1030 GO SUB 2000
 1040 PRINT INK 5;"2. Then load your own program inthe normal way, Poke 23607,249  and it is instantly converted   to the new text. Now use LLIST  to see the enhanced output      from the 2040-printer."
 1050 GO SUB 2000
 1060 PRINT INK 5;"3. Now Poke 23607,60 and LLIST .Compare this normal listing withthe enhanced one."
 1070 GO SUB 2000
 1080 PRINT INK 5;"4. SAVE 'text'CODE ,64000,1536  (this also saves U.D.G's.)"
 1090 GO SUB 2000
 1100 RETURN 
 2000 PRINT : FOR j=20 TO 30
 2010 BEEP .1,-j
 2020 NEXT j
 2030 RETURN

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

People

No people associated with this content.

Scroll to Top