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:
- Lines 1–13: REM statements containing the entire machine code payload for the spreadsheet engine.
- Lines 110–330: Main menu — presents options E (Enter), C (Continue), S (Save with data), W (Save without data), and loops on invalid input.
- Lines 1000–1030: “Enter” path — clears memory, allocates the data array, sets entry point address, and falls through to the execution dispatcher.
- Lines 2000–2010: “Continue” path — sets a different entry point address and jumps to the dispatcher.
- Lines 3000–3050: Save-with-data routine — prompts the user to ready the tape, then performs a
SAVE. - Lines 4000–4010: Save-without-data path — calls
CLEARfirst, then jumps to the save routine. - 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. - Lines 9000–9080: Error handler — displays column/row context for a calculation error using PEEKed system variables, then relaunches the Continue path.
- 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, callsRAND USR 18929for reinitialisation, then returns to SLOW mode and re-enters the loop.I = 0— exits to the main menu (line 110).I = 255— triggers aCOPY(screen print to ZX Printer).- Any other value — updates
Zto17334and 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 usingCHR$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 plainUSRin 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; allGO TOtargets are literal line numbers.- The
FOR I=0 TO 60 / NEXT Idelay loop at lines 310–320 provides a brief pause to display the “INVALID” error message before clearing and re-prompting.
Content
Image Gallery
Source Code
1 REM 0 0 0 0 0975479511A56571D521C1D1C1E1C1F1C201C211C221C231C241C251D1C1D1D1D1E1D1F1D201D211D221D231D241D251E1C1E1D1E1E1E1F1E201E211E221E231E241E251F1C1F1D1F1E1F1F1F201F211F22FF 08A7F7530 0303099795F41 6 011 E7B E7B1D301930303030303030303030303030303030303030907F75 0A275 0C575 0E875 0 B76 02E76 05176 07476 09776 0BA76 0DD76 0 077 02377 04677 06977 08C77 0AF77 0D277 0F577 01878 03B78 05E78 08178 0A478 0C778 0EA78 0 D79 03079 05379 07679 09979 030303030303030303030303030303030303030303030303030303030
2 REM 218240AF7723772377237723772A1040 1 6 0ED4A2287402A C40232289402A8740 1E820ED4A22DB403E831E A 142 02A8940 9 122 0 9161F772315C2BD41231DC2BA412A8940 18F 0 93E 51E 977 1 A 0 977 138 0 91DC2D341 0 0CD824CCD1942CD4542CDC542C3B6432A8940 184 0 91E 93A8440C62616 5772372 11E 0 91685723C 123 0 91DC2 042C9 342C92A8940 147 0 9 0EB219040 6 03A85404F 9 0 9 0 6 3EB1A7723131A7713C5 1 9 0 9 0C1 5C23242C93A8440CD824B3E 9CD824BEF 434CDB44B2A8740 9 0E53A8540CD824B3EEACD824BEF 434CDB44BE1 9 023228C402A8940C382423030
3 REM 186 0 9 0228E40 6 3 E 9ED5B8E402A8C40C5 1 8 0EDB023EB 13A 0 9 0EBC1 DC29542C52A8E40 1 A 0 9 0228E402A8C40 1EA 0 9 0228C40C1 5C28C42C93A8240CD824B3E42CD824BEF 434C35C4C2A8940 9 0E53A8340CD824B3E ACD824BEF 434CDB44BE1 9 0 165 0 9 03ADA401E 877231DC2FA42CD66433ADA40FE83C8CD32437EFEFFC8FE 0C8 6 04F21 041 9 9 9 05E23562A8940 1D6 2 9 0C3BD46 0 0 0 0 0 0 03E 9CD824B3A8440CD824B3A8240CD824BEF F 4343EEACD824B3A8540CD824B3A8340CD824BEF F 4 F34CDB44B2A8740 9 0C92A8940 1D6 2 9 03E 01620772315C27243C9303030
4 REM CDBB 2444D5114CA8243CDBD 77EC92A89403E801620772315C29843C9CD9143E1EB2A89401AFEFFCAB343772313C3A74313D5C9CD9F43AB94ABB4B7B2BAB1A68080B194A9A6B9A68080A894A8A6B1A8BAB1A6B9AA80FFCD8243FE23CA6544FE24CAFD44FE22CA9A44FE21CACE44FE2DCA4944FE31CA1A45FE28C8 0 0FE2CCA1949FE38CA8A49FE36CA4144FE35CA4544C3204CD445CD9F43AEB3BBA6B1AEA996B4B5B9AEB4B3FF 640CD3244C3B64321 0102B7DFE 0C23544 5C23244C9 1 0 0C9 1FF 0C9CDC744AF77237723772377C3E3413E8332DA40CDC5423E8A32DA40C93A8240FE 0CA8244F5CD5744F13D328240CDC542C3B744
5 REM 3A8440FE 0CAD9433D328440CDF241CD4542CD 043C3BF443A8240FE 8CAAB44F5CD5744F13CC373443A8440FE11CAD9433CC38B44 6 ACD3244C3D943 6 ACD3244C3D943CD5744218240C93A8340FE 0CAE544F5CD5744F13D328340CDC542C3B7443A8540FE 0CAD9433D328540CD1942CD4542CD 043C3BF443A8340FE 2CA E45F5CD5744F13CC3DC443A8540FE21CAD9433CC3EE44CD9F43B1B4A6A980A9A6B9A6809880B9AEB9B1AAB880FFC34C4CE53A8240CD824B3E42CD824BEF 4343E44CD824B3A8340CD824B3E ACD824BEF 4 F F34C36A4C2A8940 9D113D5E53E 0 6 877122313 5C26745E1D1 E 0C3C545 620C3824530
6 REM CD3244CD8243E1D1C1FE 0CA9A45FE76CACE45FE77CAAD45FE40D2C54577122313 C79FE 8CABD45C3C54579FE 0CAC5453E 0772B1B D12C3C545 634CD3244C3B6433E 877C5D5E5C376453E 077C3BD453A8640FE28C2 046CD9F43B4B3B1BE80A09C80ABB4B7B2BAB1A6AA80A6B1B1B4BCAAA9FF 632CD3244C3B6433C3286403D2ADB40FE 0CA1546 123 0 93DC2104622E140CD9F43AAB3B9AAB780ABB4B7B2BAB1A6FF2AE140EB2A8940 1D6 2C3AE463E 877C5D5E5 620CD3244CD8243E1D1C1FE 0CA5646FE76CA8246FE77CA6946FE40D2364677122313 C79FE20CA8546C3364679FE 0CA36463E 0772B1B D12C33646303030
7 REM 3E 0773A86404F 6 0C3F54B21 041 9 9 9ED5BE1407B77237A77233E 07722E340CD32433A864077C33647C5D5E5CD6643E1D1C1 9 E 0C336461AFEFFC8FE40D2CC46772313C3BD46131AE5D5473A84404F3A8240573E26808182D1E1CD2B47E5D51A473A85404F3A83408081F516 0D6 ADAFC4614C3F34642F115FA 94714D6 A15C2 3474F78D1E1 0 0CD1C4779 0 0CD1C4713C3BD46 0FE40DA24473E64473E1C807723C9FE40DA32473E80772313C9 620CD3244CD9F4390B791AAB1A6B9AEBBAA80B4B78090A691A7B8B4B1BAB9AAFFCD8243FE26CAE947FE37CA8247CD9F43AEB3BBA6B1AEA9809680B4B5B9AEB4B3FFC3364730
8 REM 2AE1407EFEFFC3 04C23C38547F5C6807723CDB447CDD1473A8B4047F190D6267723CDDD473AD940473AE540907723C38547E57ED61C47FE 0CAC747 E AAF80 DC2C14747237ED61C8032E540E1C93A8440473A824080328B40C93A8540473A83408032D940C9 620CD3244CD9F43B2B4BBAA80A7BE8090B791B4BC8090A891B4B1BAB2B380B4B78090AA91BDAEB9FFCD8243FE28CA3B48FE37CA4D48FE2ACA 149CD9F43AEB3BBA6B1AEA9809680B4B5B9AEB4B3FFC3E947CD9F43B9B480A8B4B18FFF1EEA E 3C35C48CD9F43B9B480B7B4BC8FFF1E 9 E 2D5C5CD6643C1E12A8940 1D6 2C38248CAE947FE26D28F47C38B473030303030
9 REM 9E5D5C53E 877 620CD3244CD8243C1D1E1FE77CA5C48FE76CAA948FE40D283487723 DC283482A8940 1D6 2 97BFEEACACB487ED626DAE947FE1AD2E94732E540CDD1474FC3DF48CDB4473AE5403D32E540 0FE24D2E947CDDD474F3AE540B9CA 149DA 1494716 0D5C5CD3243C1D1193A864077 C79B8C2F348C3 149CD 0433AE640FE 0CABD453AE740328640AF32E640C3BD45 620CD3244CD9F4390B291A6B0AA80A8BAB7B7AAB3B980B4B78090A891ADA6B3ACAAFFCD8243FE32CA6049FE28CA6A49CD9F43AEB3BBA6B1AEA9809680B4B5B9AEB4B3FFC31949CD32437E32DE40C3BD453A864032E7403E 132E640CD3243C3824930
10 REM 7EC3CA49 0 0 0 03ADE40FE 0C2AB49CD9F43B3B480A8BAB7B7AAB3B980ABB4B7B2BAB1A6FFC3BD45CD32433ADE4077CD9F43ABB4B7B2BAB1A680B1B4A6A9AAA9FFCD 043C3BD45FE 0C2EA49CD9F43B3B480ABB4B7B2BAB1A680B9B480A8ADA6B3ACAAFFC3BD453D328640C3D4452A8740228C40228E40AF32D940328B402A8E407EFE 0C2434A 1EA 02A8E40 9228E403AD9403C32D940FE24C2 14A 1 9 02A8C40 9228C40228E40AF32D9403A8B403C328B40FE1AC2 14ACD4542 640C94F 6 021 041 9 9 95E23562A1A4022E8402A1C4022EA40 1 0 01AFEFFCA824AFE26D2E24A7723 31332EC40C35E4A303030303030303030
11 REM 3E7677233AEC4077221A4023E52AEA40EBE17323722371237023221C40EF1A2A342A8E4023E52A1C402B462B4E2B562B5E79FE 9DABD4A 6 0 E 8EBD1C5EDB02AEA40221C402AE840221A402A8E40C1 92379FE 8CA A4A3E 07723 CC3D44AFE80D2FB4AD62632EE40E5EB23C5CDB447EBC1E11313C35F4B131AC5473A8B40 0 0 0 0 080 0 032EE40131A473AD940 0 0 0 080 032E540C113C35F4B2A87403AEE40FE 0CA354B 1 9 057 915C2304B3AE540FE 0CA464B 1EA 057 915C2414BD123 1 8 0EDB0E1 1 8 0 9E5C1EBD12B7E32EC4023C35E4A3AE5403D32E540D5C5E5C3214B30303030303030303030303030303030
12 REM E5D5C5 6 8FE 0CAAF4BA7 517D28C4B 4A71F4F78C6802A1C4077792377AF23772377237723221C40C1D1E1C9AF4FC3994BE5D5 02A1C4011FBFF19E57EFE 0CADF4BD680473E1090572346234EC3E54B 0 0 0 0E1221C40 0D1E1C9 1 0 0C3D74B78F68047A7CB18CB1915C2E94BC3D74B3EFF1213121312C38E4630CAE947FE DCA104CFE26D28F47C38B473E 07723C38B47303030303030303030FE2BCAD445FE29CA2D4CC31844CD32433E 077CD9F43ABB4B7B2BAB1A680A9AAB1AAB9AAA9FFCD6643C32A44CD32433E 077E5CD6643E1C334453030CDB44BC5E1 142 0 9E5C1C3D642CDB44BC5E1 142 0 9E5C1C35B4530303030
13 REM 2A8940 1A6 0 91E 93E8277 1 A 0 977 977 93E8177 124 0 91DC28B4CCDF241C93030303030303030303030303030303030303030303030303030303030
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"
Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.