Just Another Spreadsheet!

This file is part of Byte Power February 1987 . Download the collection to get this file.
Developer(s): Kristian Boisvert
Date: 1987
Type: Program
Platform(s): TS 2068

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

AddressLengthPurpose
29000≤900 bytesPrint driver (loaded separately, not in this listing)
2997615864 bytesMain spreadsheet engine
449525 bytes patchedResult-injection point (line 20 POKE loop)
4584018654 bytesSpreadsheet data/workspace (SAVEd as user file)
64494920 bytesSmall auxiliary code block
655351 byteDispatch 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.

Content

Appears On

Tape-based magazine.

Related Products

Related Articles

This little goodie will let you create formulas with all mathematical functions found on the TS2068 + 2 special functions,...

Related Content

Image Gallery

Just Another Spreadsheet!

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

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

Scroll to Top