DOSPLUS 3.5 for the Model I - SYS3/SYS Disassembled

Page Customization

Introduction/Summary

DOSPLUS 3.5 SYS3/SYS Disassembly - CLOSE@ and KILL@ (Model I)

SYS3/SYS is the low overlay that closes and removes files: CLOSE@ (request code 23H) and KILL@ (24H), and two routines other overlays request: 25H, which frees the space and the entries of a file by its logical file number (SYS14/SYS, the library command KILL), and 26H, which puts the name of an open file back into its control block without closing it (SYS11/SYS). SYS0/SYS loads it at 4E00H over the low overlay before it.

The file is a load module of 3 blocks, 728 bytes, from 4E00H to 50D7H, with the transfer address 4E00H. It uses the 256 bytes at 5100H, after its end, as the buffer for the granule allocation table (5100H); the hash index table and the directory sectors go through the system buffer at 4200HH.

The Parts of SYS3/SYS

AddressContents
4E00H-4E0BHThe routine table (routines 2-6) and routine 2 (4E00H, 4E0AH).
4E0CH-4E48HCLOSE@: devices, the last buffer, Disk space full (4E0CH).
4E49HH-4F74HHThe directory entry brought up to date and the granules beyond the end of the file given back (4E49H).
4F75HH-4FE3HHRoutine 6 and the file specification put back into the control block (4F75H, 4F82H).
4FE4HH-5077HHKILL@, routine 5 and the freeing of segments and granules (4FE4H, 5009H, 504AH, 506BH).
5078HH-50D7HThe date for an entry and the reading and writing of the two tables (5078H, 5090H).

Closing a File

CLOSE@ looks at the type byte of the control block: only an open file (80H-87H) is closed. An open device (90H) and a control block that is not open come back at once with Register A = 00H. A file first has its buffer written, through SYS0/SYS's 4C72H, when it is blocked and holds updated bytes; when that write fails with error 1BH (Disk space full), the end of file byte is set to 00H, the entry is brought up to date all the same and 1BH is returned at the end (4E3AH).

The directory entry is then read (4E49H). When the file has been written to (bit 6 of FCB+02H) the entry gets the modified flag and the month in its +01H, the day and year in its +02H, the end of file byte in +03H and the number of sectors (the ending record number, plus 1 when the end of file byte is not 00H) in +14H-15H, and is written back. The date comes from DATE$ (5078H); bits 2-0 of the year are stored, which is the year less 1980 up to 1987.

Unless the entry is non-shrinkable (bit 7 of its +01H, kept in bit 7 of FCB+02H), the granules the file holds beyond its end are given back, whether or not the file was written to (4EA5H). The granules are counted over every segment of every entry of the file (FEH links to an extended entry), the granules needed are worked out with DIVD@ from the sectors and the sectors per granule, and the difference is freed one granule at a time from the end of the last segment: each granule's bit in the allocation table (read into 5100H) is cleared, the segment's count is lowered, an emptied segment becomes FFH FFH, and an extended entry left with no segment is freed (its first byte and its hash index byte set to 00H) and the entry before it loses its FEH link (4F3AH). The entry and the table are written at the end.

Last, the control block becomes the file's specification again: name, / and the extension, : and the drive's name from DCTTBL, and 03H (4F82H). The password is not put back. Routine 6 does only this part, for an open file, without closing it (4F75H).

Removing a File

KILL@ needs an open file whose access level (bits 2-0 of FCB+01H) is 0 or 1; otherwise it returns error 25H (4FE4H). Routine 5 then frees the file: for each of its entries the segments are cleared in the allocation table (504AH), the entry is made inactive by clearing bit 4 of its first byte, and its hash index byte is set to 00H; the entry keeps its name and segments, which is what lets a recovery tool bring the file back, as the manual says. An entry whose list ends with FEH is followed to the extended entry it names. The table is written back last, and KILL@ clears the 32 bytes of the control block (4FFEH).

The granule bits are cleared by a RES n,(HL) instruction whose second byte is stored before it runs (506BH); the logical file number of the entry before a freed extended entry is stored into the operand of an LD B,n (4F48H).

Differences from the Manual

The manual (T/25) says that after CLOSE@ a device's control block holds the device's name again. DOSPLUS 3.5 returns at once for a device (4E16H); the code after the RET that would put back a name is not reached, and in the Model I file it also lacks the store of the @ that the Model III file has.

The manual does not say that CLOSE@ gives back the granules beyond the end of a file that was only read, nor that a Disk space full error while writing the last buffer still closes the file.

Variables

Memory Outside SYS3/SYS

Address
Size
Contents
4200HH-42FFHH
256 bytes
System Sector Buffer
Directory sectors (4E52H, 4F8BH) and the hash index table (50B4H).
43ABHH
32 bytes
DCTTBL
Drive names at +02H (4FC6H).
4044HH-4046HH
3 bytes
DATE$
The year less 1900, the day and the month (5078H).

Work Areas

Address
Size
Contents
5100H-51FFH
256 bytes
Allocation Table Buffer
5100H
4F57HH
1 byte
Logical File Number
Of the entry before a freed extended entry: the operand of LD B,n (4F48H, 4F56H).
5076HH
1 byte
RES Opcode
The second byte of RES n,(HL) (5072H).
5100H + cylinder
1 byte
Cylinder Byte
Bit n set when granule n is in use (4F16H, 504CH).

The Directory Entry (as SYS3/SYS uses it)

OffsetContents
+00HBit 7 extended entry, bit 4 active (4E56H, 4F36H, 502DH).
+01HBit 7 non-shrinkable, bit 6 modified, bits 3-0 the month; in an extended entry, the logical file number of the entry before (4E6DH, 4F46H).
+02HDay (bits 7-3) and year (bits 2-0) (4E7DH).
+03HThe end of file byte (4E82H).
+05H-0FHThe name and extension (4F93H).
+14H-15HThe number of sectors (4E95H).
+16H-1DHFour segment descriptors: the cylinder, then bits 7-5 the first granule and bits 4-0 the granules less 1 (4EAFH).
+1EH-1FHFFH FFH, or FEH and the logical file number of an extended entry (4F62H).

The File Control Block (as SYS3/SYS uses it)

OffsetContents
+00HType: 80H-87H an open file, 90H a device (4E0CH).
+01HBits 2-0 the access level (4FE7H).
+02HBit 7 non-shrinkable, bit 6 modified (4E5FH, 4EA5H).
+06HThe drive.
+07HThe logical file number.
+08HThe end of file byte.
+0CH-0DHThe ending record number (4E88H, 4ED0H).

Outside Routines

AddressContents
4CDBHSYS0/SYS: the file control block check and wrapper (4E32H, 4F75H, 4FE4H).
4CDFHSYS0/SYS: the wrapper entered after the check (4E13H, 5009H).
4C72HSYS0/SYS: write the buffer when it holds updated bytes (4E35H).
4485HSYS0/SYS: DISKIO%, functions 6 (SREAD) and 7 (SWRITE) (5090H).
448BHSYS0/SYS: LOCDCT% (4E4FH, 5010H).
490CH, 4915HSYS0/SYS: read and write the directory sector of a logical file number.
444EHSYS0/SYS: DIVD@ (4EE0H).
4943HSYS0/SYS: 8 bit divide (4F0DH).

Disassembly

4E00H - The Routine Table

Data: SYS3/SYS's table of routines 2-6, one word each, used by SYS0/SYS's overlay request handler (its 49C9H-49DCH) for the request codes 22H-26H. CLOSE@ (4428H) requests 23H and KILL@ (442CH) 24H; SYS14/SYS requests 25H (its 553AH) and SYS11/SYS 26H (its 56E3H). No file of the diskette requests 22H.

4E00-4E01
DEFW 4E0AH 0A 4E
Routine 2: 4E0AH, XOR A and RET, which SYS0/SYS's record locator requests when it loads SYS3/SYS back (its 4D55H-4D62H).
4E02-4E03
DEFW 4E0CH 0C 4E
Routine 3: 4E0CH, CLOSE@, which closes the file or device of the control block at Register Pair DE.
4E04-4E05
DEFW 4FE4H E4 4F
Routine 4: 4FE4H, KILL@, which removes the open file of the control block at Register Pair DE.
4E06-4E07
DEFW 5009H 09 50
Routine 5: 5009H, which frees the space and the hash index byte of the file with logical file number Register B on drive Register C.
4E08-4E09
DEFW 4F75H 75 4F
Routine 6: 4F75H, which puts the file name, extension and drive of the open file at Register Pair DE back into its control block, without closing it.

4E0AH - Routine 2

Nothing to do when SYS0/SYS's record locator brings SYS3/SYS back.

4E0A
XOR A AF
Set Register A to 00H by XORing it with itself, and set the Z FLAG: routine 2 has no work to do.
4E0B
RET C9
RETurn to SYS0/SYS's overlay request handler (49DDH) with Register A = 00H.

4E0CH - CLOSE@ - Close a File or a Device

Routine 3, requested by CLOSE@ (4428H) with Register Pair DE pointing to a file or device control block. An open file (type byte 80H-87H) has its last buffer written, its directory entry brought up to date, the granules beyond its end given back (unless the entry is non-shrinkable) and its name, extension and drive put back into the control block. Anything else (an open device, type 90H, or a control block that is not open) returns at once with Register A = 00H and nothing changed. Register A returns 00H with the Z FLAG, or an error code with the NZ FLAG.

4E0C
LD A,(DE) 1A
Load Register A with the type byte of the control block at Register Pair DE.
4E0D
AND F8H E6 F8
AND Register A with F8H, keeping bits 7-3 (bits 2-0 of an open file's type byte are not part of the test).
4E0F
CP 80H FE 80
Compare Register A against 80H, an open file.
4E11
If the Z FLAG is set (an open file), JUMP to 4E32H.
4E13
Not an open file: GOSUB to 4CDFH in SYS0/SYS, its file routine wrapper entered after its open test: Index Register IX = the control block, Register Pairs BC, DE, HL and Index Registers IX and IY saved, and the return to here with Register A = 00H; this routine's RET goes through 4CF0H, which restores them.
4E16
RET C9
RETurn through 4CF0H with Register A = 00H: a device or a control block that is not open is left as it is. The bytes up to 4E31H are not reached (no jump in DOSPLUS goes to them).
4E17-4E19
DEFB 00H,00H,00H 00 00 00
Three NOPs, not reached. In the Model III SYS3/SYS a fourth 00H follows, then LD (IX+00H),40H (an @ to the first byte of the control block) before the same code as 4E1AH here.
4E1A
LD A,(IX+03H) DD 7E 03
Not reached: load Register A with the byte at Index Register IX+03H (FCB+03H).
4E1D
LD (IX+01H),A DD 77 01
Not reached: store Register A to Index Register IX+01H (FCB+01H).
4E20
LD A,(IX+04H) DD 7E 04
Not reached: load Register A with the byte at Index Register IX+04H (FCB+04H).
4E23
CP 20H FE 20
Not reached: compare Register A against 20H, a space.
4E25
Not reached: if the Z FLAG is set (a space), JUMP to 4E2CH.
4E27
LD (IX+02H),A DD 77 02
Not reached: store Register A to Index Register IX+02H (FCB+02H).
4E2A
INC IX DD 23
Not reached: INCrement Index Register IX by 1, so the end mark goes one byte further on.
4E2C
LD (IX+02H),03H DD 36 02 03
Not reached: store 03H, the end of a specification, to Index Register IX+02H. These rows would make the control block @ and a one or two character name again, as the manual (T/25) says CLOSE@ does with a device; DOSPLUS 3.5 returns at 4E16H instead.
4E30
XOR A AF
Not reached: set Register A to 00H by XORing it with itself, and set the Z FLAG.
4E31
RET C9
Not reached: RETurn to the caller with Register A = 00H and the Z FLAG set.
4E32
An open file: GOSUB to 4CDBH in SYS0/SYS, its file control block check and wrapper: Index Register IX = the control block at Register Pair DE, the caller's registers saved, and this routine's RET goes through 4CF0H, which restores them.
4E35
GOSUB to 4C72H in SYS0/SYS, which writes the buffer when the file is blocked and the buffer holds updated bytes (bits 7 and 4 of FCB+01H), and otherwise returns Register A = 00H with the Z FLAG set.
4E38
If the Z FLAG is set (written, or nothing to write), JUMP to 4E49H to bring the directory entry up to date.
4E3A
CP 1BH FE 1B
Compare Register A, the error code of the write, against 1BH, Disk space full.
4E3C
RET NZ C0
If the NZ FLAG is set (any other error), RETurn with the error code in Register A.
4E3D
LD (IX+08H),00H DD 36 08 00
Disk space full: store 00H to the end of file byte at Index Register IX+08H (FCB+08H), so the entry ends on the last whole sector the file holds.
4E41
GOSUB to 4E49H to bring the directory entry up to date and put the name back into the control block.
4E44
RET NZ C0
If the NZ FLAG is set (an error from the directory), RETurn with its code in Register A.
4E45
LD A,1BH 3E 1B
Load Register A with 1BH, the error code Disk space full.
4E47
OR A B7
OR Register A with itself to set the NZ FLAG.
4E48
RET C9
RETurn with Register A = 1BH and the NZ FLAG set: the file is closed, and the caller is told that the last sector was not written.

4E49H - Bringing the Directory Entry Up to Date

Reads the sector of the file's directory entry (logical file number FCB+07H, drive FCB+06H). When the file has been written to (bit 6 of FCB+02H), the entry gets the modified flag, today's date, the end of file byte and the number of sectors, and is written back. Then, unless the entry is non-shrinkable (bit 7 of FCB+02H, from bit 7 of the entry's +01H), the granules beyond the end of the file are given back (4EA5H on). It ends at 4F82H, which puts the file name back into the control block.

4E49
LD B,(IX+07H) DD 46 07
Load Register B with the logical file number at Index Register IX+07H (FCB+07H).
4E4C
LD C,(IX+06H) DD 4E 06
Load Register C with the drive at Index Register IX+06H (FCB+06H).
4E4F
GOSUB to 448BH (LOCDCT%) in SYS0/SYS: Index Register IY = the drive control table of drive Register C, for the granule sizes at 4EDDH and 4F0AH.
4E52
GOSUB to 490CH in SYS0/SYS to read the directory sector of logical file number Register B on drive Register C into 4200H; Register Pair HL returns the entry's address.
4E55
RET NZ C0
If the NZ FLAG is set (a read error), RETurn with the error code in Register A.
4E56
BIT 4,(HL) CB 66
Test bit 4 of the entry's first byte at Register Pair HL, the active flag.
4E58
If the NZ FLAG is set (the entry is in use), JUMP to 4E5EH.
4E5A
LD A,18H 3E 18
Load Register A with 18H, the error code File not in directory.
4E5C
OR A B7
OR Register A with itself to set the NZ FLAG.
4E5D
RET C9
RETurn with Register A = 18H and the NZ FLAG set.
4E5E
PUSH HL E5
Save Register Pair HL, the entry's address, to the top of the stack.
4E5F
BIT 6,(IX+02H) DD CB 02 76
Test bit 6 of Index Register IX+02H (FCB+02H), the modified flag: set when the file has been written to.
4E63
If the NZ FLAG is set (written), JUMP to 4E6CH to bring the entry up to date.
4E65
LD A,16H 3E 16
Not written: load Register A with 16H, the offset of the first segment descriptor in an entry.
4E67
ADD A,L 85
ADD the low byte of the entry's address in Register L to Register A.
4E68
LD L,A 6F
Load Register L with Register A: Register Pair HL = the entry's +16H.
4E69
POP AF F1
Restore Register Pair AF from the top of the stack: it drops the entry's address saved at 4E5EH.
4E6A
JUMP to 4EA5H: the entry is not written, but the granules beyond the end are given back all the same.
4E6C
POP HL E1
Restore Register Pair HL from the top of the stack: the entry's address.
4E6D
LD A,(IX+02H) DD 7E 02
Load Register A with the flags at Index Register IX+02H (FCB+02H).
4E70
AND C0H E6 C0
AND Register A with C0H, keeping bit 7 (non-shrinkable) and bit 6 (modified).
4E72
INC L 2C
INCrement Register L by 1 to the entry's +01H (bits 7 non-shrinkable, 6 modified, 3-0 the month).
4E73
OR (HL) B6
OR Register A with the entry's +01H at Register Pair HL: bit 6, the modified flag, is now set.
4E74
AND F0H E6 F0
AND Register A with F0H to clear bits 3-0, the old month.
4E76
LD (HL),A 77
Store Register A to the entry's +01H at Register Pair HL.
4E77
GOSUB to 5078H: Register B = the month, Register C = the day (bits 7-3) and the year (bits 2-0), from DATE$.
4E7A
OR (HL) B6
OR Register A, the month (5078H leaves it in Register A as well as in Register B), with the entry's +01H at Register Pair HL: bits 7-4 as stored at 4E76H, bits 3-0 the month.
4E7B
LD (HL),A 77
Store Register A to the entry's +01H at Register Pair HL: the modified flag and the month.
4E7C
INC L 2C
INCrement Register L by 1 to the entry's +02H.
4E7D
LD (HL),C 71
Store Register C, the day and the year, to the entry's +02H at Register Pair HL.
4E7E
INC L 2C
INCrement Register L by 1 to the entry's +03H.
4E7F
LD A,(IX+08H) DD 7E 08
Load Register A with the end of file byte at Index Register IX+08H (FCB+08H).
4E82
LD (HL),A 77
Store Register A to the entry's +03H at Register Pair HL, the end of file byte.
4E83
INC L 2C
INCrement Register L by 1 to the entry's +04H.
4E84
LD A,10H 3E 10
Load Register A with 10H, the distance from +04H to +14H.
4E86
ADD A,L 85
ADD the low byte of the address in Register L to Register A.
4E87
LD L,A 6F
Load Register L with Register A: Register Pair HL = the entry's +14H, the number of sectors.
4E88
LD E,(IX+0CH) DD 5E 0C
Load Register E with the low byte of the ending record number at Index Register IX+0CH (FCB+0CH).
4E8B
LD D,(IX+0DH) DD 56 0D
Load Register D with the high byte at Index Register IX+0DH: Register Pair DE = the ending record number.
4E8E
LD A,(IX+08H) DD 7E 08
Load Register A with the end of file byte at Index Register IX+08H (FCB+08H).
4E91
OR A B7
OR Register A with itself to set the flags: the Z FLAG when the end of file byte is 00H.
4E92
If the Z FLAG is set (the file ends on a sector boundary), JUMP to 4E95H.
4E94
INC DE 13
INCrement Register Pair DE by 1: the last sector holds part of the file and counts as well.
4E95
LD (HL),E 73
Store Register E, the low byte of the number of sectors, to the entry's +14H at Register Pair HL.
4E96
INC L 2C
INCrement Register L by 1 to the entry's +15H.
4E97
LD (HL),D 72
Store Register D, the high byte, to the entry's +15H at Register Pair HL.
4E98
INC L 2C
INCrement Register L by 1 to the entry's +16H, the first segment descriptor.
4E99
PUSH HL E5
Save Register Pair HL (the entry's +16H) to the top of the stack.
4E9A
LD B,(IX+07H) DD 46 07
Load Register B with the logical file number at Index Register IX+07H (FCB+07H) again (5078H changed Register Pair BC).
4E9D
LD C,(IX+06H) DD 4E 06
Load Register C with the drive at Index Register IX+06H (FCB+06H).
4EA0
GOSUB to 4915H in SYS0/SYS to write the directory sector of logical file number Register B on drive Register C from 4200H.
4EA3
POP HL E1
Restore Register Pair HL from the top of the stack: the entry's +16H.
4EA4
RET NZ C0
If the NZ FLAG is set (a write error), RETurn with the error code in Register A.
4EA5
BIT 7,(IX+02H) DD CB 02 7E
Test bit 7 of Index Register IX+02H (FCB+02H), the non-shrinkable flag the file control block took from the entry's +01H.
4EA9
If the NZ FLAG is set (non-shrinkable), JUMP to 4F82H: the granules are kept and the name goes back into the control block.
4EAC
LD DE,0000H 11 00 00
Load Register Pair DE with 0000H, the count of the granules the file holds.
4EAF
LD A,(HL) 7E
Load Register A with the cylinder of the segment descriptor at Register Pair HL.
4EB0
INC L 2C
INCrement Register L by 1 to the descriptor's second byte.
4EB1
CP FEH FE FE
Compare Register A against FEH: FEH (a link to an extended entry) and FFH (the end) are not cylinders.
4EB3
If the NC FLAG is set (FEH or FFH), JUMP to 4EC1H.
4EB5
LD A,(HL) 7E
Load Register A with the descriptor's second byte at Register Pair HL (bits 7-5 the first granule, bits 4-0 the number of granules less 1).
4EB6
INC L 2C
INCrement Register L by 1 to the next descriptor.
4EB7
AND 1FH E6 1F
AND Register A with 1FH to keep the number of granules less 1.
4EB9
INC A 3C
INCrement Register A by 1: the number of granules in the segment.
4EBA
ADD A,E 83
ADD Register E, the low byte of the count, to Register A.
4EBB
LD E,A 5F
Load Register E with Register A, the new low byte of the count.
4EBC
If the NC FLAG is set (no carry), JUMP back to 4EAFH for the next descriptor.
4EBE
INC D 14
INCrement Register D by 1 for the carry into the high byte of the count.
4EBF
JUMP back to 4EAFH for the next descriptor, with Register Pair DE the count so far.
4EC1
If the NZ FLAG is set (FFH, the end of the list), JUMP to 4ECEH with Register Pair DE = the granules the file holds.
4EC3
LD B,(HL) 46
FEH: load Register B with the descriptor's second byte at Register Pair HL, the logical file number of the extended entry.
4EC4
GOSUB to 490CH in SYS0/SYS to read the directory sector of logical file number Register B into 4200H; Register Pair HL returns the extended entry's address.
4EC7
RET NZ C0
If the NZ FLAG is set (a read error), RETurn with the error code in Register A.
4EC8
LD A,L 7D
Load Register A with Register L, the low byte of the extended entry's address.
4EC9
ADD A,16H C6 16
ADD 16H to Register A, the offset of its first segment descriptor.
4ECB
LD L,A 6F
Load Register L with Register A: Register Pair HL = the extended entry's +16H.
4ECC
JUMP back to 4EAFH to count its segments. Register B and the buffer now hold the last entry of the file.
4ECE
PUSH BC C5
Save Register Pair BC (Register B the logical file number of the entry in the buffer, Register C the drive) to the top of the stack.
4ECF
PUSH HL E5
Save Register Pair HL (the byte after the end mark) to the top of the stack.
4ED0
LD L,(IX+0CH) DD 6E 0C
Load Register L with the low byte of the ending record number at Index Register IX+0CH (FCB+0CH).
4ED3
LD H,(IX+0DH) DD 66 0D
Load Register H with the high byte at Index Register IX+0DH.
4ED6
LD A,(IX+08H) DD 7E 08
Load Register A with the end of file byte at Index Register IX+08H (FCB+08H).
4ED9
OR A B7
OR Register A with itself to set the flags: the Z FLAG when the end of file byte is 00H.
4EDA
If the Z FLAG is set (the file ends on a sector boundary), JUMP to 4EDDH.
4EDC
INC HL 23
INCrement Register Pair HL by 1: Register Pair HL = the number of sectors the file uses.
4EDD
LD A,(IY+0FH) FD 7E 0F
Load Register A with the sectors per granule at Index Register IY+0FH (DCT+0FH).
4EE0
GOSUB to 444EH (DIVD@) in SYS0/SYS: Register Pair HL = the sectors divided by the sectors per granule, Register A = the remainder.
4EE3
OR A B7
OR Register A with itself to test the remainder; this also clears the C FLAG for the SBC at 4EE8H.
4EE4
If the Z FLAG is set (no remainder), JUMP to 4EE7H.
4EE6
INC HL 23
INCrement Register Pair HL by 1: a part granule counts as a whole one. Register Pair HL = the granules the file needs.
4EE7
EX DE,HL EB
Exchange Register Pairs DE and HL: Register Pair HL = the granules held, Register Pair DE = the granules needed.
4EE8
SBC HL,DE ED 52
SUBtract Register Pair DE from Register Pair HL (the C FLAG is clear): the granules held beyond the end.
4EEA
EX DE,HL EB
Exchange Register Pairs DE and HL: Register Pair DE = the granules to give back.
4EEB
POP HL E1
Restore Register Pair HL from the top of the stack: the byte after the end mark.
4EEC
POP BC C1
Restore Register Pair BC from the top of the stack.
4EED
If the Z FLAG is set (no granule to give back), JUMP to 4F82H.
4EF0
If the C FLAG is set (fewer granules than the file needs), JUMP to 4F82H: nothing is given back.
4EF3
GOSUB to 5090H to read the granule allocation table of drive Register C into 5100H.
4EF6
RET NZ C0
If the NZ FLAG is set (a read error), RETurn with Register A = 14H, Gat read error.
4EF7
DEC L 2D
DECrement Register L by 1 to the end mark FFH.
4EF8
DEC L 2D
DECrement Register L by 1 to the second byte of the last segment descriptor.
4EF9
LD A,D 7A
Load Register A with Register D, the high byte of the granules still to give back.
4EFA
OR E B3
OR Register A with Register E, the low byte: the Z FLAG when Register Pair DE is 0000H.
4EFB
If the Z FLAG is set (none left), JUMP to 4F6BH to write the entry and the table.
4EFD
PUSH DE D5
Save Register Pair DE, the granules still to give back, to the top of the stack.
4EFE
LD A,(HL) 7E
Load Register A with the descriptor's second byte at Register Pair HL.
4EFF
AND E0H E6 E0
AND Register A with E0H, keeping bits 7-5, the segment's first granule within its cylinder.
4F01
RLCA 07
Rotate Register A left one bit (bits 7-5 move towards bits 2-0).
4F02
RLCA 07
Rotate Register A left one bit (bits 7-5 move towards bits 2-0).
4F03
RLCA 07
Rotate Register A left one bit: Register A = the first granule, 0-7.
4F04
LD E,A 5F
Load Register E with Register A, the first granule.
4F05
LD A,(HL) 7E
Load Register A with the descriptor's second byte at Register Pair HL again.
4F06
AND 1FH E6 1F
AND Register A with 1FH, the number of granules less 1.
4F08
ADD A,E 83
ADD Register E to Register A: the number of the segment's last granule, counted from the first granule of its first cylinder.
4F09
LD E,A 5F
Load Register E with Register A, the number of the segment's last granule.
4F0A
LD A,(IY+10H) FD 7E 10
Load Register A with the granules per cylinder at Index Register IY+10H (DCT+10H).
4F0D
GOSUB to 4943H in SYS0/SYS: Register A = Register E divided by Register A (the cylinders on from the segment's first), Register E = the remainder (the granule within that cylinder).
4F10
DEC L 2D
DECrement Register L by 1 to the descriptor's cylinder.
4F11
ADD A,(HL) 86
ADD the segment's first cylinder at Register Pair HL to Register A: the cylinder of the last granule.
4F12
INC L 2C
INCrement Register L by 1 back to the descriptor's second byte.
4F13
LD D,A 57
Load Register D with Register A, the cylinder.
4F14
PUSH BC C5
Save Register Pair BC to the top of the stack.
4F15
PUSH HL E5
Save Register Pair HL, the descriptor, to the top of the stack.
4F16
LD L,D 6A
Load Register L with Register D, the cylinder.
4F17
LD H,51H 26 51
Load Register H with 51H: Register Pair HL = 5100H + the cylinder, the cylinder's byte in the granule allocation table.
4F19
LD A,E 7B
Load Register A with Register E, the granule within the cylinder.
4F1A
GOSUB to 506BH to clear bit Register A of the byte at Register Pair HL: the granule is free.
4F1D
POP HL E1
Restore Register Pair HL from the top of the stack: the descriptor.
4F1E
POP BC C1
Restore Register Pair BC from the top of the stack.
4F1F
DEC (HL) 35
DECrement the descriptor's second byte at Register Pair HL by 1: the segment has one granule less. A segment of one granule (bits 4-0 = 0) borrows from bits 7-5 and ends with bits 4-0 = 1FH.
4F20
LD A,(HL) 7E
Load Register A with the descriptor's second byte at Register Pair HL.
4F21
INC A 3C
INCrement Register A by 1, so that bits 4-0 of 1FH become 00H.
4F22
AND 1FH E6 1F
AND Register A with 1FH: 00H when bits 4-0 were 1FH, the segment had only the granule just given back.
4F24
POP DE D1
Restore Register Pair DE from the top of the stack: the granules still to give back.
4F25
If the NZ FLAG is set (the segment still holds granules), JUMP to 4F68H for the next granule.
4F27
LD (HL),FFH 36 FF
The segment is empty: store FFH to the descriptor's second byte at Register Pair HL.
4F29
DEC L 2D
DECrement Register L by 1 to the descriptor's cylinder.
4F2A
LD (HL),FFH 36 FF
Store FFH to the cylinder at Register Pair HL: this descriptor is now the end of the list.
4F2C
DEC L 2D
DECrement Register L by 1 to the second byte of the descriptor before it.
4F2D
LD A,L 7D
Load Register A with Register L, the low byte of the address.
4F2E
AND 1FH E6 1F
AND Register A with 1FH: the offset within the 32 byte entry.
4F30
CP 16H FE 16
Compare Register A against 16H, the offset of the first descriptor.
4F32
If the NC FLAG is set (the descriptor before is in this entry), JUMP to 4F68H for the next granule.
4F34
XOR L AD
XOR Register A (the offset) with Register L: Register A = Register L AND E0H, the start of the entry.
4F35
LD L,A 6F
Load Register L with Register A: Register Pair HL = the entry, which has no segment left.
4F36
BIT 7,(HL) CB 7E
Test bit 7 of the entry's first byte at Register Pair HL, the extended entry flag (FXDE).
4F38
If the Z FLAG is set (the file's first entry), JUMP to 4F6BH to write the entry and the table.
4F3A
LD (HL),00H 36 00
An extended entry without segments: store 00H to its first byte at Register Pair HL, so the entry is free.
4F3C
GOSUB to 4915H in SYS0/SYS to write the directory sector of logical file number Register B (the extended entry) from 4200H.
4F3F
RET NZ C0
If the NZ FLAG is set (a write error), RETurn with the error code in Register A.
4F40
LD A,B 78
Load Register A with Register B, the logical file number of the freed entry.
4F41
AND E0H E6 E0
AND Register A with E0H: bits 7-5 times 32, the entry's offset in its sector.
4F43
LD L,A 6F
Load Register L with Register A, the low byte of the entry's address in the buffer.
4F44
LD H,42H 26 42
Load Register H with 42H: Register Pair HL = the freed entry in the buffer at 4200H.
4F46
INC L 2C
INCrement Register L by 1 to the entry's +01H, which in an extended entry is the logical file number of the entry before it.
4F47
LD A,(HL) 7E
Load Register A with the logical file number of the entry before at Register Pair HL.
4F48
LD (4F57H),A 32 57 4F
Store Register A to 4F57H, the operand of the LD B,n at 4F56H.
4F4B
GOSUB to 50B4H to read the hash index table of drive Register C into 4200H.
4F4E
RET NZ C0
If the NZ FLAG is set (a read error), RETurn with Register A = 16H, Hit read error.
4F4F
LD L,B 68
Load Register L with Register B, the freed entry's logical file number: Register Pair HL = 4200H + the number, its byte in the hash index table.
4F50
LD (HL),00H 36 00
Store 00H to the hash index byte at Register Pair HL: the entry is free.
4F52
GOSUB to 50C6H to write the hash index table from 4200H.
4F55
RET NZ C0
If the NZ FLAG is set (a write error), RETurn with Register A = 17H, Hit write error.
4F56
LD B,00H 06 00
Load Register B with the logical file number of the entry before: the operand at 4F57H is 00H in the file and is stored at 4F48H before this runs.
4F58
GOSUB to 490CH in SYS0/SYS to read the directory sector of logical file number Register B into 4200H.
4F5B
RET NZ C0
If the NZ FLAG is set (a read error), RETurn with the error code in Register A.
4F5C
LD A,B 78
Load Register A with Register B, the logical file number.
4F5D
AND E0H E6 E0
AND Register A with E0H, the entry's offset in its sector.
4F5F
ADD A,1FH C6 1F
ADD 1FH to Register A: the entry's last byte.
4F61
LD L,A 6F
Load Register L with Register A: Register Pair HL = the entry's +1FH.
4F62
LD (HL),FFH 36 FF
Store FFH to the entry's +1FH at Register Pair HL (the logical file number of the link).
4F64
DEC L 2D
DECrement Register L by 1 to the entry's +1EH.
4F65
LD (HL),FFH 36 FF
Store FFH to the entry's +1EH at Register Pair HL, which was FEH: the entry no longer links to an extended entry.
4F67
DEC L 2D
DECrement Register L by 1 to the entry's +1DH, the second byte of its last descriptor.
4F68
DEC DE 1B
DECrement Register Pair DE by 1: one granule less to give back.
4F69
JUMP back to 4EF9H for the next granule, with Register Pair DE one less.
4F6B
GOSUB to 4915H in SYS0/SYS to write the directory sector of the entry in the buffer (logical file number Register B).
4F6E
RET NZ C0
If the NZ FLAG is set (a write error), RETurn with the error code in Register A.
4F6F
GOSUB to 50A2H to write the granule allocation table from 5100H.
4F72
RET NZ C0
If the NZ FLAG is set (a write error), RETurn with Register A = 15H, Gat write error.
4F73
JUMP to 4F82H to put the name back into the control block.

4F75H - Routine 6 - Putting the Name Back

Requested with code 26H (SYS11/SYS, its 56E3H) for the open file at Register Pair DE: the directory entry is read and the file's name, extension and drive are put back into the control block as a file specification, as CLOSE@ does, but nothing is written to the diskette.

4F75
GOSUB to 4CDBH in SYS0/SYS, its file control block check and wrapper: Index Register IX = the control block at Register Pair DE; error 26H when it is not open.
4F78
LD C,(IX+06H) DD 4E 06
Load Register C with the drive at Index Register IX+06H (FCB+06H).
4F7B
LD B,(IX+07H) DD 46 07
Load Register B with the logical file number at Index Register IX+07H (FCB+07H).
4F7E
GOSUB to 490CH in SYS0/SYS to read the directory sector of logical file number Register B on drive Register C into 4200H.
4F81
RET NZ C0
If the NZ FLAG is set (a read error), RETurn with the error code in Register A.

4F82H - The File Specification Put Back

Makes the file control block at Index Register IX the file's specification again: the name (up to 8 characters), a / and the extension when there is one, a : and the drive's name from DCTTBL, and 03H at the end. The password is not put back (the manual, T/25, says the same). The directory sector of the file's entry is read again first when the buffer holds another sector.

4F82
LD A,(IX+07H) DD 7E 07
Load Register A with the logical file number of the file's entry at Index Register IX+07H (FCB+07H).
4F85
XOR B A8
XOR Register A with Register B, the logical file number of the entry whose sector is in the buffer.
4F86
LD B,(IX+07H) DD 46 07
Load Register B with the file's logical file number at Index Register IX+07H.
4F89
AND 1FH E6 1F
AND Register A with 1FH, the bits of the sector: 00H when the buffer holds the sector of the file's entry.
4F8B
If the NZ FLAG is set (another sector), GOSUB to 490CH in SYS0/SYS to read the directory sector of logical file number Register B on drive Register C into 4200H.
4F8E
RET NZ C0
If the NZ FLAG is set (a read error), RETurn with the error code in Register A.
4F8F
LD A,(IX+06H) DD 7E 06
Load Register A with the drive at Index Register IX+06H (FCB+06H).
4F92
PUSH AF F5
Save Register Pair AF (Register A the drive) to the top of the stack.
4F93
LD A,(IX+07H) DD 7E 07
Load Register A with the logical file number at Index Register IX+07H.
4F96
AND E0H E6 E0
AND Register A with E0H, the entry's offset in its sector.
4F98
ADD A,05H C6 05
ADD 05H to Register A, the offset of the name in an entry.
4F9A
LD L,A 6F
Load Register L with Register A, the low byte of the address of the name in the buffer.
4F9B
LD H,42H 26 42
Load Register H with 42H: Register Pair HL = the entry's name in the buffer at 4200H.
4F9D
PUSH IX DD E5
Save Index Register IX, the control block, to the top of the stack.
4F9F
POP DE D1
Restore Register Pair DE from the top of the stack: Register Pair DE = the control block.
4FA0
LD B,08H 06 08
Load Register B with 08H, the length of the name.
4FA2
LD A,(HL) 7E
Load Register A with the name character at Register Pair HL.
4FA3
CP 20H FE 20
Compare Register A against 20H, a space (the padding after the name).
4FA5
If the Z FLAG is set (the end of the name), JUMP to 4FACH.
4FA7
LD (DE),A 12
Store the character in Register A to the control block at Register Pair DE.
4FA8
INC L 2C
INCrement Register L by 1 to the next character of the entry.
4FA9
INC DE 13
INCrement Register Pair DE by 1 to the next byte of the control block.
4FAA
DECrement Register B and loop back to 4FA2H while Register B is not zero.
4FAC
LD A,L 7D
Load Register A with Register L, the low byte of the address after the name characters copied.
4FAD
ADD A,B 80
ADD Register B, the characters of the name not looked at, to Register A.
4FAE
LD L,A 6F
Load Register L with Register A: Register Pair HL = the entry's +0DH, the extension.
4FAF
LD A,(HL) 7E
Load Register A with the first character of the extension at Register Pair HL.
4FB0
CP 20H FE 20
Compare Register A against 20H, a space: an entry with no extension has spaces there.
4FB2
If the Z FLAG is set (no extension), JUMP to 4FC4H.
4FB4
LD A,2FH 3E 2F
Load Register A with 2FH, the / before an extension.
4FB6
LD (DE),A 12
Store the / in Register A to the control block at Register Pair DE.
4FB7
INC DE 13
INCrement Register Pair DE by 1 to the next byte of the control block.
4FB8
LD B,03H 06 03
Load Register B with 03H, the length of the extension.
4FBA
LD A,(HL) 7E
Load Register A with the extension character at Register Pair HL.
4FBB
CP 20H FE 20
Compare Register A against 20H, a space (the padding after the extension).
4FBD
If the Z FLAG is set (the end of the extension), JUMP to 4FC4H.
4FBF
LD (DE),A 12
Store the character in Register A to the control block at Register Pair DE.
4FC0
INC L 2C
INCrement Register L by 1 to the next character of the entry.
4FC1
INC DE 13
INCrement Register Pair DE by 1 to the next byte of the control block.
4FC2
DECrement Register B and loop back to 4FBAH while Register B is not zero.
4FC4
POP AF F1
Restore Register Pair AF from the top of the stack: Register A = the drive.
4FC5
PUSH DE D5
Save Register Pair DE, the next byte of the control block, to the top of the stack.
4FC6
LD HL,43ABH 21 AB 43
Point Register Pair HL to 43ABH, DCTTBL in SYS0/SYS (eight 4 byte entries: the DCT address, then the drive's two character name).
4FC9
ADD A,A 87
ADD Register A to itself: Register A = the drive number times 2.
4FCA
ADD A,A 87
ADD Register A to itself: the drive times 4, the offset of its DCTTBL entry.
4FCB
ADD A,02H C6 02
ADD 02H to Register A, the offset of the name in the entry.
4FCD
LD E,A 5F
Load Register E with Register A, the low byte of the offset into DCTTBL.
4FCE
LD D,00H 16 00
Load Register D with 00H: Register Pair DE = the offset.
4FD0
ADD HL,DE 19
ADD Register Pair DE to Register Pair HL: Register Pair HL = the drive's name in DCTTBL.
4FD1
POP DE D1
Restore Register Pair DE from the top of the stack: the next byte of the control block.
4FD2
LD A,3AH 3E 3A
Load Register A with 3AH, the : before a drive.
4FD4
LD (DE),A 12
Store the : in Register A to the control block at Register Pair DE.
4FD5
INC DE 13
INCrement Register Pair DE by 1 to the next byte of the control block.
4FD6
LDI ED A0
Copy the first character of the drive's name from Register Pair HL to Register Pair DE, INCrementing both and DECrementing Register Pair BC.
4FD8
LD A,(HL) 7E
Load Register A with the second character of the drive's name at Register Pair HL.
4FD9
CP 20H FE 20
Compare Register A against 20H, a space (a one character name, as "0 ").
4FDB
If the Z FLAG is set (a one character name), JUMP to 4FDFH.
4FDD
LDI ED A0
Copy the second character from Register Pair HL to Register Pair DE, INCrementing both and DECrementing Register Pair BC.
4FDF
LD A,03H 3E 03
Load Register A with 03H, the end of a specification.
4FE1
LD (DE),A 12
Store the 03H in Register A to the control block at Register Pair DE.
4FE2
XOR A AF
Set Register A to 00H by XORing it with itself, and set the Z FLAG.
4FE3
RET C9
RETurn through 4CF0H (the registers restored) with Register A = 00H.

4FE4H - KILL@ - Remove a File

Routine 4, requested by KILL@ (442CH) with Register Pair DE pointing to an open file control block. The file needs an access level of 0 or 1 (FCB+01H bits 2-0), else error 25H. Its granules are given back in the granule allocation table, every entry of the file is made inactive (bit 4 of the first byte cleared, the rest left, so a recovery tool can find it) and has its hash index byte cleared; then the 32 bytes of the control block are set to 00H.

4FE4
GOSUB to 4CDBH in SYS0/SYS, its file control block check and wrapper: Index Register IX = the control block at Register Pair DE; error 26H when it is not open.
4FE7
LD A,(IX+01H) DD 7E 01
Load Register A with the flags at Index Register IX+01H (FCB+01H).
4FEA
AND 07H E6 07
AND Register A with 07H, bits 2-0, the access level the file was opened with.
4FEC
CP 02H FE 02
Compare Register A against 02H: the C FLAG is set for access levels 0 and 1.
4FEE
If the C FLAG is set (access level 0 or 1), JUMP to 4FF4H.
4FF0
LD A,25H 3E 25
Load Register A with 25H, the error code Illegal access attempted to protected file.
4FF2
OR A B7
OR Register A with itself to set the NZ FLAG.
4FF3
RET C9
RETurn through 4CF0H with Register A = 25H and the NZ FLAG set.
4FF4
LD C,(IX+06H) DD 4E 06
Load Register C with the drive at Index Register IX+06H (FCB+06H).
4FF7
LD B,(IX+07H) DD 46 07
Load Register B with the logical file number at Index Register IX+07H (FCB+07H).
4FFA
GOSUB to 500CH, routine 5 after its wrapper call, to give back the file's granules and free its entries.
4FFD
RET NZ C0
If the NZ FLAG is set (an error), RETurn with the error code in Register A.
4FFE
PUSH IX DD E5
Save Index Register IX, the control block, to the top of the stack.
5000
POP HL E1
Restore Register Pair HL from the top of the stack: Register Pair HL = the control block.
5001
LD B,20H 06 20
Load Register B with 20H, the 32 bytes of a file control block.
5003
LD (HL),00H 36 00
Store 00H to the control block at Register Pair HL.
5005
INC HL 23
INCrement Register Pair HL by 1 to the next byte of the control block.
5006
DECrement Register B and loop back to 5003H while Register B is not zero.
5008
RET C9
RETurn through 4CF0H with the Z FLAG set: the file is removed and its control block cleared.

5009H - Routine 5 - Freeing a File's Space and Entries

Requested with code 25H (SYS14/SYS, its 553AH) with Register B the logical file number of a file's first entry and Register C its drive; KILL@ comes in at 500CH. For each entry of the file in turn: its segments are freed in the granule allocation table (read into 5100H), the entry is made inactive and written, and its byte in the hash index table is cleared; an entry whose list ends with FEH goes on to the extended entry it names. The table is written back at the end.

5009
GOSUB to 4CDFH in SYS0/SYS, its file routine wrapper entered after the open test: Index Register IX = Register Pair DE, the registers saved, and this routine's RET goes through 4CF0H.
500C
GOSUB to 5090H to read the granule allocation table of drive Register C into 5100H.
500F
RET NZ C0
If the NZ FLAG is set (a read error), RETurn with Register A = 14H, Gat read error.
5010
GOSUB to 448BH (LOCDCT%) in SYS0/SYS: Index Register IY = the drive control table of drive Register C, for the granules per cylinder at 505EH.
5013
GOSUB to 490CH in SYS0/SYS to read the directory sector of logical file number Register B on drive Register C into 4200H; Register Pair HL returns the entry's address.
5016
RET NZ C0
If the NZ FLAG is set (a read error), RETurn with the error code in Register A.
5017
LD A,16H 3E 16
Load Register A with 16H, the offset of the first segment descriptor.
5019
ADD A,L 85
ADD the low byte of the entry's address in Register L to Register A.
501A
LD L,A 6F
Load Register L with Register A: Register Pair HL = the entry's +16H.
501B
LD E,(HL) 5E
Load Register E with the descriptor's first byte at Register Pair HL, the cylinder (or FEH, FFH).
501C
INC L 2C
INCrement Register L by 1 to the descriptor's second byte.
501D
LD D,(HL) 56
Load Register D with the second byte at Register Pair HL (the granules, or the logical file number after FEH).
501E
LD A,E 7B
Load Register A with Register E, the first byte of the descriptor, for the compare.
501F
CP FEH FE FE
Compare Register A against FEH: FEH (a link) and FFH (the end) set the NC FLAG.
5021
If the NC FLAG is set (FEH or FFH, the end of this entry's list), JUMP to 5029H.
5023
INC L 2C
INCrement Register L by 1 to the next descriptor.
5024
GOSUB to 504AH to free the segment's granules: Register E the cylinder, Register D the granules.
5027
JUMP back to 501BH for the next descriptor at Register Pair HL.
5029
LD A,L 7D
Load Register A with Register L, the low byte of the address in the entry.
502A
AND E0H E6 E0
AND Register A with E0H, the start of the entry.
502C
LD L,A 6F
Load Register L with Register A: Register Pair HL = the entry.
502D
RES 4,(HL) CB A6
Reset bit 4 of the entry's first byte at Register Pair HL, the active flag: the entry is no longer in use, but keeps its name and segments.
502F
GOSUB to 4915H in SYS0/SYS to write the directory sector of logical file number Register B from 4200H.
5032
RET NZ C0
If the NZ FLAG is set (a write error), RETurn with the error code in Register A.
5033
GOSUB to 50B4H to read the hash index table of drive Register C into 4200H.
5036
RET NZ C0
If the NZ FLAG is set (a read error), RETurn with Register A = 16H, Hit read error.
5037
LD L,B 68
Load Register L with Register B, the logical file number.
5038
LD H,42H 26 42
Load Register H with 42H: Register Pair HL = the entry's byte in the hash index table at 4200H.
503A
LD (HL),00H 36 00
Store 00H to the hash index byte at Register Pair HL: the entry is free.
503C
GOSUB to 50C6H to write the hash index table from 4200H.
503F
RET NZ C0
If the NZ FLAG is set (a write error), RETurn with Register A = 17H, Hit write error.
5040
LD B,D 42
Load Register B with Register D: after FEH, the logical file number of the extended entry.
5041
LD A,E 7B
Load Register A with Register E, the byte that ended the list.
5042
CP FEH FE FE
Compare Register A against FEH, a link to an extended entry.
5044
If the Z FLAG is set (an extended entry follows), JUMP back to 5013H to free it as well.
5046
GOSUB to 50A2H to write the granule allocation table from 5100H.
5049
RET C9
RETurn (through 4CF0H) with Register A and the flags of the write: the Z FLAG when done, else error 15H.

504AH - Freeing a Segment

Clears in the granule allocation table at 5100H the bits of the granules of the segment Register E (cylinder), Register D (bits 7-5 the first granule, bits 4-0 the number less 1). The segment may run on into the next cylinders: the granule count wraps at the granules per cylinder (DCT+10H at Index Register IY).

504A
PUSH DE D5
Save Register Pair DE to the top of the stack.
504B
PUSH HL E5
Save Register Pair HL to the top of the stack.
504C
LD L,E 6B
Load Register L with Register E, the cylinder.
504D
LD H,51H 26 51
Load Register H with 51H: Register Pair HL = 5100H + the cylinder, its byte in the granule allocation table.
504F
LD A,D 7A
Load Register A with Register D, the second byte of the segment descriptor.
5050
AND 1FH E6 1F
AND Register A with 1FH, the number of granules less 1.
5052
LD E,A 5F
Load Register E with Register A, the number of granules less 1.
5053
INC E 1C
INCrement Register E by 1: Register E = the number of granules.
5054
XOR D AA
XOR Register A (bits 4-0 of Register D) with Register D: Register A = Register D AND E0H, the first granule in bits 7-5.
5055
RLCA 07
Rotate Register A left one bit (bits 7-5 move towards bits 2-0).
5056
RLCA 07
Rotate Register A left one bit (bits 7-5 move towards bits 2-0).
5057
RLCA 07
Rotate Register A left one bit: Register A = the first granule, 0-7.
5058
PUSH AF F5
Save Register Pair AF (Register A the granule) to the top of the stack.
5059
GOSUB to 506BH to clear bit Register A of the table byte at Register Pair HL.
505C
POP AF F1
Restore Register Pair AF from the top of the stack.
505D
INC A 3C
INCrement Register A by 1 to the next granule.
505E
CP (IY+10H) FD BE 10
Compare Register A against the granules per cylinder at Index Register IY+10H (DCT+10H).
5061
If the C FLAG is set (still in this cylinder), JUMP to 5065H.
5063
XOR A AF
Set Register A to 00H by XORing it with itself: granule 0 ...
5064
INC L 2C
... of the next cylinder: INCrement Register L by 1 to its table byte.
5065
DEC E 1D
DECrement Register E by 1, the granules still to free.
5066
If the NZ FLAG is set, JUMP back to 5058H for the next granule.
5068
POP HL E1
Restore Register Pair HL from the top of the stack.
5069
POP DE D1
Restore Register Pair DE from the top of the stack.
506A
RET C9
RETurn with Register Pairs DE and HL as they came in.

506BH - Freeing a Granule

Clears bit Register A (0-7) of the byte at Register Pair HL, by storing the second byte of a RES n,(HL) instruction (86H + n times 8) at 5076H and running it.

506B
AND 07H E6 07
AND Register A with 07H to keep the bit number, 0-7, of the granule.
506D
RLCA 07
Rotate Register A left one bit (the bit number moves towards bits 5-3).
506E
RLCA 07
Rotate Register A left one bit (the bit number moves towards bits 5-3).
506F
RLCA 07
Rotate Register A left one bit: Register A = the bit number times 8, bits 5-3 of a RES n,(HL) opcode.
5070
OR 86H F6 86
OR Register A with 86H, the second byte of RES 0,(HL).
5072
LD (5076H),A 32 76 50
Store Register A to 5076H, the second byte of the instruction at 5075H.
5075
RES 0,(HL) CB 86
Reset bit n of the byte at Register Pair HL; n is set by the byte 5072H stores to 5076H (86H here is RES 0,(HL)).
5077
RET C9
RETurn with the granule's bit cleared in the byte at Register Pair HL.

5078H - The Date for the Directory Entry

Returns Register B = the month (bits 3-0 of 4046H) and Register C = the day (bits 4-0 of 4045H) in bits 7-3 and bits 2-0 of the year (4044H, the year less 1900) in bits 2-0, the form of an entry's +02H; Register A returns the month as well. The manual gives bits 2-0 as the year less 1980: 80 is a multiple of 8, so the two agree for 1980-1987.

5078
PUSH HL E5
Save Register Pair HL to the top of the stack.
5079
LD HL,4044H 21 44 40
Point Register Pair HL to 4044H, DATE$ in SYS0/SYS (the year less 1900, the day, the month).
507C
LD A,(HL) 7E
Load Register A with the year at Register Pair HL (4044H).
507D
INC HL 23
INCrement Register Pair HL by 1 to 4045H, the day.
507E
AND 07H E6 07
AND Register A with 07H, bits 2-0 of the year.
5080
LD C,A 4F
Load Register C with Register A, bits 2-0 of the year.
5081
LD A,(HL) 7E
Load Register A with the day at Register Pair HL (4045H).
5082
INC HL 23
INCrement Register Pair HL by 1 to 4046H, the month.
5083
AND 1FH E6 1F
AND Register A with 1FH to keep bits 4-0, the day, 1-31.
5085
RLCA 07
Rotate Register A left one bit (the day moves towards bits 7-3).
5086
RLCA 07
Rotate Register A left one bit (the day moves towards bits 7-3).
5087
RLCA 07
Rotate Register A left one bit: the day in bits 7-3.
5088
OR C B1
OR Register A with Register C, the year bits.
5089
LD C,A 4F
Load Register C with Register A: Register C = the day and the year.
508A
LD A,(HL) 7E
Load Register A with the month at Register Pair HL (4046H).
508B
AND 0FH E6 0F
AND Register A with 0FH to keep bits 3-0, the month, 1-12.
508D
LD B,A 47
Load Register B with Register A, the month for the entry's +01H.
508E
POP HL E1
Restore Register Pair HL from the top of the stack.
508F
RET C9
RETurn with Register B (and Register A) the month and Register C the day and year.

5090H - Reading and Writing the Tables

5090H reads and 50A2H writes the granule allocation table (directory sector 0) of drive Register C through 5100H; 50B4H reads and 50C6H writes the hash index table (directory sector 1) through 4200H, the system buffer. Each returns the Z FLAG when done, or the NZ FLAG with error 14H, 15H, 16H or 17H.

5090
PUSH DE D5
Save Register Pair DE to the top of the stack.
5091
PUSH HL E5
Save Register Pair HL to the top of the stack.
5092
LD E,00H 1E 00
Load Register E with 00H, directory sector 0, the granule allocation table.
5094
LD HL,5100H 21 00 51
Point Register Pair HL to 5100H, the buffer for the table, after the end of SYS3/SYS.
5097
LD A,06H 3E 06
Load Register A with 06H, the SREAD function of DISKIO%, which reads sector Register E of the directory cylinder.
5099
GOSUB to 4485H (DISKIO%) in SYS0/SYS to read the table of drive Register C into the buffer at Register Pair HL (5100H).
509C
POP HL E1
Restore Register Pair HL from the top of the stack.
509D
POP DE D1
Restore Register Pair DE from the top of the stack.
509E
RET Z C8
If the Z FLAG is set (read), RETurn with Register A from DISKIO%.
509F
LD A,14H 3E 14
Load Register A with 14H, the error code Gat read error; the NZ FLAG stays set.
50A1
RET C9
RETurn with Register A = 14H and the NZ FLAG set.
50A2
PUSH DE D5
Save Register Pair DE to the top of the stack.
50A3
PUSH HL E5
Save Register Pair HL to the top of the stack.
50A4
LD E,00H 1E 00
Load Register E with 00H, directory sector 0, the granule allocation table.
50A6
LD HL,5100H 21 00 51
Point Register Pair HL to 5100H, the buffer that holds the table.
50A9
LD A,07H 3E 07
Load Register A with 07H, the SWRITE function of DISKIO%, which writes sector Register E of the directory cylinder.
50AB
GOSUB to 4485H (DISKIO%) in SYS0/SYS to write the buffer at Register Pair HL (5100H) to the table of drive Register C.
50AE
POP HL E1
Restore Register Pair HL from the top of the stack.
50AF
POP DE D1
Restore Register Pair DE from the top of the stack.
50B0
RET Z C8
If the Z FLAG is set (written), RETurn with Register A from DISKIO%.
50B1
LD A,15H 3E 15
Load Register A with 15H, the error code Gat write error; the NZ FLAG stays set.
50B3
RET C9
RETurn with Register A = 15H and the NZ FLAG set.
50B4
PUSH DE D5
Save Register Pair DE to the top of the stack.
50B5
PUSH HL E5
Save Register Pair HL to the top of the stack.
50B6
LD E,01H 1E 01
Load Register E with 01H, directory sector 1, the hash index table.
50B8
LD HL,4200H 21 00 42
Point Register Pair HL to 4200H, the system sector buffer.
50BB
LD A,06H 3E 06
Load Register A with 06H, the SREAD function of DISKIO%.
50BD
GOSUB to 4485H (DISKIO%) in SYS0/SYS to read the hash index table of drive Register C into the buffer at Register Pair HL (4200H).
50C0
POP HL E1
Restore Register Pair HL from the top of the stack.
50C1
POP DE D1
Restore Register Pair DE from the top of the stack.
50C2
RET Z C8
If the Z FLAG is set (read), RETurn with Register A from DISKIO%.
50C3
LD A,16H 3E 16
Load Register A with 16H, the error code Hit read error; the NZ FLAG stays set.
50C5
RET C9
RETurn with Register A = 16H and the NZ FLAG set.
50C6
PUSH DE D5
Save Register Pair DE to the top of the stack.
50C7
PUSH HL E5
Save Register Pair HL to the top of the stack.
50C8
LD E,01H 1E 01
Load Register E with 01H, directory sector 1, the hash index table.
50CA
LD HL,4200H 21 00 42
Point Register Pair HL to 4200H, the buffer that holds the table.
50CD
LD A,07H 3E 07
Load Register A with 07H, the SWRITE function of DISKIO%.
50CF
GOSUB to 4485H (DISKIO%) in SYS0/SYS to write the buffer at Register Pair HL (4200H) to the hash index table of drive Register C.
50D2
POP HL E1
Restore Register Pair HL from the top of the stack.
50D3
POP DE D1
Restore Register Pair DE from the top of the stack.
50D4
RET Z C8
If the Z FLAG is set (written), RETurn with Register A from DISKIO%.
50D5
LD A,17H 3E 17
Load Register A with 17H, the error code Hit write error; the NZ FLAG stays set.
50D7
RET C9
RETurn with Register A = 17H and the NZ FLAG set. 50D7H is the last byte of SYS3/SYS.

5100H - The Table Buffer

Not in the file: the granule allocation table of the drive is read here (5090H) and written from here (50A2H), one byte per cylinder from 5100H, bit n set when granule n of the cylinder is in use.

5100-51FF
DEFS 256
The buffer for directory sector 0, the granule allocation table (byte 5100H + the cylinder), cleared bit by bit by 506BH.