The Agon's SD card holds the boot files, your saved modules and any files
your programs write. VIOS reads and writes it directly through a FAT32
driver on the eZ80; nothing goes through MOS once VIOS runs. While the host
harness runs on the Mac, files there can be reached too, under /host/.
Card format and path rules
- The card must be FAT32. Other formats are refused ("not FAT32").
- Names are 8.3: up to 8 characters, a dot, up to 3 characters
(
NOTES.TXT,APP.FTH). Long names are not supported. - Names are case-insensitive:
/vios/vios.binand/VIOS/VIOS.BINare the same file. - Paths are absolute and start with
/; there is no current directory. - A path is 1 to 127 printable characters with no spaces.
- Directories must exist before you write into them.
SAVEandBOOT-TRIALcreate/VIOSand the package directories themselves.
What is on the card
A card prepared with tools/vios_sd_install.py and used for a while looks
like this:
| Path | Written by | Contents |
|---|---|---|
/autoexec.txt |
the installer (one viosboot line added) |
MOS runs it at power-on |
/mos/viosboot.bin |
the installer | the boot stub: loads VIOS from the ESP or from the SD copy |
/vios/vios.bin, /vios/vios.man |
the installer | SD copy of the VIOS resident and its manifest (size, CRC) |
/vios/boot.cnt |
the boot stub | unfinished-boot counter; VIOS deletes it once healthy |
/VIOS/BOOT0.REC, /VIOS/BOOT1.REC |
BOOT-TRIAL, startup |
the journaled boot record |
/VIOS/BOOT_A.VIB, /VIOS/BOOT_B.VIB |
BOOT-TRIAL |
the two boot slots (module lists) |
/VIOS/CACHE_A.VIC, /VIOS/CACHE_B.VIC |
startup | boot-module cache, one per slot |
/VIOS/xxxxxxxx/yyyyyyyy.VIM |
SAVE, BOOT-TRIAL |
module packages, content-addressed |
/VIOS/USER.FTH |
you | Forth source loaded at every boot |
| anything else | you | your files |
/vios and /VIOS are the same directory (case-insensitive names). Files
ending in .TMP are temporaries of an interrupted save; VIOS writes every
package, cache and slot through a temporary and a rename, so the final name
is either complete or absent. See Modules and Persistence
for packages, slots and the cache, and Installing for the boot
files.
Listing a directory: DIR
DIR path lists one directory, one line per entry:
DIR /VIOS
entry BOOT0.REC size 32 dir 0
entry BOOT_A.VIB size 348 dir 0
entry 2E5A9E54 size 0 dir 1
entry USER.FTH size 41 dir 0
dir 1 marks a subdirectory. From the Mac, the CLI's :ls /VIOS shows the
same list, and :put LOCAL /PATH and :get /PATH [LOCAL] copy text files to
and from the card.
Running source files: LOAD and INCLUDE
LOAD path reads a Forth source file and evaluates it, exactly
as if you had typed it. INCLUDE is the same command under its
other common name. Both are console commands: type them on their own, not
inside a definition.
S" /VIOS/LIB.FTH" S" : DOUBLE 2 * ;" FILE-WRITE .
S" /VIOS/APP.FTH" S" INCLUDE /VIOS/LIB.FTH 21 DOUBLE ." FILE-WRITE .
LOAD /VIOS/APP.FTH
0 0 42
Rules:
- A source file is at most 4096 bytes and must not contain NUL bytes.
- Files can
LOADorINCLUDEother files up to 4 deep. - A file must end outside a definition, or
LOADfails with "incomplete definition in source file". - Commands such as
MODULE-LOAD,DIRor anotherLOADwork inside a file, one per line or between words, as at the console. - Unlike module source, a loaded file may print, open files, spawn tasks: it runs as ordinary console input.
- Words defined by
LOADare ordinary RAM definitions: they are gone after a restart unless the file is loaded again. To keep code, make it a module.
/host/ paths load files from the Mac (see below), which is the fastest
edit-and-run loop: edit on the Mac, LOAD /host/app.fth on the Agon.
USER.FTH: your startup file
If /VIOS/USER.FTH exists, VIOS prints user startup: /VIOS/USER.FTH and
loads it once at every boot, after the boot slot's modules and before
AUTORUN. It is the place for settings and small conveniences that are not
worth a module:
\ /VIOS/USER.FTH
DECIMAL
: HI ." Hello from USER.FTH" CR ;
HI
If it fails, the console shows user startup failed: and the error, the
stacks are reset, and boot continues; fix the file (from the Mac with
:put, or with FILE-WRITE) or delete it with FILE-REMOVE. An endless
loop in USER.FTH is stopped by the normal execution budget.
Whole files: FILE-READ, FILE-WRITE, FILE-REMOVE
For small files, three words move a whole file at once. They return 0 for success, not a Forth true flag:
| Word | Stack | Result |
|---|---|---|
FILE-WRITE |
( addr u src n -- ior ) |
create or replace file addr u with n bytes from src; 0 ok, 1 error, 2 if n > 4096 |
FILE-READ |
( addr u dest cap -- n ior ) |
read the whole file into dest (at most cap, at most 4096 bytes); length and 0, or 0 and 1 |
FILE-REMOVE |
( addr u -- ior ) |
delete a file or an empty directory; 0 ok, 1 error |
FS-ERROR prints the last file system message, and
SD-MOUNT ( -- ior ) mounts the card again, for example
after you swapped it (0 = mounted).
CREATE BUF 256 ALLOT
S" /VIOS/HELLO.TXT" S" Hello, SD card!" FILE-WRITE .
S" /VIOS/HELLO.TXT" BUF 256 FILE-READ . DUP . BUF SWAP TYPE CR
S" /VIOS/NOPE.TXT" BUF 256 FILE-READ . . FS-ERROR
S" /VIOS/HELLO.TXT" FILE-REMOVE .
0 0 15 Hello, SD card!
1 0 file not found
0
FILE-WRITE flushes the file to the card before it returns, so the data
survives a power cut right after. FILE-READ fails with "file exceeds
buffer" when the file is larger than cap; read big files as a stream
instead. These words work on SD paths only, not on /host/.
Common FS-ERROR messages: file not found, path not found, invalid
name (not 8.3), access denied or full, file exceeds buffer, not
mounted, not FAT32, disk full: short file write, write protected.
Streams: OPEN, READ, WRITE, CLOSE
For files of any size, open a handle and move data in pieces (see Handles, Pipes and Devices for the full handle model and error codes). Up to 4 files can be open at once. A file opened for writing (mode 2) is created or truncated; there is no append mode and no seek.
S" /VIOS/BIG.DAT" 2 OPEN CONSTANT BH
: FILL-BIG 50 0 DO BUF 100 BH WRITE DROP LOOP ;
FILL-BIG BH CLOSE .
S" /VIOS/BIG.DAT" BUF 256 FILE-READ . . FS-ERROR
0 1 0 file exceeds buffer
The file is 5000 bytes, too big for FILE-READ. Count its bytes with a
read loop:
VARIABLE FH
: FILE-SIZE ( addr u -- n )
1 OPEN FH ! 0
BEGIN BUF 256 FH @ READ DUP 0 > WHILE + REPEAT
DROP FH @ CLOSE DROP ;
S" /VIOS/BIG.DAT" FILE-SIZE .
S" /VIOS/BIG.DAT" FILE-REMOVE .
5000 0
READ returns 0 at the end of the file and a negative code on an error,
so 0 > ends the loop either way.
Files on the Mac: /host/
While tools/vios_harness.py runs on the Mac, every path that starts with
/host/ names a file in the harness's host directory, ~/VIOS-host unless
you start the harness with --host-root DIR (--host-root "" turns the
service off):
.venv/bin/python tools/vios_harness.py --backend resident --tcp 127.0.0.1:8765 --host-root ~/VIOS-host
LOAD, INCLUDE, OPEN, READ, WRITE and CLOSE accept /host/
paths; FILE-READ, FILE-WRITE, FILE-REMOVE and DIR do not. Paths
are relative to the host directory and cannot use .. or escape it through
a symbolic link; at most 4 host files are open at once. Each operation is one request
over the USB link carrying up to 200 bytes; without a harness the request
times out after about a second and OPEN returns -5.
LOAD /host/game.fth
Limits
| Limit | Value |
|---|---|
| File system | FAT32, 8.3 names, absolute paths |
| Path length | 1..127 printable characters, no spaces |
LOAD / INCLUDE file size |
4096 bytes |
LOAD / INCLUDE nesting |
4 |
FILE-READ / FILE-WRITE size |
4096 bytes |
| Open files | 4 SD streams, 8 handles in total |
| Module package | 260-byte header + source (up to 4096) + 4-byte CRC |
/host/ request |
200 bytes per read or write; 4 open host files |
The console command SYNC name only prints @name; it is a marker for host
tools and does not flush the card. VIOS flushes on its own: FILE-WRITE
before it returns, streams when they are closed.