--- title: "Tychk" id: 53876 type: "computer_media" slug: "tychk" url: "http://localhost/computer_media/tychk/" markdown_url: "http://localhost/computer_media/tychk.md" published_at: "2024-05-13T19:05:04+00:00" modified_at: "2026-03-30T21:46:07+00:00" author: "David Anderson" featured_image: url: "http://localhost/wp-content/uploads/2019/02/20230809-041332.jpg" excerpt: "A memory-walking diagnostic tool that reports every BASIC line's number, byte length, and alternating-weight checksum — all printed to screen and printer simultaneously." 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/" genre: - name: "Utility" slug: "utility" taxonomy: "genre" url: "http://localhost/type/utility/" media_contents: - id: 55396 title: "SINCUS Exchange Tape 103 – Potpourri" type: "computer_media" url: "http://localhost/computer_media/sincus-exchange-tape-103-potpourri/" media_type: "Program" mediadate: "198x" images: - url: "http://localhost/wp-content/uploads/2024/05/SCR-20240623-fdll.png" media_type_tags: "Utility" --- # Tychk This program walks the BASIC program area in memory to produce a line-by-line report of each line number, its byte length, and a weighted checksum of its contents. It uses system variables at addresses 23635–23636 (PROG, the start of the BASIC program) and 23627–23628 (VARS, marking the end) to determine the memory range to scan. For each line it reads the two-byte line number and two-byte length field directly with PEEK, then iterates over the line’s bytes computing an alternating-weight checksum where even-positioned bytes are doubled. Results are sent simultaneously to the screen via PRINT and to a printer via LPRINT. *** ## Program Analysis ### Program Structure The program occupies lines 9987–9999, placing it at the very top of the line-number space so it can analyze whatever program precedes it in memory without disturbing its own working. The REM lines at 9987–9990 serve as a self-documenting header listing the variables and I/O channels used. Execution begins at line 9991 and follows a simple sequential flow with a single backward `GO TO 9992` loop. ### Memory Layout Traversal The scanner uses two well-known system variable pairs to bracket the BASIC program area: - **PROG** (23635–23636): two-byte address of the first byte of the BASIC program, used to initialize `byt`. - **VARS** (23627–23628): two-byte address of the variables area, which immediately follows the last BASIC line, used as the stop sentinel. Each BASIC line in memory has the standard four-byte header: two bytes of line number (high byte first) followed by two bytes of line length (low byte first, little-endian). The code at line 9993 reads the line number as `256*PEEK byt + PEEK (byt+1)` (big-endian), and line 9994 reads the length as `256*PEEK (byt+1) + PEEK byt` (little-endian), correctly reflecting the ZX Spectrum BASIC file format. ### Checksum Algorithm Line 9995 computes a weighted sum over the line’s payload bytes. The variable `odd` alternates between 1 and 0 using `NOT odd`, and the contribution of each byte is `(odd+1) * PEEK byt`. This means: - Odd-positioned bytes (1st, 3rd, …) contribute with weight `2` (since `odd=1`, `odd+1=2`). - Even-positioned bytes (2nd, 4th, …) contribute with weight `1` (since `odd=0`, `odd+1=1`). This alternating-weight scheme is reminiscent of modular checksum designs used to detect transposition errors, though it is a custom rather than standard algorithm. ### Output Line 9996 prints each record to the screen and line 9997 sends an identical record to the printer using `LPRINT`. The `TAB` calls at columns 6 and 13 create a fixed-width columnar layout: line number, a colon separator, byte length, another colon, and the checksum. ### Loop Control After processing a line, line 9998 checks whether `byt` has reached or passed `stop` (the VARS pointer). If more lines remain, control returns to 9992 to read the next line header. The loop terminates naturally at line 9999 with `STOP`. ### Variable Summary | Variable | Role | | --- | --- | | `start` | Address of first byte of BASIC program (PROG system variable) | | `stop` | Address of first byte of VARS area (end sentinel) | | `byt` | Current memory pointer, advances through program bytes | | `line` | Current BASIC line number decoded from header | | `length` | Byte count of current line’s payload | | `sum` | Accumulated weighted checksum for current line | | `odd` | Alternating flag (1/0) controlling byte weight | | `i` | `FOR` loop counter over line bytes | ### Anomalies and Notes The variable `sum` is initialized once at line 9992 but is never reset between lines — it accumulates across all lines rather than resetting per line. This means the printed `sum` column is a running total, not a per-line checksum, which may or may not be the intended behavior. Similarly, `start` is computed but only used to set `byt`; because `byt` begins at `start`, the value of `start` itself is not needed afterward. Because this program resides at lines 9987–9999, it will include its own lines in the scan output when run standalone, which is an unavoidable self-referential side-effect of the design. ## Source Code ``` 9987 REM ! LIST 9988 REM ! LPRINT 9989 REM !INT +START,STOP,BYT,LINE,LENGTH,SUM,ODD,I 9990 REM ! OPEN # 9991 LET start=256*PEEK 23636+PEEK 23635: LET stop=256*PEEK 23628+PEEK 23627: LET byt=start 9992 LET line=0: LET length=0: LET sum=0 9993 LET line=256*PEEK byt+PEEK (byt+1): LET byt=byt+2 9994 LET length=256*PEEK (byt+1)+PEEK byt: LET byt=byt+2 9995 LET odd=1: FOR i=1 TO length: LET sum=sum+(odd+1)*PEEK byt: LET odd=NOT odd: LET byt=byt+1: NEXT i 9996 PRINT line;TAB 6;": ";length;TAB 13;": ";sum 9997 LPRINT line;TAB 6;": ";length;TAB 13;": ";sum 9998 IF byt