--- title: "Big Message" id: 56866 type: "computer_media" slug: "big-message" url: "http://localhost/computer_media/big-message/" markdown_url: "http://localhost/computer_media/big-message.md" published_at: "2024-09-29T12:28:14+00:00" modified_at: "2026-03-30T21:20:36+00:00" author: "David Anderson" featured_image: url: "http://localhost/wp-content/uploads/2024/09/334_BigM.png" excerpt: "Enter any message and watch it explode into huge block letters, drawn pixel-by-pixel straight from the character ROM font data." 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 1000" slug: "ts1000" taxonomy: "post_tag" url: "http://localhost/tag/ts1000/" model: - name: "Timex/Sinclair 1000" slug: "ts-1000" taxonomy: "model" url: "http://localhost/model/ts-1000/" genre: - name: "Demo" slug: "demo" taxonomy: "genre" url: "http://localhost/type/demo/" media_contents: - id: 56738 title: "Timex Sinclair Public Domain Library Tape 1007" type: "computer_media" url: "http://localhost/computer_media/timex-sinclair-public-domain-library-tape-1007/" media_type: "Program" mediadate: "198x" images: - url: "http://localhost/wp-content/uploads/2024/09/334_BigM.png" media_type_tags: "Demo" --- This program renders text entered by the user as large bitmap characters on screen, using the ZX81’s character ROM data. It reads each character’s 8-byte font pattern from memory starting at address 7680 plus the character code multiplied by 8, then extracts individual bits by repeatedly checking whether the value is 128 or greater and doubling the remainder. Each bit is printed as either a space or an inverse-video character (CHR$ 128) at a calculated screen position, effectively scaling the font up column by column. The loop structure iterates over characters in the input string, then over each row byte, then over each of 3 bit-planes to build the magnified display. *** ## Program Analysis ### Program Overview The program accepts a string input from the user and renders it enlarged on screen by reading font bitmap data directly from ROM. Each character’s 8×8 pixel pattern is extracted bit by bit and displayed as a magnified block character grid using `AT`-positioned `PRINT` statements. ### Program Structure | Lines | Purpose | | --- | --- | | 10–20 | Prompt and accept user input string `M$` | | 30 | Store string length in variable `LEN` | | 50–60 | Outer loop over each character; compute ROM address base | | 63–67 | Initialise row (`A`) and column (`B`) print positions | | 70–240 | Nested loops: scan font rows, extract bits, print magnified pixels | | 260 | Advance to next character in string | | 270–300 | Stop, housekeeping, and save/run stubs | ### Font ROM Access The character font data is accessed via `PEEK` at address `7680 + (CH * 8)`, where `CH` is the character code obtained from `CODE M$(L)`. On the ZX81, the character ROM begins at address 7680 (0x1E00), with each character occupying 8 consecutive bytes representing its 8-pixel-tall bitmap rows. The inner `FOR R` loop walks these 8 bytes in descending order (with a fractional step of `-0.25`, discussed below). ### Bit Extraction Technique Individual bits are extracted from each font byte using the classic shift-and-test method. At line 140, if `RC < 128` the most-significant bit is 0 (print a space, `CNTR=0`); otherwise the bit is 1 (`CNTR=128`, which is `CHR$ 128`, the filled inverse-video block on the ZX81). Line 160 subtracts 128 if set, and line 170 doubles `RC` to shift the next bit into the MSB position. `CHR$ 128` is the checkerboard/inverse-space character used here as a solid block. ### Notable Techniques and Anomalies - **Fractional STEP value:** The loop at line 70 uses `STEP (-0.25)` to iterate from `R+7` down to `R`. Because the loop variable is also named `R` (shadowing the address variable set at line 60), this actually traverses 33 iterations (from `R+7` to `R` in steps of −0.25), which is far more than the 8 font rows needed. This is almost certainly a bug — the intended step was likely `-1`. - **Variable name collision:**`R` is used both for the ROM base address (line 60) and as the `FOR` loop variable (line 70), which overwrites the base address value on entry to the loop. - **Redundant reset in G loop:** Line 120 reads `IF G=2 OR 3 THEN LET RC=D`. Due to ZX81 BASIC evaluation rules, `OR 3` is always true (3 is non-zero), so `RC` is reset to `D` on every iteration of the `G` loop. This means each pass of the inner `G` loop reprints the same bit three times in consecutive rows, creating a 3× vertical magnification per bit. The intent was likely `IF G=2 OR G=3`. - **LEN as a variable name:** Line 30 uses `LET LEN=LEN M$`, storing the string length in a user variable also named `LEN`. This works because ZX81 BASIC allows multi-character variable names for numeric variables, and the keyword `LEN` is tokenised — the context distinguishes function call from variable reference. - **Column advance without row reset:** After each font byte (line 220–230), the screen column `B` is incremented and `A` reset to 1, building the character left-to-right on screen with each font byte’s bits printed vertically. - **Lines 280–300:**`CLEAR`, `SAVE`, and `RUN` after `STOP` are never executed during normal program flow and appear to be development/save artefacts. ### Screen Layout Logic Each bit within a font row is printed at screen position `AT A,B` where `A` is the row (reset to 1 per font-byte column) and `B` advances once per font byte processed. The `G` loop (1 to 3) causes `A` to increment three times per bit, so each pixel row of the font is rendered as 3 character rows tall on screen, giving a magnified appearance. The horizontal expansion depends on how many font bytes are printed per character (controlled by the `R` loop). ## Source Code ``` 10 PRINT ,," INPUT MESSAGE" 20 INPUT M$ 30 LET LEN=LEN M$ 50 FOR L=1 TO LEN 55 LET CH=CODE M$(L) 60 LET R=7680+(CH*8) 63 LET A=1 67 LET B=1 70 FOR R=R+7 TO R STEP (-0.25) 80 LET RC=PEEK R 90 FOR H=1 TO 7 100 LET D=RC 110 FOR G=1 TO 3 120 IF G=2 OR 3 THEN LET RC=D 130 LET CNTR=0 140 IF RC<128 THEN GOTO 170 150 LET CNTR=128 160 LET RC=RC-128 170 LET RC=RC*2 180 PRINT AT A,B;CHR$ CNTR; 190 LET A=A+1 200 NEXT G 210 NEXT H 220 LET A=1 230 LET B=B+1 240 NEXT R 260 NEXT L 270 STOP 280 CLEAR 290 SAVE "1033%4" 300 RUN ```