--- title: "VU-Calc" id: 51808 type: "computer_media" slug: "vu-calc" url: "http://localhost/computer_media/vu-calc/" markdown_url: "http://localhost/computer_media/vu-calc.md" published_at: "2023-08-13T23:14:33+00:00" modified_at: "2026-04-04T20:17:56+00:00" author: "David Anderson" featured_image: url: "http://localhost/wp-content/uploads/2019/02/20230809-041332.jpg" excerpt: "A full spreadsheet application packed into REM statement machine code, with a BASIC menu for entering, continuing, and saving your data to tape." 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: "Psion" slug: "psion" taxonomy: "post_tag" url: "http://localhost/tag/psion/" - name: "Sinclair Research Ltd." slug: "sinclair-research-ltd" taxonomy: "post_tag" url: "http://localhost/tag/sinclair-research-ltd/" - name: "Timex Computer Corporation" slug: "timex-computer-corporation" taxonomy: "post_tag" url: "http://localhost/tag/timex-computer-corporation/" - name: "TS 1000" slug: "ts1000" taxonomy: "post_tag" url: "http://localhost/tag/ts1000/" model: - name: "Timex/Sinclair 1000" slug: "ts-1000" taxonomy: "model" url: "http://localhost/model/ts-1000/" genre: - name: "Spreadsheet" slug: "spreadsheet" taxonomy: "genre" url: "http://localhost/type/spreadsheet/" media_type: "Cassette" download_url: "https://archive.org/download/timex-sinclair-software-archive/VU-Calc (1981)(Psion Software - Sinclair Research)(UK)(TS1000)(Cassette).zip" mediadate: "1981" producer_company: - id: 11401 title: "Timex Computer Corporation" type: "company" url: "http://localhost/company/timex-computer-corporation/" - id: 11292 title: "Sinclair Research Ltd." type: "company" url: "http://localhost/company/sinclair-research-ltd/" related_products: - id: 14545 title: "VU-CALC" type: "product" url: "http://localhost/product/vu-calc/" media_type_tags: "Spreadsheet" --- VU-Calc is a spreadsheet application that runs entirely in machine code, with the BASIC program serving primarily as a loader and menu system. The program stores a large machine code payload across REM statements in lines 1–13, which is then executed via USR calls at addresses in the 16000–19000 range. The menu system allows the user to enter the spreadsheet fresh (clearing memory with CLEAR and dimensioning a 9,825-byte string array B$ for data storage), continue a previously loaded session, or save the spreadsheet with or without data to tape. An error-handler routine at line 9000 uses PEEK calls on system variables 16601 and 16523 to report the current column and row when a calculation error occurs. *** ## Program Analysis ### Program Structure The program is divided into several logical sections: 1. **Lines 1–13:** REM statements containing the entire machine code payload for the spreadsheet engine. 2. **Lines 110–330:** Main menu — presents options E (Enter), C (Continue), S (Save with data), W (Save without data), and loops on invalid input. 3. **Lines 1000–1030:** “Enter” path — clears memory, allocates the data array, sets entry point address, and falls through to the execution dispatcher. 4. **Lines 2000–2010:** “Continue” path — sets a different entry point address and jumps to the dispatcher. 5. **Lines 3000–3050:** Save-with-data routine — prompts the user to ready the tape, then performs a `SAVE`. 6. **Lines 4000–4010:** Save-without-data path — calls `CLEAR` first, then jumps to the save routine. 7. **Lines 5000–5140:** Main execution dispatcher loop — calls machine code via `USR Z`, interprets the return value to decide whether to switch modes, trigger a screen copy, or exit. 8. **Lines 9000–9080:** Error handler — displays column/row context for a calculation error using PEEKed system variables, then relaunches the Continue path. 9. **Line 9990:** Emergency save line. ### Machine Code Payload in REM Statements Lines 1 through 13 contain dense Z80 machine code embedded in REM statements. This is a standard technique for storing executable binary data within a BASIC program. The code spans roughly 13 × ~120 bytes, giving approximately 1,500+ bytes of machine code. The dispatcher at line 5005 uses `USR Z` to call into this code at varying entry points, with `Z` set to different addresses depending on context. Key addresses referenced in the BASIC loader: | Address | Context | | --- | --- | | `16770` | Fresh-entry point (after `CLEAR`, “Enter” path) | | `16812` | Continue-session entry point | | `17334` | Main loop re-entry point (set after first USR call) | | `18929` | Called via `RAND USR` in FAST mode for initialisation | ### Data Storage via DIM B$ On the “Enter” path, line 1010 allocates `DIM B$(9825)` — a single string variable used as a flat byte array to hold the spreadsheet cell data. This is a classic technique for obtaining a contiguous block of RAM accessible both from BASIC and from machine code via a known address. Line 1015 uses `POKE 16606,0` to adjust a system variable (the RAMTOP or error pointer area) as part of the initialisation. ### Execution Dispatcher Loop (Lines 5000–5140) The loop at line 5005 calls `USR Z` and examines the integer return value `I`: - `I = 63479` — triggers a mode switch: enters FAST mode, calls `RAND USR 18929` for reinitialisation, then returns to SLOW mode and re-enters the loop. - `I = 0` — exits to the main menu (line 110). - `I = 255` — triggers a `COPY` (screen print to ZX Printer). - Any other value — updates `Z` to `17334` and continues looping. Line 5000 uses the idiom `LET B$(1 TO 1)=B$(1 TO 1)` to force BASIC to verify that the array exists and is accessible before jumping into machine code; this will raise an error gracefully if the array has not been dimensioned (i.e., if “Continue” is chosen without prior data in memory). ### Error Handler (Lines 9000–9080) The error handler at line 9000 reads two system variables to report where a calculation error occurred: - `PEEK 16601` — holds the current column number (0-based); line 9015 adds 1 for display, and line 9020 converts it to two display characters using `CHR$` arithmetic with offset 28 (the ZX81 character code for digit “0” minus zero). - `PEEK 16523` — holds the current row, displayed similarly with offset 38. After user acknowledgement, line 9080 jumps back to the “Continue” path, allowing the session to be resumed. ### Save Mechanism The `SAVE "VU-CALC"` on line 3040 saves the entire BASIC program including the REM-embedded machine code and the populated `B$` array, effectively checkpointing the spreadsheet state to tape. The save-without-data path (line 4000) calls `CLEAR` first, which collapses the variable area and removes `B$`, saving only the program code. ### Notable Techniques and Idioms - Using `RAND USR` (line 5110) rather than plain `USR` in an expression discards the return value, suitable for a call that does not need to report back to BASIC. - The inverse-video characters in PRINT statements (e.g., `%E%N%T%E%R`) are used throughout to create highlighted labels on the menu and status screens. - `VAL "number"` is not used here; all `GO TO` targets are literal line numbers. - The `FOR I=0 TO 60 / NEXT I` delay loop at lines 310–320 provides a brief pause to display the “INVALID” error message before clearing and re-prompting. ## Source Code ``` 1 REM 00000975479511A56571D521C1D1C1E1C1F1C201C211C221C231C241C251D1C1D1D1D1E1D1F1D201D211D221D231D241D251E1C1E1D1E1E1E1F1E201E211E221E231E241E251F1C1F1D1F1E1F1F1F201F211F22FF08A7F75300303099795F416011E7BE7B1D301930303030303030303030303030303030303030907F750A2750C5750E8750B7602E760517607476097760BA760DD76007702377046770697708C770AF770D2770F5770187803B7805E78081780A4780C7780EA780D7903079053790767909979030303030303030303030303030303030303030303030303030303030 2 REM 218240AF7723772377237723772A1040160ED4A2287402AC40232289402A87401E820ED4A22DB403E831EA14202A8940912209161F772315C2BD41231DC2BA412A894018F093E51E9771A0977138091DC2D34100CD824CCD1942CD4542CDC542C3B6432A8940184091E93A8440C62616577237211E091685723C123091DC2042C9342C92A8940147090EB219040603A85404F909063EB1A7723131A7713C519090C15C23242C93A8440CD824B3E9CD824BEF434CDB44B2A874090E53A8540CD824B3EEACD824BEF434CDB44BE19023228C402A8940C382423030 3 REM 186090228E4063E9ED5B8E402A8C40C5180EDB023EB13A090EBC1DC29542C52A8E401A090228E402A8C401EA090228C40C15C28C42C93A8240CD824B3E42CD824BEF434C35C4C2A894090E53A8340CD824B3EACD824BEF434CDB44BE1901650903ADA401E877231DC2FA42CD66433ADA40FE83C8CD32437EFEFFC8FE0C8604F2104199905E23562A89401D6290C3BD4600000003E9CD824B3A8440CD824B3A8240CD824BEFF4343EEACD824B3A8540CD824B3A8340CD824BEFF4F34CDB44B2A874090C92A89401D62903E01620772315C27243C9303030 4 REM CDBB2444D5114CA8243CDBD77EC92A89403E801620772315C29843C9CD9143E1EB2A89401AFEFFCAB343772313C3A74313D5C9CD9F43AB94ABB4B7B2BAB1A68080B194A9A6B9A68080A894A8A6B1A8BAB1A6B9AA80FFCD8243FE23CA6544FE24CAFD44FE22CA9A44FE21CACE44FE2DCA4944FE31CA1A45FE28C800FE2CCA1949FE38CA8A49FE36CA4144FE35CA4544C3204CD445CD9F43AEB3BBA6B1AEA996B4B5B9AEB4B3FF640CD3244C3B643210102B7DFE0C235445C23244C9100C91FF0C9CDC744AF77237723772377C3E3413E8332DA40CDC5423E8A32DA40C93A8240FE0CA8244F5CD5744F13D328240CDC542C3B744 5 REM 3A8440FE0CAD9433D328440CDF241CD4542CD043C3BF443A8240FE8CAAB44F5CD5744F13CC373443A8440FE11CAD9433CC38B446ACD3244C3D9436ACD3244C3D943CD5744218240C93A8340FE0CAE544F5CD5744F13D328340CDC542C3B7443A8540FE0CAD9433D328540CD1942CD4542CD043C3BF443A8340FE2CAE45F5CD5744F13CC3DC443A8540FE21CAD9433CC3EE44CD9F43B1B4A6A980A9A6B9A6809880B9AEB9B1AAB880FFC34C4CE53A8240CD824B3E42CD824BEF4343E44CD824B3A8340CD824B3EACD824BEF4FF34C36A4C2A89409D113D5E53E068771223135C26745E1D1E0C3C545620C3824530 6 REM CD3244CD8243E1D1C1FE0CA9A45FE76CACE45FE77CAAD45FE40D2C54577122313C79FE8CABD45C3C54579FE0CAC5453E0772B1BD12C3C545634CD3244C3B6433E877C5D5E5C376453E077C3BD453A8640FE28C2046CD9F43B4B3B1BE80A09C80ABB4B7B2BAB1A6AA80A6B1B1B4BCAAA9FF632CD3244C3B6433C3286403D2ADB40FE0CA1546123093DC2104622E140CD9F43AAB3B9AAB780ABB4B7B2BAB1A6FF2AE140EB2A89401D62C3AE463E877C5D5E5620CD3244CD8243E1D1C1FE0CA5646FE76CA8246FE77CA6946FE40D2364677122313C79FE20CA8546C3364679FE0CA36463E0772B1BD12C33646303030 7 REM 3E0773A86404F60C3F54B21041999ED5BE1407B77237A77233E07722E340CD32433A864077C33647C5D5E5CD6643E1D1C19E0C336461AFEFFC8FE40D2CC46772313C3BD46131AE5D5473A84404F3A8240573E26808182D1E1CD2B47E5D51A473A85404F3A83408081F5160D6ADAFC4614C3F34642F115FA94714D6A15C23474F78D1E100CD1C477900CD1C4713C3BD460FE40DA24473E64473E1C807723C9FE40DA32473E80772313C9620CD3244CD9F4390B791AAB1A6B9AEBBAA80B4B78090A691A7B8B4B1BAB9AAFFCD8243FE26CAE947FE37CA8247CD9F43AEB3BBA6B1AEA9809680B4B5B9AEB4B3FFC3364730 8 REM 2AE1407EFEFFC304C23C38547F5C6807723CDB447CDD1473A8B4047F190D6267723CDDD473AD940473AE540907723C38547E57ED61C47FE0CAC747EAAF80DC2C14747237ED61C8032E540E1C93A8440473A824080328B40C93A8540473A83408032D940C9620CD3244CD9F43B2B4BBAA80A7BE8090B791B4BC8090A891B4B1BAB2B380B4B78090AA91BDAEB9FFCD8243FE28CA3B48FE37CA4D48FE2ACA149CD9F43AEB3BBA6B1AEA9809680B4B5B9AEB4B3FFC3E947CD9F43B9B480A8B4B18FFF1EEAE3C35C48CD9F43B9B480B7B4BC8FFF1E9E2D5C5CD6643C1E12A89401D62C38248CAE947FE26D28F47C38B473030303030 9 REM 9E5D5C53E877620CD3244CD8243C1D1E1FE77CA5C48FE76CAA948FE40D283487723DC283482A89401D6297BFEEACACB487ED626DAE947FE1AD2E94732E540CDD1474FC3DF48CDB4473AE5403D32E5400FE24D2E947CDDD474F3AE540B9CA149DA14947160D5C5CD3243C1D1193A864077C79B8C2F348C3149CD0433AE640FE0CABD453AE740328640AF32E640C3BD45620CD3244CD9F4390B291A6B0AA80A8BAB7B7AAB3B980B4B78090A891ADA6B3ACAAFFCD8243FE32CA6049FE28CA6A49CD9F43AEB3BBA6B1AEA9809680B4B5B9AEB4B3FFC31949CD32437E32DE40C3BD453A864032E7403E132E640CD3243C3824930 10 REM 7EC3CA4900003ADE40FE0C2AB49CD9F43B3B480A8BAB7B7AAB3B980ABB4B7B2BAB1A6FFC3BD45CD32433ADE4077CD9F43ABB4B7B2BAB1A680B1B4A6A9AAA9FFCD043C3BD45FE0C2EA49CD9F43B3B480ABB4B7B2BAB1A680B9B480A8ADA6B3ACAAFFC3BD453D328640C3D4452A8740228C40228E40AF32D940328B402A8E407EFE0C2434A1EA02A8E409228E403AD9403C32D940FE24C214A1902A8C409228C40228E40AF32D9403A8B403C328B40FE1AC214ACD4542640C94F60210419995E23562A1A4022E8402A1C4022EA401001AFEFFCA824AFE26D2E24A772331332EC40C35E4A303030303030303030 11 REM 3E7677233AEC4077221A4023E52AEA40EBE17323722371237023221C40EF1A2A342A8E4023E52A1C402B462B4E2B562B5E79FE9DABD4A60E8EBD1C5EDB02AEA40221C402AE840221A402A8E40C192379FE8CAA4A3E07723CC3D44AFE80D2FB4AD62632EE40E5EB23C5CDB447EBC1E11313C35F4B131AC5473A8B4000000800032EE40131A473AD940000080032E540C113C35F4B2A87403AEE40FE0CA354B19057915C2304B3AE540FE0CA464B1EA057915C2414BD123180EDB0E11809E5C1EBD12B7E32EC4023C35E4A3AE5403D32E540D5C5E5C3214B30303030303030303030303030303030 12 REM E5D5C568FE0CAAF4BA7517D28C4B4A71F4F78C6802A1C4077792377AF23772377237723221C40C1D1E1C9AF4FC3994BE5D502A1C4011FBFF19E57EFE0CADF4BD680473E1090572346234EC3E54B0000E1221C400D1E1C9100C3D74B78F68047A7CB18CB1915C2E94BC3D74B3EFF1213121312C38E4630CAE947FEDCA104CFE26D28F47C38B473E07723C38B47303030303030303030FE2BCAD445FE29CA2D4CC31844CD32433E077CD9F43ABB4B7B2BAB1A680A9AAB1AAB9AAA9FFCD6643C32A44CD32433E077E5CD6643E1C334453030CDB44BC5E114209E5C1C3D642CDB44BC5E114209E5C1C35B4530303030 13 REM 2A89401A6091E93E82771A097797793E8177124091DC28B4CCDF241C93030303030303030303030303030303030303030303030303030303030 110 SLOW 120 CLS 130 PRINT " V U - C A L C" 132 PRINT 133 PRINT 134 PRINT 140 PRINT 150 PRINT "%E%N%T%E%R E : TO ENTER VU-CALC" 160 PRINT 170 PRINT " C : TO CONTINUE VU-CALC" 180 PRINT 190 PRINT " S : TO SAVE WITH DATA" 200 PRINT 210 PRINT " W : TO SAVE WITHOUT DATA" 240 PRINT AT 21,0;"%O%P%T%I%O%N%?" 250 INPUT O$ 260 IF O$="E" THEN GOTO 1000 270 IF O$="C" THEN GOTO 2000 280 IF O$="S" THEN GOTO 3000 290 IF O$="W" THEN GOTO 4000 300 PRINT AT 21,0;"%I%N%V%A%L%I%D" 310 FOR I=0 TO 60 320 NEXT I 330 GOTO 240 1000 CLEAR 1010 DIM B$(9825) 1015 POKE 16606,0 1020 LET Z=16770 1030 GOTO 5000 2000 LET Z=16812 2010 GOTO 5000 3000 CLS 3005 PRINT "%P%U%T% %T%A%P%E% %O%N% %R%E%C%O%R%D" 3010 PRINT 3020 PRINT "%T%H%E%N% %P%R%E%S%S% %N%E%W%L%I%N%E" 3030 INPUT O$ 3040 SAVE "VU-CAL%C" 3050 GOTO 110 4000 CLEAR 4010 GOTO 3000 5000 LET B$(1 TO 1)=B$(1 TO 1) 5002 CLS 5005 LET I=USR Z 5010 IF I=63479 THEN GOTO 5100 5020 IF I=0 THEN GOTO 110 5030 IF I=255 THEN COPY 5040 LET Z=17334 5050 GOTO 5005 5100 FAST 5110 RAND USR 18929 5120 LET Z=17334 5130 SLOW 5140 GOTO 5005 9000 CLS 9002 SLOW 9005 PRINT "%E%R%R%O%R% %W%H%I%L%E% %C%A%L%C%U%L%A%T%I%N%G" 9010 PRINT 9015 LET A=PEEK (16601)+1 9020 PRINT "%C%O%L ";CHR$ (INT (A/10)+28);CHR$ (A-INT (A/10)*10+28) 9030 PRINT 9040 PRINT "%R%O%W ";CHR$ (PEEK 16523+38) 9050 PRINT 9060 PRINT "%P%R%E%S%S% %N%E%W%L%I%N%E% %T%O% %C%O%N%T%I%N%U%E" 9070 INPUT O$ 9080 GOTO 2000 9990 SAVE "VU-CAL%C" ```