--- title: "VU-File" id: 51811 type: "computer_media" slug: "vu-file" url: "http://localhost/computer_media/vu-file/" markdown_url: "http://localhost/computer_media/vu-file.md" published_at: "2023-08-13T23:14:33+00:00" modified_at: "2026-04-04T20:17:57+00:00" author: "David Anderson" featured_image: url: "http://localhost/wp-content/uploads/2019/02/20230809-041332.jpg" excerpt: "A full-featured database manager with machine code at its core, handling record entry, search, sorting, printing, and cassette save through a BASIC menu shell." 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: "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: "Database" slug: "database" taxonomy: "genre" url: "http://localhost/type/database/" media_type: "Cassette" download_url: "https://archive.org/download/timex-sinclair-software-archive/VU-File (1981)(Psion Software - Sinclair Research)(UK)(TS1000)(Cassette).zip" mediadate: "1981" producer_company: - id: 11292 title: "Sinclair Research Ltd." type: "company" url: "http://localhost/company/sinclair-research-ltd/" - id: 11401 title: "Timex Computer Corporation" type: "company" url: "http://localhost/company/timex-computer-corporation/" related_products: - id: 14547 title: "VU-FILE (TS 1000)" type: "product" url: "http://localhost/product/vu-file/" media_type_tags: "Database" --- VU-File is a database management program that allows users to define record formats, enter and edit data records, search, sort, order, list, and print filed information. The program relies heavily on machine code routines called via RAND USR and USR at addresses such as 17986, 17983, 17989, 19151, 19154, 19157, and 19160, with the BASIC shell acting primarily as a launcher and menu dispatcher. A 9,999-character string array F$ is used as the main data store, with the first 20 characters reserved for the file name and bytes 21–52 used for the printer format. System variables are read directly with PEEK at addresses including 16565, 16566, 16567, 16583, 16584, 16586, and 18585 to display record count, percent-full statistics, and field ordering information. The program includes a Psion-branded title screen and supports cassette saving of the file and data via a USR call to address 8192 with a SAVE command string. *** ## Program Analysis ### Program Structure The BASIC portion of VU-File is a thin shell surrounding a large machine code body embedded within the `F$` string array and at fixed memory addresses. The program is organized into distinct line-number regions: - Lines 50–51: REM statements that serve as containers for the machine code payload (the long token-encoded REM line at line 50 is the MC store). - Lines 1100–1200: Initialization — dimensioning `F$(9999)`, setting the default file name, switching to SLOW mode, and jumping into machine code via `RAND USR 17986`. - Lines 1300–1400: CLS and dispatch to the status/menu entry point at line 3400. - Lines 2000–2080: Main menu display (options 1–4) and keypress routing. - Lines 3200–3810: Option handlers for each menu choice, each delegating immediately to a machine code routine. - Lines 9995–9996: An alternate save/restart path used by the machine code to re-enter BASIC after a save operation. ### Machine Code Integration Virtually all real work is done in machine code. The BASIC accesses it through two mechanisms: - `RAND USR addr` — calls the routine and discards the return value (used for side-effecting operations like initializing the MC, setting record/printer formats, and performing the save handshake). - `LET A=USR addr` — calls the routine and uses the integer return value to drive a computed `GOTO`, implementing a state-machine dispatch back into BASIC. The key machine code entry points are tabulated below: | Address | Called via | Purpose | | --- | --- | --- | | 17986 | `RAND USR` | MC initialization / startup | | 17983 | `USR` (return used) | LPRINT layout handler, returns dispatch value | | 17989 | `RAND USR` | Set printer format | | 17992 | `RAND USR` | Set record format (option 1 / layout) | | 19151 | `USR` (return used) | Save completion check (0 = success) | | 19154 | `RAND USR` | Prepare data for tape save | | 19157 | `USR` (return used) | Main database engine entry; returns menu state | | 19160 | `USR` (return used) | Status display refresh, returns dispatch value | | 8192 | `USR` with string arg | Psion I/O driver — sends “SAVE:P:VU-FILE:” command | ### Computed GOTO Dispatch The program uses a computed `GOTO` pattern at lines 3400–3410 and 3548–3549 to return control from machine code to the appropriate BASIC handler: - `LET A=USR 19157` at line 3400 obtains a state index. - `GOTO 3450+50*A` routes to one of: 3450 (menu), 3500 (status display), 3550 (LPRINT), 3600 (save), 3800 (layout), etc. - Similarly, `GOTO 3410` after updating `A` at lines 3548–3549 creates a tight re-entry loop for the status display. Menu option routing at line 2080 uses `GOTO 3000+200*(I-28)`, mapping key codes 29–32 (characters 1–4) to lines 3200, 3400, 3600, 3800 respectively. ### Data Storage in F$ The single string `F$(9999)` serves as the entire database store. The layout of this string is: - Characters 1–20: File name / title (read back at line 3500 and written at lines 1150 and 3650). - Characters 21–52: Printer format record, LPRINTed directly at line 3550. - Characters 53 onwards: Managed entirely by the machine code for record data and metadata. ### System Variable PEEKs Lines 3500–3510 read system variables directly to display database statistics on screen without machine code assistance: | Address | System Variable | Use in Program | | --- | --- | --- | | 16565–16566 | Record count (lo/hi byte) | Displayed as total records | | 16567 | Field ordering index | Displayed as “ordered by field” | | 16583–16584 | Total capacity (lo/hi) | Denominator for percent-full calculation | | 16586 + 18585 | Used space (lo/hi, split) | Numerator for percent-full calculation | | 16603 | Field count | Displayed as “fields” | Note that the percent-full formula uses `PEEK 18585` for the high byte of used space alongside `PEEK 16586` for the low byte — this address pairing is unusual and likely reflects the machine code’s use of a non-standard RAM location to store a running total. ### Tape Save Mechanism Saving is handled by calling address 8192 (the Psion I/O driver) with the string `"SAVE:P:VU-FILE:"` as a `USR` argument — a technique specific to the Psion hardware interface. The machine code at 19151 returns a non-zero value on failure, and the BASIC at line 3695 halts with `STOP` in that case. Lines 9995–9996 provide an alternative re-entry path that re-runs the program after a successful save triggered from within machine code. ### Notable Techniques - The REM line at line 50 is an unusually large machine code store — the encoded token stream is the MC binary, a common technique for embedding executable code in BASIC programs. - Key input at line 2060 uses `CODE INKEY$` in a busy-wait loop, checking for codes 29–32 (digits 1–4) without any `PAUSE` delay. - The `RAND USR` idiom is used consistently for calls whose return values are irrelevant, keeping the BASIC stack clean. - The program uses `FAST` mode only during the tape save sequence (line 3645), switching back to `SLOW` at line 3700 for normal operation. - All user-facing text for the database UI (field entry prompts, search instructions, error messages, command lists) is stored as string literals within the machine code REM block, not in separate BASIC PRINT statements. ## Source Code ``` 50 REM ##[)]# FOR #I#J#K#L#M#N#O#P#Q#R#S#T#U#V#W#X# F###S 3 IF ##▘ ▘####▝#"# ▗# OR #N##B[,,] 3######## ##▘▘####[)]# FOR #I#J#K#L#M#N#O#P#Q#R#S#T#U#V#W#X#; GOSUB # CONT PI# LPRINT SLOW STOP STEP <># TO # AND # FAST LLIST ** THEN>=#<=# OR ""# ##▚##[I]###INKEY$ #[-]PI####PEEK PI# POKE PI#?###PI# FOR INKEY$ #[0]INKEY$ LN [0]INKEY$ LN #INKEY$ ###LN W#LN #INKEY$ #4#LN PLOT #LN [W]PI** GOSUB #[E]RNDE**RND▘#▝[J][Y]C▌ GOSUB [4] STEP / RUN 7[Y]F4 PLOT FOR Q#7 FOR MEXP RND7"#[L]C+[J][Y]UEXP RND4▀W/ GOSUB ><$4 CLSAT ""#[L]COS / LLIST GOSUB #[L]RND[J]M AND RNDE>=RND6PEEK RNDLN FOR INKEY$ CG FOR LN #PI AND #PI/ PAUSE ▛▐#K▘8#7#TAN 5▙RND GOSUB # AND RND#[S]COS PRINT WM AND RNDXLN LPRINT INKEY$ GOSUB #[N]RND LET TAN EPEEK RND6>=RNDE[P]RND76[P]RNDY▘##PILN [?]# GOSUB #[N]RNDESTR$ RND7Y#[Y]C▘F[R] GOSUB ##£▞ EPEEK RNDLN #PI**#$ FOR <#[L]C▝ GOSUB [K] GOSUB #PEEK RNDTAN LN ## RETURN STOPTAB -PILN [?]#U AND RNDX4 LOAD LPRINT TAN FASTSTR$ ,, GOSUB #[W]RND[R] GOSUB #ZSGN LPRINT TAN E>=RNDQ TAN U AND RND#ESGN RND[J]▐#K▘8# NEWZ( PLOT TAN ESGN RNDU<=RND#- # NEWZ#;#( UNPLOT #[R]""ESGN RNDTAN LN [0]INKEY$ [J]M AND RNDESGN RND FASTLN FOR INKEY$ LPRINT COS #7 NEWZXC NEXT ▞ #, RETURN#C FOR GOSUB [4] REM [K]PI/ SLOWE**RND)#▝LN PEEK PI GOSUB #[G]RNDE[E]RNDLN ?#**#X#▘ LN -##7▀.[R]4 PLOT LN -##[R]4 LOAD ▀LN -##7.[R]C RUN ▀/ LLIST FASTE>=RND[R] GOSUB PI##▀ LPRINT TAN LN [0]INKEY$ )3 IF LN VAL INKEY$ XC POKE #▚#,, GOSUB # FASTC4 GOSUB #>=RNDLN #PIS,PI#LN POKE PIACS #4~~ GOSUB #>=RND; FOR GOSUB [S]/▖; FOR GOSUB [K]AT [R]TAN AT ▘ TAN E[G]RND,,6[G]RND GOSUB #[E]RND[R] GOSUB #6[I]RNDEINT RND,,6INT RND GOSUB #[G]RND[R] GOSUB #6[C]RNDE>=RND,,6>=RND[R]TAN 6STR$ RNDLN [?]#[J]MNOT RNDLN ##LN ##ENOT RNDACS +ESTR$ RND▘ COPY COPY GOSUB #[L]RNDS# RETURN#4"ACS #4 LPRINT LN [?]#7#[V]# RETURN#4:ACS #4ABS LN [?]#F▘▘ #[V]# RETURN#4)ACS #COS ACS #4[X])5 LN [?]#;#[V]# RETURN#4)ACS #TAB ##)5 LN [?]#[R] GOSUB ##[V]# RETURNRNDK?ACS #TAB ###UNOT RND[E]#7### RETURN#4(ACS #TAB ##UNOT RND INPUT █MNOT RND### RETURN#4.ACS #TAB ## GOSUB #[N]RNDR GOSUB #ESTR$ RND AND ##Q F▘▘ #[V]# RETURN#4+ACS PICOS ACS #TAB ##LN [?]#Y#7[Y]4 CLS7###ACS #4J GOSUB #NOT RNDACS )KB FAST5~~INKEY$ ▘~~ GOSUB [L]4▀[J]/,,▘~~ GOSUB [L]4▝Y█ LPRINT 4$[L]W▘ COPY COPY#7LN [£]#### RETURN STOPTAB ##ACS #TAB ##TAN LN [V]▝GC IF H##LN [X]▛#TAN ▞MVAL LN [V]▝AT G4 PLOT ( PLOT TAN LN [=]#Y█[I]#TAN Y#[Y]4▘,,▘5 GOSUB #**RND FOR R GOSUB #S▖ FOR ,,/£E(RNDR GOSUB # FOR K▀[R] GOSUB PI6STR$ RNDTAN LN [£]#▘[S]"Y "[S]4 CLS###LN ## RETURN STOPCOS U<=RND#U AND RNDX[S]COS ▛#A ▘▙RND,, GOSUB #STR$ RND#7# FOR Q[?]7▘▘ LN [=]# PLOT ▘TAN E**RND)▖ LET GOSUB #[L]RND) GOSUB #[N]RNDLN ###[?]#LN [0]INKEY$ Y M AND RND) SLOW IF GOSUB #[L]RNDE**RNDTAN LN $#Y=RNDE(RND7#7#,,FFF6[W]RNDE£RND▘[A] ,,6**RND) GOSUB #[P]RND GOSUB #[C]RNDY▘M[R]RNDTAN LN $#LN FOR INKEY$ FOR COS LN ASN #4 PLOT TAN LN ?## NEW##LN #PI6SGN RND4 PRINT #[I]#LN #PI6PEEK RNDTAN LN #PICOS 6SGN RND NEW""TAB [3]# PLOT ▘TAN U[R]RNDM AND RNDLN ▝#LN ?##LN [A]#4▞LN PRINT # PLOT ▘TAN LN [/]#LN ▝#LN [3]#C8LN [/]## GOSUB #[U]RND,: [S]K▝#$▌C▒7<,[Y]4▞( SAVE £C<>[R]USR ▝#/NOT E[S]RND6SGN RND# PLOT █##[-]PIESGN RND6[S]RNDEPEEK RND6[U]RNDTAN EINT RND6SGN RNDTAN #[N]""SGN TAN RND12 COPYSFAAAC~~LN ##LN ## RETURNE4▌LN 2INKEY$ / DIM RETURNF4▌LN 8INKEY$ / STEP RETURN#ABS ########▀##[;]##[▒]##>#####COS ##6##[Y]#LN W#LN ##LN 4#U<=RND[R]C RUN #<=#LN ZINKEY$ LN #####Y▝LN [;]#LN #INKEY$ Y▀#[;]#Y▘LN [;]#LN GOSUB # RETURN#""LN #PI GOSUB #[P]RND. GOSUB #[P]RNDC*##LN NINKEY$ GOSUB #SGN RND GOSUB [K]. GOSUB #>=RNDLN 8INKEY$ COS #5INKEY$ Q 6>=RNDLN ###[L]#EINT RND6SGN RNDTAN LN [V]▝ FOR 5[Z] CLEAR[R] GOSUB #RCOS 5 COPY RETURN[R] GOSUB #4 GOTO TAN Y "[S]4 CLSTAN LN #PI6SGN RNDTAN LN #####[J]M AND RNDLN WINKEY$ C RUN FOR LN [?]#▘#*LN TO #LN ASN #**E[N]RNDLN [?]#/ FASTY▞LN [;]#LN NEXT #U AND RNDM[R]RND#5INKEY$ Y,,LN [;]#[J]M[K]RNDM AND RNDLN ASN #**LN NEXT #U AND RNDM[K]RNDTAN ESTR$ RND7# RETURN#COS FTAN Y▛LN [;]#[J]M AND RND5. IF 6[L]RNDLN WINKEY$ COS FOR LN HINKEY$ RETURN STOPASN EINKEY$ RETURN#4▌LN [?]#/ REM LN [?]#LN [O]# FOR ▄#K▘=LN X# GOSUB #[N]RND[R] GOSUB PI##EPEEK RND£#LN QINKEY$ AND EINKEY$ E>=RND,,6>=RNDEPEEK RND#▞ FOR E[N]RND<$C▝ GOSUB [K]U AND RND PRINT LN EINKEY$ LET M AND RND###LN TINKEY$ 6PEEK RNDTAN LN NEW#COS NEW"" RETURN█4 PLOT PLOT ▘TAN U[R]RNDM AND RNDLN ▝#ESGN RNDLN [?]#LN ###LN [Z]#4▞LN .##[?]#LN [O]#LN ▝#LN [V]#C8LN [O]## GOSUB #[U]RND,: [S]S▝#$▌C▒7<,[Y]4▞( SAVE £C<>[R]>=▝#/NOT LN .##EINKEY$ E[S]RND6SGN RNDTAN Y▖LN [;]#▘RND[0]LN TO #LN [V]▝8""LN 8INKEY$ C FOR TAN LN GOSUB # RETURN STOPCOS RETURN#COS 53 IF 6[L]RND5 6[N]RNDE**RND FAST)6 [R] GOSUB #▞4FQ ( CLS6**RND6STR$ RNDQ█LN ##LN [?]#LN X# GOSUB #**RND[R] GOSUB ####[R]4▞ LPRINT 6**RND/[Q]M2#53# FOR GOSUB [K] LPRINT 6**RNDTAN U2##EPEEK RND# NEWZX[(]**WW#▐#K▘8 FAST$R LPRINT COS F FAST)3#U2##,[Y]4 LOAD <7( SAVE LPRINT [R]TAN U2#WTAB W#LN 7#Y~~▞▜LN [.]#LN S#4" RETURN#TAB ##LN 8INKEY$ # IF #LN ##LN ▛#ESGN RND#K▖ PLOT RND/▝ NEW[Z]#LN NEW#4 FOR LN 5INKEY$ ESGN RND#ACS #CLN LN ZINKEY$ /COS U[K]RND[R]M AND RNDC▞LN [O]##[(]#ESGN RND6PEEK RNDLN [(]#SQR EPEEK RND# NEWZ▐#K▘86PEEK RND GOSUB # AND RND#WM AND RND[S]4 LLIST RTAN LN EINKEY$ LN ▝#LN ### NEW[Z]#LN NEW#4 RUN LN 5INKEY$ Y COPYM2#Y#▞4E£RND▐#K▘8Y#7[Y]C▝Q ( SAVE TAN ESGN RNDACS #TAB W#Y"LN [;]#LN GOSUB # RETURNYCOS RETURNNASN W#/ INPUT ESTR$ RND GOSUB #[Y]RND▘4 GOSUB [K]TAN U""RNDXM""RNDCOS ESTR$ RND)5 ;6STR$ RNDTAN E(RNDF:=[J]F$ASN ##▞4[Y]4▌F( IF / LET #M""RNDE**RND6STR$ RND LPRINT 6AT RNDLN ▗#▘▝ TAN LN [=]#4 POKE EAT RND DIM E(RND), ;6[Y]RNDY COPYM2#▘A 5▙RND) THENRND GOSUB [K]TAN E[G]RND GOSUB #[C]RND#[L]TAB [7]INKEY$ TAN Y▝LN [;]#LN PLOT #LN PLOT #E**RND)#▝LN KINKEY$ GOSUB #INT RNDE[G]RNDLN QINKEY$ **LN ## GOSUB #[G]RNDLN #INKEY$ Y▀LN [;]#LN PLOT #LN (#LN ##COS FAST FOR LN HINKEY$ RETURN STOPQ[?] FOR LPRINT COS #F#/ FOR 5 THENRND# INPUT INKEY$ LN PLOT #[J]M AND RNDESGN RND FASTLN ## LPRINT COS #7 NEWZXC NEXT ▞ #, RETURN#C FOR GOSUB [4] REM ##/ SLOW LPRINT 6VAL RNDY▌LN [;]#LN ##LN [B]#LN [V]▝84▌LN 8INKEY$ C LOAD LN EINKEY$ EVAL RND DIM ▞##[J]LN ##Y£E#RND▘▜ GOSUB [L]+4 SAVE GOSUB #£RND, RETURN#4▀=RND[R] GOSUB #6TAN RNDY:LN ##▘▘ TAN 5#RND) #▞▒#ACS T*ACS >K▝ INPUT H( PRINT #7U[X]RND[W]4 DIM U[W]RND[X]4 STOPTAN LN [/]#E#RND[R] GOSUB ###COS Y▒LN ##▘▘ TAN LN [/]# GOSUB ##RNDTAN £PRESS NEWLINE TO DELETE£[R][E][C][O][R][D]█[L][A][Y][O][U][T] USE THE KEYBOARDAS A TYPEWRITER TO ENTER TITLESOF A BLANK RECORD. MOVE CURSORWITH THE ARROWS. STOP TO EXIT£[D][A][T][A]█[F][I][E][L][D][S] MOVE THE CURSORUSING THE ARROW KEYS AND PRESSNEWLINE TO MARK THE START OFEACH DATA FIELD. STOP TO EXIT£[L][I][S][T] PRESS ANY KEY TO STOP£[P][R][I][N][T] PRESS ANY KEY TO STOP£USE SHIFT TO MOVE THE CURSOR TO THE FIELD WHICH WILL DEFINE THE RECORD ORDER AND PRESS NEWLINE £[A][L][T][E][R]█[A]█[R][E][C][O][R][D] STOP TO EXITSHIFT-6 TO SKIP A DATA FIELD£CRC CHECK FAILED PLEASE RELOAD£PRESS NEWLINE FOR THE STRING SELECT TO APPLY TO ANY FIELD OR USE SHIFT TO MOVE THE CURSOR TO DESIRED FIELD AND PRESS NEWLINE £[S][E][A][R][C][H]█[M][O][D][E] STOP TO EXITPRESS NEWLINE FOR ANOTHER RECORDOR ENTER A SELECTING STRING £DO YOU WANT THE STRING SELECT TO REMAIN ACTIVE? PRESS Y OR N FOR YES OR NO£[C][O][M][M][A][N][D][S]█[A][R][E][:] ENTER ALTER INFORMFORWARD BACK RESET ORDER SELECTQUIT LIST PRINT COPY DELETE£[E][N][T][E][R]█[A]█[R][E][C][O][R][D] STOP TO EXIT£ FIELDS RECORDS PERCENT FULLORDERED BY FIELD£ REM 51 REM 1100 DIM F$(9999) 1150 LET F$( TO 20)="VU-FILE" 1160 SLOW 1200 RAND USR 17986 1300 CLS 1400 GOTO 3400 2000 CLS 2005 PRINT AT 3,8;"[P][S][I][O][N]█[C][O][M][P][U][T][E][R][S]" 2010 PRINT AT 6,12;"VU-FILE" 2020 PRINT AT 11,6;"1-SET RECORD FORMAT" 2030 PRINT AT 13,6;"2-ENTER VU-FILE" 2040 PRINT AT 15,6;"3-SAVE VU-FILE AND DATA" 2050 PRINT AT 17,6;"4-SET PRINTER FORMAT" 2055 PRINT AT 21,1;"PRESS 1 TO 4 FOR DESIRED OPTION" 2060 LET I=CODE INKEY$ 2070 IF I<29 OR I>32 THEN GOTO 2060 2075 CLS 2080 GOTO 3000+200*(I-28) 3200 RAND USR 17989 3220 GOTO 2000 3400 LET A=USR 19157 3410 GOTO 3450+50*A 3450 GOTO 2000 3500 PRINT AT 0,0;F$( TO 20);" ";PEEK 16603 3505 PRINT PEEK 16565+256*PEEK 16566;TAB 17;INT (100*(PEEK 18585+256*PEEK 16586)/(PEEK 16583+256*PEEK 16584)) 3510 PRINT TAB 20;PEEK 16567 3548 LET A=USR 19160 3549 GOTO 3410 3550 LPRINT F$(21 TO 52) 3560 LET A=USR 17983 3570 GOTO 3410 3600 CLS 3610 PRINT "ENTER FILE NAME" 3620 PRINT AT 10,0;"SET PLAYER TO RECORD" 3630 PRINT "BEFORE PRESSING NEWLINE" 3640 INPUT N$ 3645 FAST 3650 LET F$( TO 20)=N$ 3660 CLS 3670 RAND USR 19154 3690 PRINT USR 8192;"SAVE:P:VU-FILE:" 3695 IF USR 19151<>0 THEN STOP 3700 SLOW 3710 GOTO 2000 3800 RAND USR 17992 3810 GOTO 2000 9995 PRINT USR 8192;"SAVE:P:VU-FILE:" 9996 IF USR 19151=0 THEN RUN ```