--- title: "Program Checksum" id: 55067 type: "computer_media" slug: "linecheck" url: "http://localhost/computer_media/linecheck/" markdown_url: "http://localhost/computer_media/linecheck.md" published_at: "2024-06-14T01:24:05+00:00" modified_at: "2026-03-30T21:44:49+00:00" author: "David Anderson" featured_image: url: "http://localhost/wp-content/uploads/2019/02/20230809-041332.jpg" excerpt: "This BASIC line-checker walks every program line in RAM, computing and printing a per-line checksum that could reveal tampering or corruption." category: - name: "Archived Media" slug: "archived-media" taxonomy: "category" url: "http://localhost/category/archived-media/" post_tag: - name: "Downloadable" slug: "downloadable" taxonomy: "post_tag" url: "http://localhost/tag/downloadable/" - name: "TS 2068" slug: "ts2068" taxonomy: "post_tag" url: "http://localhost/tag/ts2068/" model: - name: "Timex/Sinclair 2068" slug: "ts-2068" taxonomy: "model" url: "http://localhost/model/ts-2068/" indiv: - name: "John Bell" slug: "bell-john" taxonomy: "indiv" url: "http://localhost/indiv/bell-john/" genre: - name: "Utility" slug: "utility" taxonomy: "genre" url: "http://localhost/type/utility/" media_type: "Program" programmers: - name: "John Bell" slug: "bell-john" taxonomy: "indiv" url: "http://localhost/indiv/bell-john/" download_url: "https://archive.org/download/timex-sinclair-software-archive/Linecheck%20%281985%29%28Bell%2C%20John%29%28TS2068%29%28US%29%28Program%29.zip" mediadate: "1985" related_content: - id: 10579 title: "In Sync: Linecheck" type: "article" url: "http://localhost/article/in-sync-linecheck/" media_type_tags: "Utility" --- # Program Checksum This utility program walks through the BASIC program area in RAM, starting at memory address 26710, computing a simple checksum for each line. For each line, it reads the two-byte line number and the two-byte length field, then iterates over pairs of bytes in the line body, subtracting alternate bytes to produce a running total. The checksum and line number for each line are printed to a printer via LPRINT, formatted with TAB 6 for alignment. The loop terminates when it encounters line 9999, which is the program’s own final line. *** ## Program Analysis ### Program Structure The program is entirely self-contained in lines `9988`–`9999`, with `9988` and `9989` serving as title/author REMs. The main loop runs from `9991` to `9999`, with `GO TO 9991` at the end creating an unconditional loop that advances a memory pointer (`loc`) line by line through the BASIC program area. ### Memory Layout Traversal The program exploits the standard Sinclair BASIC line storage format. Each line in memory is laid out as: 1. Two bytes: line number (high byte first) 2. Two bytes: line length (low byte first, little-endian) 3. *length* bytes: the line body Line `9991` reads the line number as `PEEK loc * 256 + PEEK (loc+1)` (big-endian), and line `9992` reads the length as `PEEK (loc+2) + PEEK (loc+3) * 256` (little-endian), both consistent with the Sinclair BASIC line format. ### Checksum Algorithm The checksum loop at `9993`–`9995` steps through the line body two bytes at a time, computing `total = total + PEEK(a) - PEEK(a+1)`. This is an alternating add/subtract byte checksum rather than a simple sum or XOR, which gives it slightly different sensitivity to byte-pair swaps. It is a lightweight integrity indicator rather than a cryptographic hash. ### Output Formatting Line `9996` uses `LPRINT` to send output directly to a printer, printing the line number followed by the checksum value, with `TAB 6` providing consistent column alignment between the two values. ### Termination Condition The loop checks `IF linum=9999 THEN STOP` at line `9998`, halting when the traversal reaches the program’s own last line (`9999`). This is a self-referential termination: the program uses its own final line number as the sentinel. Because line `9997` advances `loc` before the check, the checksum for line `9999` itself is not printed (the `GO TO` at `9999` would never be reached after a `STOP`, but the check at `9998` fires first). ### Notable Techniques and Potential Issues - The hard-coded start address `26710` at line `9990` assumes the BASIC program begins at a fixed location, which is only valid for a specific memory configuration. On systems where the program start address differs, `loc` would need to be set via `PEEK` of the relevant system variable instead. - The checksum loop uses `STEP 2` and accesses `PEEK (a+1)`, so if the line body has an odd length, the final byte is paired with the first byte of the next line’s header — a potential off-by-one anomaly at line boundaries. - Using lines in the `9988`–`9999` range keeps the utility at the very end of a program, minimizing interference with code it is designed to audit and making it easy to append to any existing listing. - No variable initialization for `total` persists between iterations — it is reset to `0` at the start of each loop pass in line `9991`, ensuring per-line independence. ### Variable Summary | Variable | Purpose | | --- | --- | | `loc` | Current memory address of the start of the line being examined | | `total` | Accumulator for the per-line alternating checksum | | `linum` | Line number of the current line | | `length` | Byte length of the current line’s body | | `a` | Loop index over byte pairs within the line body | ## Source Code ``` 9988 REM LINE CHECK 9989 REM by John Bell 9990 LET loc=26710 9991 LET total=0: LET linum=PEEK loc*256+PEEK (loc+1) 9992 LET length=PEEK (loc+2)+PEEK (loc+3)*256 9993 FOR a=(loc+4) TO (loc+length+2) STEP 2 9994 LET total=total+PEEK (a)-PEEK (a+1) 9995 NEXT a 9996 LPRINT linum;TAB 6;total 9997 LET loc=loc+length+4 9998 IF linum=9999 THEN STOP 9999 GO TO 9991 ```