TRS-80 DOS - VTOS 4.0.2 for the Model I - SYS8/SYS Disassembled
Page Customization
Page Index
SYS8/SYS
Other Navigation
Introduction/Summary
VTOS 4.0.2 SYS8/SYS Disassembly - Disk Space for a File (Model I)
SYS8/SYS is the system overlay that finds the extent of a granule SYS0/SYS could not find, and gives a file more disk space. When SYS0/SYS works out the sector of a file's next record (4A3CH) and none of the five extents in the file's control block holds the granule, it issues request 9AH (4AB9H); the request handler loads SYS8/SYS at 4E00H (directory entry code 22H) and calls it with Index Register IX = the control block and Register Pair BC = the granule of the file wanted. When SYS1/SYS was the overlay in memory before, SYS0/SYS loads it again afterwards; no other overlay is put back (4AA2H). The manual: "This overlay performs several functions which are intrinsic to the operation of VTOS. You should never purge this overlay."
The file starts with a record of type 05H (the name SYS8), a record of type 1FH holding the copyright notice of Randolph Cook (1980) and three load blocks that fill 4E00H-5096H, 663 bytes; then a record of type 07H with the name SYS8A and three load blocks of that patch: 5000H (13H becomes 14H), 5005H (0AH becomes 0BH) and 5008H-5026H (the search for a free directory record rewritten). The page shows the bytes after the patch. The last record gives the transfer address 4E00H; one byte 03H follows it, which the loader never reads.
What SYS8/SYS Does
The file's directory record (entry code +07H of the control block, drive +06H) is read into 4200H and its extents are walked: each is a cylinder and a granule byte (bits 7-5 the first granule on the cylinder, bits 4-0 the granules less one) at +16H-+1FH; a cylinder FEH links to an extension record whose entry code follows it, FFH ends the list (4E4CH). The first extent that reaches the granule wanted is the answer.
When the list ends first, the file is given granules up to the one wanted (4E97H): the allocation table (directory cylinder, sector 0) is read into 5100H; each granule extends the last extent when the granule after its end is free (an extent counts at most 32 granules and may run on over the next cylinders) or starts a new extent at the first free granule found from the cylinder reached on, then from cylinder 0 (from cylinder 0 at once when no cylinder has been reached yet in the request: a record with no extent, or a last extent of 32 granules). A record's fifth extent place (+1EH-+1FH) is kept for the link: when the four others are full, a free directory record is taken (4F8CH), searched for from the directory sector of the file's own record and passing over the codes of the system files, given the file's hash code in the hash index, made an extension record (attribute 90H, +01H the entry code of the record linking to it, no extents) and linked from the full record with FEH and its entry code. The allocation table and the directory record are written back after each run (4F80H). The walk then starts again and finds the new extent.
| Return | Registers |
|---|---|
| Z, NC | An extent of the control block is the one (its count brought up to date, 4E45H): Register Pair HL = the extent (Register L the cylinder, Register H the granule byte), Register A = the granule's place in it, Register Pair DE = the address of the control block's granule byte. |
| Z, C | The extent is not in the control block: the extents of the second to fourth places move one place up, the fifth is dropped (4E34H); Register Pair BC = the extent (Register C the cylinder, Register B the granule byte), Register Pair DE = the file's granules before it, Register Pair HL = +13H of the control block. SYS0/SYS stores it there as the second extent (4ADCH). Register A = 00H. |
| NZ | An error code in Register A: 11H or 12H (directory read or write), 14H or 15H (allocation table read or write), 16H or 17H (hash index read or write), 1BH DISK SPACE FULL, 1EH DIRECTORY FULL - CAN'T EXTEND FILE, or 0FH from a directory write to a write protected diskette. A request other than 9AH returns the NZ FLAG with Register A = the code AND 70H, which is no error code. |
Points to Note
When the extent found is not in the control block, Register A is 00H (4E42H), not the granule's place kept at 4E4AH; SYS0/SYS takes it as the place (4AADH), and the record is read or written in the extent's first granule. That happens for a granule that is not the first of an extent beyond those the control block holds, and for an extent this request has just made when it added more than one granule: a write positioned more than one granule past the end of the file (ALLOC's sector, for one) goes into the wrong granule, and the granule wanted is left unwritten.
4EBDH-4EC5H halve the file's entry code until it is below the count of cylinders, but the result is never used: Register A is loaded again at 4ECAH and Register L still holds the count of cylinders, so a file with no extent gets its first granule from the search that starts at cylinder 0 (4F46H).
The cylinder of a granule that extends an extent is tested against CBH, not against the drive's last cylinder (4F02H); the allocation table has FFH for a cylinder that does not exist, so no granule is taken there.
When a record runs full, the walk is restarted from 4F21H with Register Pair BC holding the granules still to add instead of the granule wanted; that walk can itself give the file granules, and 4E93H then walks again with the granule wanted and adds the rest, so the count comes out exact.
4FE5H, an entry that would start the search for a free record at the tick counter 4040H, is never called. 5026H, a byte 00H loaded by the patch, is never reached.
Before the patch SYS8A the search for a free directory record tested one index byte and returned (its old 5019H-501BH) and passed over directory sectors 2 and 3, so it tried two places, both codes 02H-07H: on a diskette with the system files those hold SYS0/SYS-SYS5/SYS, and no extension record could ever be made.
After request 9AH SYS0/SYS reloads only SYS1/SYS (4AA2H). A record access made from code inside another overlay that needs SYS8/SYS returns into SYS8/SYS's bytes: SYS7/SYS reading a file of commands long enough to have an extension record (its 4EF5H), or a buffer written back from inside SYS3/SYS's close.
Memory Map
Load Areas
| Addresses Size | Contents |
|---|---|
| 4E00H-4E06H 7 bytes | Entry Function 1 only. |
| 4E07H-4E4BH 69 bytes | Function 1 The extent found, compared with the five of the control block, returned. |
| 4E4CH-4E96H 75 bytes | Find the Extent in the Directory The extents of the record and its extension records walked. |
| 4E97H-4F23H 141 bytes | More Granules The allocation table read, the last extent extended, a full record. |
| 4F24H-4F65H 66 bytes | A New Extent The first cylinder with a free granule, its first free granule. |
| 4F66H-4F7FH 26 bytes | Take the Granule The bit set, the extent counted, the next granule. |
| 4F80H-4F8BH 12 bytes | Write the Table and the Record Allocation table and directory sector written back. |
| 4F8CH-4FE4H 89 bytes | An Extension Record A free record taken, filled and linked. |
| 4FE5H-5026H 66 bytes | Find a Free Directory Record The hash index searched for a free entry code. |
| 5027H-503FH 25 bytes | Bit of a Granule BIT n,B and SET n,A built in place. |
| 5040H-5096H 87 bytes | Table and Index Sectors Read and write the allocation table and the hash index. |
Variables
SYS8/SYS Cells
| Address Size | Contents |
|---|---|
| 4E4AH 1 byte | Place in the Extent Operand of LD A,00H at 4E49H: the granule's place in its extent (4E12H), returned at 4E4BH. |
| 4F3CH 1 byte | Cylinders Operand of CP 00H at 4F3BH: the drive's cylinders, at most CBH (4F35H). |
| 4F88H 1 byte | Entry Code of the Record Operand of LD B,00H at 4F87H: the record in 4200H (4E54H); written back by 4F89H, linked from by 4F8CH. |
| 4FE0H 1 byte | Entry Code of the New Record Operand of LD (HL),00H at 4FDFH: the extension record, stored at 4FA0H. |
| 5014H 1 byte | Sectors of Records Operand of CP 00H at 5013H: the directory sectors that hold records (4FFFH). |
| 5032H 1 byte | BIT Opcode Second byte of BIT n,B at 5031H, built at 502EH. |
| 503EH 1 byte | SET Opcode Second byte of SET n,A at 503DH, built at 5039H. |
| 5100H-51FFH 256 bytes | Allocation Table Not in the file: the drive's allocation table (5040H, 4F6BH, 5053H). |
Memory Outside the File
| Address Size | Contents |
|---|---|
| 4040H 1 byte | Tick Counter Read by the unused entry 4FE5H. |
| 4200H-42FFH 256 bytes | Sector Buffer SYS0/SYS's buffer: the directory sector of the record (4E5AH, 4FADH, 4FD4H) or the hash index (4F8FH). |
| IX+06H, IX+07H 2 bytes | Control Block: Drive, Entry Code The drive and the directory entry code of the file. |
| IX+0EH-IX+1FH 18 bytes | Control Block: Extents The five extents compared at 4E21H; a granule byte brought up to date at 4E45H; the second to fourth moved up at 4E3DH. |
| Drive Code Table +06H-+08H 3 bytes | Drive Geometry +06H the last cylinder (4EB1H, 4F2AH), +07H the sectors of a track and cylinder (4FEBH), +08H the granules of a cylinder (4EEBH); +09H the directory cylinder through 4B65H. |
Outside Routines
| Address | Contents |
|---|---|
| 4797H | SYS0/SYS: byte Register A of the drive code table of drive Register C. |
| 4B10H | SYS0/SYS: read the directory sector of entry code Register B into 4200H, Register Pair HL = the record. |
| 4B1FH | SYS0/SYS: write the directory sector in 4200H and read it back. |
| 4B45H | SYS0/SYS: read a directory cylinder sector, checking its data mark. |
| 4B65H | SYS0/SYS: Register D = the directory cylinder of drive Register C. |
| 4B6CH | SYS0/SYS: Register A = Register A times Register E. |
| 4B7BH | SYS0/SYS: Register A = Register E divided by Register A, Register E = the remainder. |
| 4768H | SYS0/SYS: driver function 0EH, write a sector with the FAH data mark. |
| 4772H | SYS0/SYS: driver function 0AH, read a sector without storing it. |
Disassembly
4E00H - Entry: Function 1 Only
SYS8/SYS is loaded at 4E00H by the request handler of SYS0/SYS (4C31H) for a request code whose bits 3-0 are AH (directory entry code 22H) and called at 4E00H with Register A = the request code. Its one function is 1, request 9AH, which SYS0/SYS issues at 4AB9H when no extent in an open file's control block holds the granule of the record position: Index Register IX = the file's control block, Register Pair BC = the granule of the file wanted (counted from 0). Any other code returns at once; XFER (SYS6/SYS member 28) issues 8AH only to have the file in memory.
4E07H - Function 1: The Extent of the Granule Wanted
4E4CH walks the extents of the file's directory records, giving it more granules when it has too few, until an extent holds the granule wanted. The granule's place in that extent is kept at 4E4AH. When one of the five extents of the control block (+0EH-+1FH) has the same cylinder and first granule, its granule byte is brought up to date and SYS8/SYS returns with the NC FLAG, Register Pair HL = the extent (Register L the cylinder, Register H the granule byte) and Register A = the place. Otherwise the extents from the second place on move one place up (the fifth is lost) and SYS8/SYS returns with the CARRY FLAG, Register Pair BC = the extent (Register C the cylinder, Register B the granule byte), Register Pair DE = the file's granules before it and Register Pair HL = +13H of the control block, where SYS0/SYS's 4ADCH stores it as the second extent; Register A is then 00H, not the place.
Load Register A with the granule's place in the extent, the operand 4E4AH (00H in the file, stored at 4E12H). LD does not change the flags.
4E4CH - Find the Extent in the Directory
Register Pair BC = the granule wanted, Index Register IX = the control block. The file's directory record (entry code +07H, drive +06H) is read and its extents (+16H-+1FH: cylinder and granule byte, a cylinder FEH links to an extension record whose entry code follows, FFH ends the list) are walked, Register Pair HL counting the granules before each. The first extent whose last granule is the granule wanted or beyond it is returned: Register Pair HL = the extent (Register L the cylinder, Register H the granule byte), Register Pair DE = the granules before it, Register A = 00H with the Z FLAG. At the end of the list 4E97H gives the file more granules and the walk starts again. 4F88H keeps the entry code of the record in 4200H.
4E97H - Give the File More Granules
Register Pair BC = the granule wanted, Register Pair DE = the granules the file holds, Register Pair HL = the byte FFH that ends the extents of the record in 4200H. The allocation table of the drive is read into 5100H and granule after granule is taken until the file holds the granule wanted: each one extends the last extent when the granule after its end is free on the allocation table (4ED3H), else starts a new extent at the first free granule from the cylinder reached, or from cylinder 0 when none has been reached yet in this request: a record with no extent, or a last extent that already counts 32 granules (4F24H). A record whose four extent places are full gets an extension record (4F8CH). At the end the allocation table and the directory record are written back (4F80H).
4F24H - A New Extent
Register Pair DE = the granule byte place of the empty extent, Register L = the cylinder to start from. The allocation table is searched for a byte that is not FFH, from cylinder Register L to the last one and then from cylinder 0 (two passes, Register B). When every byte is FFH the table and the record are written back and error 1BH (DISK SPACE FULL) is returned.
Compare Register A against the cylinders of the drive, the operand 4F3CH (00H in the file, stored at 4F35H).
4F66H - Take the Granule
Register C = the granule on cylinder Register L, Register Pair HL = its allocation byte, Register Pair DE = the granule byte of the extent. The granule is marked in use; a new extent gets the cylinder; the extent's count goes up by one. While granules are still to add, 4ED3H tries to add the next one to the same extent.
4F80H - Write the Table and the Record
Writes the allocation table at 5100H back (error 15H) and then the directory sector in 4200H with the record whose entry code is at 4F88H (SYS0/SYS's 4B1FH: errors 12H or 0FH). Returns the Z FLAG when both writes are good.
Load Register B with the entry code of the record in 4200H, the operand 4F88H (00H in the file, stored at 4E54H).
4F8CH - An Extension Record
The hash index is read into 4200H and a free directory record is found (4FE8H), starting in the directory sector of the file's own record. Its index byte gets the file's hash code and the index is written back. The new record gets the attribute byte 90H (bit 7 an extension record, bit 4 in use), +01H the entry code of the record that links to it (4F88H), 20 bytes 00H and ten bytes FFH (no extents). The full record then gets FEH and the new entry code at +1EH-+1FH, the link 4E8CH follows. No free record gives error 1EH, DIRECTORY FULL - CAN'T EXTEND FILE.
Store the entry code of the new record, the operand 4FE0H (00H in the file, stored at 4FA0H), at Register Pair HL.
4FE5H - Find a Free Directory Record
4FE8H: Register A = the entry code to start from (4F98H passes the sector of the file's record with record 0; 4FE5H would pass the tick counter), Register C = the drive, the hash index in 4200H. Entry codes are tried from that sector on, each sector's eight records (+20H) in turn, then the next sector, up to the last directory sector of the drive (its sectors a cylinder less 2, put into 5014H); codes 00H-07H and 20H-27H (the system files' records) are passed over. A second pass starts at 40H, the third record of directory sector 2. Returns the Z FLAG and Register Pair HL = the free index byte (Register L the entry code), or the NZ FLAG. The patch SYS8A (a 07H record and three load blocks) put the loop 5008H-5026H in: before it the search returned after testing one index byte (old 5019H-501BH) and passed over sector indexes 0 and 1, so only two places were tried, both codes 02H-07H: on a diskette with the system files those are system records and error 1EH was certain.
Compare Register A against the sectors that hold records, the operand 5014H (00H in the file, stored at 4FFFH).
5027H - Test or Set the Bit of a Granule
5027H: Register A = a granule (0-7), Register B = an allocation byte; builds BIT n,B at 5031H and returns the Z FLAG when the granule's bit is 0, free. 5034H: Register A = a granule; builds SET n,A at 503DH and returns Register A = the granule's bit.
Test bit n of Register B (the opcode's second byte at 5032H, 40H in the file, set at 502EH): the Z FLAG is set when the granule is free.
Set bit n of Register A (the opcode's second byte at 503EH, C7H in the file, set at 5039H): Register A = the granule's bit alone.
5040H - The Allocation Table and the Hash Index
Register C = the drive. Each routine finds the directory cylinder with 4B65H. 5040H reads sector 0, the allocation table, into 5100H (error 14H); 5053H writes it with the FAH data mark and reads it back (error 15H); 506CH reads sector 1, the hash index, into 4200H (Register A = 16H with the read's flags); 507EH writes it back (error 17H). The reads go through 4B45H, which checks for the data mark of the directory.
5100H - The Allocation Table Buffer
Not in the file.