--- title: "Just Another Spreadsheet!" id: 63194 type: "computer_media" slug: "just-another-spreadsheet" url: "http://localhost/computer_media/just-another-spreadsheet/" markdown_url: "http://localhost/computer_media/just-another-spreadsheet.md" published_at: "2026-01-30T21:13:39+00:00" modified_at: "2026-04-03T07:57:56+00:00" author: "David Anderson" featured_image: url: "http://localhost/wp-content/uploads/2026/01/just-spreadsheet-1.png" excerpt: "A machine-code spreadsheet with a BASIC shell that uses PEEK 65535 as a jump table to hand control back to its own engine after every operation." 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: "Kristian Boisvert" slug: "boisvert-kristian" taxonomy: "indiv" url: "http://localhost/indiv/boisvert-kristian/" genre: - name: "Finance" slug: "finance" taxonomy: "genre" url: "http://localhost/type/finance/" - name: "Spreadsheet" slug: "spreadsheet" taxonomy: "genre" url: "http://localhost/type/spreadsheet/" media_contents: - id: 63048 title: "Byte Power February 1987" type: "computer_media" url: "http://localhost/computer_media/byte-power-february-1987/" media_type: "Program" programmers: - name: "Kristian Boisvert" slug: "boisvert-kristian" taxonomy: "indiv" url: "http://localhost/indiv/boisvert-kristian/" mediadate: "1987" producer_company: - id: 25181 title: "Byte Power" type: "company" url: "http://localhost/company/byte-power/" images: - url: "http://localhost/wp-content/uploads/2026/01/just-spreadsheet-1.png" - url: "http://localhost/wp-content/uploads/2026/01/just-spreadsheet-2.png" article_media: - id: 63081 title: "Just Another Spreadsheet" type: "article" url: "http://localhost/article/just-another-spreadsheet/" media_type_tags: "Finance, Spreadsheet" --- # Just Another Spreadsheet! This program implements a spreadsheet application, written by Kristian Boisvert and published by Byte Power in 1987. The BASIC loader shell manages screen setup, file I/O (SAVE/LOAD of a CODE block at address 45840), and error handling for cell formula evaluation, while the bulk of the spreadsheet logic resides in machine code loaded separately. The program uses PEEK 65535 as a dynamic dispatch mechanism—jumping to whatever address is stored at the top of the 64KB address space—to hand control back to the machine code engine after each BASIC operation. Three separate CODE blocks are saved to tape: a print driver expected at address 29000 (up to 900 bytes), a main engine block at 29976 (15864 bytes), and a small block at 64494 (920 bytes). *** ## Program Structure The listing is purely a BASIC shell; the real spreadsheet logic lives in machine code loaded from tape. The program divides into clearly labelled sections: 1. **Lines 6–8:** Initialisation — sets ink/paper/border, clears memory to 28999, dimensions a work string, then immediately dispatches to machine code via `GO TO PEEK 65535`. 2. **Lines 9–20:** Formula calculation stub — evaluates `VAL a$` (the cell formula) inside an `ON ERR` guard, then patches five bytes of machine code with the result and returns control to the engine. 3. **Lines 100–110:** Quit — calls `USR 0` to force a hard reset. 4. **Lines 200–270:** File I/O — SAVE and LOAD of the spreadsheet data as a CODE block (45840, length 18654). 5. **Lines 7000–7020:** Error handler — prints a formatted error message including the offending cell address read from system variables, beeps, and waits for a keypress. 6. **Lines 8000–8020:** File-name input subroutine with a 10-character length check. 7. **Lines 9000–9020:** Splash screen and tape loader — loads two CODE blocks, optionally auto-runs. 8. **Line 9999:** Master SAVE — saves the BASIC program, then the two CODE blobs, then verifies all three. ## Dynamic Dispatch via PEEK 65535 The most striking idiom is the repeated use of `GO TO PEEK VAL "65535"` (lines 8, 20, 270, 7020). Because `GO TO` expects a line number, the machine code engine stores the target BASIC line number as a single byte at address 65535 (the last byte of the 64 KB address space). This gives the engine a lightweight, one-byte callback mechanism: it sets the byte and then triggers the appropriate BASIC line by falling through to a `GO TO`. Known targets visible in the listing are line 270 (redraw/continue) and whatever value is set for lines 8 and 20. ## Machine Code Integration | Address | Length | Purpose | | --- | --- | --- | | 29000 | ≤900 bytes | Print driver (loaded separately, not in this listing) | | 29976 | 15864 bytes | Main spreadsheet engine | | 44952 | 5 bytes patched | Result-injection point (line 20 POKE loop) | | 45840 | 18654 bytes | Spreadsheet data/workspace (SAVEd as user file) | | 64494 | 920 bytes | Small auxiliary code block | | 65535 | 1 byte | Dispatch register (target BASIC line number) | Line 20 uses `PEEK 23627` and `PEEK 23628` to read the system variable STKEND (the top of the calculator stack), offset by 262, to locate the floating-point result of `VAL a$`. It then copies five bytes (the standard five-byte float format) into address 44952, injecting the computed value directly into machine code data. ## Formula Evaluation Technique Cell formulas are evaluated entirely through BASIC’s own expression evaluator. The machine code places the formula text into `a$` (dimensioned to 255 characters at line 6), then triggers line 10 which executes `LET e=VAL a$`. This piggybacks on the built-in floating-point parser at zero implementation cost in the machine code. The `ON ERR GO TO 7010` guard on line 10 catches any syntax or arithmetic error in the formula. ## Error Reporting The error handler at line 7010 decodes the offending cell address from two dedicated memory locations: - `PEEK 65533` — column index (offset by 1 and 64 to produce a letter via `CHR$`) - `PEEK 65534` — row number, with a leading zero suppressed by the `("0" AND …<10)` conditional string trick The expression `CHR$ VAL "((PEEK 65533)+1+64)"` converts a 0-based column index to a letter (A=65 in ASCII). The row display uses the classic Sinclair idiom of multiplying a string by a boolean: `("0" AND condition)` yields `"0"` when the condition is true, or `""` when false. ## Loader and Auto-Boot Line 9006 loads two anonymous CODE blocks in sequence with `LOAD ""CODE`. Line 9010 checks `PEEK 23681` (system variable FLAGS2, specifically the printer-buffer flag area) for zero; if zero it lists line 9999 and stops, presumably a development/save mode. Otherwise line 9020 runs the program normally. The `PRINT AT 0,0;` at line 7 before `LET l=VAL "USR 29976"` is used to set the print position before calling the machine code, which likely uses it as a signal. ## Key BASIC Idioms - `VAL "number"` used pervasively for all numeric literals — a token-saving technique that stores the number as a short string rather than a five-byte float in the BASIC line. - `ON ERR GO TO` / `ON ERR RESET` — TS2068 extended error-trapping keyword (rendered as `{` in zmakebas source). - `PRINT #0;` in line 7010 directs output to stream 0 (the lower screen/editor area) for the error message. - `GO SUB VAL "8000"` for the filename input subroutine, consistent with the VAL idiom throughout. ## Source Code ``` 0 REM SPREADSHEET WRITTEN BY KRISTIAN BOISVERT ©1987 BYTE POWER 2 REM PRINT DRIVER SHOULD BE AT 29000 AND SHOULDN'T BE MORE THAN 900 BYTES LONG!!! 6 INK VAL "0": PAPER VAL "7": BORDER VAL "7": CLEAR VAL "28999": DIM a$(VAL "255"): LET E=VAL "0" 7 PRINT AT VAL "0",VAL "0";: LET l=VAL "USR 29976" 8 GO TO PEEK VAL "65535" 9 REM CALCULATE---DON'T MESS WITH THIS PART!!! 10 ON ERR GO TO VAL "7010": LET e=VAL a$ 20 ON ERR RESET : LET A=VAL "PEEK 23627+256*PEEK 23628+262": FOR F=VAL "0" TO VAL "4": POKE F+VAL "45902",PEEK (A+F): NEXT F: PRINT AT VAL "0",VAL "0";: LET A$="": LET L=USR VAL "44952": GO TO PEEK VAL "65535" 100 REM QUIT PROGRAM 110 PRINT USR 0 200 REM SAVE FILE 210 GO SUB VAL "8000": IF B$="" THEN GO TO VAL "210" 220 SAVE B$CODE VAL "45840",VAL "18654" 230 PRINT AT VAL "20",VAL "0";"REWIND TO VERIFY ";B$: VERIFY B$CODE 240 GO TO VAL "270" 250 REM LOAD FILE 255 GO SUB VAL "8000" 260 LOAD B$CODE VAL "45840" 270 PRINT AT VAL "0",VAL "0";: LET L=VAL "USR 38619": GO TO PEEK VAL "65535" 7000 REM ON ERROR IN FORMULA 7010 PRINT #VAL "0";AT VAL "0",VAL "0";TAB VAL "7";"ERROR IN CELL "; FLASH VAL "1";CHR$ VAL "((PEEK 65533)+1+64)";("0" AND VAL "PEEK 65534<10");PEEK VAL "65534" 7020 ON ERR RESET : BEEP VAL ".5",VAL "20": PAUSE VAL "0": PRINT AT VAL "0",VAL "0";: GO TO VAL "270" 8000 REM GET STRING 8010 INPUT "FILE NAME:"; LINE B$: IF LEN B$>VAL "10" THEN GO TO VAL "8010" 8020 RETURN 9000 CLS : PRINT AT VAL "8",VAL "3";"JUST ANOTHER SPREADSHEET!";AT VAL "10",VAL "8";"©1987 BYTE POWER";AT VAL "12",VAL "2";"WRITTEN BY KRISTIAN BOISVERT" 9005 PRINT AT VAL "20",VAL "0";"STILL LOADING..." 9006 INK VAL "7": PRINT AT VAL "15",VAL "0";: LOAD ""CODE : PRINT AT VAL "15",VAL "0";: LOAD ""CODE 9010 INK VAL "0": PRINT AT VAL "20",VAL "0";TAB VAL "31";" ": IF VAL "PEEK 23681=0" THEN PRINT AT VAL "15",VAL "0";: LIST VAL "9999": STOP 9020 RUN 9999 SAVE "SHEET" LINE VAL "9000": SAVE "SHEET"CODE VAL "29976",VAL "15864": SAVE "SHEET"CODE VAL "64494",VAL "920": VERIFY "SHEET": VERIFY "SHEET"CODE : VERIFY "SHEET"CODE ```