--- title: "Slow Message" id: 55105 type: "computer_media" slug: "slow-message" url: "http://localhost/computer_media/slow-message/" markdown_url: "http://localhost/computer_media/slow-message.md" published_at: "2024-06-16T14:47:33+00:00" modified_at: "2026-03-30T21:45:23+00:00" author: "David Anderson" featured_image: url: "http://localhost/wp-content/uploads/2019/02/20230809-041332.jpg" excerpt: "A pixel-by-pixel double-size text scroller renders any message you type using machine code for smooth scrolling — enter your message and watch it loop forever." 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/" indiv: - name: "D. J. Currie" slug: "d-j-currie" taxonomy: "indiv" url: "http://localhost/indiv/d-j-currie/" genre: - name: "Banner" slug: "banner" taxonomy: "genre" url: "http://localhost/type/banner/" media_contents: - id: 54965 title: "ISTUG Public Domain Library 5" type: "computer_media" url: "http://localhost/computer_media/istug-public-domain-library-5/" media_type: "Program" programmers: - name: "D. J. Currie" slug: "d-j-currie" taxonomy: "indiv" url: "http://localhost/indiv/d-j-currie/" mediadate: "198x" images: - url: "http://localhost/wp-content/uploads/2024/06/slow-message.png" media_type_tags: "Banner" --- # Slow Message This program displays a user-entered text message as a continuously repeating scrolling marquee, rendering each character at double size on screen. The user inputs a message via INPUT, and each character is individually printed in INK 5 at the bottom of the screen (line 21), then examined pixel-by-pixel using the POINT command to reconstruct it scaled 2× in both dimensions using PLOT. Between each character display, a machine code routine at address 60000 is called 16 times to perform a smooth horizontal scroll of the double-size rendering area. The 17-byte machine code routine (loaded via READ/DATA and POKE) implements a left-shift scroll using Z80 instructions operating on the display memory starting at address 0x57FF. The message loops indefinitely by jumping back to line 80 after all characters have been processed. *** ## Program Analysis ### Program Structure The program is organized into three logical phases: initialization (lines 10–40), user input (lines 50–70), and the main display loop (lines 80–220), with machine code data at line 230. 1. **Lines 10–40:** Reserve memory with `CLEAR 59999`, then load 17 bytes of machine code into address 60000 via `READ`/`POKE`. 2. **Lines 50–70:** Prompt for a message string, reject empty input, and store the message length in `n`. 3. **Lines 80–100:** Outer loop iterates over each character in the message using index `q`, calling the double-size print subroutine at line 110, then repeating indefinitely. 4. **Lines 110–220:** Subroutine that prints a character at screen row 21, samples its pixels with `POINT`, and plots a 2× scaled version, then scrolls via machine code. 5. **Line 230:**`DATA` block containing the 17-byte Z80 machine code routine. ### Double-Size Character Rendering The subroutine at line 110 uses a clever technique to scale characters. Each character `y$(q)` is printed with `INK 5` at position `AT 21,0` — the bottom row of the screen. The nested loops over `a` (rows 7 down to 0) and `b` (columns 0 to 7) use `POINT (b,a)` to test each pixel of the rendered character at the bottom of the display. For each lit pixel, an additional 2×2 block is plotted at `PLOT x-16+2*b+c, y+2*a-d` using inner loops `c` and `d` (both 0 to 1), effectively doubling the character in both axes. The row loop runs from 7 to 0 (descending) because BASIC graphics coordinates place row 0 at the bottom. The target position is anchored by `x=255` and `y=100`, placing the scaled output in the upper-right region of the display. Note that `x-16+2*b` can reach a maximum of `255-16+14 = 253`, staying within the 256-pixel-wide screen. ### Machine Code Scroll Routine The 17-byte routine stored at address 60000 performs a hardware-level left scroll of the relevant screen area. The DATA values decode as the following Z80 instructions: | Offset | Bytes | Mnemonic | Notes | | --- | --- | --- | --- | | 0 | 33 FF 57 | `LD HL, 0x57FF` | Points near display file | | 3 | 0E C0 | `LD C, 0xC0` | Row count / mask | | 5 | 06 20 | `LD B, 32` | 32 bytes per row | | 7 | 7B | `LD A, E` | Load accumulator | | 8 | CB 16 | `RL (HL)` | Rotate left through carry | | 10 | 2B | `DEC HL` | Move to next byte | | 11 | 10 FB | `DJNZ -5` | Loop 32 times | | 13 | 0D | `DEC C` | Decrement row counter | | 14 | 20 F5 | `JR NZ, -11` | Loop over rows | | 16 | C9 | `RET` | Return to BASIC | This routine is called 16 times per character (line 210: `FOR r=1 TO 16: RANDOMIZE USR 60000: NEXT r`), producing a smooth 16-pixel leftward scroll for each character-width cycle, matching the 2× scaled 8-pixel character (16 pixels wide). `RANDOMIZE USR` is the standard idiom for calling machine code from BASIC, discarding the return value. ### Key BASIC Idioms - `CLEAR 59999` reserves RAM above address 59999, protecting the machine code from being overwritten by BASIC string/variable storage. - `IF t$="" THEN GO TO 50` at line 50 provides simple input validation, ensuring the message is non-empty before proceeding. - The variable `y$` is assigned from `t$` at line 60 but is never modified — it appears redundant; `t$` could be used directly throughout. - `PRINT AT 21,0;" "` at line 220 clears the character used as a pixel source before returning, preventing leftover ink from affecting the next character’s `POINT` sampling. ### Notable Techniques and Observations The use of `POINT` to read back pixel data from a character rendered on-screen is an elegant way to access the font bitmap without needing to know font memory addresses. By printing to a known screen location and sampling with `POINT`, the program is font-agnostic and will correctly scale any character the system can display, including user-defined graphics. One minor anomaly: the variable `y$` (line 60) is a direct copy of `t$` and serves no functional purpose — the loop at line 90 references `y$(q)`, which is equivalent to `t$(q)`. This may be a leftover from an earlier version where the strings diverged. The scroll loop calls the machine code 16 times rather than passing a loop count as a parameter, which is less efficient but simpler to implement in BASIC. Each call scrolls the display one pixel left, for a total of 16 pixels — exactly one double-width character column. ## Source Code ``` 10 REM SLOW MESSAGE Enter a message of any length and leave spaces at the end as the message will repeat. by D.J. Currie 20 CLEAR 59999 30 FOR f=0 TO 16: READ a: POKE 60000+f,a: NEXT f 40 LET x=255: LET y=100 50 INPUT "Enter message - ";t$: IF t$="" THEN GO TO 50 60 LET y$=t$ 70 LET n=LEN y$ 80 FOR q=1 TO n 90 GO SUB 110: NEXT q 100 GO TO 80 110 REM Print double size 120 PRINT INK 5;AT 21,0;y$(q) 130 FOR a=7 TO 0 STEP -1 140 FOR b=0 TO 7 150 IF POINT (b,a)=0 THEN GO TO 200 160 FOR c=0 TO 1 170 FOR d=0 TO 1 180 PLOT x-16+2*b+c,y+2*a-d 190 NEXT d: NEXT c 200 NEXT b: NEXT a 210 FOR r=1 TO 16: RANDOMIZE USR 60000: NEXT r 220 PRINT AT 21,0;" ": RETURN 230 DATA 33,255,87,14,192,6,32,183,203,22,43,16,251,13,32,245,201 240 SAVE "Message" LINE 10 ```