Scrolls demonstrates two machine code routines that perform hardware-level screen scrolling — one scrolling the display right and one scrolling it left. The routines are loaded into RAM at addresses 26715 and 26753 respectively via POKE loops reading DATA statements, then invoked with RANDOMIZE USR. Line 2000 offers a separate demonstration that cycles through all 255 values of the system variable at address 23606, which controls the horizontal pixel scroll offset, printing a string at a fixed screen position to show the effect. Line 500 contains an extended comment mapping out screen third boundaries (64–88 in display RAM terms) that likely guided the machine code design.
Program Analysis
Program Structure
The program is divided into three functional areas:
- Initialization (lines 10–20): Two
FORloops useREADandPOKEto install machine code into RAM at addresses 26715–26733 and 26753–26779. - Scroll-right demo (lines 995–1160): Prints a test string, then calls the left-scroll routine 100 times via
RANDOMIZE USR 26753, reprints the string, and calls the right-scroll routine 100 times viaRANDOMIZE USR 26715. - Hardware pixel-scroll demo (line 2000–2010): Cycles system variable address 23606 through values 1–255 while displaying a fixed string, then resets to 0.
Execution begins at line 10 and falls through to line 20, then hits GO TO 1090 at line 995 (line 500’s REM and line 996’s STOP are bypassed). The DATA statements at lines 1000–1080 are read sequentially by the two initialization loops.
Machine Code Routines
The two routines are disassembled below. Display RAM on the ZX Spectrum begins at 0x4000 (16384 decimal); pixel rows are interleaved in a non-linear pattern, but the routines treat the screen as a flat 32-byte-wide, 192-row block for simplicity, using the range 0x4000–0x5800 (64–88 in high-byte terms).
Scroll Right Routine (address 26715)
| Bytes | Mnemonic | Notes |
|---|---|---|
| 33,0,64 | LD HL,&4000 | Point HL to start of display RAM |
| 14,32 | LD C,32 | 32 bytes per row |
| 175 | XOR A | Clear A (carry flag source / shift-in bit) |
| 126 | LD A,(HL) | Load byte |
| 31 | RRA | Rotate right through carry |
| 119 | LD (HL),A | Store shifted byte |
| 35 | INC HL | Advance pointer |
| 13 | DEC C | Decrement column counter |
| 32,249 | JR NZ,-7 | Loop for 32 bytes |
| 62,88 | LD A,88 | High byte of end address (0x5800) |
| 188 | CP H | Compare with current high byte |
| 32,241 | JR NZ,-15 | If not at end, do next row |
| 201 | RET | Return |
This routine scrolls all pixel bytes one bit to the right using RRA (rotate right through carry). The carry propagates across each byte in a row but resets between rows (carry is cleared by the XOR A only at the start), meaning the rightmost bit of each byte wraps into the leftmost bit of the next — effectively a bitwise right-shift across the full 32 bytes of each row. The outer loop advances row by row until the high byte of HL reaches 88 (0x58).
Scroll Left Routine (address 26753)
| Bytes | Mnemonic | Notes |
|---|---|---|
| 33,31,64 | LD HL,&401F | Point HL to byte 31 of first row (last byte) |
| 22,0 | LD D,0 | Row counter high = 0 |
| 30,65 | LD E,65 | Used in DE for row stepping |
| 14,32 | LD C,32 | 32 bytes per row |
| 175 | XOR A | Clear A / carry |
| 126 | LD A,(HL) | Load byte |
| 23 | RLA | Rotate left through carry |
| 119 | LD (HL),A | Store shifted byte |
| 43 | DEC HL | Move left |
| 13 | DEC C | Decrement column counter |
| 32,249 | JR NZ,-7 | Loop for 32 bytes |
| 25 | ADD HL,DE | Advance HL to next row’s last byte |
| 62,88 | LD A,88 | End high-byte sentinel |
| 188 | CP H | Compare |
| 40,3 | JR Z,+3 | If at end, jump to RET |
| 43 | DEC HL | Adjust to last byte of next row |
| 24,235 | JR -21 | Next row loop |
| 201 | RET | Return |
This routine works from right to left within each row, using RLA (rotate left through carry) to shift pixels leftward. DE (value 65 = 0x41) is added to HL after each row to step forward 65 bytes, then HL is decremented by 1 to land on the last byte of the next row — a compact way to handle the 32-byte row stride from an end-of-row position.
Hardware Pixel-Scroll Demo (line 2000)
System variable address 23606 (the CHARS system variable, normally a pointer to the character set) is repurposed here as a pixel scroll offset. Cycling it through 0–255 causes the display hardware to shift the pixel output horizontally, producing a smooth scrolling effect without moving any screen data. The POKE 23606,0 at line 2010 restores normal character rendering after the demo.
Notable Techniques
RANDOMIZE USRis used to call machine code, discarding the return value — the standard method for invoking Z80 routines from BASIC.- The
XOR Abefore the inner byte loop clears both A and the carry flag in a single byte, ensuring no spurious carry from the previous row bleeds into the shift. - The high-byte sentinel check (
LD A,88 / CP H) efficiently detects the end of display RAM without a full 16-bit comparison. - Line 500’s lengthy
REMserves as a developer scratch pad, documenting address ranges for screen thirds — typical of iterative machine code development within BASIC. - The
'''(three newlines via multiple apostrophes inPRINT) creates vertical spacing in the demo output at line 1090.
Anomalies and Notes
- The loop variable at line 1140 is
A(uppercase) while the loop at line 1100 usesa(lowercase). In Spectrum BASIC these are the same variable, so theNEXT aat line 1160 correctly terminates the loop begun at line 1140. - Lines 1 and 2 contain
REMstatements with cryptic shorthand (e.g.RANDOMIZE,SGN,LET) that appear to be development notes about variable usage rather than executable code. - Line 996’s
STOPis unreachable in normal execution since line 995 performs aGO TO 1090, but it acts as a safety barrier between the jump and theDATAstatements should the flow ever fall through.
Content
Source Code
1 REM !@# RANDOMIZE >XSGN LET <>zzzzzzzzzzzzz
2 REM !@A+ RANDOMIZE >XSGN (+ FOR <>zzzzz
10 FOR g=26715 TO 26733: READ a: POKE g,a: NEXT g
20 FOR g=26753 TO 26779: READ a: POKE g,a: NEXT g
500 REM 1000 1002 2000 2002 itm3 itm1 itm3 itm6 all 64 88 64 88 top third 64 72 64 72 mid third 72 80 72 80 low third 80 88 80 88 top 2/3 64 80 64 80 low 2/3 72 88 72 88
995 GO TO 1090
996 STOP
997 REM
998 REM SCROLL RIGHT (26715)
1000 DATA 33,0,64,14,32,175,126
1010 DATA 31,119,35,13,32,249,62
1020 DATA 88,188,32,241,201
1030 REM
1040 REM SCROLL LEFT (26753)
1050 DATA 33,31,64,22,0,30,65,14
1060 DATA 32,175,126,23,119,43
1070 DATA 13,32,249,25,62,88,188
1080 DATA 40,3,43,24,235,201
1090 PRINT "this is a test of the system"''''" Also Try RUN 2000"
1100 FOR a=1 TO 100
1110 RANDOMIZE USR 26753
1120 NEXT a
1130 PRINT "this is a test of the system"''''" Also Try RUN 2000"
1140 FOR A=1 TO 100
1150 RANDOMIZE USR 26715
1160 NEXT a
2000 FOR A=1 TO 255: POKE 23606,A: PRINT AT 12,10;"ABCDEFGHIJK": NEXT A
2010 POKE 23606,0
Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.
