64 Column

This file is part of and SINCUS Exchange Tape 102 - Utilities & Business. Download the collection to get this file.
Type: Program
Platform(s): TS 2068

This program implements a 64-column text editor using machine code poked from a hex string starting at address 63206 to drive a custom display routine. The machine code is initialized via a hex-string loop (lines 70–80) and activated with RANDOMIZE USR 63218, which installs a display interrupt handler outputting to port 255. UDG memory at 63256–63271 is patched (lines 90–95) to create a custom character set supporting the doubled horizontal resolution. The editor tracks cursor position using variables B (row, 1–24) and C (column, 1–64), with DF holding the display file base address that wraps between 16384 and 24575 in 8192-byte pages. Key presses 4, 5, and 6 toggle inverse video and cursor direction, while the ON ERR / RESET idiom at lines 9990–9992 provides a clean exit that restores normal display mode.


Program Analysis

Program Structure

The program divides into four logical phases: machine code installation (lines 40–95), main editor loop (lines 100–315), a forward-cursor subroutine implied at line 15 (called via GO SUB 15 but not explicitly listed — likely handled by the GO SUB 25 character-rendering routine), and an error/exit handler (lines 9989–9992). The entry point at line 10 jumps to line 40, which checks whether the machine code is already installed before proceeding with initialization.

Machine Code Installation

Lines 65–84 poke 49 bytes of Z80 machine code into address 63206 (U) by parsing a hex string two characters at a time. The expression 16*VAL U$(N)+VAL U$(N+1) converts each hex digit pair into a byte value. RANDOMIZE USR 63218 then executes the installed routine, which sets up a display interrupt using OUT 255,62 (port 255, value 62) to drive the 64-column display hardware, likely a peripheral or shadow memory bank. The check at line 40 (PEEK 23746=128) detects prior installation and skips re-poking.

UDG Patching

Lines 90–95 loop over addresses 63256–63263, patching three layers of UDG data to construct a character set suitable for half-width (64-column) rendering:

  • POKE A, 248 — sets the low UDG row to a fixed mask
  • POKE (A+8), 255-PEEK (A+16) — inverts the third bank into the second
  • POKE (A+16), 255 — fills the third bank solid

This builds the inverse-video cursor glyph used during editing at the two UDG pages above the machine code.

Display File Navigation

The Spectrum’s display file is non-linear: pixel rows are stored in three 2048-byte banks. The program works around this using the variable DF, which represents the current character cell’s display address. The wrap logic at line 200 uses:

  • DF + 8192*(DF<22528) to advance to the next third of the screen
  • - 8191*(DF>24575) to wrap back to 16384

Within a third, line 230 computes L = DF MOD 256 to detect row boundaries, advancing DF by 1792 (7×256) when needed to skip to the next character row within the same screen third.

Character Rendering Subroutine

The subroutine at line 20 (called as GO SUB 25 from line 120 and line 260) renders a character or cursor glyph into the display file. Variable s is set to the ROM font address for character k (at 15616 + 8*(k-32)), and a FOR loop at line 25 steps through the seven pixel rows of the display file in 256-byte strides, poking ABS(i - PEEK s) to optionally invert the glyph when i=255.

Key Handling

Key codeAction
4Set I=0 (normal video)
5Set I=255 (inverse video)
6Toggle cursor direction (PEEK 23658 XOR 8)
12Jump to line 250 (delete/back-cursor path)
32–122Printable characters rendered and cursor advanced

The polling loop at line 130 reads INKEY$ directly and retries on a null return, forming an efficient busy-wait without PAUSE.

Error Handler and Exit

Line 100 uses the TS2068 ON ERR GO TO 9990 keyword ({ in source) to trap any runtime error and route to the cleanup routine. Lines 9990–9992 restore the display by sending OUT 255,128 to disable the 64-column mode, executing the machine code entry point at 63206 to tear down the interrupt, and finally issuing ON ERR RESET (©) to clear the error handler — a tidy three-step shutdown sequence.

Notable Techniques and Anomalies

  • Line 15 is targeted by GO SUB 15 at line 190 but does not exist as a separate line; execution falls through to line 20, making the subroutine entry point flexible.
  • The DATA statement at line 55 defines values read into a–f at line 60, but these variables do not appear to be used later in the listed code — they may serve as spare workspace or the listing is incomplete.
  • The hex string in U$ begins with a leading asterisk (*) at position 1, so the loop correctly starts at N=2, skipping it as a sentinel/flag character.
  • The boolean arithmetic idiom 8*(PEEK 23658=8) exploits the fact that Spectrum BASIC returns −1 for true comparisons, so the absolute value or negation is used implicitly through the multiplication producing 0 or 8.

Content

Appears On

The workhorse tape — assemble Z80 code, manage databases, analyze statistics, cast I Ching hexagrams, balance your checkbook, and switch between four font styles. SINCUS Tape 102 turns the TS 2068 into a serious productivity machine.

Related Products

Related Articles

Related Content

Image Gallery

Source Code

    5 REM 64COL-P                     Type in 64 columns             
   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,62
  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
  215 IF C=1 THEN GO TO 230
  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
  290 LET L=DF-256*INT (DF/256)
  295 IF L<>0 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 

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

People

No people associated with this content.

Scroll to Top