--- title: "GrafProgs" id: 71061 type: "computer_media" slug: "grafprogs" url: "http://localhost/computer_media/grafprogs/" markdown_url: "http://localhost/computer_media/grafprogs.md" published_at: "2026-08-27T11:30:12+00:00" modified_at: "2026-08-27T11:31:30+00:00" author: "David Anderson" featured_image: url: "http://localhost/wp-content/uploads/2026/08/grafprogs-1.png" alt: "GrafProgs screen" excerpt: "A twelve-part suite of text-scaling demos drives a machine code renderer to produce enlarged, colored, and word-wrapped titles across the full screen." 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: "Demo" slug: "demo" taxonomy: "genre" url: "http://localhost/type/demo/" - name: "Graphics" slug: "graphics" taxonomy: "genre" url: "http://localhost/type/graphics/" media_type: "Program" download_url: "https://archive.org/download/timex-sinclair-software-archive/GrafProgs%20%28198x%29%28-%29%28TS2068%29%28US%29%28Program%29.zip" mediadate: "198x" images: - url: "http://localhost/wp-content/uploads/2026/08/grafprogs-1.png" alt: "GrafProgs screen" media_type_tags: "Demo, Graphics" --- # GrafProgs GrafProgs is a multi-part demonstration and utility suite for displaying enlarged, pixel-scaled text on screen using a machine code routine loaded at address 32256. The BASIC programs (numbered 1 through 12) showcase various text-scaling effects, including ripple layouts, stacked titles, UDG-based lettered graphics, word-wrapped paragraphs, and full-screen character fills. Program 1 uses direct PEEK of the ROM character set at address 15360 to manually render scaled characters via PLOT and DRAW, while Programs 2–12 delegate rendering to the machine code routine via USR 32256, passing parameters through memory addresses 23306 onward. UDGs are loaded by PEEKing ROM glyph data at fixed addresses such as 16024 and 15896, and the word-wrap routine in Program 12 walks a string backward to find space characters for clean line breaks. Several REMs at the top document a relocation utility for moving the machine code block to a user-specified address, with address fixup DATA for five internal pointer patches. *** ### Program Structure GrafProgs is organized as a sequence of twelve self-contained demonstration programs sharing a common subroutine framework. Each numbered program (100, 200, 300, 400, 500, 600, 700, 800, 900, 1000, 2000, 2050) runs independently and chains to the next via a direct `RUN` call to the following program’s entry point after a “repeat?” prompt. Lines 10–70 are pure `REM` commentary containing a relocation utility for the companion machine code file. ### Machine Code Interface The core rendering engine is a 300-byte machine code block loaded at address 32256 (decimal) via `LOAD "GrafProgsC" CODE`. BASIC communicates with it by POKEing a parameter block starting at address 23306: | Offset | Variable | Purpose | | --- | --- | --- | | +0 | `xx` | X pixel position (computed to center the string) | | +1 | `yy` | Y pixel position | | +2 | `xs` | Horizontal scale factor | | +3 | `ys` | Vertical scale factor | | +4 | 8 | Fixed value (glyph height in pixels) | | +5… | character codes | String data, terminated by 255 | The routine is invoked with `LET w= USR 32256`, discarding the return value. Addresses 23606–23607 are also manipulated (e.g., `POKE 23606,216: POKE 23607,250`) in Programs 4 and 10 to control an animation loop offset, stepped through a `FOR f` loop before calling the routine repeatedly. ### Subroutine at Line 260 The central rendering subroutine at line 260 computes horizontal centering with `LET xx=(256-8*xs*LEN p$)/2`, builds the parameter block via sequential POKEs, appends the string character codes, writes the 255 terminator, and calls `USR 32256`. It is called by every demonstration program. ### Program 1 — Pure BASIC Pixel Renderer Program 1 (lines 110–190) is the only demo that does not use the machine code routine. It reads character bitmaps directly from ROM using `PEEK (15360 + CODE a$(n)*8 + f)`, then extracts individual bits with successive `INT(p/2)` divisions, using `PLOT` and `DRAW` to render scaled pixels. The inner `FOR i=i TO t` construct is a deliberate trick: when a bit is set, the loop variable `i` is advanced to `t`, effectively skipping the remaining bit-extraction steps for that pixel block. Line 160 handles screen wrapping when the rendered string overflows 255 pixels wide. ### UDG Loading from ROM Glyphs Programs 3, 4, and 10 load UDGs by PEEKing ROM addresses that contain pre-drawn glyph data. Program 4’s `DATA` at line 430 maps UDG letters to ROM addresses such as 16024, 15896, 16016, 15992, and 15968. Program 10 extends this to eleven UDGs (a–l), using a variable `d$` still in scope from the DATA read — a potential hazard if execution order is disrupted, since `d$` holds the address string for UDG “i” and is reused for UDG “j” (`PEEK (VAL d$+n)`). ### Word-Wrap Routine (Program 12) Lines 2060–2160 implement a word-wrapping paragraph renderer for a Shakespeare quotation. The algorithm scans each 32-character slice backward for a space (lines 2100–2110), then feeds the trimmed substring to the machine code renderer, advancing `yy` by `y = ys*8` after each line. Edge cases for short trailing strings are handled at line 2080. ### Notable Techniques and Idioms - `SGN PI` is used throughout as a compact literal for 1 (since PI > 0), and `NOT PI` evaluates to 0 — both save bytes over typing the digits directly. - `INT PI` (≈ 3) is used at line 1020 to set `ys`, again saving a byte. - `VAL b$` in line 1010 converts DATA strings to numbers, a common memory-saving technique. - Line 290 (`POKE 23606,0: POKE 23607,60`) resets the system variable pair, likely restoring an attribute or display pointer modified by the animation sequence. - The relocation utility in REMs 10–60 provides a five-entry DATA table of byte offsets and patches self-referential address bytes within the machine code block using two helper functions `FN a(x)` and `FN b(x)` for high and low bytes respectively. ### Bugs and Anomalies - Line 170 contains `PRINT AT 21,31'` — the trailing apostrophe issues an extra newline after the `AT` position, which may produce an unintended blank line during the overflow scroll in Program 1. The REM on line 70 acknowledges a fix is needed. - The double colon `::` at line 730 (`LET yy=f*5::`) is a harmless empty statement artifact. - In line 1010, the DATA entry `"i",d$` uses the BASIC variable `d$` rather than a string literal; this relies on `d$` retaining the value `"15968"` from the immediately preceding READ iteration, which is correct but fragile. - Line 2130 advances `a$` with `a$(n+1 TO)` but does not guard against `n` exceeding `LEN a$` when the last segment ends exactly at the string boundary, potentially causing a subscript error on edge-case input. ### Save/Load Structure Line 2180 saves both the BASIC program (`SAVE "GrafProgs" LINE 2140`) and the machine code block (`SAVE "GrafProgsC" CODE 32256,300`). Line 2170 provides a bootstrap loader that clears RAM to 32255, loads the code file, and runs the program. ## Source Code ``` 10 REM Screen Utilities ZX COMPUTING April/May 85 Utility; use to relocate starting address of m/c in memory, original=32256,300 20 REM INPUT "Start address? ";s:CLEAR s-1:PRINT "Load code":LOAD "p2"CODE 30 REM DEF FN a(x)=INT ((s+x)/256) 40 REM DEF FN b(x)=s+x-256*FN a(x) 50 REM RESTORE :FOR i=1 TO 5:READ x,x:POKE s+x,FN b(x):POKE s+1+x,FN a(x):NEXT i 60 REM DATA 106,32,127,164,86,3,154,48,251,156 70 REM this utility needs fix-ing 100 REM Program 1 110 PAPER 7:BORDER 7:INK 9:CLS 120 LET w=4:LET t=4:LET a=7*w:LET d=168:LET a$="ABCDE":REM w max=8, min=32/48; d max=21, min=1; try d=0 130 FOR n=1 TO LEN a$:FOR f=0 TO 7:LET p= PEEK (15360+ CODE a$(n)*8+f) 140 FOR i=0 TO 7:IF p-2* INT (p/2) THEN FOR i=i TO t:PLOT a-i*w,d-f*t-1:DRAW 1-w,0:NEXT i:REM fool around with i & 1 here 150 LET p= INT (p/2):NEXT i:NEXT f:LET a=a+w*8 160 IF a>255 AND d-t*8>t*8-1 THEN LET d=d-t*8:LET a=w*8-1 170 IF a>255 AND d-t*8