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 fromR+7down toR. Because the loop variable is also namedR(shadowing the address variable set at line 60), this actually traverses 33 iterations (fromR+7toRin 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:
Ris used both for the ROM base address (line 60) and as theFORloop 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 3is always true (3 is non-zero), soRCis reset toDon every iteration of theGloop. This means each pass of the innerGloop reprints the same bit three times in consecutive rows, creating a 3× vertical magnification per bit. The intent was likelyIF 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 namedLEN. This works because ZX81 BASIC allows multi-character variable names for numeric variables, and the keywordLENis tokenised — the context distinguishes function call from variable reference. - Column advance without row reset: After each font byte (line 220–230), the screen column
Bis incremented andAreset to 1, building the character left-to-right on screen with each font byte’s bits printed vertically. - Lines 280–300:
CLEAR,SAVE, andRUNafterSTOPare 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).
Content
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
Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.
