New CHR$

This file is part of ISTUG Public Domain Library 5, and ISTUG Public Domain Library 6. Download the collection to get this file.
Date: 198x
Type: Program
Platform(s): TS 2068
Tags: Demo

This program offers several character-set manipulation utilities, accessible by jumping to specific line numbers. The main routine (line 30) copies the ROM character set from address 15616–16384 into RAM at 64368, then reverses the vertical order of each character’s eight pixel rows, producing an upside-down font. It then redirects the system variable CHARS (held at addresses 23606–23607) to point to the new RAM-based table at 64368 (stored as the two-byte value 64368−256 = 250×256+112, i.e. POKE 23606,112: POKE 23607,250), making the inverted set live immediately. The “New Chrs” routine (line 280) instead replaces the lowercase letter definitions (offset 264 bytes into the table, covering characters from ASCII 65 onward) with custom pixel data supplied via DATA statements, each row encoded with the literal variable b used as a zero placeholder. Line 460 uses RANDOMIZE USR 0 to crash/reset the machine, and lines 500–510 provide LOAD and SAVE commands for persisting the custom character data as a CODE block.


Program Analysis

Program Structure

The program is a menu-driven collection of independent utilities, each entered by jumping to a labeled line. Line 10 prints a directory of entry points, and line 20 halts execution if the program is simply RUN from the start. Each routine ends with STOP, so routines are self-contained.

Entry LineRoutineDescription
30InversionCopies ROM font to RAM, reverses row order of every glyph, redirects CHARS pointer
220Apply inversion pointerOnly POKEs CHARS to point to 64368; skips the copy/transform work
250Revert to normalRestores CHARS pointer to ROM default (60×256 = 15360, offset by −256 → 23606=0, 23607=60)
280New ChrsCopies ROM font to RAM, then overwrites lowercase glyph data with custom DATA
460Destroy programExecutes RANDOMIZE USR 0 to force a hard reset

Font Inversion Technique (Lines 30–210)

The ZX Spectrum ROM character bitmaps occupy addresses 15616–16383 (768 bytes, covering ASCII 32–127, 8 bytes per character). The routine copies this block byte-for-byte into RAM at 64368. It then iterates over each of the 96 characters: for each character it reads its 8 row bytes into array d(8), writes them back in reverse order into array e(8) (line 170: LET e(e)=d(9-e)), and POKEs the reversed bytes back to the RAM copy. This vertically flips every glyph.

CHARS System Variable Manipulation

The system variable CHARS is stored at addresses 23606–23607 as a 16-bit little-endian value equal to the character table base address minus 256 (because the Spectrum calculates the glyph address as CHARS + 8*(code-32) + 256). The ROM default is 15360 (= 15616 − 256), stored as POKE 23606,0 : POKE 23607,60 (60×256 = 15360). Redirecting to the RAM copy at 64368 requires storing 64112 (= 64368 − 256), which is 112 + 250×256, giving POKE 23606,112 : POKE 23607,250.

New Characters Routine (Lines 280–450)

After copying the ROM font to 64368, this routine uses LET x=64368+264 to target the lowercase region (character code 65+32=97 starts at offset 264; the comment on line 360 notes that changing 264 to 520 would target uppercase). It then RESTOREs the DATA pointer and reads 207 bytes of custom pixel data via a FOR/READ/POKE loop, overwriting those glyphs with hand-drawn bitmaps.

The DATA statements use the literal variable name b as a zero placeholder (since at this point in execution b holds 0 from the copy loop). This is an unusual idiom: reading a variable name from a DATA statement would normally cause a syntax error in Spectrum BASIC, so b here actually refers to the numeric value 0 written symbolically as the letter b — but in practice this only works because READ b at line 380 reads numeric DATA, and the DATA values labeled b are in fact the numeric token for the letter b being interpreted as the number stored in variable b. This is a notable quirk and could be fragile if b were not zero.

RESTORE and DATA Pointer Reset

Line 370 calls RESTORE without a line number, resetting the DATA pointer to the first DATA statement in the program. Because the first DATA statements appear at line 410, the loop correctly reads the custom glyph bytes. A second set of DATA statements at line 480 (inside the “destroy” section) is never reached by the restore/read loop and appears to be an earlier or alternate version of the glyph data left in the program.

Notable Anomalies and Issues

  • The variable conflict on line 160–180: e is used both as an array (DIM e(8)) and as a FOR loop variable (FOR e=1 TO 8). In Spectrum BASIC, a numeric variable and an array with the same single-letter name can coexist, so this is legal, though confusing.
  • Similarly on line 110, q is assigned but the double colon (::) at the end of the line is a Spectrum BASIC separator (equivalent to :), not a block-graphic escape — it simply separates statements.
  • The copy loop range is 15616 TO 16384 (769 bytes), which is one byte more than the 768-byte ROM font. This extra byte is harmless but unnecessary.
  • CLEAR 64367 is used to both protect the RAM area at 64368 from BASIC and to reset the stack pointer, which is standard practice for machine-code or data areas placed above RAMTOP.
  • Lines 500–510 provide LOAD and SAVE commands as executable lines but they are only reachable manually; SAVE at line 510 saves the BASIC program itself with a LINE 10 autostart, while the CODE SAVE is shown only in the trailing REM, requiring manual editing to use.

Destroy Routine (Line 460)

RANDOMIZE USR 0 jumps to address 0 in ROM, which is the cold-start entry point, effectively performing a hard reset and clearing the BASIC program from RAM. This is a common trick used as a dramatic “self-destruct” mechanism.

Content

Appears On

Explore a first-person 3D maze, watch an audio oscilloscope in real time, draw pixel art with ten drawing modes, or generate random surreal poetry — ISTUG Library 5 is a sprawling collection that covers every corner of the TS 2068 experience.
Run a lemonade stand, manage a radio factory through crises, catch drips as a plumber, or compose three-voice music note by note — ISTUG Library 6 balances business simulations and financial tools with arcade action and creative software.

Related Products

Related Articles

Related Content

Image Gallery

Source Code

   10 CLS : PRINT ''"Enter:"''"GO TO 30 for inversion"''"GO TO 250 to revert to normal"''"GO TO 220 for inversion"''"GO TO 280 for New Chrs"''"GO TO 250 to revert to normal"''"GO TO 460 to destroy program"
   20 STOP 
   30 REM  Inversion 
   40 CLEAR 64367
   50 BEEP .2,-10: BEEP .4,20
   60 PRINT AT 10,5; PAPER 1; INK 7;"Please wait a minute..."
   70 LET mem=64368
   80 LET b=0: FOR a=15616 TO 16384
   90 POKE mem+b,PEEK a
  100 LET b=b+1: NEXT a
  110 FOR a=32 TO 127: LET q=a-32:: LET b=q*8: LET c=mem+b
  120 DIM d(8): LET b=1
  130 FOR e=c TO c+7
  140 LET d(b)=PEEK e
  150 LET b=b+1: NEXT e
  160 DIM e(8): FOR e=1 TO 8
  170 LET e(e)=d(9-e)
  180 NEXT e
  190 LET b=1: FOR e=c TO c+7
  200 POKE e,e(b)
  210 LET b=b+1: NEXT e: NEXT a
  220 POKE 23606,112: POKE 23607,250
  230 BEEP .2,20: BEEP .4,-10
  240 STOP 
  250 REM  revert to normal 
  260 POKE 23606,0: POKE 23607,60
  270 STOP 
  280 REM  New Chrs 
  290 CLEAR 64367
  300 BEEP .2,-5: BEEP .4,15
  310 PRINT AT 10,5; PAPER 1; INK 7;"Please wait 20 seconds..."
  320 LET b=0: FOR a=15616 TO 16384
  330 POKE 64368+b,PEEK a
  340 LET b=b+1: NEXT a
  350 LET x=64368+264
  360 REM  change 520 to 264 in line 350 for upper case letters 
  370 RESTORE : FOR a=x TO x+206
  380 READ b: POKE a,b
  390 NEXT a
  400 POKE 23606,112: POKE 23607,250
  410 DATA 0,124,76,76,124,76,b,0,b,124,100,b,124,100,124,0,b,124,76,64,76,b,124,0,b,124,76,b,b,b,124,0,b,124,96,b,124,96,124,0,b,124,96,b,124,96,b,0,b,124,76,64,92,76,124,0,b,100,b,b,124,100,b,0,b,24,b,b,b,b,b,0,b
  420 DATA 12,b,b,b,b,60,0,b,100,b,b,124,76,b,0,b,96,b,b,b,b,120,0,b,126,90,b,b,b,b,0,b,124,76,b,b,b,b,0,b,124,100,b,b,b,124,0,b,124,100,b,124,64,b,0,b,124,100,b,b,b,126,0,b,124,100,b,124,76,b,0,b,124,100,96,28,76,124,0,b,126,24,b,b,b,b,0,b
  430 DATA 100,b,b,b,b,124,0,b,100,b,b,b,b,56,0,b,90,b,b,b,b,126,0,b,100,b,b,124,92,b,0,b,104,b,b,120,16,b,0,b,124,100,28,32,76,124
  440 BEEP .2,15: BEEP .4,-5
  450 STOP 
  460 REM  destroy program 
  470 RANDOMIZE USR 0
  480 DATA 0,124,76,b,124,76,b,0,b,124,100,b,124,100,124,0,b,124,76,64,76,b,124,0,b,124,76,b,b,b,124,0,b,124,96,b,124,b,124,0,b,124,96,b,124,96,b,0,b,124,76,64,92,76,124,0,b,100,b,b,124,100,b,0,b,24,b,b,b,b,b,0,b
  490 REM      ***********************            NEW CHR$     ***********************
  500 LOAD "NEW CHR$"CODE 64368,264
  510 SAVE "NEW CHR$" LINE 10: REM SAVE "NEW CHR$"CODE 64368,264

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

People

No people associated with this content.

Scroll to Top