This program implements a multi-screen slideshow loader and display system, storing up to 27 screens in memory between addresses 29952 and 63744 at 1024-byte intervals. It uses embedded Z80 machine code, self-installed at address 65000 via a POKE loop in line 330, to perform fast block memory copies between the loaded screen buffers and the display file at 16384 (0x4000). The machine code routine is stored as a decimal-encoded string, with each opcode represented as a three-digit value parsed using VAL and a sliding-window string technique. A user-selectable speed parameter controls the PAUSE duration between frame transitions during playback, creating a simple animation or slideshow effect.
Program Analysis
Program Structure
The program is organized as a menu-driven loader with four named entry points, whose line numbers are stored in variables for direct GO TO a dispatch after an INPUT a at line 70. The four functional sections are:
- loadfile (line 90) — loads an arbitrary CODE block and returns to menu.
- loadscreen / loadscr (line 130) — loads a SCREEN$ into successive 1024-byte-stepped buffer slots starting at 29952.
- display (line 220) — plays back all stored screens as a slideshow at a user-defined speed.
- Machine code installer (line 330) — installs the Z80 routine and chains to
RUN.
The program must be bootstrapped by running line 330 first (which ends with RUN, restarting from line 10) so the machine code is in place before any display or load operations are attempted.
Memory Layout
| Address | Purpose |
|---|---|
| 16384 (0x4000) | Display file (6144 bytes) |
| 22528 (0x5800) | Attribute file (768 bytes) |
| 29952 (0x7500) | First screen buffer slot |
| 29952 + n×1024 | Successive screen buffer slots |
| 63744 (0xF900) | Last valid buffer slot |
| 65000 (0xFDE8) | Machine code routine |
Each slot is 1024 bytes, which is notably not a full Spectrum screen (6912 bytes). This means only the first 1024 bytes of each SCREEN$ load are stored per slot — likely just the beginning of the pixel area. The CLEAR 29952 at line 10 sets RAMTOP to protect high memory but leaves the screen buffer region accessible. The guard IF pp>63744 at line 150 prevents overwriting the machine code at 65000.
Machine Code Installer
Line 330 is the bootstrap routine. It performs CLEAR 65000 to protect the target area, then decodes a 75-character decimal string (25 three-digit groups) into 25 bytes POKEd from address 65000 onward. The sliding-window idiom VAL a$(TO PI) extracts the first three characters as a number, and LET a$=a$(4 TO) advances the string. PI truncates to 3 in this context (since TO PI means TO 3 after integer truncation by VAL‘s argument slicing — actually the slice a$(TO PI) takes characters 1 to INT(PI)=3).
Z80 Machine Code Analysis
The encoded decimal string is: 033000064017000121062032001032000237176006023035005194247253061200195240253
Decoded bytes (hex): 21 00 40 11 00 79 3E 20 01 20 00 ED B0 06 17 23 05 C2 F7 FD 3D C8 C3 F0 FD
This disassembles as two interleaved routines whose entry points are patched by the BASIC via POKEs before each RANDOMIZE USR 65000 call:
- Load mode (line 170–200): POKEs set up a LDIR-based copy from a buffer slot to display memory at 0x4000.
- Display mode (line 240–300): POKEs reverse the source/destination to copy from display memory to a buffer slot, or vice versa for playback.
- The routine at offset +15 (
06 17 23 05 C2 F7 FD) is a counted loop withDJNZ-style logic usingDEC B / JP NZtargeting back into the routine. - The tail
3D C8 C3 F0 FD—DEC A / RET Z / JP 0xFDF0— provides a loop-exit with return, jumping back to offset +16 (0xFDF0 = 65008) until the counter reaches zero.
The high-byte of the source/destination addresses is the only value changed between calls (via POKE 65005,pp/256 or POKE 65005,f/256), making this a compact parameterized block-copy trampoline.
Key BASIC Idioms
- Named dispatch: Variables
loadfile,loadscr,loadscreen, anddisplayhold line numbers;GO TO aafterINPUT aroutes execution without a lookup table. - VAL with PI truncation:
VAL a$(TO PI)exploits the fact thatPI≈3.14…truncates to index 3 in a string slice, extracting exactly three characters per iteration. - Self-modifying machine code via POKE: Rather than multiple routines, a single code block is reconfigured for copy direction and address before each call.
- RUN at end of bootstrap: Line 330 ends with
RUN, cleanly restarting the program with machine code now installed andCLEARprotecting it.
Bugs and Anomalies
- 1024-byte screen slots vs. 6912-byte screens: A full Spectrum SCREEN$ is 6912 bytes (6144 pixel + 768 attribute). Storing screens at 1024-byte intervals means screens overlap heavily or only partial screen data is preserved. This appears to be an intentional design choice for a partial-screen animation or the buffer stores only luminance/pixel rows, discarding attributes.
- pp initialization:
ppis initialized to 29952 at line 20 but is incremented before the first load at line 140, meaning the first screen is stored at 30976 (29952+1024), not 29952. This may be intentional if the first slot is reserved. - display loop starts at 29952: The FOR loop at line 270 starts at 29952, before the first actually loaded slot (30976 if the above is correct), so the first frame displayed may be uninitialized memory.
Content
Source Code
10 CLEAR 29952
20 LET pp=29952
30 PRINT "Instructions:"'"loadfile"'"loadscreen"'"display": BEEP .05,15: PAUSE 0
40 CLS : LET loadfile=90: LET loadscr=130: LET loadscreen=130
50 LET display=220
60 BEEP .1,15: PRINT AT 20,0;"L&K Ready."
70 INPUT a
80 GO TO a
90 REM loadfile
100 PRINT AT 21,0; BRIGHT 1;"Loading file."
110 LOAD ""CODE
120 GO TO 40
130 REM loadscr loadscreen
140 LET pp=pp+1024
150 IF pp>63744 THEN GO TO 40
160 LOAD ""SCREEN$
170 POKE 65000,33: POKE 65003,17: POKE 65015,35
180 POKE 65002,64: POKE 65001,0
190 POKE 65005,pp/256: POKE 65004,0
200 RANDOMIZE USR 65000
210 GO TO 40
220 REM display
230 INPUT AT 21,0;"speed";sp
240 POKE 65000,17: POKE 65003,33: POKE 65015,19
250 POKE 65001,0: POKE 65002,64: POKE 65004,0
260 CLS
270 FOR f=29952 TO 63744 STEP 1024
280 PAUSE sp
290 POKE 65005,f/256
300 RANDOMIZE USR 65000
310 NEXT f
320 GO TO 40
330 CLEAR 65000: LET a$="033000064017000121062032001032000237176006023035005194247253061200195240253": FOR f=65000 TO 65024: POKE f,VAL a$( TO PI): LET a$=a$(4 TO ): NEXT f: RUN
340 SAVE "L&K" LINE 330
Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.
