TRS-80 DOS - VTOS v4.0 - Disassembled

Overview

VTOS (Virtual Technology Operating System) was written by Randolph Cook and published by Virtual Technology Inc. in 1980 as a disk operating system for the TRS-80 Model I; the files on this site are those of release 4.0.2 (the manuals say VTOS 4.0). It has a resident part, SYS0/SYS, and overlays, SYS1/SYS-SYS10/SYS, which the request handler of SYS0/SYS loads at 4E00H when a program or the system issues RST 28H with a request code: bits 3-0 of the code name the overlay and bits 6-4 the function in it.

Every file of the system diskette, the system files included, has a directory record; the overlays are found by their directory entry codes. The diskette holds the system files BOOT/SYS, DIR/SYS, SYS0/SYS-SYS10/SYS and CONFIG/SYS; the programs BACKUP/CMD, FORMAT/CMD, PATCH/CMD, GETDATE/CMD and VTCOMM/CMD; the drivers KSM/DVR, PR2/DVR and RS232/DVR with PR2DVR/DOC; the filters ADDLF/FLT and UPCASE/FLT; BASIC/CMD with BASIC/OVN and BASIC/OVX; the patch files BASIC/FIX, PENCIL/FIX and SCRIPSIT/FIX; and DEMO/JCL, DEMO/KSM and MAKE/JCL.

SYS0/SYS loads its banner into video memory and its code and data at 400CH-50FAH: the restart vectors and device control blocks, the system cells at 4300H-43FFH, the entry points at 4400H-447FH, the clock and task interrupt routine, the floppy disk driver at 4600H, the drive code tables at 4700H, the file routines, the request handler and program loader, and the start up code at 4E00H, which the first overlay loaded later overwrites.

BOOT/SYS

BOOT/SYS is granule 0 of cylinder 0, four sectors (1024 bytes). Sector 0 is the boot sector the ROM reads into 4200H and runs: it reads the directory record of SYS0/SYS (the first record of sector 4 of the directory cylinder, whose number is byte 2 of the sector), loads the file's first extent through a buffer at 5100H-51FFH and jumps to its transfer address, 4E00H; it displays NO SYSTEM when the record holds no file and DISK ERROR when a sector cannot be read in two tries, then halts. Sector 1 is a second boot sector for a boot through a disk driver: it is entered with Index Register IY pointing to drive 0's drive code table and reads through the driver that table jumps to; no program on the diskette runs it. Sector 2 is the system information sector, which SYS0/SYS reads over the boot sector at every boot: the switch that loads CONFIG/SYS (byte 01H), the drive code tables of drives 0-7 (bytes 20H-6FH, those of drives 1-7 copied to 470AH-474FH), the serial number shown after VTOS SERIAL # (bytes C0H-C7H) and the 64 bytes C0H-FFH the reset checks before it goes on. Sector 3 is a copy of a granule allocation table. The fifth sector of the granule carries the sector number 7CH, written so by FORMAT/CMD, and is not part of the file.

A disassembly of BOOT/SYS can be found here.

SYS0/SYS - Resident DOS Core

The resident part of VTOS. BOOT/SYS loads its 123 load blocks and jumps to its transfer address, 4E00H. Three blocks go straight into video memory (the banner, stored negated and decoded by the reset, the words VTOS SERIAL # and the large letters VTOS); the rest fills 400CH-405CH, 4300H-4DFFH and 4E00H-50FAH. The file carries the patches SYS0B, SYS0C, SYS0D and SYS0E2 in its load blocks. Its parts:

Address RangeFunction
3C00H-3E7FHLoad blocks in video memory: the banner, VTOS SERIAL #, the letters VTOS
400CH-405CHRST 28H, RST 30H and RST 38H vectors, the device control blocks KI, DO and PR, the exits 402DH and 4030H, the keyboard image, the version byte, the tick counter, the interrupt mask and vectors
4300H-43D7HSystem cells (current drive, overlay in memory, system flags, BREAK vector), the CONFIG/SYS file specification, the job log routine, the keyboard driver, the device control blocks JL, SI and LO
4400H-44FFHThe entry points, the control blocks of the program to run (4480H) and of the overlays (44A0H), character I/O for routed, NIL and file devices, text display and printing
4500H-45F0HTwelve task slots, the interrupt service routine, the task dispatcher and the clock task
4600H-47AEHThe floppy disk driver, the drive code tables of drives 0-7 and the driver calls
47B0H-4BBBHFile routines: position, read and write records and bytes, end of file, sector of a record through the extents (with SYS8/SYS for new space), directory sector read and write, arithmetic
4BBCH-4C30HKeyboard decode (CLEAR, SHIFT 0 case reversal, key repeat set up) and requests with bit 7 clear
4C31H-4DFFHThe RST 28H request handler and overlay load, program load and run, the loader, time and date, the clock display and trace tasks, hex output
4E00H-50FAHThe reset, run once: banner, top of memory, keyboard driver, devices, interrupts, the date and day of the week, the system information sector, drive code tables, AUTO command, CONFIG/SYS; its last part runs at 405DH, the key repeat routine at 41E5H

A disassembly of SYS0/SYS can be found here.

SYS1/SYS

SYS1/SYS is the command interpreter. The request handler of SYS0/SYS loads it at 4E00H for every request code whose bits 3-0 are 3, and bits 6-4 of the code choose one of seven functions: 93H and A3H (the normal and abort exits, 402DH and 4030H) display VTOS READY and read a line of up to 63 characters into 4318H; B3H (4405H) copies a caller's command line there and executes it; C3H (441CH) reads a file or device specification into a control block; D3H (4473H) adds a default extension; E3H (4476H) reads a parameter list in parentheses (names alone, decimal and X'hex' numbers, "texts", ON/OFF/YES/NO) against a caller's table; F3H interprets a line where it is. A command line that starts with a period is a comment and one that starts with an exclamation mark runs CHAIN. Otherwise the first word is looked up in a table of 8 byte entries (a name of 6 characters and a word): 36 commands run a member of the library SYS6/SYS through request 88H, BOOT jumps to a HALT, which restarts the Model I as the reset button does, and a hidden first entry, matched only by the word O!, runs member 1DH. Any other word is loaded and run as a program file, with the extension CMD when it has none. The file carries the patch SYS1A (5185H-519BH), which lets the parameter reader take small letters in ON, OFF, YES and NO.

A disassembly of SYS1/SYS can be found here.

SYS2/SYS - Opening and Creating Files

SYS2/SYS opens files and devices. The request handler of SYS0/SYS loads it at 4E00H for every request code whose bits 3-0 are 4, and the program loader of SYS0/SYS opens every program file through it. Bits 6-4 of the code choose the function: 94H (4424H) opens a file or device, A4H (4420H) opens or, when the file is not in the directory, creates it with full access, C4H (44B8H) tests whether a drive is there and its diskette turns (with the write protect state in the CARRY FLAG), D4H gives the one byte hash code of a file name and E4H the 16 bit hash code of a password.

A file is found through the hash index, sector 1 of the directory cylinder, which holds the name hash of every directory record at the place given by its directory entry code; each byte that matches leads to the record, whose 11 characters of name and extension must be the same. The drive named is searched, or each ready drive from 0 to 7. The password given is checked against the record's update password (full access) and access password (the level in the attribute byte; execute only files are opened read only with BREAK left off); a password whose hash code is CAD2H opens every file with full access. The control block is then filled in from the record: the access level, the buffer, the drive, the entry code, the end of file, the record length and up to five extents. A device specification (an asterisk and two letters) turns the control block into a route to the device control block of that name.

A new file gets a free record of the hash index, searched from a place chosen by the tick counter at 4040H; the first two records of directory sectors 2-9 are kept for the system files. The file carries the patch SYS2ABC in its bytes.

A disassembly of SYS2/SYS can be found here.

SYS3/SYS - Closing Files and Devices

SYS3/SYS closes files and devices. The request handler of SYS0/SYS loads it at 4E00H for every request code whose bits 3-0 are 5. Request 95H (4428H) closes the file or device whose control block is at Register Pair DE; request B5H (44BBH) writes the name of the file of a directory entry code and drive as text, which the DEVICE command uses to show the file a device is routed to.

A device route is closed by turning its control block back into the text of its name, an asterisk and two letters. For a file, a changed record buffer is written first; the end of file of the control block is then put into the directory record when it differs, and a file that was written while open gets the update mark that DIR shows as a plus sign and that BACKUP looks for, and the date of the system. Unless ALLOC set the record to keep its space, the granules the file holds beyond its end are cleared in the granule allocation table and taken off its extents, and an extension record left with no extent is freed with its hash index byte and the link to it. The control block ends as the text of the file specification, the name, extension and drive, without the password.

The file carries the patch SYS3ABC as seven load blocks, which make B5H reach its routine, round the granules a file needs by the sectors of a granule of its drive, read the right directory sector for the name and give drives 4-7 their own digits, and drop a call into the ROM from the close of a device.

A disassembly of SYS3/SYS can be found here.

SYS4/SYS - Error Messages

SYS4/SYS shows the error messages. A program or the system jumps or calls 4409H with an error code in Register A; SYS0/SYS issues request 86H and the request handler loads SYS4/SYS at 4E00H. Bits 5-0 of the code are the error, 00H-29H (a higher number shows UNKNOWN ERROR CODE); bit 6 asks for the text of the message alone; bit 7 returns to the caller afterwards instead of going to VTOS READY. Bit 6 of the system flags at 430FH forces the long form.

The message is put together in the sector buffer at 4200H and both displayed and written to the job log. The long form starts on a new line with three asterisks, ERRCOD= and the error number in decimal, then the text and three asterisks; it is followed by a line naming the file or device of the last file request, from its directory record when the file is open or as the specification was typed when it is not, and a line REFERENCED AT X'nnnn' with the address of the CALL that started that request. Its lines are indented with the space compression codes of the ROM's display driver.

The 42 messages are made of 52 words. A table of one byte for each error gives the start of its word list; each byte of a list names a word, bit 7 marks the last one and bit 6 of the last one the errors whose file is not open. A table of word starts gives each word's address, and a word ends where the next begins, so the words are kept with no lengths and no separators.

A disassembly of SYS4/SYS can be found here.

SYS5/SYS - The DEBUG Monitor

SYS5/SYS is the DEBUG monitor. SYS0/SYS issues request 87H when a program meets a breakpoint byte F7H (RST 30H), when BREAK is pressed once G has armed it, when a program is started with DEBUG on, or when a program calls 440DH (the D key held during the boot does the same). The monitor saves every register, including the alternate set, the index registers, the stack pointer and the program counter, in 4065H-407CH, puts back the bytes its breakpoints replaced and shows the registers, with the flags as letters and 16 bytes at the address each register holds, and four lines of memory; S shows a whole screen of memory instead, and A shows the bytes as characters.

Its commands: D sets the display address and the semicolon and the minus sign move it; M changes memory byte by byte; R changes a saved register; U keeps the display up to date until a key is pressed; G runs the program from the saved or a new address with up to two breakpoints and arms BREAK; I steps one instruction and C does the same but runs a CALL to its end. I and C find the length of the instruction and its branch target from three small tables. Any other key is handed on through RST 28H, where SYS9/SYS, the extended DEBUG commands, takes it when it is loaded.

A disassembly of SYS5/SYS can be found here.

SYS6/SYS - The Library of Commands

SYS6/SYS is the library of commands: 37 member codes in 29 members. SYS1/SYS looks up the first word of a command line in its command table; an entry with bit 7 of its word set names a member code, which SYS1/SYS runs with request 88H, the code in Register B and Register Pair HL on the rest of the line. The file starts with one header of type 08H for each code (the code, the transfer address, and the record and byte of the file where the member starts); the program loader of SYS0/SYS finds the header of the code wanted and loads that member, at 5200H (FILTER and SET at 5A00H). Some codes share a member and enter it at different addresses: DATE and TIME; DEBUG, CLOCK, TRACE and VERIFY; APPEND and COPY; LIST and PRINT; FILTER and SET; LOAD and RUN. Member 9 (code 1CH) has no command word: SYSTEM requests it for SYSGEN, which writes the system configuration to CONFIG/SYS or, with SYSGEN=OFF, kills that file. The word O! runs a hidden member that shows an encoded copyright notice.

The file commands: DIR lists the files of a drive or of every ready drive (A, I, P, S); FREE shows the free files and space of each drive; COPY copies a file or device to a file or device and APPEND adds a file to the end of another; LIST and PRINT show a file as text or in hex on the display or the printer; BUILD makes a text file from typed lines; ALLOC gives a file space its close keeps; KILL removes a file or a device; RENAME renames a file; ATTRIB changes a file's passwords, protection level and visibility; DUMP writes memory to a load file; LOAD and RUN load a program, RUN then starting it; XFER copies a file from one diskette to another in the same drive.

The diskette commands: AUTO stores the command line the boot executes; PROT changes the diskette's name, master password and the passwords of its files (LOCK, UNLOCK); PURGE offers the files of a drive one by one for removal. The system commands: DATE and TIME set the clock; CLOCK, TRACE, DEBUG and VERIFY switch the clock display, the trace display, the DEBUG monitor and the read back after writes; MEMORY shows or lowers the top of memory; LIB lists the commands; SYSTEM sets the system options (FAST and SLOW, BREAK, the cursor, the type ahead, the lower case driver, the screen print of J, K and L, the drive step rates and delays, SYSGEN); CHAIN compiles a file of commands into SYSTEM/JCL and runs it through SYS7/SYS.

The device commands: DEVICE shows the drives and the devices; ROUTE sends a device to another device, a file or NIL; LINK joins two devices; RESET puts a device or all of them back; SET and FILTER load a driver or a filter for a device; SPOOL puts a queue in memory, and on disk when wanted, in front of an output device and prints from it in the background.

A disassembly of SYS6/SYS can be found here.

SYS7/SYS - The Execution Phase of CHAIN

SYS7/SYS runs a file of commands. CHAIN (in SYS6/SYS) compiles the file into SYSTEM/JCL, opens it and issues request 99H; SYS7/SYS then sets bit 5 of the system flags, saves the keyboard driver and points the two exits every command ends through (402DH and 4030H) at itself, and makes SYS0/SYS's 44BEH, a request to SYS7/SYS, the keyboard driver. From then on every line the ROM's line input asks for comes from the file, and when a command ends, SYS7/SYS reads the next line and executes it. Single key requests (INKEY$, a program's own key wait) still go to the keyboard. BREAK held down when a command ends stops it with MANUAL CHAINING ABORT!; the end of the file with CHAINING COMPLETED; an error with CHAINING ABORTED!.

Lines starting with two slashes are directives of the execution phase, carried out by SYS7/SYS itself: //PAUSE, //DELAY, //FLASH (the screen), //ALERT (a sound made by switching the cassette select latch), //WAIT (a time of day), //KEYIN (a key from the keyboard chooses a block of lines labelled //1, //2 and so on, ended by three slashes), //STOP, //EXIT and //ABORT.

A disassembly of SYS7/SYS can be found here.

SYS8/SYS - Disk Space for a File

SYS8/SYS finds the extent of a granule that is not in a file's control block and gives a file more disk space. SYS0/SYS issues request 9AH when it works out the sector of a record and none of the five extents in the control block holds its granule. SYS8/SYS walks the extents of the file's directory record and of the extension records linked from it; when the list ends first, it reads the allocation table and takes granules up to the one wanted, extending the last extent or starting a new one, and when a record's four extent places are full it makes an extension record (a free directory record found through the hash index, given the file's hash code) and links it. The allocation table and the directory record are then written back. A patch, SYS8A, rewrote the search for a free directory record.

A disassembly of SYS8/SYS can be found here.

SYS9/SYS - The Extended DEBUG Commands

SYS9/SYS adds commands to the DEBUG monitor of SYS5/SYS. DEBUG (EXT) loads it; it copies its command reader to the top of memory, lowers the top of memory below it, and points the hook at 4310H, where every request below 80H goes, at the copy. DEBUG hands each key that is not one of its own commands to that hook, so the copy runs the extended command with SYS5/SYS's routines for keys and hex numbers: B (block move), E (enter bytes), F (fill), J (jump over a byte), L (locate a byte), N (next block), O (back to VTOS), P (print memory), Q (read or write a port), T (type text), V (compare blocks), W (search for a word) and the digits 0-7 (read or write sectors of a drive).

A disassembly of SYS9/SYS can be found here.

SYS10/SYS - Remove a File or a Device

SYS10/SYS removes a file or a device; programs reach it through 442CH (request 9CH) with the control block in Register Pair DE, as KILL, PURGE and SYSGEN=OFF do. For a file opened with full access or the KILL level, every extent of its directory record and of the extension records linked from it is given back on the allocation table, each record's in use bit and hash index byte are cleared, the table is written back and the control block cleared. For a device, only a NIL device in the free device control blocks 43D8H-43F8H can be removed (the system devices give PROTECTED SYSTEM DEVICE, a device in use DEVICE IN USE); its block is cleared, and every route that led to a now free block is made NIL.

A disassembly of SYS10/SYS can be found here.