64 Column

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

This program implements a 64-column text display mode for the TS2068, using machine code to reconfigure the SCLD and custom character rendering. It embeds a Z80 machine code routine as a hex string in line 65, POKEing it into RAM at address 63206, then executes it via RANDOMIZE USR to set up the hardware for the wider display. The program manages a scrolling text buffer in the display file area (16384–24575), cycling through screen thirds in 8192-byte steps, and supports two character sets (normal and inverse, toggled with key 6) by switching between ROM font data at 15616 and custom UDG data at 63272. Key 5 sets inverse video (i=255), key 4 sets normal (i=0), and key 12 triggers a backspace-like operation; all other printable ASCII characters (32–122) are rendered into the display using the GO SUB at line 20, which copies eight bytes of font data using a stride of 256 bytes to write one column of the 64-column grid.


Program Structure

The program is divided into three broad phases:

  1. Initialisation (lines 10–95): Checks whether the machine code is already installed (line 40, testing address 23746 for 128), clears RAM above 63205, reads UDG slot assignments, decodes and POKEs the hex machine code string, runs it, then patches eight bytes of UDG data.
  2. Main editor loop (lines 100–245): Sets up the ON ERR handler, sends OUT 255,14 to select the 64-column mode, then processes keystrokes and manages the display file pointer df.
  3. Error / save epilogue (lines 9989–9998): On error, restores normal display via OUT 255,128, re-enters the machine code, resets the error trap, and optionally saves the program.

Machine Code Loader

Lines 65–85 implement a classic hex-string loader. The string in u$ encodes Z80 opcodes as ASCII hex pairs. The loop at line 70 steps through the string two characters at a time, computing each byte as 16*VAL u$(n) + VAL u$(n+1) and POKEing it to successive addresses from 63206. RANDOMIZE USR 63218 then calls into the middle of the routine, suggesting the first few bytes at 63206–63217 are a separate sub-routine (called later in the error handler at line 9991) and the entry point at 63218 is the ULA reconfiguration code.

The hex string decodes to approximately 48 bytes of Z80 code. Notable opcodes visible in the stream include DI (F3), EI (FB), OUT (n),A (D3), IN A,(n) (DB), and RET (C9), consistent with ULA port manipulation (port 0xF4 is the TS2068 ULA control port).

Display File Management

The TS2068 Spectrum-compatible display occupies 6144 bytes from 16384 to 22527, but this program extends its notion of the display across three 8192-byte “pages” between 16384 and 24575. The variable df tracks the current character cell’s display-file byte address. Wrapping logic appears in two places:

  • Line 200 (forward scroll): df = df + 8192*(df<22528) - 8191*(df>24575) — advances one page, wrapping back to 16384 when past 24575.
  • Line 310 (backward scroll): df = df - 8192*(df>24575) + 8191*(df<22528) — the inverse operation.

Column position is tracked in c (1–64) and row in b (1–24). When c reaches 0 the program decrements b and resets c to 64, implementing a simple 64×24 grid.

Character Rendering Subroutine

The subroutine at lines 20–35 renders one character into the display. Line 20 computes s = 15616 + 8*(k-32), the address of the character’s font data in the ROM (the Spectrum font starts at 15616, i.e. 0x3C00). Lines 25–35 then loop over eight pixel rows, each separated by 256 bytes in the display file (one scan line in 64-column mode uses 256-byte row strides rather than the normal 32). The expression ABS(i - PEEK s) implements colour inversion: when i=0 the byte is used as-is; when i=255 all bits are flipped via 255 - PEEK s.

Character Set Switching

Two sources of font data are used:

Variable iFont source addressDescription
015616ROM character set (normal)
25563272Custom UDG area (patched at lines 90–95)

Line 120 selects the UDG set when PEEK 23658 = 8 (a flag byte toggled by key 6 at line 145). The patch loop at lines 90–95 sets bytes at 63256–63263 to 248 and computes rows at +8 and +16 from existing data, creating a derived alternate character shape.

Key Handling

Key code (k)Action
4Normal video (i=0)
5Inverse video (i=255)
6Toggle alternate character set (flips byte at 23658 between 0 and 8)
12Backspace / cursor left (GO TO 250, which calls line 255 to reverse-render and decrements position)
<32 or >122Ignored
32–122Render character via GO SUB 15 then advance cursor

Notable Techniques and Idioms

  • VAL u$(n) on a single hex digit character correctly returns 0–9, but will return 0 for hex digits A–F. The hex string in line 65 uses only lowercase letters; however VAL "a" returns 0 in Spectrum BASIC, so bytes containing nibbles a–f would be mis-decoded. Inspection shows the string uses only digits 0–9 and letters — this is a potential bug for any byte nibble above 9.
  • The ON ERR GO TO 9990 / ON ERR RESET idiom provides a clean shutdown path that restores normal display mode before stopping.
  • Line 40’s guard (PEEK 23746 = 128) allows the program to be re-run without re-installing the machine code, saving time and avoiding corruption of already-patched memory.
  • GO SUB 15 at line 190 is a shorthand jump to line 20 via the nearest line; the actual subroutine starts at line 20 but BASIC finds the next line at or after 15, which is 20.
  • The boolean arithmetic for display wrapping (8192*(df<22528) etc.) exploits the fact that Spectrum BASIC evaluates boolean expressions as 1 (true) or 0 (false).

Content

Appears On

Capital Area Timex Sinclair User Group’s Library Tape.

Related Products

Related Articles

Related Content

Image Gallery

64 Column

Source Code

   10 GO TO 40
   20 LET s=15616+8*(k-32)
   25 FOR d=df TO df+1792 STEP 256
   30 POKE d,ABS (i-PEEK s): LET s=s+1
   35 NEXT d: RETURN 
   40 IF PEEK 23746=128 THEN GO TO 100
   50 CLEAR 63205: LET u=63206
   55 DATA 10,11,12,13,14,15
   60 READ a,b,c,d,e,f
   65 LET u$="*2100603600237cfe7820f8c9f33e01d3f4dbffcbffd3ff3e80f5fbcd8e0ef3dbffcbbfd3ffafd3f4f1fe80200332c25cfbc9"
   70 FOR n=2 TO LEN u$-1 STEP 2
   75 POKE u,16*VAL u$(n)+VAL u$(n+1)
   80 LET u=u+1: NEXT n
   85 RANDOMIZE USR 63218
   90 FOR a=63256 TO 63263
   95 POKE a,248: POKE (a+8),255-PEEK (a+16): POKE (a+16),255: NEXT a
  100 ON ERR GO TO 9990
  105 OUT 255,14
  110 LET df=16384: LET b=24: LET c=65: LET i=0
  120 LET s=63256+8*(PEEK 23658=8): GO SUB 25
  130 LET k=CODE INKEY$
  135 IF k=0 THEN GO TO 130
  145 IF k=6 THEN POKE 23658,8*(PEEK 23658=0)
  155 IF k=5 THEN LET i=255
  160 IF k=4 THEN LET i=0
  170 IF k=12 THEN GO TO 250
  180 IF k<32 OR k>122 THEN GO TO 115
  190 GO SUB 15: IF b=1 AND c=2 THEN GO TO 115
  200 LET df=df+8192*(df<22528)-8191*(df>24575)
  205 LET c=c-1
  210 IF c>1 THEN GO TO 115
  220 LET b=b-1: LET c=64
  225 GO TO 115
  230 LET l=df-256*INT (df/256)
  235 IF l<>0 THEN GO TO 115
  240 LET df=df+1792
  245 GO TO 115
  255 LET s=15616*(i=0)+63272*(i=255)
  260 GO SUB 25
  270 IF b=24 AND c=65 THEN GO TO 115
  275 IF c<65 THEN GO TO 285
  280 LET c=1: LET b=b+1
  285 IF c>1 THEN GO TO 305
  300 LET df=df-1792
  305 LET c=c+1
  310 LET df=df-8192*(df>24575)+8191*(df<22528)
  315 GO TO 115
 9989 STOP 
 9990 OUT 255,128
 9991 RANDOMIZE USR 63206
 9992 ON ERR RESET 
 9998 SAVE "64 col" LINE 10

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

People

No people associated with this content.

Scroll to Top