Syncsum

Developer(s): David Ornstein
Date: 1982
Type: Cassette
Platform(s): TS 1000
Tags: Utility

Syncsum is a utility that extracts machine code from a REM statement and relocates it to a reserved area just below RAMTOP, where it can then be called via USR. The program operates in two passes: the first run reserves space by lowering RAMTOP by 27 bytes (configurable via the variable R at line 10) and issues NEW to clear BASIC memory, and the second run (entered with GOTO 100) decodes and POKEs the machine code bytes into that reserved region. The machine code is stored in REM line 1 as pairs of shifted ASCII characters (each nibble encoded by subtracting 28 and treating the result as a hex digit), which the extraction loop at lines 110–140 decodes. Once installed, the routine can be invoked with PRINT USR 32741 (or the 1K/2K equivalents 17381 and 18405) to compute a checksum of a loaded program.


Program Analysis

Program Structure

The program is designed to run in two distinct passes, separated by a NEW command that clears BASIC memory while leaving the reserved area below RAMTOP intact.

  1. First pass (lines 6–50): Sets FAST mode, reads the current RAMTOP from system variables at addresses 16388–16389, subtracts R (27) bytes, writes the new RAMTOP back, and executes NEW.
  2. Second pass (lines 100–150, entered with GOTO 100 after reloading): Reads the (now-lowered) RAMTOP, decodes the 27 machine code bytes stored in REM line 1, POKEs them into the reserved region, then calls NEW again to leave just the installed routine.

Line 60 (NEXT B) is never reached in normal execution — it acts as a guard or dead code following the NEW at line 50.

RAMTOP Manipulation

System variables at addresses 16388 (low byte) and 16389 (high byte) hold RAMTOP as a 16-bit little-endian value. Lines 20–40 lower RAMTOP by R bytes using integer arithmetic to split the new value back into its two bytes:

  • POKE 16388, RAMTOP - 256 * INT(RAMTOP / 256) — stores the low byte (equivalent to RAMTOP MOD 256).
  • POKE 16389, INT(RAMTOP / 256) — stores the high byte.

The instructions in the REM at line 5 specify three possible USR addresses: 32741 for a 16K RAM pack, 17381 for 1K, and 18405 for 2K, corresponding to the different RAMTOP values produced by each configuration minus the 27-byte reservation.

Machine Code Encoding in REM

The 27 machine code bytes are encoded in REM line 1 as a sequence of 54 characters. Each byte is represented by two characters, each encoding one nibble. The decode formula at line 120 is:

X = ((PEEK(16509 + 5 + B*2) - 28) * 16 + (PEEK(16509 + 5 + B*2 + 1) - 28))

  • Address 16509 is the start of the BASIC program area (D_FILE system variable, or equivalently the program start).
  • Offset 5 skips the line header (2-byte line number + 2-byte length + 1-byte token for REM).
  • Each stored character has 28 subtracted to recover its nibble value (0–15), giving two nibbles packed into one byte.

The decoded Z80 machine code from line 1 is: 21 7D 40 ED 5B 0C 40 06 00 7C BA 20 08 7D BB 20 04 48 06 00 C9 78 AE 47 23 18 EE. This appears to be a loop that computes a XOR-based checksum over a region of memory (likely the BASIC program), returning the result in the BC or A register for use with USR.

Key BASIC Idioms

  • Two-byte PEEK arithmetic (PEEK(addr) + PEEK(addr+1) * 256) is the standard idiom for reading 16-bit system variables.
  • INT(x / 256) and x - 256 * INT(x / 256) substitute for the absent MOD operator when splitting a 16-bit value into bytes.
  • Using NEW mid-program (line 50) to reset BASIC while preserving memory below the new RAMTOP is a well-established technique for installing persistent machine code routines.

Notable Techniques

TechniqueLinesPurpose
Nibble-pair encoding in REM1, 120Stores machine code as printable characters offset by 28
RAMTOP reservation via system variable POKEs20–40Carves out 27 bytes below RAMTOP for the routine
Two-pass load-and-run with NEW50, 150Installs code while clearing BASIC overhead
Configurable reservation size via R10Allows easy adjustment if the machine code size changes

Anomalies and Notes

  • Line 60 (NEXT B) is unreachable dead code; execution never falls through line 50’s NEW. It may be a leftover from an earlier version or an intentional no-op placeholder.
  • The variable R at line 10 is hardcoded to 27, matching the exact byte count of the machine code in line 1. Changing the machine code without updating R would corrupt the installation.
  • The offset calculation 16509 + 5 + B*2 assumes the program is loaded at address 16509, which is the default BASIC program start. If the system variable D_FILE differs, the extraction would read wrong bytes — though in normal use the reload guarantees a clean state.

Content

Appears On

Related Products

Related Articles

Short program to provide checksums to users as they type in programs, to ensure they’ve been entered correctly.

Related Content

Image Gallery

Syncsum

Source Code

   1 REM 217D40ED5B0C4006007CBA20087DBB2004480600C978AE472318EE
   2 REM 
   3 REM   % % %S% %Y% %N% %C% %S% %U% %M% % 
   4 REM 
   5 REM TO OBTAIN SYNCSUM, LOAD         THIS PROGRAM AND RUN IT         THEN LOAD IT AGAIN AND          ENTER "GOTO 100". THEN          LOAD YOUR MAIN PROGRAM          AND IF YOU HAVE A 16K           RAM PACK, YOU CAN ENTER         THE COMMAND PRINT USR           32741 (17381 FOR 1K OR          18405 FOR 2K). SYNCSUM          SHOULD BE CONSTANT FOR          EACH PROGRAM YOU HAVE. 
   6 FAST 
   7 REM 
   8 REM ENTER R AS THE NUMBER           OF BYTES YOU WANT TO            RESERVE ABOVE RAMTOP
   9 REM 
  10 LET R=27
  20 LET RAMTOP=PEEK (16388)+PEEK (16389)*256-R
  30 POKE 16388,RAMTOP-256*INT (RAMTOP/256)
  40 POKE 16389,INT (RAMTOP/256)
  50 NEW 
  60 NEXT B
 100 LET RT=PEEK (16388)+PEEK (16389)*256
 110 FOR B=0 TO 26
 120 LET X=((PEEK (16509+5+B*2)-28)*16+(PEEK (16509+5+B*2+1)-28))
 130 POKE RT+B,X
 140 NEXT B
 150 NEW 

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

Scroll to Top