--- title: "Banner" id: 56134 type: "computer_media" slug: "banner-2" url: "http://localhost/computer_media/banner-2/" markdown_url: "http://localhost/computer_media/banner-2.md" published_at: "2024-07-20T21:09:34+00:00" modified_at: "2026-03-30T21:41:03+00:00" author: "David Anderson" featured_image: url: "http://localhost/wp-content/uploads/2022/04/20230809-041332.jpg" excerpt: "Type any message and watch this banner printer translate each letter into tall, blocky dot-matrix characters — one column of bits at a time." 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: "Banner" slug: "banner" taxonomy: "genre" url: "http://localhost/type/banner/" media_type: "Program" download_url: "https://archive.org/download/timex-sinclair-software-archive/Banner%20%28198x%29%28TS2068%29%28US%29%28Program%29.zip" mediadate: "198x" media_type_tags: "Banner" --- # Banner This program prints a user-supplied message as large banner text using the printer (LPRINT). Each character of the input is looked up in a DATA table that stores five 7-bit column values representing a 5×7 dot-matrix font; each column value is then decoded into a row of printed characters using a binary decomposition routine (lines 200–330). The decomposition walks through bit weights 64, 32, 16, 8, 4, 2, and 1 in sequence, calling subroutine 500 to append four copies of the character (producing wide dots) or subroutine 510 to append four spaces for zero bits. Each column is printed twice (two LPRINT calls in line 340), giving tall, blocky output. A notable anomaly exists in the DATA for “W” and “X” (lines 1230–1240), which share identical column values, meaning “X” will print as “W”. *** ## Program Analysis ### Program Structure The program is divided into four logical sections: 1. **Input and character loop (lines 20–50):** Accepts a message string, iterates over each character, and scans the DATA table to find a matching entry. 2. **Column dispatch (lines 100–150):** For each matched character, calls the binary decoder subroutine five times — once per font column — then prints two blank lines and restores the DATA pointer for the next character. 3. **Binary decoder (lines 200–340):** Converts a 7-bit column value into a printed row by testing each bit weight (64, 32, 16, 8, 4, 2, 1) and appending either four copies of the character or four spaces. 4. **DATA table (lines 1000–1390):** Stores letter/digit entries as a character key followed by five integers representing the dot-matrix column bitmaps of a 5×7 font. ### Font Encoding Each glyph is stored as five column values, each a 7-bit integer (0–127). Bit 64 is the topmost row and bit 1 is the bottommost. The decoder in lines 200–330 walks down the bit weights in order. Subroutine 500 appends four copies of the input character (`A$`) to `P$`, and subroutine 510 appends four spaces, producing wide dots. Line 340 then LPRINTs `P$` twice, doubling the row height for a tall, bold appearance. ### Binary Decomposition Technique Rather than using bitwise operators (unavailable in standard Sinclair BASIC), the decoder manually tests each power of two with subtraction and branching. The pattern repeats seven times: - If `X - weight >= 0`, call subroutine 500 (dot) and subtract the weight from `X`. - If `X - weight < 0`, call subroutine 510 (space). Because both the `>=0` and `<0` branches fall through to the next test line rather than branching around it, the second `IF` on each pair of lines is always evaluated. This is correct in practice because after a successful subtraction the new `X` will always be less than the original weight, making the `<0` branch false — but it is slightly wasteful. ### DATA Table and RESTORE Usage All font data is stored in DATA statements beginning at line 1000. The inner loop at lines 40–50 uses sequential `READ` to scan for a matching character. After each complete character is rendered, line 150 calls `RESTORE` to reset the DATA pointer to the beginning, ready for the next character lookup. This means every character search always starts from line 1000, giving O(n) scan time per character where n is the position of the glyph in the table. ### Notable Bugs and Anomalies | Issue | Location | Detail | | --- | --- | --- | | Duplicate “W”/”X” data | Lines 1230–1240 | Both entries share identical column values `127,32,16,32,127`, so printing “X” produces the same glyph as “W”. | | Missing “0” key | Line 1390 | The digit zero entry uses `DATA 0,62,81,73,69,62`; the key is the number `0` rather than the string `"0"`, so `READ X$` will read it as the string `"0"` in practice — this works on most Sinclair BASIC interpreters but is inconsistent with the other entries. | | Unmatched characters cause infinite loop | Lines 40–50 | If the input contains a character not present in the DATA table (e.g., lowercase letters or punctuation other than space), `READ` will exhaust all DATA and produce an error rather than gracefully skipping the character. | ### Key BASIC Idioms - `M$(L TO L)` — single-character substring extraction using the slice syntax. - `RESTORE` at line 150 resets the DATA pointer after each character, enabling repeated table scans within a single run. - `P$` is built up as a string buffer then flushed with two `LPRINT` calls, minimizing the number of print operations per row. - Five separate `GO SUB 200` calls (lines 100–140) handle the five columns of each glyph, keeping the decoder subroutine simple and single-purpose. ## Source Code ``` 20 CLS : LET P$="": INPUT "MESSAGE?";M$ 30 FOR L=1 TO LEN M$: LET A$=M$(L TO L): PRINT A$; 40 READ X$,L1,L2,L3,L4,L5: IF A$=X$ THEN GO TO 100 50 GO TO 40 100 LET X=L1: GO SUB 200 110 LET X=L2: GO SUB 200 120 LET X=L3: GO SUB 200 130 LET X=L4: GO SUB 200 140 LET X=L5: GO SUB 200 150 LPRINT : LPRINT :: RESTORE : NEXT L : STOP 200 IF X-64>=0 THEN GO SUB 500: LET X=X-64: GO TO 220 210 IF X-64<0 THEN GO SUB 510 220 IF X-32>=0 THEN GO SUB 500: LET X=X-32: GO TO 240 230 IF X-32<0 THEN GO SUB 510 240 IF X-16>=0 THEN GO SUB 500: LET X=X-16: GO TO 260 250 IF X-16<0 THEN GO SUB 510 260 IF X-8>=0 THEN GO SUB 500: LET X=X-8: GO TO 280 270 IF X-8<0 THEN GO SUB 510 280 IF X-4>=0 THEN GO SUB 500: LET X=X-4: GO TO 300 290 IF X-4<0 THEN GO SUB 510 300 IF X-2>=0 THEN GO SUB 500: LET X=X-2: GO TO 320 310 IF X-2<0 THEN GO SUB 510 320 IF X-1>=0 THEN GO SUB 500 330 IF X-1<0 THEN GO SUB 510 340 LPRINT P$: LPRINT P$: LET P$="": RETURN 500 LET P$=P$+A$+A$+A$+A$: RETURN 510 LET P$=P$+" ": RETURN 1000 DATA " ",0,0,0,0,0 1010 DATA "A",124,18,17,18,124 1020 DATA "B",65,127,73,73,54 1030 DATA "C",62,65,65,65,34 1040 DATA "D",65,127,65,65,62 1050 DATA "E",127,73,73,65,65 1060 DATA "F",127,9,9,1,1 1070 DATA "G",62,65,65,73,121 1080 DATA "H",127,8,8,8,127 1090 DATA "I",0,65,127,65,0 1100 DATA "J",32,64,64,64,63 1110 DATA "K",127,8,20,34,65 1120 DATA "L",127,64,64,64,64 1130 DATA "M",127,2,12,2,127 1140 DATA "N",127,2,4,8,127 1150 DATA "O",62,65,65,65,62 1160 DATA "P",127,9,9,9,6 1170 DATA "Q",62,65,81,33,94 1180 DATA "R",127,9,25,41,70 1190 DATA "S",38,73,73,73,50 1200 DATA "T",1,1,127,1,1 1210 DATA "U",63,64,64,64,63 1220 DATA "V",7,24,96,24,7 1230 DATA "W",127,32,16,32,127 1240 DATA "X",127,32,16,32,127 1250 DATA "Y",3,4,120,4,3 1260 DATA "Z",97,81,73,69,67 1300 DATA "1",0,66,127,64,0 1310 DATA "2",114,73,73,73,70 1320 DATA "3",34,65,73,73,54 1330 DATA "4",24,20,18,127,16 1340 DATA "5",39,69,69,69,57 1350 DATA "6",60,74,73,73,48 1360 DATA "7",1,113,9,5,3 1370 DATA "8",54,73,73,73,54 1380 DATA "9",6,73,73,41,30 1390 DATA 0,62,81,73,69,62 9998 SAVE "BANNER" ```