--- title: "VU-CALC for Printer" id: 71477 type: "computer_media" slug: "vu-calc-for-printer" url: "http://localhost/computer_media/vu-calc-for-printer/" markdown_url: "http://localhost/computer_media/vu-calc-for-printer.md" published_at: "2026-09-09T08:51:48+00:00" modified_at: "2026-09-09T08:55:52+00:00" author: "David Anderson" featured_image: url: "http://localhost/wp-content/uploads/2026/09/vu-calc-print.png" excerpt: "A BASIC loader that bolts full-size printer support onto the VU-CALC spreadsheet by POKEing a Z80 machine code routine and routing output through configurable column and row entry points." category: - name: "Archived Media" slug: "archived-media" taxonomy: "category" url: "http://localhost/category/archived-media/" post_tag: - name: "1988" slug: "year-1988" taxonomy: "post_tag" url: "http://localhost/tag/year-1988/" - 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: "Rudy A. Hilsmann" slug: "r-a-hilsmann" taxonomy: "indiv" url: "http://localhost/indiv/r-a-hilsmann/" genre: - name: "Spreadsheet" slug: "spreadsheet" taxonomy: "genre" url: "http://localhost/type/spreadsheet/" media_type: "Program" programmers: - name: "Rudy A. Hilsmann" slug: "r-a-hilsmann" taxonomy: "indiv" url: "http://localhost/indiv/r-a-hilsmann/" download_url: "https://archive.org/download/timex-sinclair-software-archive/VU-CALC%20for%20Printer%20(1988)(Hilsmann%2C%20R.%20A.)(TS2068)(US)(Program).zip" tsrun_member: "VU-CALC for Printer (1988)(Hilsmann, R. A.)(TS2068)(US)(Program).tap" mediadate: "1988" images: - url: "http://localhost/wp-content/uploads/2026/09/vu-calc-print.png" related_products: - id: 14546 title: "VU-CALC" type: "product" url: "http://localhost/product/vu-calc-2068/" media_type_tags: "Spreadsheet" --- # VU-CALC for Printer VU-CALC for Printer is a BASIC loader and extension program that adds printer output capability to the VU-CALC spreadsheet application. It loads two binary code files (“VCALC” and “VCPRINT”) and initializes a set of entry-point addresses stored in variables (e1, e2, e3) that serve as USR jump vectors into machine code routines. A 162-byte Z80 machine code routine, embedded as DATA at line 9500 and POKEd into addresses 62000–62161, handles the actual printer interface, including column and line positioning using byte-pair encoding across two memory addresses. The program supports two output paths: a direct COPY command for the 2040 printer, or a configurable column/row print region routed through the custom machine code. *** ### Program Structure The program is organized into functional blocks by line-number ranges: - **Lines 5–60:** Bootstrap — clears memory, sets display attributes, loads the two CODE files, and jumps to line 3200. - **Lines 1000–1200:** Utility subroutines for file-name input (`a$`) and screen/paper setup. - **Lines 2000–2070:** Printer selection and output routing — either COPY (2040 printer) or the custom machine code path. - **Lines 3000–3300:** Main menu (Exit / Clear worksheet / Return to VU-CALC). - **Lines 3200–3201:** Variable initialization block — sets up entry-point addresses and system pointers, then jumps to `USR e1`. - **Lines 4000, 5000:** File save and string-to-value conversion helper. - **Lines 9000–9200:** Error handler — reports column and row of the error using PEEK of system addresses. - **Lines 9300–9400:** Reinitializer and SAVEr — writes all three binary components back to tape. - **Lines 9500–9620:** Machine code DATA and POKEing loop for the printer routine. ### Machine Code Integration The 162-byte machine code routine is stored as decimal DATA at lines 9500–9520 and loaded into addresses 62000–62161 by the loop at lines 9600–9620. Three entry points within the VU-CALC CODE file are stored as integer variables: `e1` (29764), `e2` (29767), and `e3` (29770). All returns from BASIC subroutines re-enter the spreadsheet engine via `GO TO USR e2` or `GO TO USR e3`, making BASIC act purely as a callback layer around the machine code core. The printer routine at 62000 is invoked by `RANDOMIZE USR VAL "62006"`, skipping the first six bytes which hold configuration data (column low/high, line, and width low/high bytes) rather than executable code. ### Column and Line Encoding Lines 2025–2035 implement a two-byte little-endian encoding of pixel column and line values: - `cc` (column) is multiplied by 7 (pixel width per character column), then split: high byte POKEd to 62005, low byte to 62004. - The remaining width (`350 - cc`) is similarly split into 62000 and 62001. - The line value `ll` is decoded from a two-character string `l$` using `CODE l$(1)-64`, with an optional tens component from `l$(2)` if it is a printable character, giving a compact way to enter two-digit row numbers via a single INPUT into a `DIM l$(2)` string. ### Key BASIC Idioms - `VAL "number"` is used pervasively in `GO TO`, `GO SUB`, POKE addresses, and literal constants — a standard memory optimization that avoids storing the numeric value in the tokenized line. - `SGN PI` evaluates to 1 and is used wherever the literal `1` is needed (e.g., BORDER color, array index). - `NOT PI` evaluates to 0 and appears in the error-handler row decode and in the menu range check (`a> NOT PI` means `a>0`). - `LN PI` evaluates to approximately 1.1447…, which truncates to 1 in integer contexts — used at line 3201 as `xcol + LN PI` to compute `xrow = xcol + 1 = 32881` without a literal 1. - `GO TO VAL "3e3"` is scientific notation inside VAL, evaluating to 3000 — a compact loop-back idiom. ### Variable Namespace and Uppercase Anomaly Lines 2030 and 2035 mix `l$` (lowercase) and `L$` (uppercase) when referencing the same string variable. In Sinclair BASIC, variable names are case-insensitive for string arrays, so `CODE L$(VAL "2")` correctly accesses the second element of the same `DIM l$(2)` array declared at line 2020. Similarly, line 9300 uses uppercase variable names (`BFRE`, `DCONTX`, etc.) that duplicate lowercase equivalents from line 3201; in BASIC these are distinct numeric variables, but line 9300 is a standalone reinitializer that sets its own copies before jumping to `USR E3`. ### Save/Restore Architecture Line 9400 saves all three components to tape in sequence: the BASIC program itself as `VCALC` with LINE 10 autostart, the printer machine code block (62000, 162 bytes) as `VCPRINT`, and the main spreadsheet CODE (29328, 5225 bytes) also as `VCALC` CODE. The boot sequence at lines 10–60 loads them back in the same order. Line 9998 contains a `SAVE` command (char code 12 via the `\\{12}` escape) targeting `9500,` — a partial save line likely used during development. ### Error Reporting The error handler at lines 9000–9200 decodes a two-byte row address stored at `xrow` (32881) into a spreadsheet-style alphabetic row label. The high byte `b` provides the tens letter (added to 64, giving ‘A’=65 for row 1–26), and the low byte `a` provides the units letter (added to 65). When `b = NOT PI` (i.e., b=0), only the single-character suffix is displayed by slicing `d$(2 TO 2)`. ## Source Code ``` 5 REM VU-CALC for printer R.A.Hilsmann SMUG Bytes 8/88 10 CLEAR VAL "29327":BORDER SGN PI:INK VAL "9":LOAD "VCALC"CODE 60 LOAD "VCPRINT"CODE :GO TO VAL "3200" 1000 GO SUB VAL "1100":LOAD a$ CODE :CLS :GO TO USR e2 1100 GO SUB VAL "1200":PRINT ''''"ENTER data file name":INPUT a$:RETURN 1200 PAPER VAL "7":BORDER SGN PI:CLS :RETURN 2000 INPUT "print to 2040 Printer ";a$ 2010 IF a$="n" OR a$="N" THEN GO TO VAL "2020" 2015 IF a$="y" OR a$="Y" THEN GO TO VAL "2060" 2017 GO TO VAL "2000" 2020 DIM l$(VAL "2"):POKE VAL "23658", VAL "8":INPUT "Printout to which column ";cc:INPUT "Printout to which line ";l$ 2025 LET cc=cc* VAL "7":LET ch= INT (cc/ VAL "256"):POKE VAL "62005",ch:LET cl=cc-(VAL "256"*ch):POKE VAL "62004",cl 2030 LET ll= VAL "(CODE l$(1)-64)":IF CODE L$(VAL "2")> VAL "32" THEN LET LL= VAL "26+(CODE L$(2)-64)" 2035 POKE VAL "62003",ll:LET cl= VAL "350"-cc:LET ch= INT (cl/ VAL "256"):LET cl=cl-(VAL "256"*ch):POKE VAL "62000",cl:POKE VAL "62001",ch 2050 RANDOMIZE USR VAL "62006":GO TO VAL "2070" 2060 COPY 2070 GO TO USR E3 3000 GO SUB VAL "1200":PRINT AT VAL "9", VAL "2";"ENTER 1 : EXIT PROGRAM"'' TAB VAL "9";"2 :CLEAR WORKSHEET"'' TAB VAL "9";"3 :RETURN TO VU-CALC":INPUT "OPTION? ";a 3010 IF a> NOT PI AND a< VAL "4" THEN GO TO VAL "3000+a*100" 3020 GO TO VAL "3e3" 3100 GO SUB VAL "1200":STOP 3200 DIM b$(VAL "100"):DIM c$(VAL "20"):DIM l$(VAL "2"):GO SUB VAL "1200" 3201 LET e1= VAL "29764":LET e2= VAL "29767":LET e3= VAL "29770":LET zz= VAL "34553":LET bfre= VAL "34562":LET dcontx= VAL "34140":LET xcol= VAL "32880":LET xrow=xcol+ LN PI:GO TO USR e1 3300 GO TO USR e2 4000 GO SUB VAL "1100":SAVE a$ CODE zz, VAL "(PEEK bfre+256* PEEK (bfre+1)-zz)":CLS :GO TO USR e2 5000 LET c$= STR$ VAL b$:GO TO USR dcontx 9000 GO SUB VAL "1200":PRINT ''''"ERROR was at"''"COLUMN "; PEEK xcol+ SGN PI 9100 LET a= PEEK xrow:LET b= INT (a/ VAL "26"):LET a=a-b* VAL "26":LET d$= CHR$ (b+ VAL "64")+ CHR$ (a+ VAL "65"):IF b= NOT PI THEN LET d$=d$(VAL "2" TO VAL "2") 9200 PRINT "ROW ";d$:INPUT "Press ENTER TO CONTINUE ";x$:GO TO USR e2 9300 CLEAR VAL "29327":DIM B$(VAL "100"):DIM C$(VAL "20"):LET BFRE= VAL "34562":LET DCONTX= VAL "34140":LET XCOL= VAL "32880":LET XROW= VAL "32881":LET E1= VAL "29764":LET E2= VAL "29767":LET E3= VAL "29770":GO TO USR E3 9400 CLEAR :SAVE "VCALC" LINE 10:SAVE "VCPRINT"CODE 62000,162:SAVE "VCALC"CODE 29328,5225 9500 DATA 10,1,0,21,84,0,213,229,197,245,237,91,48,242,33,13,135,237,75,50,242,197,237,75,52,242,219,127,203,103,32,250,126,254,96,32,63,237,161,234,92,242,24,63,126,254,33,204,177,242,254,95,204,180,242 9510 DATA 254,64,204,183,242,254,35,204,186,242,254,34,204,189,242,254,58,204,192,242,254,39,204,195,242,254,36,204,198,242,254,59,204,201,242,254,38,204,204,242,254,63,204,207,242,211,127,237,161,234,74,242,62,13,211 9520 DATA 127,62,10,211,127,193,16,7,241,193,225,209,195,74,116,197,25,24,149,62,12,201,62,9,201,62,18,201,62,15,201,62,14,201,62,20,201,62,13,201,62,27,201,62,11,201,62,10,201,62,24,201 9600 RESTORE 9500 9610 FOR X=62000 TO 62161 9620 READ a:POKE x,a:NEXT x 9998 \{12}9500, 9999 REM **VU-CALC for full-size printer** 1.LOAD "VCALC"CODE 2.GO TO 9500 3.GO TO 9400 ```