LDOS 5.3.1 for the Model III - SYS8/SYS Disassembled
Page Customization
Page Index
SYS8/SYS
Other Navigation
Introduction/Summary
LDOS 5.3.1 SYS8/SYS Disassembly - @ALLOC, Dynamic File Space Allocation (Model III)
SYS8/SYS gives an open disk file its space while the file is written. SYS0/SYS keeps up to five extents of a file in its control block; when the record it positions to lies in a granule that none of them holds, it issues request 9AH (its 4AB3H, called from 4A98H) and the supervisor dispatcher loads SYS8/SYS into the overlay area at 4E00H and calls it with Index Register IX = the file control block and Register Pair BC = the granule wanted, counted from the file's first granule (0). SYS8/SYS reads the file's directory records and counts the granules of their extents up to the one wanted; when the file has fewer granules, it takes the missing ones from the granule allocation table, writes the table and the directory record back, and counts again. The manual says only that this overlay is needed to allocate file space when files are written and must be on every working system diskette. Request 8AH (function 00H) loads SYS8/SYS and returns at once (4E00H).
The file is a load module of 735 bytes: a record of type 1FH with the text Copyright 1991 MISOSYS, Inc., All rights reserved, three load blocks for 4E00H-5095H, a load block for the two bytes 4BC8H-4BC9H (0296H, the 662 bytes that SYS8/SYS takes up in the overlay area) and the transfer address record for 4E00H.
What @ALLOC Returns
SYS8/SYS returns to SYS0/SYS at 4A9BH, after the CALL 4AB3H (the dispatcher drops the return address of the RST 28H itself).
| Register | Contents |
|---|---|
| Z FLAG | Set on success with Register A = the granule's offset in its extent (0-31). On failure the NZ FLAG with the error number in Register A: 11H directory read error, 12H directory write error or 0FH write protected (from DIRWR), 14H GAT read error, 15H GAT write error, 16H HIT read error, 17H HIT write error, 1BH disk space full, 1EH directory full. |
| DE | The file's granule where the extent starts. |
| NO CARRY FLAG | A slot of the control block held the extent and was brought up to date in place (its granule byte, whose count may have grown); Register Pair HL = the extent: Register H its granule byte, Register L its cylinder (4E45H). |
| CARRY FLAG | No slot held the extent: the second to fourth slots have moved on one slot and the fifth is dropped (4E34H); Register Pair BC = the extent (Register B the granule byte, Register C the cylinder) and Register Pair HL = the granule byte of the second slot, which SYS0/SYS (4AD5H) fills with the extent and its first granule. |
The extent slots of the file control block are five groups at +0EH-+1FH: a cylinder byte and a granule byte at +0EH, +12H, +16H, +1AH and +1EH, the word before each of the last four holding the file's granule where that extent starts (the first slot starts at granule 0).
Extents and Directory Records
The space of a file is described by the extents of its directory record, the record whose number is at +07H of the file control block (+06H holds the drive). Directory record n is the 32 byte slot n AND E0H of sector (n AND 1FH) + 2 of the directory cylinder; DIRRD (4B10H) reads that sector into 4300H.
| Bytes | What SYS8/SYS reads or writes |
|---|---|
| +00H | The attributes. An extension record SYS8/SYS makes gets 90H: bit 7 an extension record, bit 4 a record in use (4FAAH). |
| +01H | In an extension record: the number of the record it extends. |
| +16H-+1DH | Four extents of two bytes: a cylinder byte, then a granule byte whose bits 7-5 are the extent's first granule on that cylinder and bits 4-0 the number of its granules less one, so an extent holds 1-32 granules. A cylinder byte of FFH is an extent not in use, the end of the file's space. |
| +1EH-+1FH | FEH and the number of an extension record where the file's extents go on, or FFH when there is none. |
An extent may run on over the end of its cylinder: its granules are counted on from its first granule over the granules of a cylinder (4ED9H). The granules of a cylinder are bits 7-5 of byte +08H of the drive code table plus one, doubled when bit 5 of byte +04H says the drive has two sides (5033H).
How Space Is Found
The granule allocation table, sector 0 of the directory cylinder, is read into 5100H-51FFH: byte 5100H + c is cylinder c (00H-CAH), and bit n set is granule n of that cylinder in use. The number of granules to allocate is the granule wanted less the granules the file has, plus one. For each one (4ED0H):
- When the last extent in use holds fewer than 32 granules and the granule after it is free, that granule is taken and the extent's count goes up by one, so a file written on its own stays in one extent.
- Otherwise the next extent of the record is started (4F24H): the table is searched for a cylinder whose byte is not FFH, from the cylinder at 4767H (01H: nothing changes it) to the drive's last cylinder, then once more from cylinder 0, and the first free granule of that cylinder starts the extent. No free granule anywhere is error 1BH, disk space full, after the granules taken so far are written back.
- When the four extents of the record are full, the table and the record are written back and an extension record is made (4F86H): the hash index table (sector 1) is read into 4300H, a free record is found from the column of the file's own record on (4FDEH), given the file's hash byte so that it counts as in use, and built with no extents; the record it extends gets FEH and its number at +1EH-+1FH. No free record is error 1EH, directory full.
When the granules are all taken the table is written back with the deleted data mark and verified (4F7AH), then the directory sector of the record read last, and the extents are counted again from the file's first record. The search for a new extent starts at a fixed cylinder; the code at 4EABH still builds a random number from the refresh register and TIMER$ (4288H) and fetches the number of cylinders, which this release does not use: the 5.1.4 update notes give a patch (for the Model I D5 CD C1 44 D1 6C; on the Model III, where @MULT is 444EH, D5 CD 4E 44 D1 6C) that makes the search start at a random cylinder again, and in this file it fits over 4EBEH-4EC3H.
About This Page
The Model III file is the Model I file of the same release with the same code at the same addresses; its 11 different bytes are operands that name the Model III resident area: TIMER$ 4288H (4EAFH; Model I 4040H), DIVEA 4B7AH (4EF5H), MULTEA 4B6BH (4FEFH), DIRCYL 4B64H (5041H, 5054H, 506DH, 507FH; on the Model I these routines are one byte higher), the system sector buffer 4300H (5072H, 5084H; Model I 4200H), and the overlay length block at 4BC8H-4BC9H (Model I 4BC9H-4BCAH).
Every byte of the file is shown, in address order: the load block at 4BC8H first, then 4E00H-5095H. SYS8/SYS changes seven of its own bytes while it runs, all operands (the table of Variables): the offset it returns (4E4AH), the number of cylinders (4F36H), the record read last (4F82H), the new record (4FD9H), the number of columns of the hash index table (5008H), and the bit numbers of a BIT n,B and a SET n,A (5025H, 5031H).
Memory Map
Load Blocks in File Order
The four load blocks of the file in the order the overlay loader (4C8CH) reads them, after the copyright record. The transfer address is 4E00H.
| Address | Contents |
|---|---|
| 4E00H-4EFFH | 256 bytes |
| 4F00H-4FFFH | 256 bytes |
| 5000H-5095H | 150 bytes |
| 4BC8H-4BC9H | 2 bytes |
Sections of the Disassembly
| Address | Contents |
|---|---|
| 4BC8H | The Overlay Length (Data) |
| 4E00H | @ALLOC: Entry and the Extent Slots of the File Control Block |
| 4E4CH | Walk the File's Extents |
| 4E97H | Allocate: The Granules Missing, Then Grow the Last Extent |
| 4F24H | A New Extent at the First Free Granule; Allocate One Granule |
| 4F86H | Make and Link an Extension Record |
| 4FDEH | Find a Free Directory Record in the Hash Index Table |
| 501AH | Test and Set a Granule's Bit |
| 5033H | Double a Count for a Drive with Two Sides |
| 503FH | Read and Write the Granule Allocation Table and the Hash Index Table |
Memory SYS8/SYS Uses
| Address | Contents |
|---|---|
| 4288H | TIMER$, read for the random number that this release does not use (4EAFH). |
| 4300H-43FFH | The system sector buffer: the directory sector that DIRRD reads (4E5AH, 4FA6H, 4FCDH), and the hash index table (4F89H). |
| 444EH | @MULT, not called in this release: the 5.1.4 patch for a random start calls it at 4EBFH. |
| 4767H | The fifth byte of WRSECT, 01H: the cylinder where the search for a free granule starts (4EBFH). |
| 4768H, 4772H | WRPROT and VERSEC: write a system sector with the deleted data mark and verify it (505CH, 5061H, 5087H, 508CH). |
| 479CH | DCTBYT: a byte of the drive code table: +04H (5036H), +06H (4EB9H, 4F2AH), +07H (4FE1H), +08H (4EE8H). |
| 4B10H, 4B1FH | DIRRD and DIRWR: read and write the directory sector of a record (4E5AH, 4F83H, 4FA6H, 4FC5H, 4FCDH, 4FDAH). |
| 4B45H, 4B64H | RDSSEC and DIRCYL: read a sector of the directory cylinder (5049H, 5075H) and find that cylinder. |
| 4B6BH, 4B7AH | MULTEA and DIVEA: 8 bit multiply (4FEFH) and divide (4EF5H). |
| 4BC8H-4BC9H | The length of the system file in the overlay area: 0296H for SYS8/SYS. |
| 4E00H-5095H | SYS8/SYS in the overlay area. |
| 5100H-51FFH | The granule allocation table of the file's drive, read and written by SYS8/SYS (503FH, 5052H). |
Variables
The entry points of SYS8/SYS, then the data of the file, the operands it changes while it runs, and the cells outside the file that it uses, by address.
Entry Points
| Address | Name | Contents |
|---|---|---|
| 4E00H | @ALLOC | Request 9AH: find the extent that holds granule Register Pair BC of the file at Index Register IX, allocating space first when needed, and bring the control block's extent slots up to date. |
| 4E4CH | Count the granules of the file's extents to the one wanted; allocate and count again when the file is too short. | |
| 4E97H | Allocate the granules missing: grow the last extent, or start the next one. | |
| 4F24H | Start an extent at the first free granule; 4F60H takes one granule into an extent. | |
| 4F7AH | Write the allocation table and the directory sector of the record read last. | |
| 4F86H | Make an extension record and link it. | |
| 4FDEH | Find a free directory record in the hash index table (5004H: search from Register Pair HL). | |
| 501AH | Test bit Register A of Register B; 5027H: Register A = the bit for granule Register A. | |
| 5033H | Double Register A for a drive with two sides. | |
| 503FH | Read the granule allocation table into 5100H; 5052H write it. | |
| 506BH | Read the hash index table into 4300H; 507DH write it. |
Data in the File
| Address Size | Contents |
|---|---|
| 4BC8H-4BC9H 2 bytes | DEFW 0296H 4BC8H-4BC9H: 0296H (662), the number of bytes from 4E00H that SYS8/SYS takes up (4E00H-5095H). Loading SYS8/SYS puts it over the length the system file loaded before it left here. |
Operands Changed While It Runs
| Address Size | Contents |
|---|---|
| 4E4AH 1 byte | The operand of LD A,00H at 4E49H: the granule's offset in its extent, stored by 4E12H and returned in Register A. |
| 4F36H 1 byte | The operand of CP 00H at 4F35H: the number of cylinders of the drive, stored by 4F2FH; the search for a free granule stops there. |
| 4F82H 1 byte | The operand of LD B,00H at 4F81H: the number of the directory record read last by the walk (the file's record or an extension record), stored by 4E54H; written back by 4F81H, and read by 4FAEH and 4FC9H as the record an extension record extends. |
| 4FD9H 1 byte | The operand of LD (HL),00H at 4FD8H: the number of the new extension record, stored by 4F9AH, put in +1FH of the record it extends. |
| 5008H 1 byte | The operand of CP 00H at 5007H: the number of columns of the hash index table in use, the directory sectors less 2, stored by 4FF8H. |
| 5025H 1 byte | The second byte of BIT 0,B at 5024H (40H in the file): 40H + 8n, stored by 5021H, makes it BIT n,B. |
| 5031H 1 byte | The second byte of SET 0,A at 5030H (C7H in the file): C7H + 8n, stored by 502CH, makes it SET n,A. |
Cells Outside the File That SYS8/SYS Uses
| Address Size | Contents |
|---|---|
| IX +06H 1 byte | The file control block's drive, read into Register C for every disk call (4E57H, 4E98H and on). |
| IX +07H 1 byte | The number of the file's directory record, where the walk starts (4E50H); its column in the hash index table is where the search for a free record starts (4F8DH) and its byte there is the hash the extension record gets (4F9EH). |
| IX +0EH-+1FH 18 bytes | The five extent slots of the file control block, brought up to date at 4E45H or moved on at 4E3DH. |
| 4288H 1 byte | TIMER$, the count of the timer interrupts: the high byte of a random number this release does not use (4EAFH). |
| 4300H-43FFH 256 bytes | The system sector buffer: a directory sector (record at Register Pair HL from DIRRD), or the hash index table, one byte per record, 00H for a free record. |
| 4767H 1 byte | 01H, the first cylinder of the search for a free granule (4EBFH). |
| 5100H-51FFH 256 bytes | The granule allocation table: byte 5100H + c for cylinder c (00H-CAH), bit n set when granule n is in use. |
Disassembly
4BC8H - The Overlay Length (Data)
Every system file from SYS1/SYS to SYS12/SYS carries a load block for the two bytes 4BC8H-4BC9H in the resident area of SYS0/SYS. They hold the length of the file's part in the overlay area: for SYS8/SYS 0296H, the 662 bytes 4E00H-5095H. In the file this block is the last load block, after the three blocks of 4E00H-5095H and before the transfer address record (4E00H). The two bytes are data, not instructions.
4E00H - @ALLOC: Entry and the Extent Slots of the File Control Block
SYS0/SYS issues request 9AH (its 4AB3H) when the record it positions to lies in a granule that none of the five extent slots of the file control block holds; the supervisor dispatcher loads SYS8/SYS into 4E00H and calls 4E00H with Index Register IX = the file control block and Register Pair BC = the file's granule wanted (counted from 0). 4E4CH finds the extent that holds that granule in the file's directory records, giving the file more granules first when it has too few. The slots of the control block are five pairs of a cylinder byte and a granule byte at +0EH, +12H, +16H, +1AH and +1EH, with the starting granule of the second to fifth slot in the word before each pair (the first slot starts at granule 0). The slot that holds the extent gets the extent's granule byte again (its count may have grown); when no slot holds it, the second to fourth slots move on by one slot, the fifth is dropped, and SYS0/SYS (4AD5H) fills the second slot. Request 8AH (function 00H), which COPY issues, only loads the file and returns.
4E4CH - Walk the File's Extents
Counts the granules of the file's extents in its directory record (+16H-+1DH, four extents of a cylinder byte and a granule byte: bits 7-5 the first granule on the cylinder, bits 4-0 the granules less one) until the extent that holds granule Register Pair BC. A cylinder byte of FEH (in +1EH, after the fourth extent) links to an extension record, whose number is in +1FH; the count goes on there. A cylinder byte of FFH is an extent not in use, the end of the file's space: then 4E97H allocates the granules up to the one wanted and the walk starts again. The number of the record read last is kept in the operand at 4F82H.
4E97H - Allocate: The Granules Missing, Then Grow the Last Extent
Entered with Register Pair BC = the granule wanted, Register Pair DE = the granules the file has, Register Pair HL = the FFH where the record's space ends (an extent not in use, or +1EH when all four are in use). The granule allocation table is read into 5100H. The granules to allocate are the granule wanted less the granules the file has, plus one. While the last extent holds fewer than 32 granules and the granule after it (counted on from its first granule, over the cylinders) is free, it is added to that extent; otherwise the next extent of the record is started at a free granule (4F24H). When the four extents are full the table and the record are written back, an extension record is made and linked (4F86H), and the walk starts again.
4F24H - A New Extent at the First Free Granule; Allocate One Granule
Register Pair DE = the granule byte of a free extent of the record, Register Pair HL = the allocation table byte where the search starts (cylinder 1, or the cylinder after the last extent). The search runs to the drive's last cylinder and then once more from cylinder 0, looking for a byte that is not FFH (all granules in use); none found is error 1BH, disk space full, after the granules allocated so far are written back. The first free granule of that cylinder starts the extent: its number goes into bits 7-5 of the granule byte. 4F60H marks the granule in use in the table, gives a new extent its cylinder, counts the granule into the extent and loops back to 4ED0H until the granules missing are allocated.
4F86H - Make and Link an Extension Record
The record's four extents are full, so the file goes on in an extension record. The hash index table (sector 1 of the directory cylinder) is read into 4300H and a free record looked for (4FDEH), from the column of the file's own record on; none free is error 1EH, directory full. The new record gets the file's hash byte in the table (so it counts as in use), and the table is written back. The new record is built in its directory sector: 90H (bit 7 an extension record, bit 4 in use), the number of the record it extends, twenty bytes of 00H and ten of FFH (four extents not in use and no link), and written. Then the record it extends is read again and gets FEH and the new record's number in +1EH-+1FH.
4FDEH - Find a Free Directory Record in the Hash Index Table
Entered with Register A = the column of the hash index table to start at (the sector of the file's own record less 2) and the table in 4300H-43FFH. A byte of the table is the hash of the record at that place: byte n is record n, record n AND E0H of directory sector (n AND 1FH) + 2, and 00H is a record not in use. The number of columns that hold records is the sectors of a directory cylinder less 2 (the allocation table and the hash index table), worked out from the drive code table and stored at 5008H. The first pass looks down each column (rows 00H, 20H ... E0H) from the start column to the last; the second pass starts again at 40H, row 2 of column 0, and so never offers records 00H and 20H. Returns the Z FLAG with Register Pair HL = the free byte (Register L = the free record's number), or the NZ FLAG when none is free.
501AH - Test and Set a Granule's Bit
501AH builds the instruction BIT n,B at 5024H for bit n = Register A (bits 2-0) by storing 40H + 8n at its second byte 5025H, and runs it: the Z FLAG is set when bit n of Register B is 0, the granule free. 5027H builds SET n,A at 5030H by storing C7H + 8n at 5031H and runs it on Register A = 00H: Register A = the granule's bit, 1 shifted left n times.
5033H - Double a Count for a Drive with Two Sides
Register A = a count for one side of a cylinder. When bit 5 of byte +04H of the file's drive code table (drive Register C) is set, the drive has two sides and the count is doubled. Register D is used and not kept.
503FH - Read and Write the Granule Allocation Table and the Hash Index Table
Four routines for the two system sectors of the directory cylinder of drive Register C. 503FH reads sector 0, the granule allocation table, into 5100H-51FFH (error 14H, GAT read error); 5052H writes it back from 5100H with the deleted data mark and verifies it (error 15H, GAT write error). 506BH reads sector 1, the hash index table, into 4300H-43FFH (error 16H, HIT read error); 507DH writes it back from 4300H and verifies it (error 17H, HIT write error). A verify of a sector with the deleted data mark returns 06H, so 06H is success. Each returns the Z FLAG on success; Register A then holds the error number of the routine, which the caller does not use.