--- title: "64 Column" id: 53820 type: "computer_media" slug: "64col-p" url: "http://localhost/computer_media/64col-p/" markdown_url: "http://localhost/computer_media/64col-p.md" published_at: "2024-05-13T19:02:00+00:00" modified_at: "2026-04-13T00:12:04+00:00" author: "David Anderson" featured_image: url: "http://localhost/wp-content/uploads/2024/05/64col-p.png" excerpt: "A machine-code-powered 64-column text editor." category: - name: "Archived Media" slug: "archived-media" taxonomy: "category" url: "http://localhost/category/archived-media/" post_tag: - name: "Downloadable" slug: "downloadable" taxonomy: "post_tag" url: "http://localhost/tag/downloadable/" - name: "TS 2068" slug: "ts2068" taxonomy: "post_tag" url: "http://localhost/tag/ts2068/" model: - name: "Timex/Sinclair 2068" slug: "ts-2068" taxonomy: "model" url: "http://localhost/model/ts-2068/" genre: - name: "64 Column" slug: "64-column" taxonomy: "genre" url: "http://localhost/type/64-column/" - name: "Demo" slug: "demo" taxonomy: "genre" url: "http://localhost/type/demo/" - name: "Programming" slug: "programming" taxonomy: "genre" url: "http://localhost/type/programming/" media_contents: - id: 55361 title: "SINCUS Exchange Tape 102 – Utilities & Business" type: "computer_media" url: "http://localhost/computer_media/sincus-exchange-tape-102-utilities-business/" media_type: "Program" images: - url: "http://localhost/wp-content/uploads/2024/05/64col-p.png" media_type_tags: "64 Column, Demo, Programming" --- # 64 Column 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 code | Action | | --- | --- | | 4 | Set `I=0` (normal video) | | 5 | Set `I=255` (inverse video) | | 6 | Toggle cursor direction (`PEEK 23658` XOR 8) | | 12 | Jump to line 250 (delete/back-cursor path) | | 32–122 | Printable 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. ## 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 ```