Banner Writer reads a user-supplied message and prints each character at 32 times normal size by directly reading the ZX81’s character ROM bitmap data using PEEK. For each character, it looks up the 8-byte font data starting at address 7680 plus the character code multiplied by 8, then iterates over each bit of each row to render an enlarged version on screen. The STEP value of -0.25 in the FOR loop at line 70, combined with the loop counter G running 1 to 3 in line 110, controls both the height scaling and line thickness of the output. After each character is rendered, a COPY command sends the screen contents to a ZX printer. The program runs in FAST mode to reduce rendering time, though each letter still takes approximately 35 seconds to generate.
Program Analysis
Program Structure
The program is organized into three main phases: input collection (lines 10–20), a three-level nested rendering loop (lines 50–260), and a termination step. The outermost loop (line 50) iterates over each character in the input string M$. The middle loop (line 70) iterates over the 8 bytes of font data for the character. The innermost loops (lines 90–210) expand each byte’s bits into large printed blocks.
- Lines 1–9: REM documentation and FAST mode setup
- Lines 10–20: Display prompt and collect input string
M$ - Lines 50–60: Outer character loop; compute ROM address for each character
- Lines 63–67: Initialize screen position variables
A(row) andB(column) - Lines 70–240: Nested loops to read, decode, and print enlarged character pixels
- Line 250: COPY to ZX printer
- Lines 260–270: Advance to next character; STOP
Font Data Access via PEEK
The program reads character bitmap data directly from memory using PEEK. Line 60 computes the base address as 7680 + (CH * 8), where CH is the character code obtained from CODE M$(L). Each character occupies 8 consecutive bytes in the font table, one byte per pixel row. The FOR loop at line 70 traverses these bytes in reverse order (from R+7 down to R) using a fractional STEP of -0.25, which causes each byte address to be visited multiple times, contributing to vertical scaling.
Bit Extraction Technique
Each font byte is decoded one bit at a time using repeated subtraction and left-shifting rather than bitwise operations, which are unavailable in this BASIC dialect. Line 140 tests whether the current value of RC is 128 or greater (i.e., whether the most significant remaining bit is set). If so, line 150 sets CNTR to 128 (which corresponds to an inverse-video space character, effectively a filled block), and line 160 subtracts 128 from RC. Line 170 then doubles RC, shifting the next bit into the high position for the following iteration. This is a classic bit-serial extraction loop.
Scaling Mechanism
Horizontal scaling is achieved by the H loop (line 90, running 1 to 7), which repeats the bit-extraction and print sequence 7 times per font byte row, widening each pixel column. Vertical scaling is achieved by the fractional STEP (-0.25) in line 70, which causes each integer ROM address to be visited four times before moving to the next, effectively repeating each pixel row four times. The G loop (line 110, running 1 to 3) adds a further factor of 3 to line thickness. Together these produce the claimed 32× enlargement.
Screen Position Management
Variables A and B track the current print row and column respectively. A is incremented at line 190 after each G-loop iteration and reset to 1 at line 220 after each font byte is processed. B is incremented at line 230 to advance one column after all rows for a given font byte column are printed. This builds up the enlarged character column by column across the screen.
Notable Techniques and Anomalies
- The condition at line 120 reads
IF G=2 OR 3, which in this BASIC always evaluates as true (since the numeric value 3 is non-zero and treated as logical TRUE). The intended logic was likelyIF G=2 OR G=3. As written,RCis reset toDon every pass through theGloop, meaning each of the 3 repetitions re-processes the same original byte value — this is what produces the 3× line-thickness effect, but it is a coincidental bug rather than intentional logic. - The fractional STEP value of
-0.25in line 70 exploits floating-point loop behavior to visit the same integer PEEK address multiple times, a memory-efficient scaling trick that avoids explicit repeat loops. - Using character code 0 (the inverse space,
CHR$ 128effectively asCNTR=128) to represent a filled pixel block is idiomatic for this platform’s character set. - The COPY command at line 250 is issued once per character rather than once for the entire message, meaning each enlarged letter is printed to the ZX printer individually before the screen is reused for the next character.
- The variable name
CNTRis reused both as a flag (set to 0 or 128) and as the argument toCHR$, doubling as a pixel color control as noted in the REM at line 3.
Variable Summary
| Variable | Role |
|---|---|
M$ | Input message string |
L | Index into M$ (character loop counter) |
CH | Character code of current letter |
R | ROM address of current font byte (also loop variable) |
RC | Current font byte value, modified during bit extraction |
D | Saved copy of RC for reset in G loop |
H | Horizontal repeat counter (1–7) |
G | Line thickness repeat counter (1–3) |
A | Current print row |
B | Current print column |
CNTR | Pixel value: 0 (space) or 128 (filled block) |
Content
Source Code
1 REM % %B%A%N%N%E%R% %W%R%I%T%E%R%
2 REM LETTERS=32X NORMAL SIZE
3 REM LINE 130 CONTROLS BACK-FROUND; LINE 150 CONTROLS LETTER COLOR
4 REM STEP IN LINE 70 AND VARIABLE "G" CONTROL HEIGHT AND THCKNES OF LINES
5 REM SWITCHING "A" AND "B" IN LINE 180 ROTATES LETTER AOTHER 90 DEGREES
7 REM EACH LETTER TAKES ABOUT 35 SECONDS TO GENERATE AND PRINT
9 FAST
10 PRINT AT 10,3;"% %I%N%P%U%T% %A%N%Y% %L%E%N%G%T%H% %M%E%S%S%A%G%E% "
20 INPUT M$
50 FOR L=1 TO LEN M$
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
250 COPY
260 NEXT L
270 STOP
Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.
