--- title: "Banners" id: 57124 type: "computer_media" slug: "banners" url: "http://localhost/computer_media/banners/" markdown_url: "http://localhost/computer_media/banners.md" published_at: "2024-10-03T23:54:13+00:00" modified_at: "2026-04-03T07:58:43+00:00" author: "David Anderson" featured_image: url: "http://localhost/wp-content/uploads/2024/10/73_Bann.png" excerpt: "Type any message and watch this BASIC program transform it into giant banner letters printed column-by-column using raw font data peeked straight from ROM." 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: "Banner" slug: "banner" taxonomy: "genre" url: "http://localhost/type/banner/" media_contents: - id: 56733 title: "Timex Sinclair Public Domain Library Tape 1002" type: "computer_media" url: "http://localhost/computer_media/timex-sinclair-public-domain-library-tape-1002/" media_type: "Program" mediadate: "198x" images: - url: "http://localhost/wp-content/uploads/2024/10/73_Bann.png" media_type_tags: "Banner" --- # Banners This program prints large banner-style text on the ZX printer, rendering each input character approximately three inches tall using a dot-matrix expansion technique. It reads the character’s 8×8 pixel definition directly from the system font in ROM by PEEKing memory starting at address 7680, then unpacks each row’s bits by repeated division by 2 and checking for non-integer remainders. Each character column is stored in the 64-byte string D$, and once 8 columns are accumulated the GOSUB 900 routine prints them transposed, so the characters appear rotated 90°, with each pixel rendered as four spaces or four filled characters to achieve the large size. Inverse-video input characters (CODE > 63) are handled by subtracting 128 to get the base character code while inverting the fill pattern, and the output is doubled vertically by the inner loop at line 910 iterating twice. *** ## Program Analysis ### Program Structure The program is divided into three logical phases: 1. **Initialisation / display (lines 1010–1090):** Shows a title screen and instructions, then falls through to the INPUT at line 20. 2. **Bit-extraction loop (lines 10–160):** Iterates over every character of the input string, peeks its ROM font data, unpacks the bits, and stores them in the work buffer `D$`. 3. **Print subroutine (lines 900–980):** Called once every 8 characters (when the 64-byte buffer is full), it prints the buffered columns on the ZX printer in transposed, double-height form. ### Font Data Access via PEEK Character pixel data is read directly from the system character set. The expression `PEEK (7680 + N + 8 * CODE A$)` at line 70 computes the address of the *N*th byte of character `A$`‘s 8-byte bitmap. Address 7680 (0x1E00) is the start of the ZX81 character set in ROM. This approach requires no separate font table in RAM and keeps the program compact. ### Bit-Unpacking Technique Rather than using bitwise AND, the program extracts individual bits through repeated halving. At line 90, `Z` is divided by 2; if the result differs from its integer part (line 100) the least-significant bit was 1, so the pixel is “on”. `Z` is then floored at line 130 before the next iteration. This is a classic ZX81 idiom used because the platform lacks a native bitwise AND operator in BASIC. ### Buffer and Transposition `D$` is dimensioned to 64 characters (line 10), holding exactly 8 characters × 8 rows of pixel data. Pixels are stored row-major (index `N*8+X`) but printed column-major in the subroutine: the outer loop of `GOSUB 900` iterates `P` over columns 8 down to 1, and the inner loop `E` iterates over rows 7 down to 0, accessing `D$(E*8+P)`. This 90° transposition turns horizontally-stored font rows into vertically-printed banner columns. ### Double-Height Output The loop `FOR F=1 TO 2` at line 910 repeats each column twice, doubling the vertical size of the printed output and contributing to the “3 inches high” appearance described in the on-screen instructions. ### Inverse-Video Character Handling Characters with `CODE > 63` are inverse-video variants. Line 60 maps them back to the base character by subtracting 128 before the PEEK lookup. Lines 115 and 505 then swap the fill values (“0” and “1”) so that inverse characters appear with foreground and background swapped in the printed banner. ### Print Encoding In the subroutine, a “set” pixel is printed as `"% % % % "` (four alternating percent signs and spaces, 8 characters wide) and a clear pixel as `" "` (four spaces). This produces a visually bold block appearance on the thermal ZX printer. ### Variable Summary | Variable | Role | | --- | --- | | `M$` | User-entered input string | | `D$` | 64-byte pixel buffer (8 chars × 8 rows) | | `C` | Character index within `M$` | | `A$` | Current character (base form, inverse stripped) | | `N` | Row index within font byte (0–7) | | `X` | Bit index within font byte (1–8) | | `Z` | Current font byte, shifted right each iteration | | `P` | Column index in print subroutine (1–8) | | `F` | Doubling loop counter (1–2) for height | | `E` | Row index in print subroutine (0–7) | ### Notable Anomalies - The buffer flush at `GOSUB 900` is triggered only when `N*8+X=64` (line 120), meaning it fires once per 8 characters. If the input string length is not a multiple of 8, the final partial buffer is never printed — the last up-to-7 characters are silently lost. - The `FAST` / `SLOW` pair (lines 30 and 170) suppresses display refresh during the compute-intensive bit-extraction loop, which is good practice on this platform given the cost of PEEK and floating-point division. - Line 1000 contains a `SAVE` command that is never reached in normal execution (the flow goes 160→170→180→1010, bypassing line 1000), so it serves purely as a storage line embedded in the listing. ## Source Code ``` 1 REM *** BANNERS *** 2 REM *********************** 10 DIM D$(64) 20 INPUT M$ 30 FAST 40 FOR C=1 TO LEN M$ 50 LET A$=M$(C) 60 IF CODE A$>63 THEN LET A$=CHR$ (CODE M$(C)-128) 65 FOR N=0 TO 7 70 LET Z=PEEK (7680+N+8*CODE A$) 80 FOR X=1 TO 8 90 LET Z=Z/2 100 IF Z<>INT Z THEN GOTO 500 110 LET D$(N*8+X)="0" 115 IF CODE M$(C)>63 THEN LET D$(N*8+X)="1" 120 IF N*8+X=64 THEN GOSUB 900 130 LET Z=INT Z 140 NEXT X 150 NEXT N 160 NEXT C 170 SLOW 180 GOTO 1010 500 LET D$(N*8+X)="1" 505 IF CODE M$(C)>63 THEN LET D$(N*8+X)="0" 510 GOTO 120 900 FOR P=8 TO 1 STEP -1 910 FOR F=1 TO 2 920 FOR E=7 TO 0 STEP -1 930 IF D$(E*8+P)="1" THEN LPRINT "% % % % "; 940 IF D$(E*8+P)="0" THEN LPRINT " "; 950 NEXT E 960 NEXT F 970 NEXT P 980 RETURN 1000 SAVE "1007%3" 1010 CLS 1020 PRINT TAB 8;"%Z%X% %B%A%N%N%E%R%S" 1030 PRINT TAB 8;"**********" 1040 PRINT ,,;"THIS PROGRAM WILL PRINT ON THE ZX PRINTER LETTERS AND SYMBOLS 3"" HIGH IN THE FORM OF BANNERS" 1050 PRINT ,,;"THE LENGTH OF THE BANNER IS UP TO YOU. ENTER BELOW AND PRESS ENTER" 1060 PRINT ,,;"LETTERS AND GRAPHICS WILL WORK FUNCTIONS WILL NOT" 1090 GOTO 10 ```