LDOS 5.3.1 for the Model III - SYS3/SYS Disassembled

Page Customization

Introduction/Summary

LDOS 5.3.1 SYS3/SYS Disassembly - Close a File or a Device, @FNAME (Model III)

SYS3/SYS closes files and devices for LDOS and serves @FNAME. It is a system file, loaded into the overlay area at 4E00H by the supervisor dispatcher of SYS0/SYS (4BCCH) whenever a request code names it: bits 3-0 of the code are 5. The manual says this overlay must not be left off a system diskette.

The file is a load module of 751 bytes: a record of type 1FH with the text Copyright 1991 MISOSYS, Inc., All rights reserved, three load blocks for 4E00H-50A5H, a load block for the two bytes 4BC8H-4BC9H (02A6H, the 678 bytes that SYS3/SYS takes up in the overlay area) and the transfer address record for 4E00H. SYS3/SYS uses the page above it, 5100H-51FFH, for the granule allocation table, and the system buffer 4300H-43FFH for the directory sectors and the Hash Index Table.

Functions

4E00H masks the request code in Register A with 70H and branches on bits 6-4; any other function returns at once with the NZ FLAG.

RequestFunction
95H10H: @CLOSE (4428H), 4E0CH: close the file or device whose control block is at Register Pair DE. BACKUP/CMD, BASIC/CMD, BASIC/OV2, CMDFILE/CMD, CONV/CMD, HELP/CMD, LCOMM/CMD, PATCH/CMD, SYS6/SYS, SYS7/SYS and TED/CMD call it.
A5H20H: @FNAME (4293H), 501CH: write the file specification of directory record Register B of drive Register C into the buffer at Register Pair DE. SYS6/SYS, SYS7/SYS and LCOMM/CMD call it.

How a File Is Closed

A control block whose byte +00H has bits 7 and 6 clear (10H, an open device) is made into the device specification *XX again (5029H). For a file, @CLOSE starts with the file prologue of SYS0/SYS (49F3H), which refuses a block that is not open (error 26H) and makes the last RET restore the caller's Register Pairs BC, DE and HL and Index Register IX. Then:

StepWhat SYS3/SYS does
1The file's directory record (+06H the drive, +07H the record number of the control block) is read; a record that is no longer in use (attribute bit 4 clear) ends the close at once. The file's buffer is written when it was changed (4993H of SYS0/SYS).
2The end of file byte and the ending record number of the control block go into the record's +03H and +14H-+15H (4E2AH).
3When a sector of the file was written (bit 2 of +00H of the control block, set by SYS0/SYS's sector write) the record gets the MOD flag and the date, and the time on a diskette with the directory date format of this release (4E69H). A record that changed is written back (4ECFH).
4Unless the record's create flag (bit 7 of +01H) is set, the granules of the file's extents are counted, across its extension records, and compared with the granules its ending record number needs (4F03H). The granules it does not need are freed from the last extent back (4F2EH): their bits in the allocation table are cleared, an extent with no granule left becomes FFH FFH, and an extension record with no extent left is freed in the directory and the HIT and unlinked from the file's own record (4F6FH). The directory and the allocation table are written; on a write protected diskette they are not, and the close still succeeds (4FB2H).
5The control block is filled with the file specification NAME/EXT:d and 03H (4FD8H), so it can be opened again. Register A = 00H with the Z FLAG.

The Date Stamp in the Directory Record

ByteContents written by 4E69H
+01HBit 7 the create flag (kept), bit 6 the MOD flag (set), bits 5-4 kept, bits 3-0 the month (421CH).
+02HBits 7-3 the day (421BH), bits 2-0 bits 2-0 of the year (421AH, 80-99 or 0-11).
+12HOnly when bit n of 475DH is set for drive n: bits 7-3 the hours (4219H), bits 2-0 bits 5-3 of the minutes (4218H).
+13HOnly when bit n of 475DH is set: bits 7-5 bits 2-0 of the minutes, bits 4-0 the year as an offset from 1980 (0-31 for 1980-2011).

Errors

ErrorMeaning and where
0FH (15)Write protected disk: from DIRWR when a changed record is written (4ED0H, 4F84H, 4FADH). At 4FB7H it is not an error.
11H (17)Directory read error (DIRRD, 4B10H).
12H (18)Directory write error (DIRWR, 4B1FH).
14H (20)GAT read error (504FH).
15H (21)GAT write error (5062H).
16H (22)HIT read error (507BH).
17H (23)HIT write error (508DH).
26H (38)File not open, from the prologue of SYS0/SYS (49F3H).

An error from the write of the file's buffer (4993H) is passed on as it comes.

About This Page

Every byte of the file is shown, in address order: the load block at 4BC8H first, then 4E00H-50A5H. Four instructions are changed by the code before they run: BIT 0,A at 4E9CH (the drive's bit, 4E96H), LD B,00H at 4F9CH (the file's own record, 4F8EH), LD A,00H at 5013H (the drive's digit, 4FDDH) and RES 0,B at 504CH (the granule's bit, 5049H).

Memory Map

Load Blocks in File Order

The four load blocks of the file in the order the overlay loader (4C8CH) reads them, after the copyright record. The transfer address is 4E00H.

AddressContents
4E00H-4EFFH256 bytes
4F00H-4FFFH256 bytes
5000H-50A5H166 bytes
4BC8H-4BC9H2 bytes

Sections of the Disassembly

AddressContents
4BC8HThe Overlay Length (Data)
4E00HEntry: Pick the Function of the Request
4E0CHFunction 10H (Request 95H): @CLOSE
4E2AHPut the End of the File into the Directory Record
4E69HStamp the Date and the Time into the Directory Record
4ECFHWrite the Directory Record and Count the File's Granules
4F03HWork Out the Granules the File Does Not Need
4F2EHFree the Last Granule of an Extent
4F6FHAn Extent Has No Granule Left
4FB2HWrite the Directory Record and the Allocation Table
4FD8HBuild the File Specification of a Directory Record
501CHFunction 20H (Request A5H): @FNAME
5029HClose a Device
5042HMake the RES Instruction for a Granule
504FHRead the Allocation Table
5062HWrite the Allocation Table
507BHRead the Hash Index Table
508DHWrite the Hash Index Table

Memory SYS3/SYS Uses

AddressContents
4218H-421CHTIME$ minutes and hours, DATE$ year, day and month, read for the date stamp (4E71H-4E84H, 4EA8H).
4300H-43FFHThe system buffer: the sector of the file's directory record (DIRRD, 4B10H), an extension record's sector and the HIT (507BH) are read into it.
475DHThe date stamping flags of SYS0/SYS, one bit for each drive, set by @CKDRV of SYS2/SYS: read at 4E99H.
4768H, 4772HWRPROT and VERSEC, the disk primitives of SYS0/SYS used to write and verify the allocation table and the HIT.
479CHDCTBYT: bytes +04H and +08H of a drive code table.
4451H, 4B7AH@DIV and DIVEA of SYS0/SYS.
4993HWrite the file's buffer when it was changed (4E24H).
49F1H, 49F3HThe file prologue of SYS0/SYS (5029H, 4E12H); its restore at 4A14H ends @CLOSE.
4B10H, 4B1FH, 4B45H, 4B64HDIRRD, DIRWR, RDSSEC and DIRCYL of SYS0/SYS.
4BC8H-4BC9HThe length of the system file in the overlay area: 02A6H for SYS3/SYS.
4E00H-50A5HSYS3/SYS in the overlay area.
5100H-51FFHThe allocation table of the drive, read by 504FH, changed by 4F2EH and written by 5062H.

Variables

The entry points of SYS3/SYS, then the data of the file, the operands it changes, and the cells of SYS0/SYS it uses, by address.

Entry Points

AddressNameContents
4E00HThe entry: 4E00H picks the function from bits 6-4 of the request code in Register A.
4E0CH@CLOSEFunction 10H (request 95H, 4428H): close a file or a device.
4E69HStamp the date and the time into the directory record.
4F2EHFree the last granule of an extent.
4FD8HWrite the file specification of directory record Register B at Register Pair DE.
501CH@FNAMEFunction 20H (request A5H, 4293H): the file specification of a directory record.
5029HClose a device.
504FHRead the allocation table of drive Register C into 5100H.
5062HWrite the allocation table at 5100H to drive Register C.
507BHRead the HIT of drive Register C into 4300H.
508DHWrite the HIT at 4300H to drive Register C.

Data in the File

Address
Size
Contents
4BC8H-4BC9H
2 bytes
DEFW 02A6H
4BC8H-4BC9H: 02A6H (678), the number of bytes from 4E00H that SYS3/SYS takes up (4E00H-50A5H). Loading SYS3/SYS puts it over the length the system file loaded before it left here.

Self-Modified Operands

Address
Size
Contents
4E9DH
1 byte
The second byte of BIT 0,A at 4E9CH (47H in the file): 4E96H stores 47H + the drive x 8, so the instruction tests bit n of the date stamping flags (475DH) for drive n.
4F9DH
1 byte
The operand of LD B,00H at 4F9CH: the number of the file's own directory record, taken from +01H of an extension record that has become free (4F8EH).
5014H
1 byte
The operand of LD A,00H at 5013H: the drive's digit, 30H-37H (4FDDH), written after the colon of the file specification.
504DH
1 byte
The second byte of RES 0,B at 504CH (80H in the file): 5049H stores 80H + the granule x 8, so the instruction clears the granule's bit of the allocation table byte in Register B.

Cells Outside the File That SYS3/SYS Uses

Address
Size
Contents
4218H
1 byte
TIME$ minutes, kept by the ROM's clock routine (3529H) that the clock task of SYS0/SYS runs: read for +12H-+13H of the directory record (4EA8H).
4219H
1 byte
TIME$ hours: read for +12H of the directory record (4EA8H).
421AH
1 byte
DATE$ year, 80-99 for 1980-1999 and 0-11 for 2000-2011: bits 2-0 into +02H (4E74H), the offset from 1980 into +13H (4EBEH-4EC7H).
421BH
1 byte
DATE$ day of the month: bits 7-3 of +02H (4E7BH).
421CH
1 byte
DATE$ month: bits 3-0 of +01H (4E84H).
4300H-43FFH
256 bytes
The system buffer of SYS0/SYS: the directory sector of the record being worked on, or the HIT between 4F91H and 4F98H.
475DH
1 byte
The date stamping flags, the fifth byte of RSELCT among the disk primitives of SYS0/SYS: bit n for drive n, set by @CKDRV of SYS2/SYS when the diskette carries the directory date format of this release. SYS3/SYS stamps the time only when the drive's bit is set (4E99H).
5100H-51FFH
256 bytes
The page above SYS3/SYS in the overlay area: the allocation table of the drive (one byte for each cylinder, a bit set for each granule in use), read by 504FH and written by 5062H.

Disassembly

4BC8H - The Overlay Length (Data)

Every system file from SYS1/SYS to SYS12/SYS carries a load block for the two bytes 4BC8H-4BC9H in the resident area of SYS0/SYS. They hold the length of the file's part in the overlay area: for SYS3/SYS 02A6H, the 678 bytes 4E00H-50A5H. In the file this block is the last load block, after the three blocks of 4E00H-50A5H and before the transfer address record (4E00H). SYS7/SYS reads and writes the word (its 55E4H, 5692H). The two bytes are data, not instructions.

4BC8-4BC9
DEFW 02A6H A6 02
4BC8H-4BC9H: 02A6H (678), the number of bytes from 4E00H that SYS3/SYS takes up (4E00H-50A5H). Loading SYS3/SYS puts it over the length the system file loaded before it left here.

4E00H - Entry: Pick the Function of the Request

The supervisor dispatcher (4BCCH) loads SYS3/SYS into 4E00H for a request code whose bits 3-0 are 5 and calls 4E00H with Register A = the request code (from OVRLY$, 4414H, which always gets the code of the latest request) and the caller's Register Pairs BC, DE and HL. Bits 6-4 of the code pick the function: 10H (95H, @CLOSE 4428H) close a file or a device; 20H (A5H, @FNAME 4293H) build the file specification of a directory record. Any other function returns at once. The dispatcher has dropped the return address of the RST 28H, so the final RET of a function goes straight back to the program that called the vector.

4E00
AND 70H E6 70
Mask Register A (the request code, 95H or A5H, whose low four bits 5 name SYS3/SYS) with 70H, keeping bits 6-4, the function.
4E02
CP 10H FE 10
Compare Register A (the function) against 10H, @CLOSE (request 95H).
4E04
If the Z FLAG is set (function 10H), JUMP to 4E0CH to close the file or the device whose control block is at Register Pair DE.
4E06
CP 20H FE 20
Compare Register A (the function) against 20H, @FNAME (request A5H).
4E08
If the Z FLAG is set (function 20H), JUMP to 501CH to build the file specification of directory record Register B of drive Register C at Register Pair DE.
4E0B
RET C9
RETurn with Register A = the function and the NZ FLAG: SYS3/SYS has no other function.

4E0CH - Function 10H (Request 95H): @CLOSE

Register Pair DE = the control block of an open file or device. @CLOSE (4428H) is called by BACKUP/CMD, BASIC/CMD, BASIC/OV2, CMDFILE/CMD, CONV/CMD, HELP/CMD, LCOMM/CMD, PATCH/CMD, SYS6/SYS, SYS7/SYS and TED/CMD. A control block whose byte +00H has bits 7 and 6 clear (10H, an open device) is closed at 5029H. For a file the prologue of SYS0/SYS is run, the file's directory record is read, the file's buffer is written when it was changed, and the end of the file is brought into the directory record (4E2AH).

4E0C
LD A,(DE) 1A
Fetch byte +00H of the control block at Register Pair DE into Register A: 80H for an open file, 10H for an open device.
4E0D
AND C0H E6 C0
Mask Register A (byte +00H of the control block) with C0H to bits 7 and 6.
4E0F
If the Z FLAG is set (bits 7 and 6 clear, as in the 10H of an open device), JUMP to 5029H to close a device.
4E12
GOSUB to 49F3H, the file prologue of SYS0/SYS. When bit 7 of +00H is clear it returns error 26H (file not open) straight to the program. Otherwise Index Register IX = the control block, the caller's Register Pairs BC, DE and HL and Index Register IX are saved, Register A = 00H, and the last RET of this routine goes to 4A14H, which restores them.
4E15
LD B,(IX+07H) DD 46 07
Load Register B with byte +07H of the control block at Index Register IX: the number of the file's directory record.
4E18
LD C,(IX+06H) DD 4E 06
Load Register C with byte +06H of the control block at Index Register IX: the drive the file is on.
4E1B
GOSUB to 4B10H (DIRRD) to read the directory sector holding record Register B of drive Register C into 4300H: the Z FLAG and Register Pair HL at the record, or the NZ FLAG with Register A = 11H (directory read error).
4E1E
RET NZ C0
If the NZ FLAG is set (the read failed), RETurn through 4A14H with Register A = 11H.
4E1F
BIT 4,(HL) CB 66
Test bit 4 of the attribute byte (+00H) of the record at Register Pair HL: set while the record belongs to a file.
4E21
RET Z C8
If the Z FLAG is set (the record is free: the file was killed while it was open), RETurn through 4A14H with the Z FLAG and Register A = 11H, the value DIRRD leaves on success. Nothing is written.
4E22
PUSH HL E5
Save Register Pair HL (the directory record) to the stack.
4E23
PUSH BC C5
Save Register Pair BC (Register B = the record number, Register C = the drive) to the stack.
4E24
GOSUB to 4993H to write the file's buffer to its sector when the file is in byte mode (bit 7 of +01H) and the buffer was changed (bit 4 of +01H): Register A = 00H and the Z FLAG, or an error number with the NZ FLAG.
4E27
POP BC C1
Restore Register Pair BC (the record number and the drive) from the stack.
4E28
POP HL E1
Restore Register Pair HL (the directory record) from the stack.
4E29
RET NZ C0
If the NZ FLAG is set (the buffer could not be written), RETurn through 4A14H with the error number in Register A.

4E2AH - Put the End of the File into the Directory Record

Register Pair HL = the file's directory record in the sector at 4300H. The end of file byte (+08H) and the ending record number (+0CH-+0DH) of the control block are compared with the record's +03H and +14H-+15H and copied into the record when they differ. Bit 2 of +00H of the control block, set by the sector write of SYS0/SYS (49C6H) whenever a sector of the file is written, then decides: a written file gets the date stamp (4E69H) and its record is written; a changed record of a file that was not written is written without a new date (4ECFH); otherwise the record is not written (4ED5H). Register Pair HL ends at the record's +15H on every path.

4E2A
LD A,03H 3E 03
Load Register A with 03H, the offset of the end of file byte in a directory record.
4E2C
ADD A,L 85
ADD Register L (the low byte of the record's address) to Register A.
4E2D
LD L,A 6F
Copy Register A into Register L: Register Pair HL = the record's +03H, its end of file byte. A record is one of the 32 byte slots of the sector at 4300H, so Register H does not change.
4E2E
LD A,(IX+08H) DD 7E 08
Load Register A with byte +08H of the control block at Index Register IX: the file's end of file byte, the position of the end in its last sector.
4E31
PUSH HL E5
Save Register Pair HL (the record's +03H) to the stack.
4E32
CP (HL) BE
Compare Register A (the control block's end of file byte) with the record's +03H at Register Pair HL.
4E33
If the NZ FLAG is set (they differ), JUMP to 4E49H to copy the end of the file into the record.
4E35
LD A,11H 3E 11
Load Register A with 11H, the distance from +03H to +14H.
4E37
ADD A,L 85
ADD Register L (the low byte of the record's +03H) to Register A.
4E38
LD L,A 6F
Copy Register A into Register L: Register Pair HL = the record's +14H, the low byte of its ending record number.
4E39
LD A,(IX+0CH) DD 7E 0C
Load Register A with byte +0CH of the control block at Index Register IX: the low byte of the file's ending record number.
4E3C
CP (HL) BE
Compare Register A with the record's +14H at Register Pair HL.
4E3D
If the NZ FLAG is set (they differ), JUMP to 4E49H to copy the end of the file into the record.
4E3F
INC L 2C
INCrement Register L: Register Pair HL = the record's +15H, the high byte of the ending record number.
4E40
LD A,(IX+0DH) DD 7E 0D
Load Register A with byte +0DH of the control block at Index Register IX: the high byte of the file's ending record number.
4E43
CP (HL) BE
Compare Register A with the record's +15H at Register Pair HL.
4E44
If the NZ FLAG is set (they differ), JUMP to 4E49H to copy the end of the file into the record.
4E46
POP AF F1
Take the saved address of the record's +03H off the stack into Register Pair AF, where it is not used: the record already holds the end of the file. Register Pair HL stays at the record's +15H.
4E47
JUMP to 4E63H to look at bit 2 of the control block.
4E49
POP HL E1
Restore Register Pair HL from the stack: the record's +03H.
4E4A
LD A,(IX+08H) DD 7E 08
Load Register A with byte +08H of the control block at Index Register IX: the end of file byte.
4E4D
LD (HL),A 77
Store Register A (the end of file byte) at the record's +03H (Register Pair HL).
4E4E
LD A,11H 3E 11
Load Register A with 11H, the distance from +03H to +14H.
4E50
ADD A,L 85
ADD Register L (the low byte of the record's +03H) to Register A.
4E51
LD L,A 6F
Copy Register A into Register L: Register Pair HL = the record's +14H.
4E52
LD A,(IX+0CH) DD 7E 0C
Load Register A with byte +0CH of the control block at Index Register IX: the low byte of the ending record number.
4E55
LD (HL),A 77
Store Register A at the record's +14H (Register Pair HL).
4E56
INC L 2C
INCrement Register L: Register Pair HL = the record's +15H.
4E57
LD A,(IX+0DH) DD 7E 0D
Load Register A with byte +0DH of the control block at Index Register IX: the high byte of the ending record number.
4E5A
LD (HL),A 77
Store Register A at the record's +15H (Register Pair HL).
4E5B
BIT 2,(IX+00H) DD CB 00 56
Test bit 2 of byte +00H of the control block at Index Register IX: set by the sector write of SYS0/SYS (49C6H) when a sector of the file was written.
4E5F
If the Z FLAG is set (no sector of the file was written), JUMP to 4ECFH to write the changed record without a new date.
4E61
JUMP to 4E69H to stamp the date into the record before it is written.
4E63
BIT 2,(IX+00H) DD CB 00 56
Test bit 2 of byte +00H of the control block at Index Register IX: set when a sector of the file was written.
4E67
If the Z FLAG is set (the file was not written and its record is unchanged), JUMP to 4ED5H: the record is not written back. Otherwise go on into 4E69H.

4E69H - Stamp the Date and the Time into the Directory Record

Register Pair HL = the record's +15H, Register B = the record number, Register C = the drive. Bit 6 of the record's +01H, the MOD flag (the file was changed since it was last backed up; DIR shows it as +), is set, and the date of DATE$ goes into the record: the month (421CH) into bits 3-0 of +01H, the day (421BH) into bits 7-3 of +02H and bits 2-0 of the year (421AH) into bits 2-0 of +02H. When the bit of the drive in 475DH is set (@CKDRV of SYS2/SYS sets it when the diskette carries the directory date format of this release) the time goes into +12H-+13H too: the hours (4219H) in bits 7-3 of +12H, the minutes (4218H) in bits 2-0 of +12H and bits 7-5 of +13H, and the year as an offset from 1980 (0-31) in bits 4-0 of +13H. The seconds are not kept.

4E69
PUSH HL E5
Save Register Pair HL (the record's +15H) to the stack.
4E6A
LD A,L 7D
Copy Register L (the low byte of the record's +15H) into Register A.
4E6B
AND E0H E6 E0
Mask Register A with E0H, the record's place in its sector: the low byte of the record's +00H.
4E6D
LD L,A 6F
Copy Register A into Register L: Register Pair HL = the record's +00H, its attribute byte.
4E6E
INC L 2C
INCrement Register L: Register Pair HL = the record's +01H.
4E6F
SET 6,(HL) CB F6
Set bit 6 of the record's +01H at Register Pair HL, the MOD flag: the file was changed since it was last backed up.
4E71
LD DE,421AH 11 1A 42
Load Register Pair DE with 421AH, the year of DATE$.
4E74
LD A,(DE) 1A
Fetch the year from 421AH (Register Pair DE) into Register A: a binary number, 80-99 for 1980-1999 and 0-11 for 2000-2011.
4E75
PUSH AF F5
Save Register Pair AF (Register A = the year) to the stack for the time stamp.
4E76
PUSH BC C5
Save Register Pair BC (Register B = the record number, Register C = the drive) to the stack.
4E77
AND 07H E6 07
Mask Register A (the year) with 07H to bits 2-0, the part that goes into +02H.
4E79
LD B,A 47
Copy Register A (bits 2-0 of the year) into Register B.
4E7A
INC DE 13
INCrement Register Pair DE to 421BH, the day of the month (1-31).
4E7B
LD A,(DE) 1A
Fetch the day from 421BH (Register Pair DE) into Register A.
4E7C
RLCA 07
Rotate Register A (the day) left one bit, the first of three rotations.
4E7D
RLCA 07
Rotate Register A (the day) left one bit again.
4E7E
RLCA 07
Rotate Register A (the day) left a third time: the day is in bits 7-3.
4E7F
OR B B0
OR Register B (bits 2-0 of the year) into Register A: the day in bits 7-3, the year in bits 2-0.
4E80
INC L 2C
INCrement Register L: Register Pair HL = the record's +02H.
4E81
LD (HL),A 77
Store Register A (the day and the year bits) at the record's +02H (Register Pair HL).
4E82
DEC L 2D
DECrement Register L: Register Pair HL = the record's +01H again.
4E83
INC DE 13
INCrement Register Pair DE to 421CH, the month (1-12).
4E84
LD A,(DE) 1A
Fetch the month from 421CH (Register Pair DE) into Register A.
4E85
LD B,A 47
Copy Register A (the month, 1-12) into Register B for the OR below.
4E86
LD A,(HL) 7E
Fetch the record's +01H from Register Pair HL into Register A.
4E87
AND F0H E6 F0
Mask Register A with F0H to bits 7-4, the flags of +01H, the MOD flag of 4E6FH among them.
4E89
OR B B0
OR Register B (the month) into Register A: the month in bits 3-0.
4E8A
LD (HL),A 77
Store Register A (the flags and the month) at the record's +01H (Register Pair HL).
4E8B
LD A,C 79
Copy Register C (the drive the file is on) into Register A.
4E8C
AND 07H E6 07
Mask Register A with 07H to bits 2-0, the drive number 0-7.
4E8E
LD B,A 47
Copy Register A (the drive number 0-7) into Register B.
4E8F
INC B 04
INCrement Register B: the drive plus one, the count of the loop below.
4E90
LD A,3FH 3E 3F
Load Register A with 3FH, 8 less than 47H, the second byte of BIT 0,A.
4E92
ADD A,08H C6 08
ADD 08H to Register A: the next bit number in bits 5-3 of the BIT instruction's second byte.
4E94
DECrement Register B and LOOP BACK to 4E92H until Register A = 47H + the drive x 8, the second byte of BIT n,A for bit n = the drive.
4E96
LD (4E9DH),A 32 9D 4E
Store Register A at 4E9DH, the second byte of the BIT instruction at 4E9CH.
4E99
LD A,(475DH) 3A 5D 47
Fetch the date stamping flags from 475DH into Register A: bit n is set by @CKDRV of SYS2/SYS when the diskette in drive n carries the directory date format of this release.
4E9C
BIT 0,A CB 47
Test the drive's bit of Register A (the date stamping flags): the instruction is BIT 0,A in the file and BIT n,A for drive n after 4E96H.
4E9E
If the NZ FLAG is set (the diskette carries the date format of this release), JUMP to 4EA4H to stamp the time too.
4EA0
POP BC C1
Restore Register Pair BC (the record number and the drive) from the stack.
4EA1
POP AF F1
Restore Register Pair AF from the stack: the year in Register A is not needed.
4EA2
JUMP to 4ECEH to write the record with the date but without the time.
4EA4
LD A,L 7D
Copy Register L (the low byte of the record's +01H) into Register A.
4EA5
ADD A,11H C6 11
ADD 11H to Register A: the low byte of the record's +12H.
4EA7
LD L,A 6F
Copy Register A into Register L: Register Pair HL = the record's +12H.
4EA8
LD DE,(4218H) ED 5B 18 42
Load Register Pair DE with the word at 4218H-4219H of TIME$: Register E = the minutes (4218H), Register D = the hours (4219H).
4EAC
LD A,D 7A
Copy Register D (the hours, 0-23, from 4219H) into Register A.
4EAD
LD D,E 53
Copy Register E (the minutes) into Register D.
4EAE
LD E,00H 1E 00
Load Register E with 00H: Register Pair DE = the minutes x 256.
4EB0
LD B,03H 06 03
Load Register B with 03H, the number of shifts.
4EB2
SRL D CB 3A
Shift Register D (the minutes) right one bit, bit 0 into the CARRY FLAG.
4EB4
RR E CB 1B
Rotate the CARRY FLAG into bit 7 of Register E: Register Pair DE moves right one bit.
4EB6
DECrement Register B and LOOP BACK to 4EB2H until Register Pair DE has moved three bits: Register D = bits 5-3 of the minutes, Register E = bits 2-0 of the minutes in its bits 7-5.
4EB8
RLCA 07
Rotate Register A (the hours) left one bit, the first of three rotations.
4EB9
RLCA 07
Rotate Register A (the hours) left one bit again.
4EBA
RLCA 07
Rotate Register A (the hours) left a third time: the hours (0-23) are in bits 7-3.
4EBB
OR D B2
OR Register D (bits 5-3 of the minutes) into Register A: bits 2-0.
4EBC
LD D,A 57
Copy Register A into Register D: the byte for the record's +12H.
4EBD
POP BC C1
Restore Register Pair BC (the record number and the drive) from the stack.
4EBE
POP AF F1
Restore Register Pair AF from the stack: Register A = the year from 421AH (80-99 or 0-11).
4EBF
CP 0CH FE 0C
Compare Register A (the year) against 0CH (12).
4EC1
If the NO CARRY FLAG is set (12 or more: a year from 1980 to 1999), JUMP to 4EC5H.
4EC3
ADD A,64H C6 64
ADD 64H (100) to Register A: the years 2000-2011 become 100-111.
4EC5
SUB 50H D6 50
SUBtract 50H (80) from Register A: the year as an offset from 1980, 0-31.
4EC7
AND 1FH E6 1F
Mask Register A (the year offset from 1980) with 1FH to bits 4-0.
4EC9
OR E B3
OR Register E (bits 2-0 of the minutes, in bits 7-5) into Register A: the byte for the record's +13H.
4ECA
LD E,A 5F
Copy Register A (the byte for the record's +13H) into Register E.
4ECB
LD (HL),D 72
Store Register D (the hours and bits 5-3 of the minutes) at the record's +12H (Register Pair HL).
4ECC
INC HL 23
INCrement Register Pair HL to the record's +13H.
4ECD
LD (HL),E 73
Store Register E (bits 2-0 of the minutes and the year offset) at the record's +13H (Register Pair HL).
4ECE
POP HL E1
Restore Register Pair HL from the stack: the record's +15H.

4ECFH - Write the Directory Record and Count the File's Granules

4ECFH writes the sector with the record (Register B, drive Register C) back to the diskette. 4ED5H looks at bit 7 of the record's +01H, the create flag: a file whose space was set by CREATE keeps all of it (the manual: such a file never becomes smaller than its created size). For any other file the granules of its extents are counted into Register Pair DE, following the link (FEH and a record number in place of an extent) to the extension records that hold its further extents.

4ECF
PUSH HL E5
Save Register Pair HL (the record's +15H) to the stack.
4ED0
GOSUB to 4B1FH (DIRWR) to write the directory sector at 4300H, the one holding record Register B, back to drive Register C with the deleted data mark and verify it: Register A = 00H and the Z FLAG, or 12H (directory write error) or 0FH (write protected) with the NZ FLAG.
4ED3
POP HL E1
Restore Register Pair HL (the record's +15H) from the stack.
4ED4
RET NZ C0
If the NZ FLAG is set (the write failed), RETurn through 4A14H with the error number in Register A.
4ED5
INC L 2C
INCrement Register L: Register Pair HL = the record's +16H, its first extent.
4ED6
PUSH HL E5
Save Register Pair HL (the first extent) to the stack.
4ED7
LD A,L 7D
Copy Register L (the low byte of the record's +16H) into Register A.
4ED8
SUB 15H D6 15
SUBtract 15H from Register A: the low byte of the record's +01H.
4EDA
LD L,A 6F
Copy Register A into Register L: Register Pair HL = the record's +01H.
4EDB
BIT 7,(HL) CB 7E
Test bit 7 of the record's +01H at Register Pair HL, the create flag (SYS7/SYS sets and clears it, its 533EH).
4EDD
POP HL E1
Restore Register Pair HL (the first extent) from the stack.
4EDE
If the NZ FLAG is set (a file made by CREATE), JUMP to 4FC5H: its granules are kept.
4EE1
LD DE,0000H 11 00 00
Load Register Pair DE with 0000H, the count of the granules in the file's extents.
4EE4
LD A,(HL) 7E
Fetch the extent's first byte from Register Pair HL into Register A: its cylinder, or FEH (the next byte is the number of an extension record) or FFH (no more extents).
4EE5
INC L 2C
INCrement Register L to the extent's second byte.
4EE6
CP FEH FE FE
Compare Register A (the first byte) against FEH.
4EE8
If the NO CARRY FLAG is set (FEH or FFH: not an extent), JUMP to 4EF6H.
4EEA
LD A,(HL) 7E
Fetch the extent's second byte from Register Pair HL into Register A: bits 7-5 the first granule of the extent on its cylinder, bits 4-0 the number of its granules less one.
4EEB
INC L 2C
INCrement Register L to the first byte of the next extent of the record.
4EEC
AND 1FH E6 1F
Mask Register A with 1FH to bits 4-0: the number of granules less one.
4EEE
INC A 3C
INCrement Register A: the number of granules in the extent.
4EEF
ADD A,E 83
ADD Register E (the low byte of the count) to Register A.
4EF0
LD E,A 5F
Copy Register A into Register E: the new low byte of the count in Register Pair DE.
4EF1
If the NO CARRY FLAG is set (no carry out of Register E), LOOP BACK to 4EE4H for the next extent.
4EF3
INC D 14
INCrement Register D: the carry into the high byte of the count in Register Pair DE.
4EF4
LOOP BACK to 4EE4H to add the granules of the next extent to Register Pair DE.
4EF6
If the NZ FLAG is set (FFH: every extent is counted), JUMP to 4F03H with Register Pair HL one byte past the FFH. For FEH go on: the file has an extension record.
4EF8
LD B,(HL) 46
Load Register B with the byte at Register Pair HL: the number of the extension record (attribute bit 7 set) that holds the file's further extents.
4EF9
GOSUB to 4B10H (DIRRD) to read the directory sector holding record Register B of drive Register C into 4300H: Register Pair HL = the extension record.
4EFC
RET NZ C0
If the NZ FLAG is set (the read failed), RETurn through 4A14H with Register A = 11H (directory read error).
4EFD
LD A,L 7D
Copy Register L (the low byte of the extension record) into Register A.
4EFE
ADD A,16H C6 16
ADD 16H to Register A: the low byte of the record's +16H, its first extent.
4F00
LD L,A 6F
Copy Register A into Register L: Register Pair HL = the extension record's first extent.
4F01
LOOP BACK to 4EE4H to add the granules of its extents to Register Pair DE.

4F03H - Work Out the Granules the File Does Not Need

Register Pair DE = the granules in the file's extents, Register Pair HL = one byte past the FFH that ends them, in the record whose sector is at 4300H (Register B). The granules the file needs are its ending record number (the sectors it uses) divided by the sectors in a granule, rounded up. When the extents hold more, the difference is freed: the allocation table is read into 5100H and the work starts at the last extent (4F6FH).

4F03
PUSH HL E5
Save Register Pair HL (one byte past the FFH that ends the extents) to the stack.
4F04
LD L,(IX+0CH) DD 6E 0C
Load Register L with byte +0CH of the control block at Index Register IX: the low byte of the ending record number, the number of sectors the file uses.
4F07
LD H,(IX+0DH) DD 66 0D
Load Register H with byte +0DH of the control block at Index Register IX: Register Pair HL = the ending record number.
4F0A
LD A,08H 3E 08
Load Register A with 08H, the offset of byte +08H in a drive code table.
4F0C
GOSUB to 479CH (DCTBYT): Register A = byte +08H of drive Register C's table, bits 4-0 the sectors in a granule less one.
4F0F
AND 1FH E6 1F
Mask Register A with 1FH to bits 4-0: the sectors in a granule less one.
4F11
PUSH AF F5
Save Register Pair AF (Register A = the sectors in a granule less one) to the stack.
4F12
ADD A,L 85
ADD Register L (the low byte of the ending record number) to Register A.
4F13
LD L,A 6F
Copy Register A into Register L: the low byte of the rounded count.
4F14
If the NO CARRY FLAG is set (no carry out of Register L), JUMP to 4F17H.
4F16
INC H 24
INCrement Register H, the carry: Register Pair HL = the ending record number + the sectors in a granule less one, so the division rounds up.
4F17
POP AF F1
Restore Register Pair AF from the stack: Register A = the sectors in a granule less one.
4F18
INC A 3C
INCrement Register A: the sectors in a granule.
4F19
GOSUB to 4451H (@DIV) to divide Register Pair HL by Register A: Register Pair HL = the granules the file needs, Register A = the remainder.
4F1C
XOR A AF
Set Register A to 00H (XOR A), which clears the CARRY FLAG for the SBC.
4F1D
EX DE,HL EB
Exchange Register Pairs DE and HL: Register Pair HL = the granules in the extents, Register Pair DE = the granules needed.
4F1E
SBC HL,DE ED 52
SUBtract Register Pair DE (the granules needed) and the CARRY FLAG (clear) from Register Pair HL (the granules in the extents): Register Pair HL = the granules to free.
4F20
EX DE,HL EB
Exchange Register Pairs DE and HL: Register Pair DE = the granules to free, Register Pair HL = the granules needed.
4F21
POP HL E1
Restore Register Pair HL from the stack: one byte past the FFH that ends the extents.
4F22
If the Z FLAG is set (no granule to free), JUMP to 4FC5H.
4F25
If the CARRY FLAG is set (the extents hold fewer granules than the file needs), JUMP to 4FC5H: nothing is freed.
4F28
GOSUB to 504FH to read the allocation table of drive Register C into 5100H.
4F2B
RET NZ C0
If the NZ FLAG is set (the read failed), RETurn through 4A14H with Register A = 14H (GAT read error).
4F2C
JUMP to 4F6FH to make the FFH entry an unused entry (FFH FFH) and step back to the file's last extent.

4F2EH - Free the Last Granule of an Extent

Register Pair HL = the second byte of the extent, Register Pair DE = the granules still to free, Register B = the record whose sector is at 4300H, Register C = the drive, and the allocation table at 5100H (one byte for each cylinder, a bit set for each granule in use). The extent's last granule is found (its cylinder and its place on the cylinder), its bit in the allocation table is cleared and the extent's count of granules is lowered by one. An extent left with no granule goes on at 4F6FH.

4F2E
PUSH DE D5
Save Register Pair DE (the granules still to free) to the stack.
4F2F
LD A,(HL) 7E
Fetch the extent's second byte from Register Pair HL into Register A.
4F30
AND E0H E6 E0
Mask Register A with E0H to bits 7-5: the first granule of the extent on its cylinder.
4F32
RLCA 07
Rotate Register A left one bit, the first of three rotations.
4F33
RLCA 07
Rotate Register A (the first granule in bits 7-5) left one bit again.
4F34
RLCA 07
Rotate Register A left a third time: bits 7-5 are now bits 2-0, the first granule (0-7).
4F35
LD E,A 5F
Copy Register A (the first granule) into Register E.
4F36
LD A,(HL) 7E
Fetch the extent's second byte from Register Pair HL into Register A again.
4F37
AND 1FH E6 1F
Mask Register A with 1FH to bits 4-0: the number of granules less one.
4F39
ADD A,E 83
ADD Register E (the first granule) to Register A: the extent's last granule, counted from granule 0 of the extent's cylinder.
4F3A
LD E,A 5F
Copy Register A (the last granule) into Register E.
4F3B
LD A,08H 3E 08
Load Register A with 08H, the offset of byte +08H in a drive code table.
4F3D
GOSUB to 479CH (DCTBYT): Register A = byte +08H of drive Register C's table, bits 7-5 the granules on a track less one.
4F40
RLCA 07
Rotate Register A left one bit, the first of three rotations.
4F41
RLCA 07
Rotate Register A (byte +08H of the drive code table) left one bit again.
4F42
RLCA 07
Rotate Register A left a third time: bits 7-5 are now bits 2-0.
4F43
AND 07H E6 07
Mask Register A with 07H to bits 2-0: the granules on a track less one.
4F45
INC A 3C
INCrement Register A: the granules on a track.
4F46
LD D,A 57
Copy Register A (the granules on a track) into Register D.
4F47
LD A,04H 3E 04
Load Register A with 04H, the offset of byte +04H in a drive code table.
4F49
GOSUB to 479CH (DCTBYT): Register A = byte +04H of drive Register C's table.
4F4C
BIT 5,A CB 6F
Test bit 5 of Register A (byte +04H): set when the drive uses both sides.
4F4E
LD A,D 7A
Copy Register D (the granules on a track) into Register A. LD does not change the flags.
4F4F
If the Z FLAG is set (one side), JUMP to 4F52H.
4F51
RLCA 07
Rotate Register A left one bit: twice the granules, two tracks to a cylinder.
4F52
GOSUB to 4B7AH (DIVEA) to divide Register E (the last granule) by Register A (the granules on a cylinder): Register A = the cylinders past the extent's cylinder, Register E = the granule's place on its cylinder.
4F55
DEC L 2D
DECrement Register L: Register Pair HL = the extent's first byte, its cylinder.
4F56
ADD A,(HL) 86
ADD the extent's cylinder at Register Pair HL to Register A: the cylinder that holds the granule.
4F57
LD D,A 57
Copy Register A (the cylinder) into Register D.
4F58
PUSH HL E5
Save Register Pair HL (the extent's first byte) to the stack.
4F59
PUSH BC C5
Save Register Pair BC (Register B = the record number, Register C = the drive) to the stack.
4F5A
LD H,51H 26 51
Load Register H with 51H, the page of the allocation table read into 5100H.
4F5C
LD L,D 6A
Copy Register D (the cylinder) into Register L: Register Pair HL = 5100H + the cylinder, the allocation table byte of the cylinder.
4F5D
LD B,(HL) 46
Fetch the allocation table byte at Register Pair HL into Register B: a bit set for each granule of the cylinder that is in use.
4F5E
LD A,E 7B
Copy Register E (the granule's place on its cylinder) into Register A.
4F5F
GOSUB to 5042H to clear bit Register A (the granule) of Register B.
4F62
LD (HL),B 70
Store Register B (the cylinder's byte with the granule free) into the allocation table at Register Pair HL.
4F63
POP BC C1
Restore Register Pair BC (the record number and the drive) from the stack.
4F64
POP HL E1
Restore Register Pair HL (the extent's first byte) from the stack.
4F65
INC L 2C
INCrement Register L to the extent's second byte.
4F66
DEC (HL) 35
DECrement the extent's second byte at Register Pair HL: one granule less. When bits 4-0 were 00H (one granule) they become 1FH.
4F67
LD A,(HL) 7E
Fetch the extent's second byte from Register Pair HL into Register A.
4F68
INC A 3C
INCrement Register A (the extent's second byte) for the test of bits 4-0.
4F69
AND 1FH E6 1F
Mask Register A to bits 4-0: 00H with the Z FLAG when bits 4-0 of the byte are 1FH, the extent has no granule left.
4F6B
POP DE D1
Restore Register Pair DE (the granules still to free) from the stack. POP does not change the flags.
4F6C
DEC DE 1B
DECrement Register Pair DE: one granule is freed. DEC of a register pair does not change the flags.
4F6D
If the NZ FLAG is set (the extent still has granules), JUMP to 4FB2H.

4F6FH - An Extent Has No Granule Left

Register Pair HL = the second byte of an extent with no granule left (or, from 4F2CH, the byte after the FFH that ended the extents). The two bytes become FFH FFH, the mark of an unused entry and of the end of the extents, and Register Pair HL steps back to the extent before. When there is none in this record and the record is an extension record (attribute bit 7), the extension record is freed: its attribute becomes 00H, its byte in the HIT 00H, and the link at +1EH-+1FH of the file's own record (whose number the extension record holds at +01H) becomes FFH FFH. The work then goes on at the last extent of the file's own record.

4F6F
LD (HL),FFH 36 FF
Store FFH at the extent's second byte (Register Pair HL).
4F71
DEC L 2D
DECrement Register L to the extent's first byte.
4F72
LD (HL),FFH 36 FF
Store FFH at the extent's first byte (Register Pair HL): the entry is unused and ends the extents.
4F74
DEC L 2D
DECrement Register L to the second byte of the extent before.
4F75
LD A,L 7D
Copy Register L (the low byte of the extent before) into Register A.
4F76
AND 1FH E6 1F
Mask Register A with 1FH to bits 4-0: the place of Register Pair HL in its 32 byte record.
4F78
CP 15H FE 15
Compare Register A against 15H, the place below the first extent (+16H).
4F7A
If the NZ FLAG is set (Register Pair HL is at an extent of this record), JUMP to 4FB2H.
4F7C
XOR L AD
Exclusive OR Register L into Register A (15H): bits 4, 2 and 0 of the low byte are cleared, leaving the low byte of the record's +00H.
4F7D
LD L,A 6F
Copy Register A into Register L: Register Pair HL = the record's +00H, its attribute byte.
4F7E
BIT 7,(HL) CB 7E
Test bit 7 of the attribute byte at Register Pair HL: set for an extension record.
4F80
If the Z FLAG is set (the file's own record), JUMP to 4FB2H.
4F82
LD (HL),00H 36 00
Store 00H at the attribute byte (Register Pair HL): the extension record is free.
4F84
GOSUB to 4B1FH (DIRWR) to write the directory sector at 4300H, the one holding record Register B, back to drive Register C with the deleted data mark and verify it.
4F87
RET NZ C0
If the NZ FLAG is set (the write failed), RETurn through 4A14H with the error number in Register A (12H or 0FH).
4F88
LD A,B 78
Copy Register B (the extension record's number) into Register A.
4F89
AND E0H E6 E0
Mask Register A with E0H: the record's place in its sector.
4F8B
INC A 3C
INCrement Register A: the low byte of the record's +01H.
4F8C
LD L,A 6F
Copy Register A into Register L: Register Pair HL = the extension record's +01H (Register H is 43H).
4F8D
LD A,(HL) 7E
Fetch the extension record's +01H from Register Pair HL into Register A: the number of the file's own record.
4F8E
LD (4F9DH),A 32 9D 4F
Store Register A (the file's own record number) at 4F9DH, the operand of LD B,00H at 4F9CH.
4F91
GOSUB to 507BH to read the HIT of drive Register C into 4300H.
4F94
RET NZ C0
If the NZ FLAG is set (the read failed), RETurn through 4A14H with Register A = 16H (HIT read error).
4F95
LD L,B 68
Copy Register B (the extension record's number) into Register L: Register Pair HL = its byte in the HIT at 4300H.
4F96
LD (HL),00H 36 00
Store 00H at the HIT byte (Register Pair HL): the directory record is free.
4F98
GOSUB to 508DH to write the HIT at 4300H to drive Register C and verify it.
4F9B
RET NZ C0
If the NZ FLAG is set (the write failed), RETurn through 4A14H with Register A = 17H (HIT write error).
4F9C
LD B,00H 06 00
Load Register B with the number of the file's own record (the operand at 4F9DH: 00H in the file, stored by 4F8EH).
4F9E
GOSUB to 4B10H (DIRRD) to read the directory sector holding record Register B of drive Register C into 4300H: Register Pair HL = the record.
4FA1
RET NZ C0
If the NZ FLAG is set (the read failed), RETurn through 4A14H with Register A = 11H (directory read error).
4FA2
LD A,B 78
Copy Register B (the record number) into Register A.
4FA3
OR 1FH F6 1F
OR 1FH into Register A: bits 7-5 of the record number (its place in the sector) and 1FH, the low byte of the record's +1FH.
4FA5
LD L,A 6F
Copy Register A into Register L: Register Pair HL = the record's +1FH.
4FA6
LD (HL),FFH 36 FF
Store FFH at the record's +1FH (Register Pair HL).
4FA8
DEC L 2D
DECrement Register L: Register Pair HL = the record's +1EH, the link byte.
4FA9
LD (HL),FFH 36 FF
Store FFH at the record's +1EH (Register Pair HL): the link to the extension record is gone.
4FAB
DEC L 2D
DECrement Register L: Register Pair HL = the record's +1DH, the second byte of its fourth extent.
4FAC
PUSH HL E5
Save Register Pair HL (the record's +1DH) to the stack.
4FAD
GOSUB to 4B1FH (DIRWR) to write the sector with record Register B back to drive Register C and verify it.
4FB0
POP HL E1
Restore Register Pair HL (the record's +1DH) from the stack.
4FB1
RET NZ C0
If the NZ FLAG is set (the write failed), RETurn through 4A14H with the error number in Register A.

4FB2H - Write the Directory Record and the Allocation Table

While granules remain to be freed (Register Pair DE) the work goes back to 4F2EH. Then the directory sector at 4300H is written; a write protected diskette (error 0FH) is not an error here: nothing is written and the close goes on. Otherwise the allocation table at 5100H is written too. 4FC5H, where every path of the close meets, reads the sector of the file's own record again when another sector is at 4300H, and points Register Pair DE at the control block for 4FD8H.

4FB2
LD A,D 7A
Copy Register D (the high byte of the granules still to free) into Register A.
4FB3
OR E B3
OR Register E (the low byte) into Register A: the Z FLAG is set when Register Pair DE is 0000H.
4FB4
If the NZ FLAG is set (granules remain to be freed), JUMP to 4F2EH with Register Pair HL at the second byte of the last extent.
4FB7
GOSUB to 4B1FH (DIRWR) to write the directory sector at 4300H, the one holding record Register B, back to drive Register C and verify it.
4FBA
If the Z FLAG is set (written), JUMP to 4FC1H to write the allocation table.
4FBC
CP 0FH FE 0F
Compare Register A (the error number) against 0FH, write protected.
4FBE
RET NZ C0
If the NZ FLAG is set (another error), RETurn through 4A14H with the error number in Register A (12H, directory write error).
4FBF
JUMP to 4FC5H: on a write protected diskette nothing is written and the close goes on.
4FC1
GOSUB to 5062H to write the allocation table at 5100H to drive Register C and verify it.
4FC4
RET NZ C0
If the NZ FLAG is set (the write failed), RETurn through 4A14H with Register A = 15H (GAT write error).
4FC5
LD A,(IX+07H) DD 7E 07
Load Register A with byte +07H of the control block at Index Register IX: the number of the file's own directory record.
4FC8
LD C,(IX+06H) DD 4E 06
Load Register C with byte +06H of the control block at Index Register IX: the drive.
4FCB
XOR B A8
Exclusive OR Register B (the record whose sector is at 4300H) into Register A.
4FCC
AND 1FH E6 1F
Mask Register A with 1FH to bits 4-0: 00H with the Z FLAG when both records are in the same sector (bits 4-0 of a record number give its sector).
4FCE
LD B,(IX+07H) DD 46 07
Load Register B with byte +07H of the control block at Index Register IX: the file's own record. LD does not change the flags.
4FD1
If the NZ FLAG is set (another sector is at 4300H), GOSUB to 4B10H (DIRRD) to read the sector holding record Register B of drive Register C into 4300H.
4FD4
RET NZ C0
If the NZ FLAG is set (the read failed), RETurn through 4A14H with Register A = 11H (directory read error).
4FD5
PUSH IX DD E5
Save Index Register IX (the control block) to the stack.
4FD7
POP DE D1
Restore Register Pair DE from the stack: Register Pair DE = the control block, where 4FD8H writes the file specification. Go on into 4FD8H.

4FD8H - Build the File Specification of a Directory Record

Register B = a directory record whose sector is at 4300H, Register C = its drive, Register Pair DE = where the text goes. The text is the name without its trailing spaces, then a / and the extension when the extension is not blank, then a colon, the drive's digit and 03H, the end of text mark of a file specification: NAME/EXT:d. No password is written. After @CLOSE the control block holds this text, so a program can open the file again with the same block. Returns Register A = 00H with the Z FLAG and Register Pair DE at the 03H; Register B is changed.

4FD8
LD A,C 79
Copy Register C (the drive of the directory record) into Register A.
4FD9
AND 07H E6 07
Mask Register A with 07H to bits 2-0, the drive number 0-7.
4FDB
OR 30H F6 30
OR 30H into Register A: the character of the drive's digit, 30H-37H (0-7).
4FDD
LD (5014H),A 32 14 50
Store Register A (the drive's digit) at 5014H, the operand of LD A,00H at 5013H.
4FE0
LD H,43H 26 43
Load Register H with 43H, the page of the directory sector at 4300H.
4FE2
LD A,B 78
Copy Register B (the record number) into Register A.
4FE3
AND E0H E6 E0
Mask Register A with E0H: the record's place in its sector.
4FE5
OR 05H F6 05
OR 05H into Register A: the low byte of the record's +05H, its file name.
4FE7
LD L,A 6F
Copy Register A into Register L: Register Pair HL = the record's file name (8 bytes, padded with spaces).
4FE8
PUSH HL E5
Save Register Pair HL (the record's +05H) to the stack.
4FE9
LD B,08H 06 08
Load Register B with 08H, the length of the name field.
4FEB
LD A,(HL) 7E
Fetch a character of the name from Register Pair HL into Register A.
4FEC
CP 20H FE 20
Compare Register A (the character) against 20H, a space.
4FEE
If the Z FLAG is set (a space: the name has ended), JUMP to 4FF5H.
4FF0
LD (DE),A 12
Store Register A (the character) at Register Pair DE.
4FF1
INC HL 23
INCrement Register Pair HL to the next character of the name.
4FF2
INC DE 13
INCrement Register Pair DE to the next place of the text.
4FF3
DECrement Register B and LOOP BACK to 4FEBH until 8 characters are copied.
4FF5
POP HL E1
Restore Register Pair HL from the stack: the record's +05H.
4FF6
LD A,L 7D
Copy Register L (the low byte of the record's +05H) into Register A.
4FF7
ADD A,08H C6 08
ADD 08H to Register A: the low byte of the record's +0DH, its extension.
4FF9
LD L,A 6F
Copy Register A into Register L: Register Pair HL = the record's extension (3 bytes, padded with spaces).
4FFA
LD A,(HL) 7E
Fetch the extension's first character from Register Pair HL into Register A.
4FFB
CP 20H FE 20
Compare Register A (the character) against 20H, a space.
4FFD
If the Z FLAG is set (no extension), JUMP to 500FH.
4FFF
LD A,2FH 3E 2F
Load Register A with 2FH, the character / that comes before the extension.
5001
LD (DE),A 12
Store Register A (the /) at Register Pair DE.
5002
INC DE 13
INCrement Register Pair DE to the next place of the text.
5003
LD B,03H 06 03
Load Register B with 03H, the length of the extension field.
5005
LD A,(HL) 7E
Fetch a character of the extension from Register Pair HL into Register A.
5006
CP 20H FE 20
Compare Register A (the character) against 20H, a space.
5008
If the Z FLAG is set (a space: the extension has ended), JUMP to 500FH.
500A
LD (DE),A 12
Store Register A (the character) at Register Pair DE.
500B
INC HL 23
INCrement Register Pair HL to the next character of the extension.
500C
INC DE 13
INCrement Register Pair DE to the next place of the text.
500D
DECrement Register B and LOOP BACK to 5005H until 3 characters are copied.
500F
LD A,3AH 3E 3A
Load Register A with 3AH, the character colon.
5011
LD (DE),A 12
Store Register A (the colon) at Register Pair DE.
5012
INC DE 13
INCrement Register Pair DE to the next place of the text.
5013
LD A,00H 3E 00
Load Register A with the drive's digit (the operand at 5014H: 00H in the file, stored by 4FDDH).
5015
LD (DE),A 12
Store Register A (the drive's digit) at Register Pair DE.
5016
INC DE 13
INCrement Register Pair DE to the next place of the text.
5017
LD A,03H 3E 03
Load Register A with 03H, the end of text mark of a file specification.
5019
LD (DE),A 12
Store Register A (03H, the end of text mark) at Register Pair DE.
501A
XOR A AF
Set Register A to 00H (XOR A) with the Z FLAG: success.
501B
RET C9
RETurn: for @CLOSE through 4A14H to the program, for @FNAME to 5026H.

501CH - Function 20H (Request A5H): @FNAME

Register B = a directory record number, Register C = a drive, Register Pair DE = a buffer of at least 15 bytes. @FNAME (4293H) reads the record and writes its file specification NAME/EXT:d with the 03H mark into the buffer (4FD8H). Returns Register A = 00H with the Z FLAG, or 11H (directory read error) with the NZ FLAG; Register Pairs DE and HL and Register C are kept, Register B is changed. SYS6/SYS (its 53F2H), SYS7/SYS (its 527BH, 52A0H and 531FH) and LCOMM/CMD (its 62D6H, 62F9H) call 4293H. The record is not tested for being in use.

501C
PUSH DE D5
Save Register Pair DE (the caller's buffer) to the stack.
501D
PUSH HL E5
Save Register Pair HL (the caller's) to the stack.
501E
GOSUB to 4B10H (DIRRD) to read the directory sector holding record Register B of drive Register C into 4300H: the Z FLAG on success, else the NZ FLAG with Register A = 11H.
5021
If the NZ FLAG is set (the read failed), JUMP to 5026H with Register A = 11H (directory read error).
5023
GOSUB to 4FD8H to write the file specification of record Register B of drive Register C at Register Pair DE.
5026
POP HL E1
Restore the caller's Register Pair HL from the stack.
5027
POP DE D1
Restore the caller's Register Pair DE from the stack: the start of the text.
5028
RET C9
RETurn to the program with Register A = 00H and the Z FLAG, or 11H and the NZ FLAG.

5029H - Close a Device

Register Pair DE = the control block of a device opened by @OPEN of SYS2/SYS (+00H 10H, +01H-+02H the address of its own byte +08H, where SYS2/SYS put the six byte driver LD HL with the device control block and JP 4D62H, +06H-+07H the two letters of the device name). The block is made into the device specification again: an asterisk, the two letters and 03H.

5029
GOSUB to 49F1H, the file prologue of SYS0/SYS without the open test: Index Register IX = the control block at Register Pair DE, the caller's Register Pairs BC, DE and HL and Index Register IX are saved for 4A14H, and Register A = 00H.
502C
LD C,(IX+06H) DD 4E 06
Load Register C with byte +06H of the control block at Index Register IX: the first letter of the device name.
502F
LD B,(IX+07H) DD 46 07
Load Register B with byte +07H of the control block at Index Register IX: the second letter of the device name.
5032
LD (IX+00H),2AH DD 36 00 2A
Store 2AH, an asterisk, at byte +00H of the control block at Index Register IX.
5036
LD (IX+01H),C DD 71 01
Store Register C (the first letter) at byte +01H of the control block at Index Register IX.
5039
LD (IX+02H),B DD 70 02
Store Register B (the second letter) at byte +02H of the control block at Index Register IX.
503C
LD (IX+03H),03H DD 36 03 03
Store 03H, the end of text mark, at byte +03H of the control block at Index Register IX: the block holds the device specification again.
5040
XOR A AF
Set Register A to 00H (XOR A) with the Z FLAG: success.
5041
RET C9
RETurn through 4A14H, which restores the caller's registers, to the program with Register A = 00H.

5042H - Make the RES Instruction for a Granule

Register A = a granule's place on its cylinder (0-7), Register B = the cylinder's allocation table byte. The bit number is put into the RES instruction at 504CH, which then clears that bit of Register B.

5042
AND 07H E6 07
Mask Register A (the granule's place on its cylinder) with 07H to bits 2-0.
5044
RLCA 07
Rotate Register A left one bit, the first of three rotations.
5045
RLCA 07
Rotate Register A (the granule's place on its cylinder) left one bit again.
5046
RLCA 07
Rotate Register A left a third time: the granule is in bits 5-3, the bit field of a bit instruction.
5047
OR 80H F6 80
OR 80H into Register A: the second byte of RES n,B for bit n = the granule.
5049
LD (504DH),A 32 4D 50
Store Register A at 504DH, the second byte of the instruction at 504CH.
504C
RES 0,B CB 80
Clear the granule's bit of Register B (the allocation table byte): the instruction is RES 0,B in the file and RES n,B after 5049H.
504E
RET C9
RETurn with the granule's bit clear in Register B.

504FH - Read the Allocation Table

Reads sector 0 of the directory cylinder of drive Register C, the granule allocation table (GAT), into 5100H, the page above SYS3/SYS in the overlay area. Returns the Z FLAG with Register A = 00H, or the NZ FLAG with Register A = 14H (GAT read error). Register Pairs DE and HL are kept.

504F
PUSH DE D5
Save the caller's Register Pair DE to the stack.
5050
PUSH HL E5
Save the caller's Register Pair HL to the stack.
5051
GOSUB to 4B64H (DIRCYL): Register D = the directory cylinder of drive Register C (byte +09H of its drive code table).
5054
LD E,00H 1E 00
Load Register E with 00H: sector 0 of the directory cylinder, the allocation table.
5056
LD HL,5100H 21 00 51
Load Register Pair HL with 5100H, the buffer for the allocation table.
5059
GOSUB to 4B45H (RDSSEC) to read cylinder Register D, sector Register E of drive Register C into the buffer at Register Pair HL: the Z FLAG and Register A = 00H when the sector carries the deleted data mark of a directory sector.
505C
POP HL E1
Restore the caller's Register Pair HL from the stack.
505D
POP DE D1
Restore the caller's Register Pair DE from the stack.
505E
RET Z C8
If the Z FLAG is set (the allocation table was read), RETurn with Register A = 00H.
505F
LD A,14H 3E 14
Load Register A with 14H, error 20: GAT read error.
5061
RET C9
RETurn with Register A = 14H and the NZ FLAG.

5062H - Write the Allocation Table

Writes the allocation table at 5100H to sector 0 of the directory cylinder of drive Register C with the deleted data mark, as every directory sector is written, and verifies it. Returns the Z FLAG when written and verified, else the NZ FLAG; Register A = 15H (GAT write error) either way. Register Pairs DE and HL are kept.

5062
PUSH DE D5
Save the caller's Register Pair DE to the stack.
5063
PUSH HL E5
Save the caller's Register Pair HL to the stack.
5064
GOSUB to 4B64H (DIRCYL): Register D = the directory cylinder of drive Register C.
5067
LD E,00H 1E 00
Load Register E with 00H: sector 0 of the directory cylinder, the allocation table.
5069
LD HL,5100H 21 00 51
Load Register Pair HL with 5100H, the allocation table changed by 4F2EH.
506C
GOSUB to 4768H (WRPROT) to write the buffer at Register Pair HL to cylinder Register D, sector Register E of drive Register C with the deleted data mark: the Z FLAG on success.
506F
If the NZ FLAG is set (the write failed), JUMP to 5076H.
5071
GOSUB to 4772H (VERSEC) to read cylinder Register D, sector Register E of drive Register C back without storing it: Register A = 06H for a sector with the deleted data mark, the good result.
5074
CP 06H FE 06
Compare Register A (the verify's result) against 06H: the Z FLAG is set when the verify found the deleted data mark.
5076
LD A,15H 3E 15
Load Register A with 15H, error 21: GAT write error. LD does not change the flags.
5078
POP HL E1
Restore the caller's Register Pair HL from the stack.
5079
POP DE D1
Restore the caller's Register Pair DE from the stack.
507A
RET C9
RETurn: the Z FLAG when written and verified, else the NZ FLAG; Register A = 15H.

507BH - Read the Hash Index Table

Reads sector 1 of the directory cylinder of drive Register C, the Hash Index Table (HIT, one byte for each directory record: the hash code of its file name, 00H for a free record), into 4300H. Returns the Z FLAG when read, else the NZ FLAG; Register A = 16H (HIT read error) either way. Register Pair HL = 4300H; Register Pairs BC and DE are kept.

507B
PUSH BC C5
Save Register Pair BC (Register B = the record number, Register C = the drive) to the stack.
507C
PUSH DE D5
Save the caller's Register Pair DE to the stack.
507D
GOSUB to 4B64H (DIRCYL): Register D = the directory cylinder of drive Register C.
5080
LD E,01H 1E 01
Load Register E with 01H: sector 1 of the directory cylinder, the HIT.
5082
LD HL,4300H 21 00 43
Load Register Pair HL with 4300H, the system buffer.
5085
GOSUB to 4B45H (RDSSEC) to read cylinder Register D, sector Register E of drive Register C into the buffer at Register Pair HL: the Z FLAG when the sector carries the deleted data mark.
5088
POP DE D1
Restore the caller's Register Pair DE from the stack.
5089
POP BC C1
Restore Register Pair BC (the record number and the drive) from the stack.
508A
LD A,16H 3E 16
Load Register A with 16H, error 22: HIT read error. LD does not change the flags.
508C
RET C9
RETurn: the Z FLAG when the HIT was read, else the NZ FLAG; Register A = 16H.

508DH - Write the Hash Index Table

Writes the HIT at 4300H to sector 1 of the directory cylinder of drive Register C with the deleted data mark and verifies it. Returns the Z FLAG when written and verified, else the NZ FLAG; Register A = 17H (HIT write error) either way. Register Pairs BC and DE are kept.

508D
PUSH BC C5
Save Register Pair BC (Register B = the record number, Register C = the drive) to the stack.
508E
PUSH DE D5
Save the caller's Register Pair DE to the stack.
508F
GOSUB to 4B64H (DIRCYL): Register D = the directory cylinder of drive Register C.
5092
LD E,01H 1E 01
Load Register E with 01H: sector 1 of the directory cylinder, the HIT.
5094
LD HL,4300H 21 00 43
Load Register Pair HL with 4300H, the HIT changed by 4F96H.
5097
GOSUB to 4768H (WRPROT) to write the buffer at Register Pair HL to cylinder Register D, sector Register E of drive Register C with the deleted data mark: the Z FLAG on success.
509A
If the NZ FLAG is set (the write failed), JUMP to 50A1H.
509C
GOSUB to 4772H (VERSEC) to read cylinder Register D, sector Register E of drive Register C back without storing it: Register A = 06H for a sector with the deleted data mark, the good result.
509F
CP 06H FE 06
Compare Register A (the verify's result) against 06H: the Z FLAG is set when the verify found the deleted data mark.
50A1
LD A,17H 3E 17
Load Register A with 17H, error 23: HIT write error. LD does not change the flags.
50A3
POP DE D1
Restore the caller's Register Pair DE from the stack.
50A4
POP BC C1
Restore Register Pair BC (the record number and the drive) from the stack.
50A5
RET C9
RETurn: the Z FLAG when written and verified, else the NZ FLAG; Register A = 17H.