DOSPLUS 3.5 for the Model III - SYS3/SYS Disassembled

Page Customization

Introduction/Summary

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

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, 733 bytes, from 4E00H to 50DCH, 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 4300HH.

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).
4E4EHH-4F79HHThe directory entry brought up to date and the granules beyond the end of the file given back (4E4EH).
4F7AHH-4FE8HHRoutine 6 and the file specification put back into the control block (4F7AH, 4F87H).
4FE9HH-507CHHKILL@, routine 5 and the freeing of segments and granules (4FE9H, 500EH, 504FH, 5070H).
507DHH-50DCHThe date for an entry and the reading and writing of the two tables (507DH, 5095H).

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 4497H, 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 (4E3FH).

The directory entry is then read (4E4EH). 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$ (507DH); 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 (4EAAH). 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 (4F3FH). 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 (4F87H). The password is not put back. Routine 6 does only this part, for an open file, without closing it (4F7AH).

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 (4FE9H). Routine 5 then frees the file: for each of its entries the segments are cleared in the allocation table (504FH), 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 (5003H).

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

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, which would store an @ and a name, is not reached.

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.

Differences from the Model I

The code is the same as the Model I SYS3/SYS. The Model III file has one more byte 00H and the instruction LD (IX+00H),40H in the code that is not reached (4E17H-4E1EH), so everything from 4E1FH on is 5 bytes higher, and it uses the Model III addresses of SYS0/SYS: the system buffer 4300H, DCTTBL 44E8H, DATE$ 421AH, and the jump vectors 448BH, 448EH, 4494H, 4497H, 449AH, 449DH, 44A3H and 4451H (DIVD@) in place of the Model I's direct calls.

Variables

Memory Outside SYS3/SYS

Address
Size
Contents
4300HH-42FFHH
256 bytes
System Sector Buffer
Directory sectors (4E57H, 4F90H) and the hash index table (50B9H).
44E8HH
32 bytes
DCTTBL
Drive names at +02H (4FCBH).
421AHH-421CHH
3 bytes
DATE$
The year less 1900, the day and the month (507DH).

Work Areas

Address
Size
Contents
5100H-51FFH
256 bytes
Allocation Table Buffer
5100H
4F5CHH
1 byte
Logical File Number
Of the entry before a freed extended entry: the operand of LD B,n (4F4DH, 4F5BH).
507BHH
1 byte
RES Opcode
The second byte of RES n,(HL) (5077H).
5100H + cylinder
1 byte
Cylinder Byte
Bit n set when granule n is in use (4F1BH, 5051H).

The Directory Entry (as SYS3/SYS uses it)

OffsetContents
+00HBit 7 extended entry, bit 4 active (4E5BH, 4F3BH, 5032H).
+01HBit 7 non-shrinkable, bit 6 modified, bits 3-0 the month; in an extended entry, the logical file number of the entry before (4E72H, 4F4BH).
+02HDay (bits 7-3) and year (bits 2-0) (4E82H).
+03HThe end of file byte (4E87H).
+05H-0FHThe name and extension (4F98H).
+14H-15HThe number of sectors (4E9AH).
+16H-1DHFour segment descriptors: the cylinder, then bits 7-5 the first granule and bits 4-0 the granules less 1 (4EB4H).
+1EH-1FHFFH FFH, or FEH and the logical file number of an extended entry (4F67H).

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 (4FECH).
+02HBit 7 non-shrinkable, bit 6 modified (4E64H, 4EAAH).
+06HThe drive.
+07HThe logical file number.
+08HThe end of file byte.
+0CH-0DHThe ending record number (4E8DH, 4ED5H).

Outside Routines

AddressContents
448EHSYS0/SYS: the file control block check and wrapper (4E37H, 4F7AH, 4FE9H).
448BHSYS0/SYS: the wrapper entered after the check (4E13H, 500EH).
4497HSYS0/SYS: write the buffer when it holds updated bytes (4E3AH).
4488HSYS0/SYS: DISKIO%, functions 6 (SREAD) and 7 (SWRITE) (5095H).
44A3HSYS0/SYS: LOCDCT% (4E54H, 5015H).
449AH, 449DHSYS0/SYS: read and write the directory sector of a logical file number.
4451HSYS0/SYS: DIVD@ (4EE5H).
4494HSYS0/SYS: 8 bit divide (4F12H).

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 49D3H-49E6H) 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 56E9H). 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 4D5FH-4D6CH).
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 4FE9H E9 4F
Routine 4: 4FE9H, KILL@, which removes the open file of the control block at Register Pair DE.
4E06-4E07
DEFW 500EH 0E 50
Routine 5: 500EH, 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 4F7AH 7A 4F
Routine 6: 4F7AH, 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 (49E7H) 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 4E37H.
4E13
Not an open file: GOSUB to 448BH in SYS0/SYS, a JUMP to 4CE9H, 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 4CFAH, which restores them.
4E16
RET C9
RETurn through 4CFAH with Register A = 00H: a device or a control block that is not open is left as it is. The bytes up to 4E36H are not reached (no jump in DOSPLUS goes to them).
4E17-4E1A
DEFB 00H,00H,00H,00H 00 00 00 00
Four NOPs, not reached (the Model I SYS3/SYS has three here and no LD (IX+00H),40H).
4E1B
LD (IX+00H),40H DD 36 00 40
Not reached: store 40H, an @, to the first byte of the control block at Index Register IX+00H, the start of a device specification.
4E1F
LD A,(IX+03H) DD 7E 03
Not reached: load Register A with the byte at Index Register IX+03H (FCB+03H).
4E22
LD (IX+01H),A DD 77 01
Not reached: store Register A to Index Register IX+01H (FCB+01H).
4E25
LD A,(IX+04H) DD 7E 04
Not reached: load Register A with the byte at Index Register IX+04H (FCB+04H).
4E28
CP 20H FE 20
Not reached: compare Register A against 20H, a space.
4E2A
Not reached: if the Z FLAG is set (a space), JUMP to 4E31H.
4E2C
LD (IX+02H),A DD 77 02
Not reached: store Register A to Index Register IX+02H (FCB+02H).
4E2F
INC IX DD 23
Not reached: INCrement Index Register IX by 1, so the end mark goes one byte further on.
4E31
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.
4E35
XOR A AF
Not reached: set Register A to 00H by XORing it with itself, and set the Z FLAG.
4E36
RET C9
Not reached: RETurn to the caller with Register A = 00H and the Z FLAG set.
4E37
An open file: GOSUB to 448EH 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 4CFAH, which restores them.
4E3A
GOSUB to 4497H 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.
4E3D
If the Z FLAG is set (written, or nothing to write), JUMP to 4E4EH to bring the directory entry up to date.
4E3F
CP 1BH FE 1B
Compare Register A, the error code of the write, against 1BH, Disk space full.
4E41
RET NZ C0
If the NZ FLAG is set (any other error), RETurn with the error code in Register A.
4E42
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.
4E46
GOSUB to 4E4EH to bring the directory entry up to date and put the name back into the control block.
4E49
RET NZ C0
If the NZ FLAG is set (an error from the directory), RETurn with its code in Register A.
4E4A
LD A,1BH 3E 1B
Load Register A with 1BH, the error code Disk space full.
4E4C
OR A B7
OR Register A with itself to set the NZ FLAG.
4E4D
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.

4E4EH - 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 (4EAAH on). It ends at 4F87H, which puts the file name back into the control block.

4E4E
LD B,(IX+07H) DD 46 07
Load Register B with the logical file number at Index Register IX+07H (FCB+07H).
4E51
LD C,(IX+06H) DD 4E 06
Load Register C with the drive at Index Register IX+06H (FCB+06H).
4E54
GOSUB to 44A3H (LOCDCT%) in SYS0/SYS: Index Register IY = the drive control table of drive Register C, for the granule sizes at 4EE2H and 4F0FH.
4E57
GOSUB to 449AH in SYS0/SYS to read the directory sector of logical file number Register B on drive Register C into 4300H; Register Pair HL returns the entry's address.
4E5A
RET NZ C0
If the NZ FLAG is set (a read error), RETurn with the error code in Register A.
4E5B
BIT 4,(HL) CB 66
Test bit 4 of the entry's first byte at Register Pair HL, the active flag.
4E5D
If the NZ FLAG is set (the entry is in use), JUMP to 4E63H.
4E5F
LD A,18H 3E 18
Load Register A with 18H, the error code File not in directory.
4E61
OR A B7
OR Register A with itself to set the NZ FLAG.
4E62
RET C9
RETurn with Register A = 18H and the NZ FLAG set.
4E63
PUSH HL E5
Save Register Pair HL, the entry's address, to the top of the stack.
4E64
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.
4E68
If the NZ FLAG is set (written), JUMP to 4E71H to bring the entry up to date.
4E6A
LD A,16H 3E 16
Not written: load Register A with 16H, the offset of the first segment descriptor in an entry.
4E6C
ADD A,L 85
ADD the low byte of the entry's address in Register L to Register A.
4E6D
LD L,A 6F
Load Register L with Register A: Register Pair HL = the entry's +16H.
4E6E
POP AF F1
Restore Register Pair AF from the top of the stack: it drops the entry's address saved at 4E63H.
4E6F
JUMP to 4EAAH: the entry is not written, but the granules beyond the end are given back all the same.
4E71
POP HL E1
Restore Register Pair HL from the top of the stack: the entry's address.
4E72
LD A,(IX+02H) DD 7E 02
Load Register A with the flags at Index Register IX+02H (FCB+02H).
4E75
AND C0H E6 C0
AND Register A with C0H, keeping bit 7 (non-shrinkable) and bit 6 (modified).
4E77
INC L 2C
INCrement Register L by 1 to the entry's +01H (bits 7 non-shrinkable, 6 modified, 3-0 the month).
4E78
OR (HL) B6
OR Register A with the entry's +01H at Register Pair HL: bit 6, the modified flag, is now set.
4E79
AND F0H E6 F0
AND Register A with F0H to clear bits 3-0, the old month.
4E7B
LD (HL),A 77
Store Register A to the entry's +01H at Register Pair HL.
4E7C
GOSUB to 507DH: Register B = the month, Register C = the day (bits 7-3) and the year (bits 2-0), from DATE$.
4E7F
OR (HL) B6
OR Register A, the month (507DH 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 4E7BH, bits 3-0 the month.
4E80
LD (HL),A 77
Store Register A to the entry's +01H at Register Pair HL: the modified flag and the month.
4E81
INC L 2C
INCrement Register L by 1 to the entry's +02H.
4E82
LD (HL),C 71
Store Register C, the day and the year, to the entry's +02H at Register Pair HL.
4E83
INC L 2C
INCrement Register L by 1 to the entry's +03H.
4E84
LD A,(IX+08H) DD 7E 08
Load Register A with the end of file byte at Index Register IX+08H (FCB+08H).
4E87
LD (HL),A 77
Store Register A to the entry's +03H at Register Pair HL, the end of file byte.
4E88
INC L 2C
INCrement Register L by 1 to the entry's +04H.
4E89
LD A,10H 3E 10
Load Register A with 10H, the distance from +04H to +14H.
4E8B
ADD A,L 85
ADD the low byte of the address in Register L to Register A.
4E8C
LD L,A 6F
Load Register L with Register A: Register Pair HL = the entry's +14H, the number of sectors.
4E8D
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).
4E90
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.
4E93
LD A,(IX+08H) DD 7E 08
Load Register A with the end of file byte at Index Register IX+08H (FCB+08H).
4E96
OR A B7
OR Register A with itself to set the flags: the Z FLAG when the end of file byte is 00H.
4E97
If the Z FLAG is set (the file ends on a sector boundary), JUMP to 4E9AH.
4E99
INC DE 13
INCrement Register Pair DE by 1: the last sector holds part of the file and counts as well.
4E9A
LD (HL),E 73
Store Register E, the low byte of the number of sectors, to the entry's +14H at Register Pair HL.
4E9B
INC L 2C
INCrement Register L by 1 to the entry's +15H.
4E9C
LD (HL),D 72
Store Register D, the high byte, to the entry's +15H at Register Pair HL.
4E9D
INC L 2C
INCrement Register L by 1 to the entry's +16H, the first segment descriptor.
4E9E
PUSH HL E5
Save Register Pair HL (the entry's +16H) to the top of the stack.
4E9F
LD B,(IX+07H) DD 46 07
Load Register B with the logical file number at Index Register IX+07H (FCB+07H) again (507DH changed Register Pair BC).
4EA2
LD C,(IX+06H) DD 4E 06
Load Register C with the drive at Index Register IX+06H (FCB+06H).
4EA5
GOSUB to 449DH in SYS0/SYS to write the directory sector of logical file number Register B on drive Register C from 4300H.
4EA8
POP HL E1
Restore Register Pair HL from the top of the stack: the entry's +16H.
4EA9
RET NZ C0
If the NZ FLAG is set (a write error), RETurn with the error code in Register A.
4EAA
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.
4EAE
If the NZ FLAG is set (non-shrinkable), JUMP to 4F87H: the granules are kept and the name goes back into the control block.
4EB1
LD DE,0000H 11 00 00
Load Register Pair DE with 0000H, the count of the granules the file holds.
4EB4
LD A,(HL) 7E
Load Register A with the cylinder of the segment descriptor at Register Pair HL.
4EB5
INC L 2C
INCrement Register L by 1 to the descriptor's second byte.
4EB6
CP FEH FE FE
Compare Register A against FEH: FEH (a link to an extended entry) and FFH (the end) are not cylinders.
4EB8
If the NC FLAG is set (FEH or FFH), JUMP to 4EC6H.
4EBA
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).
4EBB
INC L 2C
INCrement Register L by 1 to the next descriptor.
4EBC
AND 1FH E6 1F
AND Register A with 1FH to keep the number of granules less 1.
4EBE
INC A 3C
INCrement Register A by 1: the number of granules in the segment.
4EBF
ADD A,E 83
ADD Register E, the low byte of the count, to Register A.
4EC0
LD E,A 5F
Load Register E with Register A, the new low byte of the count.
4EC1
If the NC FLAG is set (no carry), JUMP back to 4EB4H for the next descriptor.
4EC3
INC D 14
INCrement Register D by 1 for the carry into the high byte of the count.
4EC4
JUMP back to 4EB4H for the next descriptor, with Register Pair DE the count so far.
4EC6
If the NZ FLAG is set (FFH, the end of the list), JUMP to 4ED3H with Register Pair DE = the granules the file holds.
4EC8
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.
4EC9
GOSUB to 449AH in SYS0/SYS to read the directory sector of logical file number Register B into 4300H; Register Pair HL returns the extended entry's address.
4ECC
RET NZ C0
If the NZ FLAG is set (a read error), RETurn with the error code in Register A.
4ECD
LD A,L 7D
Load Register A with Register L, the low byte of the extended entry's address.
4ECE
ADD A,16H C6 16
ADD 16H to Register A, the offset of its first segment descriptor.
4ED0
LD L,A 6F
Load Register L with Register A: Register Pair HL = the extended entry's +16H.
4ED1
JUMP back to 4EB4H to count its segments. Register B and the buffer now hold the last entry of the file.
4ED3
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.
4ED4
PUSH HL E5
Save Register Pair HL (the byte after the end mark) to the top of the stack.
4ED5
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).
4ED8
LD H,(IX+0DH) DD 66 0D
Load Register H with the high byte at Index Register IX+0DH.
4EDB
LD A,(IX+08H) DD 7E 08
Load Register A with the end of file byte at Index Register IX+08H (FCB+08H).
4EDE
OR A B7
OR Register A with itself to set the flags: the Z FLAG when the end of file byte is 00H.
4EDF
If the Z FLAG is set (the file ends on a sector boundary), JUMP to 4EE2H.
4EE1
INC HL 23
INCrement Register Pair HL by 1: Register Pair HL = the number of sectors the file uses.
4EE2
LD A,(IY+0FH) FD 7E 0F
Load Register A with the sectors per granule at Index Register IY+0FH (DCT+0FH).
4EE5
GOSUB to 4451H (DIVD@) in SYS0/SYS: Register Pair HL = the sectors divided by the sectors per granule, Register A = the remainder.
4EE8
OR A B7
OR Register A with itself to test the remainder; this also clears the C FLAG for the SBC at 4EEDH.
4EE9
If the Z FLAG is set (no remainder), JUMP to 4EECH.
4EEB
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.
4EEC
EX DE,HL EB
Exchange Register Pairs DE and HL: Register Pair HL = the granules held, Register Pair DE = the granules needed.
4EED
SBC HL,DE ED 52
SUBtract Register Pair DE from Register Pair HL (the C FLAG is clear): the granules held beyond the end.
4EEF
EX DE,HL EB
Exchange Register Pairs DE and HL: Register Pair DE = the granules to give back.
4EF0
POP HL E1
Restore Register Pair HL from the top of the stack: the byte after the end mark.
4EF1
POP BC C1
Restore Register Pair BC from the top of the stack.
4EF2
If the Z FLAG is set (no granule to give back), JUMP to 4F87H.
4EF5
If the C FLAG is set (fewer granules than the file needs), JUMP to 4F87H: nothing is given back.
4EF8
GOSUB to 5095H to read the granule allocation table of drive Register C into 5100H.
4EFB
RET NZ C0
If the NZ FLAG is set (a read error), RETurn with Register A = 14H, Gat read error.
4EFC
DEC L 2D
DECrement Register L by 1 to the end mark FFH.
4EFD
DEC L 2D
DECrement Register L by 1 to the second byte of the last segment descriptor.
4EFE
LD A,D 7A
Load Register A with Register D, the high byte of the granules still to give back.
4EFF
OR E B3
OR Register A with Register E, the low byte: the Z FLAG when Register Pair DE is 0000H.
4F00
If the Z FLAG is set (none left), JUMP to 4F70H to write the entry and the table.
4F02
PUSH DE D5
Save Register Pair DE, the granules still to give back, to the top of the stack.
4F03
LD A,(HL) 7E
Load Register A with the descriptor's second byte at Register Pair HL.
4F04
AND E0H E6 E0
AND Register A with E0H, keeping bits 7-5, the segment's first granule within its cylinder.
4F06
RLCA 07
Rotate Register A left one bit (bits 7-5 move towards bits 2-0).
4F07
RLCA 07
Rotate Register A left one bit (bits 7-5 move towards bits 2-0).
4F08
RLCA 07
Rotate Register A left one bit: Register A = the first granule, 0-7.
4F09
LD E,A 5F
Load Register E with Register A, the first granule.
4F0A
LD A,(HL) 7E
Load Register A with the descriptor's second byte at Register Pair HL again.
4F0B
AND 1FH E6 1F
AND Register A with 1FH, the number of granules less 1.
4F0D
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.
4F0E
LD E,A 5F
Load Register E with Register A, the number of the segment's last granule.
4F0F
LD A,(IY+10H) FD 7E 10
Load Register A with the granules per cylinder at Index Register IY+10H (DCT+10H).
4F12
GOSUB to 4494H 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).
4F15
DEC L 2D
DECrement Register L by 1 to the descriptor's cylinder.
4F16
ADD A,(HL) 86
ADD the segment's first cylinder at Register Pair HL to Register A: the cylinder of the last granule.
4F17
INC L 2C
INCrement Register L by 1 back to the descriptor's second byte.
4F18
LD D,A 57
Load Register D with Register A, the cylinder.
4F19
PUSH BC C5
Save Register Pair BC to the top of the stack.
4F1A
PUSH HL E5
Save Register Pair HL, the descriptor, to the top of the stack.
4F1B
LD L,D 6A
Load Register L with Register D, the cylinder.
4F1C
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.
4F1E
LD A,E 7B
Load Register A with Register E, the granule within the cylinder.
4F1F
GOSUB to 5070H to clear bit Register A of the byte at Register Pair HL: the granule is free.
4F22
POP HL E1
Restore Register Pair HL from the top of the stack: the descriptor.
4F23
POP BC C1
Restore Register Pair BC from the top of the stack.
4F24
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.
4F25
LD A,(HL) 7E
Load Register A with the descriptor's second byte at Register Pair HL.
4F26
INC A 3C
INCrement Register A by 1, so that bits 4-0 of 1FH become 00H.
4F27
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.
4F29
POP DE D1
Restore Register Pair DE from the top of the stack: the granules still to give back.
4F2A
If the NZ FLAG is set (the segment still holds granules), JUMP to 4F6DH for the next granule.
4F2C
LD (HL),FFH 36 FF
The segment is empty: store FFH to the descriptor's second byte at Register Pair HL.
4F2E
DEC L 2D
DECrement Register L by 1 to the descriptor's cylinder.
4F2F
LD (HL),FFH 36 FF
Store FFH to the cylinder at Register Pair HL: this descriptor is now the end of the list.
4F31
DEC L 2D
DECrement Register L by 1 to the second byte of the descriptor before it.
4F32
LD A,L 7D
Load Register A with Register L, the low byte of the address.
4F33
AND 1FH E6 1F
AND Register A with 1FH: the offset within the 32 byte entry.
4F35
CP 16H FE 16
Compare Register A against 16H, the offset of the first descriptor.
4F37
If the NC FLAG is set (the descriptor before is in this entry), JUMP to 4F6DH for the next granule.
4F39
XOR L AD
XOR Register A (the offset) with Register L: Register A = Register L AND E0H, the start of the entry.
4F3A
LD L,A 6F
Load Register L with Register A: Register Pair HL = the entry, which has no segment left.
4F3B
BIT 7,(HL) CB 7E
Test bit 7 of the entry's first byte at Register Pair HL, the extended entry flag (FXDE).
4F3D
If the Z FLAG is set (the file's first entry), JUMP to 4F70H to write the entry and the table.
4F3F
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.
4F41
GOSUB to 449DH in SYS0/SYS to write the directory sector of logical file number Register B (the extended entry) from 4300H.
4F44
RET NZ C0
If the NZ FLAG is set (a write error), RETurn with the error code in Register A.
4F45
LD A,B 78
Load Register A with Register B, the logical file number of the freed entry.
4F46
AND E0H E6 E0
AND Register A with E0H: bits 7-5 times 32, the entry's offset in its sector.
4F48
LD L,A 6F
Load Register L with Register A, the low byte of the entry's address in the buffer.
4F49
LD H,43H 26 43
Load Register H with 43H: Register Pair HL = the freed entry in the buffer at 4300H.
4F4B
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.
4F4C
LD A,(HL) 7E
Load Register A with the logical file number of the entry before at Register Pair HL.
4F4D
LD (4F5CH),A 32 5C 4F
Store Register A to 4F5CH, the operand of the LD B,n at 4F5BH.
4F50
GOSUB to 50B9H to read the hash index table of drive Register C into 4300H.
4F53
RET NZ C0
If the NZ FLAG is set (a read error), RETurn with Register A = 16H, Hit read error.
4F54
LD L,B 68
Load Register L with Register B, the freed entry's logical file number: Register Pair HL = 4300H + the number, its byte in the hash index table.
4F55
LD (HL),00H 36 00
Store 00H to the hash index byte at Register Pair HL: the entry is free.
4F57
GOSUB to 50CBH to write the hash index table from 4300H.
4F5A
RET NZ C0
If the NZ FLAG is set (a write error), RETurn with Register A = 17H, Hit write error.
4F5B
LD B,00H 06 00
Load Register B with the logical file number of the entry before: the operand at 4F5CH is 00H in the file and is stored at 4F4DH before this runs.
4F5D
GOSUB to 449AH in SYS0/SYS to read the directory sector of logical file number Register B into 4300H.
4F60
RET NZ C0
If the NZ FLAG is set (a read error), RETurn with the error code in Register A.
4F61
LD A,B 78
Load Register A with Register B, the logical file number.
4F62
AND E0H E6 E0
AND Register A with E0H, the entry's offset in its sector.
4F64
ADD A,1FH C6 1F
ADD 1FH to Register A: the entry's last byte.
4F66
LD L,A 6F
Load Register L with Register A: Register Pair HL = the entry's +1FH.
4F67
LD (HL),FFH 36 FF
Store FFH to the entry's +1FH at Register Pair HL (the logical file number of the link).
4F69
DEC L 2D
DECrement Register L by 1 to the entry's +1EH.
4F6A
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.
4F6C
DEC L 2D
DECrement Register L by 1 to the entry's +1DH, the second byte of its last descriptor.
4F6D
DEC DE 1B
DECrement Register Pair DE by 1: one granule less to give back.
4F6E
JUMP back to 4EFEH for the next granule, with Register Pair DE one less.
4F70
GOSUB to 449DH in SYS0/SYS to write the directory sector of the entry in the buffer (logical file number Register B).
4F73
RET NZ C0
If the NZ FLAG is set (a write error), RETurn with the error code in Register A.
4F74
GOSUB to 50A7H to write the granule allocation table from 5100H.
4F77
RET NZ C0
If the NZ FLAG is set (a write error), RETurn with Register A = 15H, Gat write error.
4F78
JUMP to 4F87H to put the name back into the control block.

4F7AH - Routine 6 - Putting the Name Back

Requested with code 26H (SYS11/SYS, its 56E9H) 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.

4F7A
GOSUB to 448EH 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.
4F7D
LD C,(IX+06H) DD 4E 06
Load Register C with the drive at Index Register IX+06H (FCB+06H).
4F80
LD B,(IX+07H) DD 46 07
Load Register B with the logical file number at Index Register IX+07H (FCB+07H).
4F83
GOSUB to 449AH in SYS0/SYS to read the directory sector of logical file number Register B on drive Register C into 4300H.
4F86
RET NZ C0
If the NZ FLAG is set (a read error), RETurn with the error code in Register A.

4F87H - 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.

4F87
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).
4F8A
XOR B A8
XOR Register A with Register B, the logical file number of the entry whose sector is in the buffer.
4F8B
LD B,(IX+07H) DD 46 07
Load Register B with the file's logical file number at Index Register IX+07H.
4F8E
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.
4F90
If the NZ FLAG is set (another sector), GOSUB to 449AH in SYS0/SYS to read the directory sector of logical file number Register B on drive Register C into 4300H.
4F93
RET NZ C0
If the NZ FLAG is set (a read error), RETurn with the error code in Register A.
4F94
LD A,(IX+06H) DD 7E 06
Load Register A with the drive at Index Register IX+06H (FCB+06H).
4F97
PUSH AF F5
Save Register Pair AF (Register A the drive) to the top of the stack.
4F98
LD A,(IX+07H) DD 7E 07
Load Register A with the logical file number at Index Register IX+07H.
4F9B
AND E0H E6 E0
AND Register A with E0H, the entry's offset in its sector.
4F9D
ADD A,05H C6 05
ADD 05H to Register A, the offset of the name in an entry.
4F9F
LD L,A 6F
Load Register L with Register A, the low byte of the address of the name in the buffer.
4FA0
LD H,43H 26 43
Load Register H with 43H: Register Pair HL = the entry's name in the buffer at 4300H.
4FA2
PUSH IX DD E5
Save Index Register IX, the control block, to the top of the stack.
4FA4
POP DE D1
Restore Register Pair DE from the top of the stack: Register Pair DE = the control block.
4FA5
LD B,08H 06 08
Load Register B with 08H, the length of the name.
4FA7
LD A,(HL) 7E
Load Register A with the name character at Register Pair HL.
4FA8
CP 20H FE 20
Compare Register A against 20H, a space (the padding after the name).
4FAA
If the Z FLAG is set (the end of the name), JUMP to 4FB1H.
4FAC
LD (DE),A 12
Store the character in Register A to the control block at Register Pair DE.
4FAD
INC L 2C
INCrement Register L by 1 to the next character of the entry.
4FAE
INC DE 13
INCrement Register Pair DE by 1 to the next byte of the control block.
4FAF
DECrement Register B and loop back to 4FA7H while Register B is not zero.
4FB1
LD A,L 7D
Load Register A with Register L, the low byte of the address after the name characters copied.
4FB2
ADD A,B 80
ADD Register B, the characters of the name not looked at, to Register A.
4FB3
LD L,A 6F
Load Register L with Register A: Register Pair HL = the entry's +0DH, the extension.
4FB4
LD A,(HL) 7E
Load Register A with the first character of the extension at Register Pair HL.
4FB5
CP 20H FE 20
Compare Register A against 20H, a space: an entry with no extension has spaces there.
4FB7
If the Z FLAG is set (no extension), JUMP to 4FC9H.
4FB9
LD A,2FH 3E 2F
Load Register A with 2FH, the / before an extension.
4FBB
LD (DE),A 12
Store the / in Register A to the control block at Register Pair DE.
4FBC
INC DE 13
INCrement Register Pair DE by 1 to the next byte of the control block.
4FBD
LD B,03H 06 03
Load Register B with 03H, the length of the extension.
4FBF
LD A,(HL) 7E
Load Register A with the extension character at Register Pair HL.
4FC0
CP 20H FE 20
Compare Register A against 20H, a space (the padding after the extension).
4FC2
If the Z FLAG is set (the end of the extension), JUMP to 4FC9H.
4FC4
LD (DE),A 12
Store the character in Register A to the control block at Register Pair DE.
4FC5
INC L 2C
INCrement Register L by 1 to the next character of the entry.
4FC6
INC DE 13
INCrement Register Pair DE by 1 to the next byte of the control block.
4FC7
DECrement Register B and loop back to 4FBFH while Register B is not zero.
4FC9
POP AF F1
Restore Register Pair AF from the top of the stack: Register A = the drive.
4FCA
PUSH DE D5
Save Register Pair DE, the next byte of the control block, to the top of the stack.
4FCB
LD HL,44E8H 21 E8 44
Point Register Pair HL to 44E8H, DCTTBL in SYS0/SYS (eight 4 byte entries: the DCT address, then the drive's two character name).
4FCE
ADD A,A 87
ADD Register A to itself: Register A = the drive number times 2.
4FCF
ADD A,A 87
ADD Register A to itself: the drive times 4, the offset of its DCTTBL entry.
4FD0
ADD A,02H C6 02
ADD 02H to Register A, the offset of the name in the entry.
4FD2
LD E,A 5F
Load Register E with Register A, the low byte of the offset into DCTTBL.
4FD3
LD D,00H 16 00
Load Register D with 00H: Register Pair DE = the offset.
4FD5
ADD HL,DE 19
ADD Register Pair DE to Register Pair HL: Register Pair HL = the drive's name in DCTTBL.
4FD6
POP DE D1
Restore Register Pair DE from the top of the stack: the next byte of the control block.
4FD7
LD A,3AH 3E 3A
Load Register A with 3AH, the : before a drive.
4FD9
LD (DE),A 12
Store the : in Register A to the control block at Register Pair DE.
4FDA
INC DE 13
INCrement Register Pair DE by 1 to the next byte of the control block.
4FDB
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.
4FDD
LD A,(HL) 7E
Load Register A with the second character of the drive's name at Register Pair HL.
4FDE
CP 20H FE 20
Compare Register A against 20H, a space (a one character name, as "0 ").
4FE0
If the Z FLAG is set (a one character name), JUMP to 4FE4H.
4FE2
LDI ED A0
Copy the second character from Register Pair HL to Register Pair DE, INCrementing both and DECrementing Register Pair BC.
4FE4
LD A,03H 3E 03
Load Register A with 03H, the end of a specification.
4FE6
LD (DE),A 12
Store the 03H in Register A to the control block at Register Pair DE.
4FE7
XOR A AF
Set Register A to 00H by XORing it with itself, and set the Z FLAG.
4FE8
RET C9
RETurn through 4CFAH (the registers restored) with Register A = 00H.

4FE9H - 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.

4FE9
GOSUB to 448EH 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.
4FEC
LD A,(IX+01H) DD 7E 01
Load Register A with the flags at Index Register IX+01H (FCB+01H).
4FEF
AND 07H E6 07
AND Register A with 07H, bits 2-0, the access level the file was opened with.
4FF1
CP 02H FE 02
Compare Register A against 02H: the C FLAG is set for access levels 0 and 1.
4FF3
If the C FLAG is set (access level 0 or 1), JUMP to 4FF9H.
4FF5
LD A,25H 3E 25
Load Register A with 25H, the error code Illegal access attempted to protected file.
4FF7
OR A B7
OR Register A with itself to set the NZ FLAG.
4FF8
RET C9
RETurn through 4CFAH with Register A = 25H and the NZ FLAG set.
4FF9
LD C,(IX+06H) DD 4E 06
Load Register C with the drive at Index Register IX+06H (FCB+06H).
4FFC
LD B,(IX+07H) DD 46 07
Load Register B with the logical file number at Index Register IX+07H (FCB+07H).
4FFF
GOSUB to 5011H, routine 5 after its wrapper call, to give back the file's granules and free its entries.
5002
RET NZ C0
If the NZ FLAG is set (an error), RETurn with the error code in Register A.
5003
PUSH IX DD E5
Save Index Register IX, the control block, to the top of the stack.
5005
POP HL E1
Restore Register Pair HL from the top of the stack: Register Pair HL = the control block.
5006
LD B,20H 06 20
Load Register B with 20H, the 32 bytes of a file control block.
5008
LD (HL),00H 36 00
Store 00H to the control block at Register Pair HL.
500A
INC HL 23
INCrement Register Pair HL by 1 to the next byte of the control block.
500B
DECrement Register B and loop back to 5008H while Register B is not zero.
500D
RET C9
RETurn through 4CFAH with the Z FLAG set: the file is removed and its control block cleared.

500EH - 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 5011H. 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.

500E
GOSUB to 448BH 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 4CFAH.
5011
GOSUB to 5095H to read the granule allocation table of drive Register C into 5100H.
5014
RET NZ C0
If the NZ FLAG is set (a read error), RETurn with Register A = 14H, Gat read error.
5015
GOSUB to 44A3H (LOCDCT%) in SYS0/SYS: Index Register IY = the drive control table of drive Register C, for the granules per cylinder at 5063H.
5018
GOSUB to 449AH in SYS0/SYS to read the directory sector of logical file number Register B on drive Register C into 4300H; Register Pair HL returns the entry's address.
501B
RET NZ C0
If the NZ FLAG is set (a read error), RETurn with the error code in Register A.
501C
LD A,16H 3E 16
Load Register A with 16H, the offset of the first segment descriptor.
501E
ADD A,L 85
ADD the low byte of the entry's address in Register L to Register A.
501F
LD L,A 6F
Load Register L with Register A: Register Pair HL = the entry's +16H.
5020
LD E,(HL) 5E
Load Register E with the descriptor's first byte at Register Pair HL, the cylinder (or FEH, FFH).
5021
INC L 2C
INCrement Register L by 1 to the descriptor's second byte.
5022
LD D,(HL) 56
Load Register D with the second byte at Register Pair HL (the granules, or the logical file number after FEH).
5023
LD A,E 7B
Load Register A with Register E, the first byte of the descriptor, for the compare.
5024
CP FEH FE FE
Compare Register A against FEH: FEH (a link) and FFH (the end) set the NC FLAG.
5026
If the NC FLAG is set (FEH or FFH, the end of this entry's list), JUMP to 502EH.
5028
INC L 2C
INCrement Register L by 1 to the next descriptor.
5029
GOSUB to 504FH to free the segment's granules: Register E the cylinder, Register D the granules.
502C
JUMP back to 5020H for the next descriptor at Register Pair HL.
502E
LD A,L 7D
Load Register A with Register L, the low byte of the address in the entry.
502F
AND E0H E6 E0
AND Register A with E0H, the start of the entry.
5031
LD L,A 6F
Load Register L with Register A: Register Pair HL = the entry.
5032
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.
5034
GOSUB to 449DH in SYS0/SYS to write the directory sector of logical file number Register B from 4300H.
5037
RET NZ C0
If the NZ FLAG is set (a write error), RETurn with the error code in Register A.
5038
GOSUB to 50B9H to read the hash index table of drive Register C into 4300H.
503B
RET NZ C0
If the NZ FLAG is set (a read error), RETurn with Register A = 16H, Hit read error.
503C
LD L,B 68
Load Register L with Register B, the logical file number.
503D
LD H,43H 26 43
Load Register H with 43H: Register Pair HL = the entry's byte in the hash index table at 4300H.
503F
LD (HL),00H 36 00
Store 00H to the hash index byte at Register Pair HL: the entry is free.
5041
GOSUB to 50CBH to write the hash index table from 4300H.
5044
RET NZ C0
If the NZ FLAG is set (a write error), RETurn with Register A = 17H, Hit write error.
5045
LD B,D 42
Load Register B with Register D: after FEH, the logical file number of the extended entry.
5046
LD A,E 7B
Load Register A with Register E, the byte that ended the list.
5047
CP FEH FE FE
Compare Register A against FEH, a link to an extended entry.
5049
If the Z FLAG is set (an extended entry follows), JUMP back to 5018H to free it as well.
504B
GOSUB to 50A7H to write the granule allocation table from 5100H.
504E
RET C9
RETurn (through 4CFAH) with Register A and the flags of the write: the Z FLAG when done, else error 15H.

504FH - 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).

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

5070H - 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 507BH and running it.

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

507DH - The Date for the Directory Entry

Returns Register B = the month (bits 3-0 of 421CH) and Register C = the day (bits 4-0 of 421BH) in bits 7-3 and bits 2-0 of the year (421AH, 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.

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

5095H - Reading and Writing the Tables

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

5095
PUSH DE D5
Save Register Pair DE to the top of the stack.
5096
PUSH HL E5
Save Register Pair HL to the top of the stack.
5097
LD E,00H 1E 00
Load Register E with 00H, directory sector 0, the granule allocation table.
5099
LD HL,5100H 21 00 51
Point Register Pair HL to 5100H, the buffer for the table, after the end of SYS3/SYS.
509C
LD A,06H 3E 06
Load Register A with 06H, the SREAD function of DISKIO%, which reads sector Register E of the directory cylinder.
509E
GOSUB to 4488H (DISKIO%) in SYS0/SYS to read the table of drive Register C into the buffer at Register Pair HL (5100H).
50A1
POP HL E1
Restore Register Pair HL from the top of the stack.
50A2
POP DE D1
Restore Register Pair DE from the top of the stack.
50A3
RET Z C8
If the Z FLAG is set (read), RETurn with Register A from DISKIO%.
50A4
LD A,14H 3E 14
Load Register A with 14H, the error code Gat read error; the NZ FLAG stays set.
50A6
RET C9
RETurn with Register A = 14H and the NZ FLAG set.
50A7
PUSH DE D5
Save Register Pair DE to the top of the stack.
50A8
PUSH HL E5
Save Register Pair HL to the top of the stack.
50A9
LD E,00H 1E 00
Load Register E with 00H, directory sector 0, the granule allocation table.
50AB
LD HL,5100H 21 00 51
Point Register Pair HL to 5100H, the buffer that holds the table.
50AE
LD A,07H 3E 07
Load Register A with 07H, the SWRITE function of DISKIO%, which writes sector Register E of the directory cylinder.
50B0
GOSUB to 4488H (DISKIO%) in SYS0/SYS to write the buffer at Register Pair HL (5100H) to the table of drive Register C.
50B3
POP HL E1
Restore Register Pair HL from the top of the stack.
50B4
POP DE D1
Restore Register Pair DE from the top of the stack.
50B5
RET Z C8
If the Z FLAG is set (written), RETurn with Register A from DISKIO%.
50B6
LD A,15H 3E 15
Load Register A with 15H, the error code Gat write error; the NZ FLAG stays set.
50B8
RET C9
RETurn with Register A = 15H and the NZ FLAG set.
50B9
PUSH DE D5
Save Register Pair DE to the top of the stack.
50BA
PUSH HL E5
Save Register Pair HL to the top of the stack.
50BB
LD E,01H 1E 01
Load Register E with 01H, directory sector 1, the hash index table.
50BD
LD HL,4300H 21 00 43
Point Register Pair HL to 4300H, the system sector buffer.
50C0
LD A,06H 3E 06
Load Register A with 06H, the SREAD function of DISKIO%.
50C2
GOSUB to 4488H (DISKIO%) in SYS0/SYS to read the hash index table of drive Register C into the buffer at Register Pair HL (4300H).
50C5
POP HL E1
Restore Register Pair HL from the top of the stack.
50C6
POP DE D1
Restore Register Pair DE from the top of the stack.
50C7
RET Z C8
If the Z FLAG is set (read), RETurn with Register A from DISKIO%.
50C8
LD A,16H 3E 16
Load Register A with 16H, the error code Hit read error; the NZ FLAG stays set.
50CA
RET C9
RETurn with Register A = 16H and the NZ FLAG set.
50CB
PUSH DE D5
Save Register Pair DE to the top of the stack.
50CC
PUSH HL E5
Save Register Pair HL to the top of the stack.
50CD
LD E,01H 1E 01
Load Register E with 01H, directory sector 1, the hash index table.
50CF
LD HL,4300H 21 00 43
Point Register Pair HL to 4300H, the buffer that holds the table.
50D2
LD A,07H 3E 07
Load Register A with 07H, the SWRITE function of DISKIO%.
50D4
GOSUB to 4488H (DISKIO%) in SYS0/SYS to write the buffer at Register Pair HL (4300H) to the hash index table of drive Register C.
50D7
POP HL E1
Restore Register Pair HL from the top of the stack.
50D8
POP DE D1
Restore Register Pair DE from the top of the stack.
50D9
RET Z C8
If the Z FLAG is set (written), RETurn with Register A from DISKIO%.
50DA
LD A,17H 3E 17
Load Register A with 17H, the error code Hit write error; the NZ FLAG stays set.
50DC
RET C9
RETurn with Register A = 17H and the NZ FLAG set. 50DCH 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 (5095H) and written from here (50A7H), 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 5070H.