TRS-80 DOS - TRSDOS v2.3 for the Model I - SYS3/SYS Disassembled

Page Customization

Introduction/Summary

TRSDOS v2.3 SYS3/SYS Disassembly - Closing and Killing Files (Model I)

SYS3/SYS is the TRSDOS 2.3 system overlay that closes and kills files. SYS0/SYS loads it into the overlay area at 4E00H whenever an RST 28H code with 5 in bits 0-3 is executed, and enters it at 4E00H with that code in Register A and Register Pair DE pointing at the FCB. Before doing anything it checks every field of the FCB, so a stray or closed FCB is refused with error 26H (FILE NOT OPEN) rather than corrupting the directory.

The file holds 768 bytes in four load records covering 4E00H-50FFH, after a name record and a 169-byte copyright comment record; its transfer address is 4E00H. The code ends at 5085H and the rest of the file, 5086H-50FFH, is FFH filler. Every byte is shown once on this page, in address order, checked against S:\1\SYS3.SYS and its listing.

Memory Map

Address RangeUse
4E00H-4E6CH
109 bytes
Check the FCB field by field, then dispatch to close or kill.
4E6DH-4F00H
148 bytes
Close: flush the buffer, update the directory entry, count the granules.
4F01H-4F6DH
109 bytes
Free the granules a shrunken file no longer needs.
4F6FH-4FCFH
97 bytes
Write the tables back and rebuild the filespec text in the FCB.
4FD0H-5038H
105 bytes
Kill: free every granule and clear every entry the file uses.
5039H-5067H
47 bytes
Free an extent's granules in the allocation table.
5068H-5085H
30 bytes
Read and write the hash index table.
5086H-50FFH
122 bytes
FFH filler, unused.

Functions

Bits 0-3 of both codes are 5 (SYS3/SYS); bits 4-6 are the function that 4E00H tests. SYS0/SYS's fixed entry points supply the codes.

CodeEntered FromFunction
95H4428HClose the open file in the FCB at Register Pair DE (4E6DH).
A5H442CHKill (delete) the open file in the FCB at Register Pair DE (4FD0H).

The Three Buffers

SYS3/SYS works on three 256-byte sectors of the directory track, each in its own buffer: the directory sector holding the file's entry in 4200H (read and written by SYS0/SYS's 4AC1H and 4AD6H), the granule allocation table in 4D00H (4AF0H and 4B03H), and the hash index table in 5100H, just above the file, read and written by SYS3/SYS's own 5068H and 5077H.

Closing

Close flushes the buffer if it holds changed records, then reads the file's directory entry and, when the end-of-file byte or the ending record number has changed, writes them back. It then counts the granules in the file's extents, following any continuation entries, and divides the ending record number by five to find how many granules the file actually needs. Any surplus granules are freed from the end of the file, an emptied extent is marked unused, and a continuation entry that becomes empty is unlinked. Finally the tables are written back and the FCB is turned back into the filespec text NAME/EXT:D.

Killing

Kill is refused with error 25H when the file's access level is 2 or more. Otherwise it frees every granule of the primary entry and of each continuation entry in the allocation table, clears each 32-byte entry to zero, zeroes each entry's hash index byte, writes the tables back and clears the FCB.

Notes from the Code

  • The FCB check at 4E00H compares the FCB's and the buffer's high bytes with the top of memory at 404AH, so a close or kill of an FCB above installed memory is rejected as FILE NOT OPEN.
  • Close reads the hash index table (4EFBH) only so that a continuation entry it empties can have its hash index byte cleared; a file with no continuation entries never changes the table.
  • After a close the FCB no longer holds the open file's control fields; its first bytes are the filespec as text, ready to be parsed again.
  • Kill follows the continuation chain through the FEH track byte, so a file spread across several directory entries is removed completely.

Variables

Self-Modified Operands

AddressPurpose
4F22H
1 byte
Operand of ADD A,nn at 4F21H: the track offset to the granule being freed (set at 4F16H).
4FC8H
1 byte
Operand of LD A,nn at 4FC7H: the drive as a character for the rebuilt filespec (set at 4F8CH).
5066H
1 byte
Operand of RES 0,B at 5065H: made RES n,B to clear the right granule bit (set at 5062H).

Addresses Outside SYS3/SYS

Address RangeUse
404AH
1 byte
High byte of the top of memory, the upper limit for the FCB check at 4E09H and 4E20H.
4200H-42FFH
256 bytes
Directory sector buffer (SYS0/SYS 4AC1H, 4AD6H).
4D00H-4DFFH
256 bytes
Granule allocation table buffer (SYS0/SYS 4AF0H, 4B03H).
5100H-51FFH
256 bytes
Hash index table buffer, above the file (5068H, 5077H).
4892H, 4878H, 4AC1H, 4AD6H, 4AF0H, 4B03H, 4B55H, 4B84H, 4B35H, 46EFH
SYS0/SYS
File call set-up, flush the buffer, read and write a directory sector, read and write the allocation table, the directory track, divide by a byte, read and write a system sector.

Disassembly

4E00H - Function Dispatcher and FCB Check

SYS0/SYS's overlay call (4BFBH) enters SYS3/SYS here with Register A = the RST 28H code whose bits 0-3 are 5, and Register Pair DE = the FCB. Before dispatching, the FCB is checked field by field; any field that is wrong returns error 26H (FILE NOT OPEN) and nothing is done. Bits 4-6 then select the function: 10H (code 95H, 4428H) closes the file, 20H (code A5H, 442CH) kills it.

4E00
PUSH IX DD E5
Save Index Register IX (the caller's) onto the stack.
4E02
PUSH HL E5
Save Register Pair HL (the caller's) onto the stack.
4E03
PUSH AF F5
Save Register Pair AF (Register A = the function code) onto the stack.
4E04
LD A,D 7A
Copy Register D (the high byte of the FCB address) into Register A.
4E05
CP 40H FE 40
Compare Register A (the FCB's high byte) against 40H, the start of RAM.
4E07
If the CARRY FLAG is set (below 4000H), JUMP to 4E65H to reject the FCB.
4E09
LD HL,404AH 21 4A 40
Point Register Pair HL to 404AH, the high byte of the top of memory.
4E0C
CP (HL) BE
Compare Register A (the FCB's high byte) against the top of memory at (HL) (Register Pair HL = 404AH).
4E0D
If the Z FLAG is set (equal), JUMP to 4E11H to go on checking.
4E0F
If the NO CARRY FLAG is set (above the top of memory), JUMP to 4E65H to reject the FCB.
4E11
LD A,(DE) 1A
Fetch byte 0 of the FCB from (DE) (Register Pair DE = the FCB) into Register A.
4E12
BIT 7,A CB 7F
Test bit 7 of Register A (byte 0): set while the file is open.
4E14
If the Z FLAG is set (not open), JUMP to 4E65H to reject the FCB.
4E16
PUSH DE D5
Save Register Pair DE (the FCB) onto the stack.
4E17
POP IX DD E1
POP Index Register IX from the stack: Index Register IX = the FCB.
4E19
LD A,(IX+04H) DD 7E 04
Fetch byte 04H (the high byte of the buffer address) from (IX+04H) (Index Register IX = the FCB) into Register A.
4E1C
CP 40H FE 40
Compare Register A (the buffer's high byte) against 40H, the start of RAM.
4E1E
If the CARRY FLAG is set (below 4000H), JUMP to 4E65H to reject the FCB.
4E20
CP (HL) BE
Compare Register A (the buffer's high byte) against the top of memory at (HL) (Register Pair HL = 404AH).
4E21
If the Z FLAG is set (equal), JUMP to 4E25H to go on checking.
4E23
If the NO CARRY FLAG is set (above the top of memory), JUMP to 4E65H to reject the FCB.
4E25
LD A,(IX+06H) DD 7E 06
Fetch byte 06H (the drive) from (IX+06H) (Index Register IX = the FCB) into Register A.
4E28
CP 00H FE 00
Compare Register A (the drive) against 00H, the lowest drive number.
4E2A
If the CARRY FLAG is set (below 0, impossible for a byte), JUMP to 4E65H to reject the FCB.
4E2C
CP 04H FE 04
Compare Register A (the drive) against 04H, one past the last drive.
4E2E
If the NO CARRY FLAG is set (drive 4 or more), JUMP to 4E65H to reject the FCB.
4E30
LD A,(IX+07H) DD 7E 07
Fetch byte 07H (the entry locator) from (IX+07H) (Index Register IX = the FCB) into Register A.
4E33
BIT 4,A CB 67
Test bit 4 of Register A (the locator): no valid locator has it set.
4E35
If the NZ FLAG is set (bit 4 set), JUMP to 4E65H to reject the FCB.
4E37
BIT 3,A CB 5F
Test bit 3 of Register A (the locator): no valid locator has it set.
4E39
If the NZ FLAG is set (bit 3 set), JUMP to 4E65H to reject the FCB.
4E3B
LD A,(IX+0EH) DD 7E 0E
Fetch byte 0EH (the first extent's track) from (IX+0EH) (Index Register IX = the FCB) into Register A.
4E3E
CP 00H FE 00
Compare Register A (the first extent's track) against 00H.
4E40
If the NZ FLAG is set (a real track), JUMP to 4E4CH.
4E42
LD A,(IX+0FH) DD 7E 0F
Fetch byte 0FH (the first extent's granule byte) from (IX+0FH) (Index Register IX = the FCB) into Register A.
4E45
CP 20H FE 20
Compare Register A (the granule byte) against 20H, the smallest value with a first granule in bits 5-7.
4E47
If the CARRY FLAG is set (below 20H, no granule), JUMP to 4E65H to reject the FCB.
4E49
LD A,(IX+0EH) DD 7E 0E
Fetch byte 0EH (the first extent's track) from (IX+0EH) (Index Register IX = the FCB) into Register A again.
4E4C
CP FFH FE FF
Compare Register A (the first extent's track) against FFH, the mark of no extent. 4E40H comes here.
4E4E
If the Z FLAG is set (FFH, an empty file), JUMP to 4E54H.
4E50
CP 23H FE 23
Compare Register A (the track) against 23H, one past the last track.
4E52
If the NO CARRY FLAG is set (track 35 or more), JUMP to 4E65H to reject the FCB.
4E54
POP AF F1
FCB Is Valid
Restore Register Pair AF (Register A = the function code) from the stack. 4E4EH comes here.
4E55
POP HL E1
Restore Register Pair HL (the caller's) from the stack.
4E56
POP IX DD E1
Restore Index Register IX (the caller's) from the stack.
4E58
AND 70H E6 70
AND Register A (the function code) with 70H, keeping bits 4-6.
4E5A
CP 10H FE 10
Compare Register A (the function) against 10H, close (code 95H).
4E5C
If the Z FLAG is set (10H), JUMP to 4E6DH to close the file.
4E5F
CP 20H FE 20
Compare Register A (the function) against 20H, kill (code A5H).
4E61
If the Z FLAG is set (20H), JUMP to 4FD0H to kill the file.
4E64
RET C9
RETURN to SYS0/SYS for any other function number, doing nothing.
4E65
POP AF F1
Reject the FCB
Restore Register Pair AF from the stack. 4E07H, 4E0FH, 4E14H, 4E1EH, 4E23H, 4E2AH, 4E2EH, 4E35H, 4E39H, 4E47H and 4E52H come here.
4E66
POP HL E1
Restore Register Pair HL (the caller's) from the stack.
4E67
POP IX DD E1
Restore Index Register IX (the caller's) from the stack.
4E69
LD A,26H 3E 26
Load Register A with 26H, error FILE NOT OPEN.
4E6B
OR A B7
OR Register A (26H) with itself, setting the NZ FLAG.
4E6C
RET C9
RETURN with Register A = 26H and the NZ FLAG.

4E6DH - Close a File (4428H)

Index Register IX = the open FCB. Writes the buffer if it holds changed records, updates the file's directory entry with the end-of-file byte and ending record number, then compares the granules the file holds with the granules its ending record number needs; any surplus granules are freed. Returns Register A = 00H and the Z FLAG, or an error number and the NZ FLAG.

4E6D
GOSUB to SYS0/SYS's 4892H, the file call set-up: it returns error 26H when the FCB is not open. 4E5CH comes here.
4E70
RET NZ C0
If the NZ FLAG is set (26H, FILE NOT OPEN), RETURN with that error.
4E71
GOSUB to SYS0/SYS's 4878H to write the buffer when it holds changed logical records.
4E74
RET NZ C0
If the NZ FLAG is set (a write error), RETURN with that error.
4E75
LD B,(IX+07H) DD 46 07
Fetch the entry locator from byte 07H of the FCB at (IX+07H) (Index Register IX = the FCB) into Register B.
4E78
LD C,(IX+06H) DD 4E 06
Fetch the drive from byte 06H of the FCB at (IX+06H) (Index Register IX = the FCB) into Register C.
4E7B
GOSUB to SYS0/SYS's 4AC1H to read the directory sector holding entry Register B of drive Register C into 4200H; Register Pair HL = the entry.
4E7E
RET NZ C0
If the NZ FLAG is set (11H, DIRECTORY READ ERROR), RETURN with that error.
4E7F
LD A,03H 3E 03
Load Register A with 03H, the offset of the end-of-file byte in the entry.
4E81
ADD A,L 85
ADD Register L (the entry's low byte) to Register A.
4E82
LD L,A 6F
Copy the sum from Register A into Register L: Register Pair HL = the entry's end-of-file byte.
4E83
PUSH HL E5
Save Register Pair HL (the end-of-file byte) onto the stack.
4E84
LD A,(IX+08H) DD 7E 08
Fetch the FCB's end-of-file byte from byte 08H at (IX+08H) (Index Register IX = the FCB) into Register A.
4E87
CP (HL) BE
Compare Register A (the FCB's end-of-file byte) against the entry's end-of-file byte at (HL) (Register Pair HL = entry+03H).
4E88
If the NZ FLAG is set (they differ), JUMP to 4E9EH to update the entry.
4E8A
LD A,11H 3E 11
Load Register A with 11H, the offset from the end-of-file byte to the ending record number.
4E8C
ADD A,L 85
ADD Register L (the entry+03H low byte) to Register A.
4E8D
LD L,A 6F
Copy the sum from Register A into Register L: Register Pair HL = the entry's ending record number.
4E8E
LD A,(IX+0CH) DD 7E 0C
Fetch the FCB's ending record number low byte from byte 0CH at (IX+0CH) (Index Register IX = the FCB) into Register A.
4E91
CP (HL) BE
Compare Register A against the entry's low byte at (HL) (Register Pair HL = entry+14H).
4E92
If the NZ FLAG is set (they differ), JUMP to 4E9EH to update the entry.
4E94
INC L 2C
INCrement Register L (the entry pointer) by 1, to the high byte.
4E95
LD A,(IX+0DH) DD 7E 0D
Fetch the FCB's ending record number high byte from byte 0DH at (IX+0DH) (Index Register IX = the FCB) into Register A.
4E98
CP (HL) BE
Compare Register A against the entry's high byte at (HL) (Register Pair HL = entry+15H).
4E99
If the NZ FLAG is set (they differ), JUMP to 4E9EH to update the entry.
4E9B
POP AF F1
Restore Register Pair AF from the stack, dropping the end-of-file pointer saved at 4E83H.
4E9C
JUMP to 4EB6H: the directory entry already matches, so skip the write.
4E9E
POP HL E1
Update the Entry
Restore Register Pair HL (the entry's end-of-file byte) from the stack. 4E88H, 4E92H and 4E99H come here.
4E9F
LD A,(IX+08H) DD 7E 08
Fetch the FCB's end-of-file byte from byte 08H at (IX+08H) (Index Register IX = the FCB) into Register A.
4EA2
LD (HL),A 77
Store Register A (the end-of-file byte) into the entry at (HL) (Register Pair HL = entry+03H).
4EA3
LD A,11H 3E 11
Load Register A with 11H, the offset to the ending record number.
4EA5
ADD A,L 85
ADD Register L (the entry+03H low byte) to Register A.
4EA6
LD L,A 6F
Copy the sum from Register A into Register L: Register Pair HL = the entry's ending record number.
4EA7
LD A,(IX+0CH) DD 7E 0C
Fetch the FCB's ending record number low byte from byte 0CH at (IX+0CH) (Index Register IX = the FCB) into Register A.
4EAA
LD (HL),A 77
Store Register A into the entry at (HL) (Register Pair HL = entry+14H).
4EAB
INC L 2C
INCrement Register L (the entry pointer) by 1, to the high byte.
4EAC
LD A,(IX+0DH) DD 7E 0D
Fetch the FCB's ending record number high byte from byte 0DH at (IX+0DH) (Index Register IX = the FCB) into Register A.
4EAF
LD (HL),A 77
Store Register A into the entry at (HL) (Register Pair HL = entry+15H).
4EB0
PUSH HL E5
Save Register Pair HL (entry+15H) onto the stack.
4EB1
GOSUB to SYS0/SYS's 4AD6H to write the directory sector back to the diskette.
4EB4
POP HL E1
Restore Register Pair HL (entry+15H) from the stack.
4EB5
RET NZ C0
If the NZ FLAG is set (12H, DIRECTORY WRITE ERROR), RETURN with that error.
4EB6
INC L 2C
Count the Granules
INCrement Register L (the entry pointer) by 1, to entry+16H, the first extent. 4E9CH comes here.
4EB7
LD DE,0000H 11 00 00
Load Register Pair DE with 0000H, the running count of granules.
4EBA
LD A,(HL) 7E
Count Loop
Fetch an extent's track from (HL) (Register Pair HL = the entry's extent) into Register A. 4EC7H, 4ECAH and 4ED7H loop back here.
4EBB
INC L 2C
INCrement Register L (the entry pointer) by 1, to the granule byte.
4EBC
CP FEH FE FE
Compare Register A (the track) against FEH, the mark of a continued file.
4EBE
If the NO CARRY FLAG is set (FEH or FFH), JUMP to 4ECCH.
4EC0
LD A,(HL) 7E
Fetch the extent's granule byte from (HL) (Register Pair HL = the granule byte) into Register A.
4EC1
INC L 2C
INCrement Register L (the entry pointer) by 1, to the next extent.
4EC2
AND 1FH E6 1F
AND Register A (the granule byte) with 1FH, keeping bits 0-4, one less than the number of granules.
4EC4
INC A 3C
INCrement Register A by 1: the number of granules in this extent.
4EC5
ADD A,E 83
ADD Register E (the running count's low byte) to Register A.
4EC6
LD E,A 5F
Copy the new low byte from Register A into Register E, the running granule count.
4EC7
If the NO CARRY FLAG is set (no overflow), LOOP BACK to 4EBAH.
4EC9
INC D 14
INCrement Register D (the running count's high byte) by 1.
4ECA
JUMP to 4EBAH to count the granules of the next extent.
4ECC
End or Continuation
If the NZ FLAG is set (FFH, the end of the extents), JUMP to 4ED9H. 4EBEH comes here.
4ECE
LD B,(HL) 46
Fetch the continuation entry's locator from (HL) (Register Pair HL = the byte after the FEH track) into Register B.
4ECF
GOSUB to SYS0/SYS's 4AC1H to read the directory sector holding entry Register B into 4200H; Register Pair HL = the continuation entry.
4ED2
RET NZ C0
If the NZ FLAG is set (11H, DIRECTORY READ ERROR), RETURN with that error.
4ED3
LD A,L 7D
Copy the continuation entry's low byte from Register L into Register A.
4ED4
ADD A,16H C6 16
ADD 16H to Register A: the offset of the entry's first extent.
4ED6
LD L,A 6F
Copy the sum from Register A into Register L: Register Pair HL = the continuation entry's first extent.
4ED7
JUMP to 4EBAH to go on counting in the continuation entry.
4ED9
PUSH HL E5
Compare with the Need
Save Register Pair HL (the entry's extent) onto the stack. 4ECCH comes here.
4EDA
LD L,(IX+0CH) DD 6E 0C
Fetch the ending record number low byte from byte 0CH at (IX+0CH) (Index Register IX = the FCB) into Register L.
4EDD
LD H,(IX+0DH) DD 66 0D
Fetch the ending record number high byte from byte 0DH at (IX+0DH) (Index Register IX = the FCB) into Register H: Register Pair HL = the sectors in the file.
4EE0
LD A,05H 3E 05
Load Register A with 05H, the five sectors in a granule.
4EE2
GOSUB to SYS0/SYS's 4B84H to divide Register Pair HL by 5: Register Pair HL = the whole granules and Register A = the leftover sectors.
4EE5
INC HL 23
INCrement Register Pair HL by 1: one granule for the leftover sectors, so Register Pair HL = the granules the file needs.
4EE6
XOR A AF
Set Register A to ZERO and clear the CARRY FLAG.
4EE7
EX DE,HL EB
Exchange Register Pairs DE and HL: Register Pair DE = the granules needed, Register Pair HL = the granules held.
4EE8
SBC HL,DE ED 52
SUBtract Register Pair DE (the granules needed) and the CARRY FLAG from Register Pair HL (the granules held): the surplus, and the Z FLAG when there is none.
4EEA
EX DE,HL EB
Exchange Register Pairs DE and HL: Register Pair DE = the surplus granule count.
4EEB
POP HL E1
Restore Register Pair HL (the entry's extent) from the stack.
4EEC
If the Z FLAG is set (no surplus), JUMP to 4F7BH to finish.
4EEF
If the CARRY FLAG is set (the file needs more than it holds, which should not happen), JUMP to 4F7BH to finish.
4EF2
DEC L 2D
DECrement Register L (the entry pointer) by 1.
4EF3
DEC L 2D
DECrement Register L (the entry pointer) by 1, back to the last extent that was counted.
4EF4
PUSH HL E5
Save Register Pair HL (the extent) onto the stack.
4EF5
PUSH DE D5
Save Register Pair DE (the surplus count) onto the stack.
4EF6
GOSUB to SYS0/SYS's 4AF0H to read the granule allocation table of the drive into 4D00H.
4EF9
If the NZ FLAG is set (14H, GAT READ ERROR), JUMP to 4EFEH.
4EFB
GOSUB to 5068H to read the hash index table into 5100H (unused here; it reports a HIT read error if the table cannot be read).
4EFE
POP DE D1
Restore Register Pair DE (the surplus count) from the stack. 4EF9H comes here.
4EFF
POP HL E1
Restore Register Pair HL (the extent) from the stack.
4F00
RET NZ C0
If the NZ FLAG is set (a read error), RETURN with that error.

4F01H - Free the Surplus Granules

Index Register IX = the FCB, Register Pair HL = the file's last extent in a directory sector at 4200H, Register Pair DE = the number of granules to free, the granule allocation table is in 4D00H and the hash index table in 5100H. Frees granules from the end of the file one at a time, shortening the last extent and, when an extent empties, marking it unused and unlinking a continuation entry that becomes empty. Returns through 4F6FH once the count reaches zero.

4F01
LD A,E 7B
Free Loop
Copy the low byte of the count left from Register E into Register A. 4F6DH loops back here.
4F02
CP 00H FE 00
Compare Register A (the count left) against 00H.
4F04
If the Z FLAG is set (no granules left to free), JUMP to 4F6FH to write the tables back.
4F06
PUSH DE D5
Save Register Pair DE (the count left) onto the stack.
4F07
LD A,(HL) 7E
Fetch the extent's granule byte from (HL) (Register Pair HL = the extent's granule byte) into Register A.
4F08
AND E0H E6 E0
AND Register A with E0H, keeping bits 5-7, the first granule.
4F0A
RLCA 07
Rotate Register A left, circularly, moving the first granule bits down.
4F0B
RLCA 07
Rotate Register A left, circularly, moving the first granule bits further.
4F0C
RLCA 07
Rotate Register A left, circularly: the first granule number moves to bits 0-2.
4F0D
LD E,A 5F
Copy the first granule number from Register A into Register E.
4F0E
LD A,(HL) 7E
Fetch the extent's granule byte from (HL) (Register Pair HL = the granule byte) into Register A again.
4F0F
AND 1FH E6 1F
AND Register A with 1FH, keeping bits 0-4, one less than the number of granules.
4F11
ADD A,E 83
ADD Register E (the first granule number) to Register A: the number of the last granule.
4F12
LD E,A 5F
Copy the last granule number from Register A into Register E.
4F13
AND FEH E6 FE
AND Register A with FEH, dropping bit 0: the granule number without its low bit.
4F15
RRCA 0F
Rotate Register A right, circularly: the granule number halved, the track offset within the extent.
4F16
LD (4F22H),A 32 22 4F
Store Register A (the track offset) into 4F22H, the operand of ADD A,nn at 4F21H. Self-Modifying Code
4F19
LD A,E 7B
Copy the last granule number from Register E into Register A.
4F1A
AND 01H E6 01
AND Register A with 01H, keeping bit 0: which granule on the track, 0 or 1.
4F1C
INC A 3C
INCrement Register A by 1: the bit number plus one.
4F1D
CPL 2F
Complement Register A: a mask with the granule's allocation bit clear.
4F1E
PUSH AF F5
Save Register Pair AF (Register A = the mask) onto the stack.
4F1F
DEC HL 2B
DECrement Register Pair HL by 1, to the extent's track byte.
4F20
LD A,(HL) 7E
Fetch the extent's track from (HL) (Register Pair HL = the track byte) into Register A.
4F21
ADD A,00H C6 00
ADD the track offset (the operand set at 4F16H) to Register A: the track the last granule is on. Self-Modifying Code
00H in the file.
4F23
EX DE,HL EB
Exchange Register Pairs DE and HL: Register Pair DE = the extent pointer.
4F24
LD H,4DH 26 4D
Load Register H with 4DH, the high byte of the allocation table.
4F26
LD L,A 6F
Copy the track from Register A into Register L: Register Pair HL = the allocation table byte for that track.
4F27
POP AF F1
Restore Register Pair AF (Register A = the mask) from the stack.
4F28
AND (HL) A6
AND Register A (the mask) with the allocation byte at (HL) (Register Pair HL = the table byte): the granule's bit is cleared.
4F29
LD (HL),A 77
Store Register A (the allocation byte) back into the table at (HL) (Register Pair HL = the table byte): the granule is free.
4F2A
EX DE,HL EB
Exchange Register Pairs DE and HL: Register Pair HL = the extent's track byte.
4F2B
INC HL 23
INCrement Register Pair HL by 1, to the extent's granule byte.
4F2C
DEC (HL) 35
DECrement the granule byte at (HL) (Register Pair HL = the granule byte): one less granule in this extent.
4F2D
LD A,(HL) 7E
Fetch the granule byte from (HL) (Register Pair HL = the granule byte) into Register A.
4F2E
INC A 3C
INCrement Register A (the new granule byte) by 1, so bits 0-4 give the count.
4F2F
AND 1FH E6 1F
AND Register A with 1FH, keeping bits 0-4: the count of granules still in the extent.
4F31
POP DE D1
Restore Register Pair DE (the count left) from the stack.
4F32
If the NZ FLAG is set (the extent still has granules), JUMP to 4F6CH to count this granule off.
4F34
LD (HL),FFH 36 FF
Extent Emptied
Store FFH into the granule byte at (HL) (Register Pair HL = the granule byte): the extent is unused.
4F36
DEC HL 2B
DECrement Register Pair HL by 1, to the track byte.
4F37
LD (HL),FFH 36 FF
Store FFH into the track byte at (HL) (Register Pair HL = the track byte): the extent is unused.
4F39
DEC HL 2B
DECrement Register Pair HL by 1, to the previous extent's granule byte.
4F3A
LD A,L 7D
Copy the entry offset from Register L into Register A.
4F3B
AND 1FH E6 1F
AND Register A with 1FH, keeping bits 0-4 of the offset within the sector.
4F3D
CP 15H FE 15
Compare Register A against 15H, the offset one below a continuation entry's first extent.
4F3F
If the NZ FLAG is set (not at the start of a continuation entry's extents), JUMP to 4F6CH.
4F41
XOR L AD
XOR Register A (15H) with Register L: the entry's base offset, so Register Pair HL points at the continuation entry's byte 01H.
4F42
LD L,A 6F
Copy Register A into Register L: Register Pair HL = the continuation entry's byte 01H.
4F43
LD A,(HL) 7E
Fetch byte 01H of the continuation entry from (HL) (Register Pair HL = the entry's byte 01H) into Register A: the primary entry's locator and, in bit 7, a flag.
4F44
LD (HL),00H 36 00
Store 00H into the entry at (HL) (Register Pair HL = the entry's byte 01H).
4F46
INC HL 23
INCrement Register Pair HL by 1, to byte 02H.
4F47
LD D,(HL) 56
Fetch byte 02H of the continuation entry from (HL) (Register Pair HL = the entry's byte 02H) into Register D.
4F48
LD H,51H 26 51
Load Register H with 51H, the high byte of the hash index table.
4F4A
LD L,B 68
Copy the continuation entry's locator from Register B into Register L: Register Pair HL = its hash index byte.
4F4B
LD (HL),00H 36 00
Store 00H into the hash index at (HL) (Register Pair HL = 5100H plus the locator): the continuation entry is free.
4F4D
BIT 7,A CB 7F
Test bit 7 of Register A (the byte read from the entry's byte 01H).
4F4F
If the Z FLAG is set (bit 7 clear), JUMP to 4F6FH to write the tables back.
4F51
PUSH DE D5
Save Register Pair DE (the count left) onto the stack.
4F52
GOSUB to SYS0/SYS's 4AD6H to write the directory sector holding the emptied continuation entry back.
4F55
POP DE D1
Restore Register Pair DE (the count left) from the stack.
4F56
RET NZ C0
If the NZ FLAG is set (12H, DIRECTORY WRITE ERROR), RETURN with that error.
4F57
LD A,B 78
Copy the continuation entry's locator from Register B into Register A.
4F58
XOR D AA
XOR Register A with Register D (the sector part of the primary's locator from byte 02H).
4F59
AND 07H E6 07
AND Register A with 07H, the sector bits: zero when both are in the same directory sector.
4F5B
LD B,D 42
Copy the primary's locator from Register D into Register B.
4F5C
When the NZ FLAG is set (a different sector), GOSUB to SYS0/SYS's 4AC1H to read the directory sector holding the primary entry into 4200H.
4F5F
RET NZ C0
If the NZ FLAG is set (11H, DIRECTORY READ ERROR), RETURN with that error.
4F60
LD A,B 78
Copy the primary's locator from Register B into Register A.
4F61
AND E0H E6 E0
AND Register A with E0H, keeping bits 5-7, the entry's offset in its sector.
4F63
ADD A,1FH C6 1F
ADD 1FH to Register A: the offset of the primary entry's last extent's second byte.
4F65
LD L,A 6F
Copy Register A into Register L: Register Pair HL = the primary entry's last extent plus 1.
4F66
LD (HL),FFH 36 FF
Store FFH into the entry at (HL) (Register Pair HL = the last extent's granule byte): the link to the continuation entry is removed.
4F68
DEC HL 2B
DECrement Register Pair HL by 1, to the track byte.
4F69
LD (HL),FFH 36 FF
Store FFH into the entry at (HL) (Register Pair HL = the last extent's track byte): the extent ends the file here.
4F6B
DEC HL 2B
DECrement Register Pair HL by 1, to the previous extent's granule byte.
4F6C
DEC E 1D
Count Off
DECrement Register E (the count of granules still to free) by 1. 4F32H and 4F3FH come here.
4F6D
JUMP to 4F01H to free the next surplus granule.

4F6FH - Write the Tables and Rebuild the Filespec

Writes the directory sector, the hash index table and the allocation table back, then turns the FCB back into the filespec text NAME/EXT:D so the caller can read or reopen the file. Returns Register A = 00H.

4F6F
GOSUB to SYS0/SYS's 4AD6H to write the directory sector back. 4F04H and 4F4FH come here.
4F72
RET NZ C0
If the NZ FLAG is set (12H, DIRECTORY WRITE ERROR), RETURN with that error.
4F73
GOSUB to 5077H to write the hash index table back to directory sector 1.
4F76
RET NZ C0
If the NZ FLAG is set (17H, HIT WRITE ERROR), RETURN with that error.
4F77
GOSUB to SYS0/SYS's 4B03H to write the allocation table back to directory sector 0.
4F7A
RET NZ C0
If the NZ FLAG is set (15H, GAT WRITE ERROR), RETURN with that error.
4F7B
LD A,(IX+07H) DD 7E 07
Rebuild the Filespec
Fetch the entry locator from byte 07H of the FCB at (IX+07H) (Index Register IX = the FCB) into Register A. 4EECH and 4EEFH jump here.
4F7E
XOR B A8
XOR Register A with Register B (the locator of the sector last read).
4F7F
AND 1FH E6 1F
AND Register A with 1FH, the sector bits: zero when the primary entry is in the sector already in 4200H.
4F81
When the NZ FLAG is set (a different sector), GOSUB to SYS0/SYS's 4AC1H to read the directory sector holding the primary entry (Register B is still its locator).
4F84
RET NZ C0
If the NZ FLAG is set (11H, DIRECTORY READ ERROR), RETURN with that error.
4F85
LD A,(IX+06H) DD 7E 06
Fetch the drive from byte 06H of the FCB at (IX+06H) (Index Register IX = the FCB) into Register A.
4F88
AND 03H E6 03
AND Register A with 03H, keeping the drive number.
4F8A
OR 30H F6 30
OR Register A with 30H, the digit 0: the drive as a character.
4F8C
LD (4FC8H),A 32 C8 4F
Store Register A (the drive character) into 4FC8H, the operand of LD A,nn at 4FC7H. Self-Modifying Code
4F8F
LD H,42H 26 42
Load Register H with 42H, the high byte of the directory buffer.
4F91
LD A,(IX+07H) DD 7E 07
Fetch the entry locator from byte 07H of the FCB at (IX+07H) (Index Register IX = the FCB) into Register A.
4F94
AND E0H E6 E0
AND Register A with E0H, keeping bits 5-7, the entry's offset in the sector.
4F96
OR 05H F6 05
OR Register A with 05H, the offset of the name field.
4F98
LD L,A 6F
Copy Register A into Register L: Register Pair HL = the entry's name field in 4200H.
4F99
PUSH HL E5
Save Register Pair HL (the name field) onto the stack.
4F9A
PUSH IX DD E5
PUSH Index Register IX (the FCB) onto the stack.
4F9C
POP DE D1
POP Register Pair DE from the stack: Register Pair DE = the FCB, where the filespec goes.
4F9D
LD B,08H 06 08
Load Register B with 08H, the eight characters of the name.
4F9F
LD A,(HL) 7E
Name Loop
Fetch a name character from (HL) (Register Pair HL = the entry's name field) into Register A. 4FA7H loops back here.
4FA0
CP 20H FE 20
Compare Register A (the name character) against 20H, a space, the padding after the name.
4FA2
If the Z FLAG is set (a space), JUMP to 4FA9H: the name has ended.
4FA4
LD (DE),A 12
Store the character (Register A) into the FCB at (DE) (Register Pair DE = the filespec).
4FA5
INC HL 23
INCrement Register Pair HL (the name pointer) by 1.
4FA6
INC DE 13
INCrement Register Pair DE (the filespec pointer) by 1.
4FA7
Name Loop End
DECrement Register B and LOOP BACK to 4F9FH until eight characters are copied.
4FA9
POP HL E1
Extension
Restore Register Pair HL (the name field) from the stack. 4FA2H comes here.
4FAA
LD A,L 7D
Copy the name field offset from Register L into Register A.
4FAB
ADD A,08H C6 08
ADD 08H to Register A: the offset of the extension.
4FAD
LD L,A 6F
Copy Register A into Register L: Register Pair HL = the entry's extension field.
4FAE
LD A,(HL) 7E
Fetch the first extension character from (HL) (Register Pair HL = the extension field) into Register A.
4FAF
CP 20H FE 20
Compare Register A against 20H, a space: no extension.
4FB1
If the Z FLAG is set (no extension), JUMP to 4FC3H to add the drive.
4FB3
LD A,2FH 3E 2F
Load Register A with 2FH, the slash before an extension.
4FB5
LD (DE),A 12
Store the slash (Register A) into the FCB at (DE) (Register Pair DE = the filespec).
4FB6
INC DE 13
INCrement Register Pair DE (the filespec pointer) by 1.
4FB7
LD B,03H 06 03
Load Register B with 03H, the three characters of the extension.
4FB9
LD A,(HL) 7E
Extension Loop
Fetch an extension character from (HL) (Register Pair HL = the extension field) into Register A. 4FC1H loops back here.
4FBA
CP 20H FE 20
Compare Register A against 20H, a space, the padding after the extension.
4FBC
If the Z FLAG is set (a space), JUMP to 4FC3H: the extension has ended.
4FBE
LD (DE),A 12
Store the character (Register A) into the FCB at (DE) (Register Pair DE = the filespec).
4FBF
INC HL 23
INCrement Register Pair HL (the extension pointer) by 1.
4FC0
INC DE 13
INCrement Register Pair DE (the filespec pointer) by 1.
4FC1
Extension Loop End
DECrement Register B and LOOP BACK to 4FB9H until three characters are copied.
4FC3
LD A,3AH 3E 3A
Drive and End
Load Register A with 3AH, the colon before a drive number. 4FB1H and 4FBCH come here.
4FC5
LD (DE),A 12
Store the colon (Register A) into the FCB at (DE) (Register Pair DE = the filespec).
4FC6
INC DE 13
INCrement Register Pair DE (the filespec pointer) by 1.
4FC7
LD A,00H 3E 00
Load Register A with the drive character from the operand at 4FC8H (set at 4F8CH). Self-Modifying Code
00H in the file.
4FC9
LD (DE),A 12
Store the drive character (Register A) into the FCB at (DE) (Register Pair DE = the filespec).
4FCA
INC DE 13
INCrement Register Pair DE (the filespec pointer) by 1.
4FCB
LD A,03H 3E 03
Load Register A with 03H, the end mark of a filespec.
4FCD
LD (DE),A 12
Store Register A (03H) into the FCB at (DE) (Register Pair DE = the filespec).
4FCE
XOR A AF
Set Register A to ZERO and clear all flags: no error closing the file.
4FCF
RET C9
RETURN to the caller with Register A = 00H and the Z FLAG.

4FD0H - Kill a File (442CH)

Index Register IX = the open FCB. Removes the file: every granule it holds is freed in the allocation table, every directory entry it uses (the primary and any continuation entries) is cleared and its hash index byte zeroed, the tables are written back and the FCB is cleared. Refused with error 25H when the file's access level is 2 or more. Returns Register A = 00H and the Z FLAG, or an error number and the NZ FLAG.

4FD0
GOSUB to SYS0/SYS's 4892H, the file call set-up. 4E61H comes here.
4FD3
RET NZ C0
If the NZ FLAG is set (26H, FILE NOT OPEN), RETURN with that error.
4FD4
LD A,(IX+01H) DD 7E 01
Fetch byte 01H of the FCB from (IX+01H) (Index Register IX = the FCB) into Register A.
4FD7
AND 07H E6 07
AND Register A with 07H, keeping bits 0-2, the access level.
4FD9
CP 02H FE 02
Compare Register A (the access level) against 02H.
4FDB
If the CARRY FLAG is set (level 0 or 1), JUMP to 4FE1H to kill the file.
4FDD
LD A,25H 3E 25
Load Register A with 25H, error ILLEGAL ACCESS ATTEMPTED TO PROTECTED FILE.
4FDF
OR A B7
OR Register A (25H) with itself, setting the NZ FLAG.
4FE0
RET C9
RETURN with Register A = 25H and the NZ FLAG.
4FE1
LD C,(IX+06H) DD 4E 06
Fetch the drive from byte 06H of the FCB at (IX+06H) (Index Register IX = the FCB) into Register C.
4FE4
LD B,(IX+07H) DD 46 07
Fetch the entry locator from byte 07H of the FCB at (IX+07H) (Index Register IX = the FCB) into Register B.
4FE7
GOSUB to 5068H to read the hash index table of drive Register C into 5100H.
4FEA
RET NZ C0
If the NZ FLAG is set (16H, HIT READ ERROR), RETURN with that error.
4FEB
GOSUB to SYS0/SYS's 4AF0H to read the allocation table of drive Register C into 4D00H.
4FEE
RET NZ C0
If the NZ FLAG is set (14H, GAT READ ERROR), RETURN with that error.
4FEF
Entry Loop
GOSUB to SYS0/SYS's 4AC1H to read the directory sector holding entry Register B into 4200H; Register Pair HL = the entry. 5024H loops back here for a continuation entry.
4FF2
RET NZ C0
If the NZ FLAG is set (11H, DIRECTORY READ ERROR), RETURN with that error.
4FF3
LD A,16H 3E 16
Load Register A with 16H, the offset of the first extent.
4FF5
ADD A,L 85
ADD Register L (the entry's low byte) to Register A.
4FF6
LD L,A 6F
Copy the sum from Register A into Register L: Register Pair HL = the entry's first extent.
4FF7
LD E,(HL) 5E
Extent Loop
Fetch the extent's track from (HL) (Register Pair HL = the extent) into Register E. 5003H loops back here.
4FF8
INC L 2C
INCrement Register L (the entry pointer) by 1, to the granule byte.
4FF9
LD D,(HL) 56
Fetch the extent's granule byte from (HL) (Register Pair HL = the granule byte) into Register D: Register Pair DE = the extent.
4FFA
LD A,E 7B
Copy the track from Register E into Register A.
4FFB
CP FEH FE FE
Compare Register A (the track) against FEH, the mark of a continued or ended file.
4FFD
If the NO CARRY FLAG is set (FEH or FFH), JUMP to 5005H: no more granules in this entry.
4FFF
INC L 2C
INCrement Register L (the entry pointer) by 1, to the next extent.
5000
GOSUB to 5039H to free the granules of the extent in Register Pair DE in the allocation table.
5003
JUMP to 4FF7H to free the granules of the next extent.
5005
LD A,L 7D
Clear the Entry
Copy the entry pointer from Register L into Register A. 4FFDH comes here.
5006
AND E0H E6 E0
AND Register A with E0H, keeping bits 5-7: the entry's start.
5008
LD L,A 6F
Copy the entry start from Register A into Register L: Register Pair HL = the start of the entry.
5009
LD (HL),00H 36 00
Store 00H into the entry's attribute byte at (HL) (Register Pair HL = the entry): the entry is free.
500B
PUSH BC C5
Save Register Pair BC (Register B = locator, Register C = drive) onto the stack.
500C
PUSH DE D5
Save Register Pair DE (Register E = track, Register D = granule byte) onto the stack.
500D
PUSH HL E5
Save Register Pair HL (the entry) onto the stack.
500E
POP DE D1
POP Register Pair DE from the stack: Register Pair DE = the entry.
500F
INC DE 13
INCrement Register Pair DE by 1, to the entry's byte 1.
5010
LD BC,001FH 01 1F 00
Load Register Pair BC with 001FH, the remaining 31 bytes of the entry.
5013
LDIR ED B0
Copy Register Pair BC (31) bytes forward through the entry from Register Pair HL to Register Pair DE (LDIR): the whole 32-byte entry is zero.
5015
POP DE D1
Restore Register Pair DE (Register E = track, Register D = granule byte) from the stack.
5016
POP BC C1
Restore Register Pair BC (Register B = locator, Register C = drive) from the stack.
5017
GOSUB to SYS0/SYS's 4AD6H to write the cleared directory sector back.
501A
RET NZ C0
If the NZ FLAG is set (12H, DIRECTORY WRITE ERROR), RETURN with that error.
501B
LD H,51H 26 51
Load Register H with 51H, the high byte of the hash index table.
501D
LD L,B 68
Copy the entry locator from Register B into Register L: Register Pair HL = its hash index byte.
501E
LD (HL),00H 36 00
Store 00H into the hash index at (HL) (Register Pair HL = 5100H plus the locator): the entry is free.
5020
LD B,D 42
Copy the granule byte from Register D into Register B: on a continuation it holds the next entry's locator.
5021
LD A,E 7B
Copy the track from Register E into Register A.
5022
CP FEH FE FE
Compare Register A (the track) against FEH, the continuation mark.
5024
If the Z FLAG is set (FEH, a continuation entry follows), LOOP BACK to 4FEFH to clear it.
5026
GOSUB to SYS0/SYS's 4B03H to write the allocation table back to directory sector 0.
5029
RET NZ C0
If the NZ FLAG is set (15H, GAT WRITE ERROR), RETURN with that error.
502A
GOSUB to 5077H to write the hash index table back to directory sector 1.
502D
RET NZ C0
If the NZ FLAG is set (17H, HIT WRITE ERROR), RETURN with that error.
502E
PUSH IX DD E5
PUSH Index Register IX (the FCB) onto the stack.
5030
POP HL E1
POP Register Pair HL from the stack: Register Pair HL = the FCB.
5031
LD B,20H 06 20
Load Register B with 20H, the 32 bytes of the FCB.
5033
XOR A AF
Set Register A to ZERO, the value stored into every FCB byte.
5034
LD (HL),A 77
Clear Loop
Store Register A (00H) into the FCB at (HL) (Register Pair HL = the FCB). 5036H loops back here.
5035
INC HL 23
INCrement Register Pair HL (the FCB pointer) by 1.
5036
Clear Loop End
DECrement Register B and LOOP BACK to 5034H until the FCB is zero.
5038
RET C9
RETURN to the caller with Register A = 00H and the Z FLAG.

5039H - Free an Extent's Granules

Register E = the extent's track, Register D = its granule byte (bits 5-7 the first granule, bits 0-4 one less than the count); the allocation table is in 4D00H. Clears the allocation bit of each of the extent's granules, stepping to the next track after the second granule on a track. Registers are preserved.

5039
PUSH HL E5
Save Register Pair HL onto the stack. 5000H calls here.
503A
PUSH BC C5
Save Register Pair BC (the caller's) onto the stack.
503B
LD L,E 6B
Copy the track from Register E into Register L.
503C
LD H,4DH 26 4D
Load Register H with 4DH: Register Pair HL = the allocation table byte for the track.
503E
LD A,D 7A
Copy the granule byte from Register D into Register A.
503F
AND 1FH E6 1F
AND Register A with 1FH, keeping bits 0-4, one less than the number of granules.
5041
LD C,A 4F
Copy the count minus one from Register A into Register C.
5042
INC C 0C
INCrement Register C by 1: the number of granules to free.
5043
XOR D AA
XOR Register A with Register D: the first granule bits 5-7 of the granule byte are left in Register A.
5044
RLCA 07
Rotate Register A left, circularly, moving the first granule bits down.
5045
RLCA 07
Rotate Register A left, circularly, moving the first granule bits further.
5046
RLCA 07
Rotate Register A left, circularly: the first granule number is in bits 0-2.
5047
PUSH AF F5
Free Loop
Save Register Pair AF (Register A = the granule number) onto the stack. 5056H loops back here.
5048
LD B,(HL) 46
Fetch the allocation byte from (HL) (Register Pair HL = the allocation table byte) into Register B.
5049
GOSUB to 505BH to clear the granule's bit in Register B.
504C
LD (HL),B 70
Store Register B (the allocation byte) back into the table at (HL) (Register Pair HL = the table byte).
504D
POP AF F1
Restore Register Pair AF (Register A = the granule number) from the stack.
504E
INC A 3C
INCrement Register A (the granule number) by 1.
504F
CP 02H FE 02
Compare Register A against 02H, past the second granule on the track.
5051
If the NZ FLAG is set (still on this track), JUMP to 5055H.
5053
XOR A AF
Set Register A to ZERO: back to the first granule.
5054
INC L 2C
INCrement Register L (the allocation table pointer) by 1, to the next track.
5055
DEC C 0D
Free Loop End
DECrement Register C (the granules left) by 1. 5051H comes here.
5056
If the NZ FLAG is set (granules are left), LOOP BACK to 5047H.
5058
POP BC C1
Restore Register Pair BC (the caller's) from the stack.
5059
POP HL E1
Restore Register Pair HL (the caller's) from the stack.
505A
RET C9
RETURN to the caller with the extent's granules freed in the table.
505B
AND 07H E6 07
Clear One Granule Bit
AND Register A (the granule number) with 07H. 5049H calls here.
505D
RLCA 07
Rotate Register A left, circularly, scaling the granule number.
505E
RLCA 07
Rotate Register A left, circularly, scaling the granule number further.
505F
RLCA 07
Rotate Register A left, circularly: the granule number times eight.
5060
OR 80H F6 80
OR Register A with 80H, the base of the RES opcode's second byte.
5062
LD (5066H),A 32 66 50
Store Register A into 5066H, the operand of RES 0,B at 5065H, making it RES (the granule number),B. Self-Modifying Code
5065
RES 0,B CB 80
RESet the granule's bit of Register B (the bit number set at 5062H): the granule is free. Self-Modifying Code
80H in the file (RES 0,B).
5067
RET C9
RETURN with Register B holding the cleared allocation byte.

5068H - Read the Hash Index Table

Register C = drive. Reads directory sector 1 into 5100H-51FFH. Returns the Z FLAG, or Register A = 16H (HIT READ ERROR) and the NZ FLAG.

5068
GOSUB to SYS0/SYS's 4B55H: Register D = the directory track of drive Register C. 4EFBH and 4FE7H call here.
506B
LD E,01H 1E 01
Load Register E with 01H, directory sector 1, the hash index.
506D
LD HL,5100H 21 00 51
Point Register Pair HL to 5100H, where the table is read.
5070
GOSUB to SYS0/SYS's 4B35H to read drive Register C, track Register D, sector Register E into 5100H.
5073
RET Z C8
If the Z FLAG is set (read), RETURN with Register A = 00H.
5074
LD A,16H 3E 16
Load Register A with 16H, error HIT READ ERROR.
5076
RET C9
RETURN with Register A = 16H and the NZ FLAG.

5077H - Write the Hash Index Table

Register C = drive. Writes 5100H-51FFH back to directory sector 1 with the FAH data mark. Returns the Z FLAG, or Register A = 17H (HIT WRITE ERROR) and the NZ FLAG.

5077
GOSUB to SYS0/SYS's 4B55H: Register D = the directory track of drive Register C. 4F73H and 502AH call here.
507A
LD E,01H 1E 01
Load Register E with 01H, directory sector 1, the hash index.
507C
LD HL,5100H 21 00 51
Point Register Pair HL to 5100H, the table to write.
507F
GOSUB to SYS0/SYS's 46EFH to write 5100H to drive Register C, track Register D, sector Register E with the FAH data mark.
5082
RET Z C8
If the Z FLAG is set (written), RETURN with Register A = 00H.
5083
LD A,17H 3E 17
Load Register A with 17H, error HIT WRITE ERROR.
5085
RET C9
RETURN with Register A = 17H and the NZ FLAG.

5086H - Unused

The last load record fills the overlay area to 50FFH with FFH; nothing uses these bytes.

5086-50FF
unused FF x 122
Filler
122 bytes of FFH in the file, below the hash index buffer at 5100H. SYS3/SYS never reads or executes them.