2068 Display Block Moves

Developer(s): Robert Hartung
Date: 1993
Type: Program
Platform(s): TS 2068

This program demonstrates screen region capture and restore using a self-modifying machine code routine on the TS2068/ZX Spectrum. It offers a menu to capture one of three portions of the display file (top, middle, or bottom third) or the full screen (6192 bytes from address 16384), storing the data temporarily at address 30000. The machine code, written into addresses 65356–65367, implements a standard Z80 LDIR block-move sequence assembled via individual POKEs, with source and destination addresses computed at runtime by decomposing values into high and low bytes. A reverse LDIR pass then restores the captured region back to the display file, and the result can be saved as a CODE file named “SCRN”. The program also supports loading a pre-existing SCRN display file for comparison.


Program Analysis

Program Structure

The program is organised into three logical phases: menu and option selection (lines 10–70), screen capture from display file to RAM buffer (lines 80–250), and RAM buffer restore back to display file with optional save (lines 260–370). Utility lines at 9997–9999 handle saving the program itself and the captured screen CODE file.

  1. Lines 1–20: CLEAR 29999 reserves RAM above address 29999; menu display and keypress wait loop.
  2. Lines 30–70: Dispatch on key k$; compute STP (start address), INS (address high byte), NOB (number of bytes), INB (bytes high byte) for each region option.
  3. Lines 80–110: Fill the screen with a tile pattern and print row numbers 0–21 so a visible test image is present during capture.
  4. Lines 120–240: POKE a Z80 LDIR routine into addresses 65356–65367, then call it with RANDOMIZE USR 65356.
  5. Lines 260–370: Reverse the LDIR arguments (source and destination swapped) to restore the buffer back to screen, then offer save or menu return.
  6. Lines 9997–9999: SAVE "SCRNmove" LINE 1 saves the BASIC program; SAVE "SCRN" CODE STP,NOB saves the captured screen region.

Machine Code Routine

The machine code is assembled piecemeal into high RAM (address 65356 on a 64 KB address space, i.e. wrapping into the mapped area). The routine is a minimal Z80 block copy:

AddressOpcode(s)MnemonicPurpose
6535601 lo hiLD BC,NOBByte count
6535911 lo hiLD DE,30000Destination (RAM buffer)
6536221 lo hiLD HL,STPSource (display file)
65365ED B0LDIRBlock copy HL→DE, BC bytes
65367C9RETReturn to BASIC

For the restore phase (lines 280–340), only the byte-count and address POKEs are updated; the opcodes at 65356, 65359, 65362, 65365, and 65367 are left in place from the initial write, saving re-POKEing the opcode bytes.

Address Decomposition Idiom

Because POKE takes a single byte value, 16-bit addresses and counts are split into high and low bytes. The pattern used throughout is:

  • High byte: INS = INT(STP/256)
  • Low byte: STP-(256*INS) (equivalent to STP MOD 256)

This avoids the MOD operator (absent on some dialects) and is a common Sinclair BASIC technique for packing 16-bit values.

Screen Region Parameters

KeyOptionStart (STP)Bytes (NOB)Notes
1Full screen1638461926144 pixels + 48 attribute bytes
2Top third163842045 (typo)Should be 2048; “204S” is a listing error
3Middle third163S4+2048 (typo)2048“163S4” should be 16384
4Bottom third16384+40962096Likely should be 2048; 2096 is suspicious

Bugs and Anomalies

  • Line 50 — NOB=204S: The literal 204S is not a valid numeric token; this is almost certainly a transcription error for 2048 (the digit 8 rendered as S).
  • Line 60 — LET STP=163S4+2048: Similarly, 163S4 is a garbled 16384 (8→S substitution).
  • Line 70 — NOB=2096: A bottom-third capture should be 2048 bytes; 2096 would overrun the pixel region into attributes or beyond.
  • Line 360 — INKEY*: The * should be $ (INKEY$); another transcription artifact.
  • Line 330 — REM MSB sou rce: A space in a REM comment — harmless but suggests the listing was typed or OCR’d with errors.
  • Line 90 — screen fill "\`.": The backtick is the £ character in Sinclair character sets; this fills the screen with £. pairs as a test pattern.
  • Full-screen NOB=6192: The standard Spectrum display is 6912 bytes (6144 pixels + 768 attributes). 6192 only covers 6144 + 48 attribute bytes, leaving most attributes uncaptured. This appears intentional for a partial-attribute save but is not documented in the menu.

Notable Techniques

  • CLEAR 29999 places the BASIC stack and the machine code buffer (at 30000 and 65356) safely outside the display file and program area.
  • Re-using the partially-POKEd routine for both directions (capture and restore) by only overwriting the operand bytes reduces code and POKE count.
  • PRINT #0;AT 1,0; writes status messages to the lower screen (stream 0) without disturbing the captured display contents in the upper screen.
  • The SAVE "SCRN" CODE STP,NOB at line 9998 uses the runtime variables directly, so the correct region is always saved regardless of which menu option was chosen.

Content

Appears On

Related Products

Related Articles

In the Z80 microprocessor used in the 2068 is a command called LDIR that may be used to quickly move...

Related Content

Image Gallery

Source Code

 1 CLEAR 29999
 10 PRINT "0 - Load SCRN display file"'"1 - Full-screen store"'"2 - Top screen store"'"3 - Middle screen store"'"4 - Bottom screen store"
 20 PAUSE 0: LET k$=INKEY$: IF k$="" THEN GO TO 20
 30 IF k$="0" THEN CLS : LOAD "SCRN" CODE : PRINT "Any key to continue": PAUSE 0: RUN
 40 IF k$="1" THEN LET STP=16384: LET INS=INT (STP/256) : LET NOB=6192: LET INB=INT (NOB/256): GO TO 80
 50 IF k$="2" THEN LET STP=16384: LET INS=INT (STP/256): LET NOB=204S: LET INB=INT (NOB/256): GO TO 80
 60 IF k$="3" THEN LET STP=163S4+2048: LET INS=INT (STP/256): LET NOB=2048: LET INB=INT (NOB/256) : GO TO 80
 70 IF k$="4" THEN LET STP=16384+4096: LET INS=INT (STP/256): LET NOB=2096: LET INB=INT (NOB/256)
 80 CLS : REM Create screen-fill
 90 FOR n=1 TO 704: PRINT "`.";:NEXT n
 100 FOR n=0 TO 21: PRINT AT n,0;n: NEXT n
 110 REM Defines selected lines/cols and copies from DFILEl to RAM
 120 POKE 65356,1: REM LD BC,no. of bytes to move
 130 POKE 65357,NOB-(256*INB) : REM n LSB
 140 POKE 65358,INB: REM n MSB 
 150 POKE 65359,17: REM LD DE,destination address 30000 
 160 POKE 65360,48: REM n LSB 
 170 POKE 65361,117: REM n MSB 
 180 POKE 65362,33: REM LD HL,source address 
 190 POKE 65363,STP-(256*INS) : REM n LSB 
 200 POKE 65364, INS: REM n MSB 
 210 POKE 65365,237: REM ED prefix
 220 POKE 65366,176: REM LDIR block-move
 230 POKE 65367,201: REM RETurn
 240 RANDOMIZE USR 65356: REM Call block-move routine
 250 PRINT #0;AT 1,0; "Any key to continue": PAUSE 0
 260 REM Moves RAM data to DFILE1
 270 CLS
 280 POKE 65357, NOB-(INB*256) : REM LSB no. bytes 
 290 POKE 65358, INB: REM MSB nobytes
 300 POKE 65360,STP-(256*INS) : REM LSB dest 
 310 POKE 65361, INS: REM MSB dest
 320 POKE 65363,48: REM LSB source in RAM (30000)
 330 POKE 65364,117: REM MSB sou rce in RAM (30000)
 340 RANDOMIZE USR 65356
 350 PRINT #0;"Key 5 to save or m for menu"
 360 PAUSE 0: IF INKEY*="5" THEN PRINT #0;AT 0,0,,,,: GO TO 9998
 370 RUN
 9997 SAVE "SCRNmove" LINE 1: STOP
 9998 SAVE "SCRN "CODE STP,NOB
 9999 RUN

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

Scroll to Top