Inverse Scroll

This file is part of and Synchro-Sette February 1983. Download the collection to get this file.
Date: February 1983
Type: Program
Platform(s): TS 1000
Tags: Home

This program implements a word-by-word scrolling marquee display on the ZX81/TS1000, presenting each word of a user-entered message in large pixel-doubled characters built from the ROM character set. The program reads the character font directly from ROM at address 7680 (the ZX81 character set base), unpacking each 8×8 bitmap bit-by-bit using PEEK and plotting individual pixels via UNPLOT on the lo-res display. Words are extracted one at a time using a space-scanning subroutine at line 1000, and after each word the screen scrolls up by a configurable number of lines (stored in G). When the last word is reached, the subroutine at line 2000 resets S=1 so the message loops continuously and sets G=21 to clear the full screen before restarting. Inverse video characters in Z$ (a string of spaces) are used as a solid fill line to create a clean background during scrolling.


Program Analysis

Program Structure

The program is organised into a main flow and three subroutines:

  1. Initialisation (lines 10–80): Sets scroll gap G=4, word position S=1, builds a fill string Z$ of inverse-video spaces, prompts for input, and appends two trailing spaces to B$ to ensure the last word is correctly terminated.
  2. Main display loop (lines 100–360): Clears the screen (GOSUB 3000), extracts a word (GOSUB 1000), scrolls G lines, then renders the word pixel-by-pixel using ROM font data before looping back to line 130.
  3. Subroutine 1000 – Word extractor: Scans B$ from position S for the next space, slices out the word into A$, and advances S.
  4. Subroutine 2000 – End-of-message detector: Checks whether the current word index N is near the end of B$; if so, resets S=1 and sets G=21 to do a full-screen clear on the next cycle.
  5. Subroutine 3000 – Screen clear: POKEs the display file pointer and scrolls 21 lines of Z$ to fill the screen with inverse-video space.

ROM Font Access

The character bitmaps are read directly from ROM starting at address 7680, which is the base of the ZX81 character set. Each character occupies 8 consecutive bytes, one per pixel row. The formula used is:

PEEK (7680 + C*8 + L) where C is the character code and L is the row (0–7).

For characters with codes ≥128 (inverse video), lines 220–240 subtract 128 and set C=0, mapping them to the space character—a limitation meaning inverse characters in the input are rendered as blank columns rather than their true glyphs.

Bit-Unpacking Technique

Each font byte is decoded by successively subtracting powers of two. The variable V starts at 128 and is halved each iteration. If the current byte value P is ≥ V, bit 7-J is set: UNPLOT is called to draw the pixel and V is subtracted from P. This is a standard shift-and-mask idiom for BASIC environments lacking bitwise operators.

Pixel Placement with UNPLOT

UNPLOT on the ZX81 sets a pixel in the lo-res 64×44 graphics grid. Characters are placed at horizontal position 8*(K-1)+J and vertical position 10-L, giving each character an 8-pixel-wide column and rendering rows top-to-bottom by inverting L. This effectively doubles the visual size of each character relative to normal text, since the lo-res grid maps roughly 2 PLOT units per character cell row.

Scrolling Mechanism

The ZX81 SCROLL keyword moves the display up one line. The loop at lines 170–190 scrolls G lines and prints Z$ (a row of inverse spaces) after each scroll to maintain a solid background. Normally G=4 (scrolling 4 lines between words); at message wrap it becomes G=21 to blank the full screen before restarting.

Screen Initialisation via POKE

Line 3000 contains POKE 16418,2. Address 16418 is the system variable DF_SZ (display file size / lower screen lines). Setting it to 2 minimises the lower screen area, maximising the main display—a common ZX81 technique to reclaim display rows.

Variable Summary

VariableRole
SCurrent start position within B$ for word scanning
GNumber of scroll lines between words (4 normal, 21 at wrap)
Z$A 64-character string of inverse spaces used as fill line
B$User-entered message (with two trailing spaces appended)
A$Current extracted word being displayed
CCharacter code of current character in word
M$Temporary holder when stripping inverse-video flag (≥128)
PCurrent font byte being unpacked
VBit-mask value (128, 64, 32, … 1)
I,J,K,L,N,ZLoop counters

Bugs and Anomalies

  • The word-extractor at line 1020 (NEXT N) will run past the end of B$ if no space is found before LEN B$, potentially causing a subscript error. The two appended spaces in line 80 mitigate this for most inputs but do not fully protect against it.
  • M$ at line 230 is assigned but never used; the intent appears to have been to render the underlying non-inverse character, but C is set to 0 instead, so all inverse characters silently become blank columns.
  • Subroutine 2000 compares N against LEN B$-1. Because B$ has two trailing spaces, the boundary check fires one word early, causing the last actual word to trigger the reset condition before it has fully rendered.
  • The pixel row rendering uses UNPLOT (which clears a pixel on ZX81), rather than PLOT which would set it. This means the program draws its characters in blank pixels against the inverse-space background—a deliberate inverse-video display effect consistent with the program’s name and the use of Z$.

Content

Appears On

Cassette to accompany the February 1983 issue of Synchro-Sette.

Related Products

Related Articles

Related Content

Image Gallery

Inverse Scroll

Source Code

  10 LET S=1
  20 LET G=4
  30 LET Z$="% % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % "
  60 PRINT AT 10,0;"TYPE IN A MESSAGE."
  70 INPUT B$
  80 LET B$=B$+"  "
 100 GOSUB 3000
 130 GOSUB 1000
 170 FOR I=1 TO G
 180 SCROLL 
 185 PRINT Z$
 190 NEXT I
 200 FOR K=1 TO LEN A$
 210 LET C=CODE A$(K)
 220 IF C<128 THEN GOTO 250
 230 LET M$=CHR$ (C-128)
 240 LET C=0
 250 FOR L=0 TO 7
 260 LET P=PEEK (7680+C*8+L)
 270 LET V=128
 280 FOR J=0 TO 7
 290 IF P<V THEN GOTO 320
 300 UNPLOT 8*(K-1)+J,10-L
 305 GOSUB 2000
 310 LET P=P-V
 320 LET V=V/2
 330 NEXT J
 340 NEXT L
 350 NEXT K
 360 GOTO 130
 1000 FOR N=S TO LEN B$
 1010 IF B$(N)=" " THEN GOTO 1050
 1020 NEXT N
 1050 LET A$=B$(S TO N-1)
 1060 LET S=N+1
 1070 RETURN 
 2000 IF N<LEN B$-1 THEN LET G=4
 2010 IF N>=LEN B$-1 THEN LET S=1
 2020 IF N>=LEN B$-1 THEN LET G=21
 2030 RETURN 
 3000 POKE 16418,2
 3010 FOR Z=1 TO 21
 3020 SCROLL 
 3030 PRINT Z$
 3040 NEXT Z
 3050 RETURN 
 9998 SAVE "INVERSCROL%L"
 9999 RUN 

Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.

People

No people associated with this content.

Scroll to Top