Percom DoubleDOS 4.24 for the Model I - SYS3/SYS Disassembled

Page Customization

Introduction/Summary

Percom DoubleDOS 4.24 SYS3/SYS Disassembly (Model I)

SYS3/SYS is the overlay of DoubleDOS (DBLDOS in Percom's manual) that closes and kills files. It is overlay 5 (directory record 05H): the overlay dispatcher of SYS0/SYS loads it at 4E00H when a request code with the low four bits 5 is given and calls its transfer address 4E00H with the code in Register A.

The file is 786 bytes: a name record, the copyright record of 169 bytes, one load block, 4E00H-504EH (591 bytes), and the transfer address 4E00H. Every loaded byte is on exactly one row below. SYS3/SYS is the same in DoubleDOS 4.20, 4.23 (all three sets) and 4.24.

Load Map

AddressesContents
4E00H-4E0CHThe dispatcher of the request codes 95H and A5H (4E00H)
4E0DH-4E95HClose a file: the end of file into the directory entry, the granules counted (4E0DH)
4E96H-4F1CHGive back the granules beyond the end of file, and free an extra entry left empty (4E96H)
4F1DH-4F71HPut the specification back in the FCB (4F1DH)
4F72H-4FCDHKill a file (4F72H)
4FCEH-4FFCHFree the granules of an extent, reset a bit (4FCEH)
4FFDH-504EHRead and write the hash index table at 5100H, and small helpers (4FFDH)

The Request Codes

CodeEntry in SYS0/SYS, job and registers
95H4428H, close the file of the open FCB at Register Pair DE (BASIC/CMD, COPY/CMD, SYS6/SYS): 4E0DH
A5H442CH, kill the file of the open FCB at Register Pair DE (BASIC/CMD, SYS6/SYS): 4F72H

How a File Is Closed

StepWhat the code does
1A changed buffer in byte mode is written through SYS0/SYS's 4878H (4E10H).
2The end of file sector of the FCB is made the number of sectors again (5022H), and the end of file offset and the number of sectors are written into the directory entry, +03H and +14H-+15H, when they differ (4E1DH).
3The granules of all the file's entries are counted (4E54H) and compared with the number of sectors divided by 5, rounded up (4E77H).
4The granules beyond the end of file are given back one at a time from the last extent, through the GAT at 4D00H (4E96H); an extra entry whose extents are all given back is freed and the entry before it ends its extents with FFH again.
5The entry and the GAT are written, and the FCB is written over with NAME/EXT:D and 03H (4F1DH).

Differences From the Manual

Percom's manual has nothing on closing or killing files; it refers to the TRSDOS manual for the commands.

Notes

The result of the buffer write at 4E10H is not tested: a write error is lost and the close goes on.

Kill tests the access level of the FCB (levels 0 and 1 allow it, 4F7AH), but SYS2/SYS opens every file with level 0, so every open file can be killed.

After the close, 4F1DH reads the sector of Register B again when it is not the sector of the file's first entry. Register B is then the record of the entry last read, which for a file with an extra entry in another sector is that entry, so the bytes copied as the name are those at the first entry's place in the extra entry's sector. The password is never put back.

SYS3/SYS reads the hash index table into 5100H, past its own end, because the GAT is at 4D00H during a kill and while granules are given back.

The byte at 4E95H after the jump to 5047H is never reached. Read as an instruction it is RET NZ; 5047H runs CALL 4AF0H and RET NZ before the INC DE that 4E96H needs.

The operands at 4EB0H, 4F6AH and 4FFBH are written while SYS3/SYS runs (the Variables below).

Variables

SYS3/SYS's Own Bytes

Address
Size
Contents
4EB0H
1 byte
Blocks After the Extent's Block
Operand of ADD A,nn at 4EAFH, stored by 4EA6H.
4F6AH
1 byte
Drive Digit
Operand of LD A,nn at 4F69H, stored by 4F2EH.
4FFBH
1 byte
Second Byte of RES n,B
Stored by 4FF7H.

Memory Outside SYS3/SYS

Address
Size
Contents
4200H-42FFH
256 bytes
Sector Buffer
The directory sectors read by 4AC1H and written by 4AD6H.
4304H-4307H
4 bytes
Directory Blocks
Of drives 0-3, read through 4B55H (503DH).
4D00H-4DFFH
256 bytes
GAT
Read by 4AF0H, written by 4B03H; one byte a block, one bit a granule.
5100H-51FFH
256 bytes
Hash Index Table
Read by 4FFDH, written by 500CH.

The Directory Entry as SYS3/SYS Changes It

OffsetContents
+00HThe attribute: 00H for a freed entry (4EDBH, 4FAAH); bit 7 marks an extra entry
+01HIn an extra entry, the record of the entry before it (4EF5H)
+03HThe end of file offset (4E40H)
+14H-+15HThe number of sectors (4E48H)
+16H-+1FHFive extents, block and granule byte; FEH and a record links to an extra entry, FFH ends them

Error Codes Returned by SYS3/SYS

CodeMeaning (where set)
11H, 12HDirectory read, directory write error (from 4AC1H, 4AD6H)
14H, 15HGAT read, GAT write error (from 4AF0H, 4B03H)
16H, 17HHash index table read, write error (5009H, 5018H)
25HThe access level does not allow a kill (4F7EH)
26HThe FCB is not open (from 4892H)

Outside Routines

AddressUse
45CFHSYS0/SYS: Write a Directory Sector and Read It Back
5014H.
4878HSYS0/SYS: Write the Buffer Back When Changed
4E10H.
4892HSYS0/SYS: The Common Start of the File Routines
4E0DH, 4F72H.
4AC1HSYS0/SYS: Read a Directory Record
4E6DH, 4EF9H, 4F23H, 4F90H, 5030H.
4AD6HSYS0/SYS: Write a Directory Record
4E4FH, 4EDDH, 4F15H, 4FACH, 5042H.
4AF0H, 4B03HSYS0/SYS: Read, Write the GAT
4F8CH, 5047H; 4F0CH, 4F19H, 4FBBH.
4B35HSYS0/SYS: Read a Directory Sector
5005H.
4B55HSYS0/SYS: The Directory Block of a Drive
503DH.
4B84HSYS0/SYS: Divide
501BH.

Disassembly

4E00H - The Request Code Dispatcher

The transfer address of SYS3/SYS. The dispatcher of SYS0/SYS (4BA2H) calls it with the request code in Register A and the FCB in Register Pair DE: bits 6-4 choose the job, the low four bits (5) name SYS3/SYS. 95H closes a file, A5H kills it.

4E00
AND 70H E6 70
AND Register A, the request code, with 70H to keep bits 6-4, the number of the job: 10H for 95H, 20H for A5H.
4E02
CP 10H FE 10
Compare Register A, the job, with 10H, the job of request code 95H, which 4428H passes to close a file.
4E04
If the Z FLAG is set (request code 95H), jump to 4E0DH to close the file of the FCB at Register Pair DE.
4E07
CP 20H FE 20
Compare Register A, the job, with 20H, the job of request code A5H, which 442CH passes to kill a file.
4E09
If the Z FLAG is set (request code A5H), jump to 4F72H to kill the file of the FCB at Register Pair DE.
4E0C
RET C9
Return to the caller of the vector entry with Register A the job and the NZ FLAG set: no other request code of SYS3/SYS has a job.

4E0DH - Close a File

Reached for request code 95H (4428H) with Register Pair DE the FCB. A changed buffer is written, the end of file is put in the directory entry when it differs, granules beyond the end of file are given back to the GAT (and an extra entry left with no extents is freed), and the FCB is written over with the file's specification as text, NAME/EXT:D, which also marks it closed. Returns Register A 00H and the Z FLAG, or the NZ FLAG and an error code: 26H the FCB is not open, 11H, 12H, 14H, 15H, 16H or 17H a read or write error.

4E0D
Call 4892H, the common start of SYS0/SYS's file routines: error 26H when the FCB at Register Pair DE is not open, else Index Register IX becomes the FCB and the routine returns through 48B3H.
4E10
Call 4878H to write the buffer back when it is changed in byte mode; the result of the write is not tested.
4E13
LD B,(IX+07H) DD 46 07
Load Register B with the directory record of the file from FCB+07H through Index Register IX.
4E16
LD C,(IX+06H) DD 4E 06
Load Register C with the drive of the file from FCB+06H through Index Register IX.
4E19
Call 5022H to turn the end of file sector at FCB+0CH-+0DH into the number of sectors and read the directory entry of record Register B: Register Pair HL returns the entry.
4E1C
RET NZ C0
If the NZ FLAG is set (error 11H), return with the error code in Register A.
4E1D
LD A,03H 3E 03
Load Register A with 03H, the offset of the end of file byte in a directory entry.
4E1F
ADD A,L 85
Add Register L, the low byte of the entry's address, to Register A.
4E20
LD L,A 6F
Copy Register A into Register L: Register Pair HL is entry +03H.
4E21
PUSH HL E5
Save Register Pair HL, the address of entry +03H, on the stack.
4E22
LD A,(IX+08H) DD 7E 08
Load Register A with the end of file offset from FCB+08H through Index Register IX.
4E25
CP (HL) BE
Compare Register A with the end of file offset of the entry at Register Pair HL, entry +03H.
4E26
If the NZ FLAG is set (it differs), jump to 4E3CH to write the end of file into the entry.
4E28
LD A,11H 3E 11
Load Register A with 11H, the distance from entry +03H to entry +14H, the number of sectors.
4E2A
ADD A,L 85
Add Register L, the low byte of entry +03H, to Register A.
4E2B
LD L,A 6F
Copy Register A into Register L: Register Pair HL is entry +14H.
4E2C
LD A,(IX+0CH) DD 7E 0C
Load Register A with the low byte of the number of sectors from FCB+0CH through Index Register IX.
4E2F
CP (HL) BE
Compare Register A with the low byte of the number of sectors at Register Pair HL, entry +14H.
4E30
If the NZ FLAG is set (it differs), jump to 4E3CH to write the end of file into the entry.
4E32
INC L 2C
Increment Register L to entry +15H, the high byte of the number of sectors.
4E33
LD A,(IX+0DH) DD 7E 0D
Load Register A with the high byte of the number of sectors from FCB+0DH through Index Register IX.
4E36
CP (HL) BE
Compare Register A with the high byte of the number of sectors at Register Pair HL, entry +15H.
4E37
If the NZ FLAG is set (it differs), jump to 4E3CH to write the end of file into the entry.
4E39
POP AF F1
Take the address of entry +03H off the stack into Register Pair AF: the entry needs no change.
4E3A
Jump to 4E54H to count the granules of the file, with Register Pair HL at entry +15H.
4E3C
POP HL E1
Restore Register Pair HL, the address of entry +03H, from the stack.
4E3D
LD A,(IX+08H) DD 7E 08
Load Register A with the end of file offset from FCB+08H through Index Register IX.
4E40
LD (HL),A 77
Store Register A, the end of file offset, at Register Pair HL, entry +03H.
4E41
LD A,11H 3E 11
Load Register A with 11H, the distance from entry +03H to entry +14H, the number of sectors.
4E43
ADD A,L 85
Add Register L, the low byte of entry +03H, to Register A.
4E44
LD L,A 6F
Copy Register A into Register L: Register Pair HL is entry +14H.
4E45
LD A,(IX+0CH) DD 7E 0C
Load Register A with the low byte of the number of sectors from FCB+0CH through Index Register IX.
4E48
LD (HL),A 77
Store Register A at Register Pair HL, entry +14H, the low byte of the number of sectors.
4E49
INC L 2C
Increment Register L to entry +15H, the high byte of the number of sectors.
4E4A
LD A,(IX+0DH) DD 7E 0D
Load Register A with the high byte of the number of sectors from FCB+0DH through Index Register IX.
4E4D
LD (HL),A 77
Store Register A at Register Pair HL, entry +15H, the high byte of the number of sectors.
4E4E
PUSH HL E5
Save Register Pair HL, the address of entry +15H, on the stack.
4E4F
Call 4AD6H to write the directory sector at 4200H back as the sector of record Register B of drive Register C.
4E52
POP HL E1
Restore Register Pair HL, the address of entry +15H, from the stack.
4E53
RET NZ C0
If the NZ FLAG is set (error 12H), return with the error code in Register A.
4E54
INC L 2C
Increment Register L to entry +16H, the first extent.
4E55
LD DE,0000H 11 00 00
Load Register Pair DE with 0000H, the count of the granules the file has.
4E58
LD A,(HL) 7E
Load Register A with the block of the extent at Register Pair HL.
4E59
INC L 2C
Increment Register L to the granule byte of the extent.
4E5A
CP FEH FE FE
Compare Register A with FEH: the NC FLAG is set for FEH (the extents go on in another entry) and FFH (the end).
4E5C
If the NC FLAG is set (FEH or FFH), jump to 4E6AH.
4E5E
LD A,(HL) 7E
Load Register A with the granule byte of the extent at Register Pair HL.
4E5F
INC L 2C
Increment Register L to the block of the next extent of the entry.
4E60
AND 1FH E6 1F
AND Register A with 1FH to keep bits 4-0, the count of granules less 1.
4E62
INC A 3C
Increment Register A: the granules of the extent.
4E63
ADD A,E 83
Add Register E, the low byte of the count, to Register A.
4E64
LD E,A 5F
Copy Register A into Register E, the low byte of the count.
4E65
If the NC FLAG is set (no carry), jump back to 4E58H for the next extent.
4E67
INC D 14
Increment Register D for the carry: Register Pair DE is the count of granules.
4E68
Jump back to 4E58H for the next extent, with Register Pair DE the count so far.
4E6A
If the NZ FLAG is set (FFH, the end of the extents), jump to 4E77H with Register Pair HL at the byte after it.
4E6C
LD B,(HL) 46
Load Register B with the byte after FEH at Register Pair HL, the record of the file's next directory entry.
4E6D
Call 4AC1H to read the directory sector of record Register B into 4200H: Register Pair HL returns the address of the entry.
4E70
RET NZ C0
If the NZ FLAG is set (error 11H), return with the error code in Register A.
4E71
LD A,L 7D
Copy Register L, the low byte of the entry's address, into Register A.
4E72
ADD A,16H C6 16
Add 16H to Register A, the offset of the extents.
4E74
LD L,A 6F
Copy Register A into Register L: Register Pair HL is the first extent of the next entry.
4E75
Jump back to 4E58H to go on counting with Register Pair DE.
4E77
PUSH HL E5
Save Register Pair HL, the address after the FFH that ends the extents, on the stack.
4E78
LD L,(IX+0CH) DD 6E 0C
Load Register L with the low byte of the number of sectors from FCB+0CH through Index Register IX.
4E7B
LD H,(IX+0DH) DD 66 0D
Load Register H with the high byte of the number of sectors from FCB+0DH through Index Register IX.
4E7E
LD A,05H 3E 05
Load Register A with 05H, the sectors of a granule.
4E80
Call 501BH to divide Register Pair HL by Register A (5): Register Pair HL returns the quotient, one less when there is no remainder.
4E83
INC HL 23
Increment Register Pair HL: the granules the file needs, the number of sectors divided by 5 and rounded up.
4E84
XOR A AF
Clear Register A to 00H and the C FLAG for the subtraction.
4E85
EX DE,HL EB
Exchange Register Pairs DE and HL: Register Pair HL is the granules the file has, Register Pair DE the granules it needs.
4E86
SBC HL,DE ED 52
Subtract Register Pair DE, the granules needed, from Register Pair HL, the granules the file has.
4E88
EX DE,HL EB
Exchange Register Pairs DE and HL: Register Pair DE is the granules to give back.
4E89
POP HL E1
Restore Register Pair HL, the address after the FFH, from the stack.
4E8A
If the Z FLAG is set (no granule to give back), jump to 4F1DH to write the specification into the FCB.
4E8D
If the C FLAG is set (the file has fewer granules than it needs), jump to 4F1DH as well.
4E90
DEC L 2D
Decrement Register L to the FFH of the end of the extents.
4E91
DEC L 2D
Decrement Register L to the granule byte of the last extent.
4E92
Jump to 5047H, which reads the GAT and goes on at 4ECEH with Register Pair DE one more.
4E95
RET NZ C0
The byte after the jump, never reached: as an instruction RET NZ, as at 504AH after the same CALL 4AF0H.

4E96H - Give Back the Last Granule

Entered from 4F13H with Register Pair HL the granule byte of the last extent and Register Pair DE the granules still to give back. The last granule of the extent is marked free in the GAT at 4D00H and the extent's count made one less; an extent left with no granule becomes FFH FFH and the extent before it is the last. When an extra entry is left with no extent it is freed, its place in the hash index table cleared, and the entry before it ended with FFH where it had FEH.

4E96
PUSH DE D5
Save Register Pair DE, the granules still to give back, on the stack.
4E97
LD A,(HL) 7E
Load Register A with the granule byte of the extent at Register Pair HL.
4E98
AND E0H E6 E0
AND Register A with E0H to keep bits 7-5, the extent's first granule in its block.
4E9A
RLCA 07
Rotate Register A left, the first of three turns that bring bits 7-5 to bits 2-0.
4E9B
RLCA 07
Rotate Register A left, the second of the three turns.
4E9C
RLCA 07
Rotate Register A left, the third turn: Register A is the first granule.
4E9D
LD E,A 5F
Copy the first granule from Register A into Register E.
4E9E
LD A,(HL) 7E
Load Register A with the granule byte of the extent at Register Pair HL again.
4E9F
AND 1FH E6 1F
AND Register A with 1FH to keep bits 4-0, the count of granules less 1.
4EA1
ADD A,E 83
Add Register E, the first granule, to Register A: the last granule, counted from the extent's block.
4EA2
LD E,A 5F
Copy the last granule from Register A into Register E.
4EA3
AND FEH E6 FE
AND Register A with FEH to drop the granule in its block.
4EA5
RRCA 0F
Rotate Register A right: the blocks after the extent's block, two granules a block.
4EA6
LD (4EB0H),A 32 B0 4E
Store Register A, the blocks after the extent's block, at 4EB0H, the operand of ADD A,nn at 4EAFH.
4EA9
LD A,E 7B
Copy the last granule from Register E into Register A.
4EAA
AND 01H E6 01
AND Register A with 01H to keep the granule in its block.
4EAC
LD E,A 5F
Copy the granule in its block from Register A into Register E.
4EAD
DEC L 2D
Decrement Register L to the block of the extent.
4EAE
LD A,(HL) 7E
Load Register A with the block of the extent at Register Pair HL.
4EAF
ADD A,00H C6 00
Add the blocks after it to Register A: the operand at 4EB0H is stored by 4EA6H (00H in the file).
4EB1
LD D,A 57
Copy Register A, the block of the last granule, into Register D.
4EB2
PUSH HL E5
Save Register Pair HL, the address of the extent's block, on the stack.
4EB3
PUSH BC C5
Save Register Pair BC, the record and the drive, on the stack.
4EB4
LD H,4DH 26 4D
Load Register H with 4DH, the page of the GAT.
4EB6
LD L,D 6A
Copy Register D, the block, into Register L: Register Pair HL is the block's byte in the GAT.
4EB7
LD B,(HL) 46
Load Register B with the GAT byte at Register Pair HL.
4EB8
LD A,E 7B
Copy Register E, the granule in its block, into Register A.
4EB9
Call 4FF0H to reset bit Register A of Register B: the granule is free.
4EBC
LD (HL),B 70
Store Register B, the GAT byte, back at Register Pair HL.
4EBD
POP BC C1
Restore Register Pair BC, the record and the drive, from the stack.
4EBE
POP HL E1
Restore Register Pair HL, the address of the extent's block, from the stack.
4EBF
INC L 2C
Increment Register L to the granule byte of the extent.
4EC0
DEC (HL) 35
Decrement the granule byte at Register Pair HL: the extent has one granule less.
4EC1
LD A,(HL) 7E
Load Register A with the granule byte at Register Pair HL.
4EC2
INC A 3C
Increment Register A: bits 4-0 are 00000 when the count was 00000 before the decrement.
4EC3
AND 1FH E6 1F
AND Register A with 1FH: the Z FLAG is set when the extent had one granule, now given back.
4EC5
POP DE D1
Restore Register Pair DE, the granules still to give back, from the stack.
4EC6
If the NZ FLAG is set (the extent has granules left), jump to 4F10H to count the granule given back.
4EC8
LD (HL),FFH 36 FF
Store FFH at Register Pair HL, the granule byte: the extent is empty.
4ECA
DEC L 2D
Decrement Register L to the block of the extent.
4ECB
LD (HL),FFH 36 FF
Store FFH at Register Pair HL, the block: the extent's place ends the extents.
4ECD
DEC L 2D
Decrement Register L to the granule byte of the extent before.
4ECE
LD A,L 7D
Copy Register L, the low byte of the address, into Register A; 504CH comes here as well.
4ECF
AND 1FH E6 1F
AND Register A with 1FH to keep the offset in the entry.
4ED1
CP 16H FE 16
Compare Register A with 16H, the offset of the first extent.
4ED3
If the NC FLAG is set (an extent of this entry), jump to 4F10H to count the granule given back.
4ED5
XOR L AD
Exclusive OR Register A, the offset, with Register L: Register A is the low byte of the entry's start.
4ED6
LD L,A 6F
Copy Register A into Register L: Register Pair HL is the entry at +00H.
4ED7
BIT 7,(HL) CB 7E
Test bit 7 of the attribute byte at Register Pair HL, entry +00H: set in an extra entry.
4ED9
If the Z FLAG is set (the file's first entry, now with no extents), jump to 4F15H to write it and the GAT.
4EDB
LD (HL),00H 36 00
Store 00H at Register Pair HL, the attribute of the extra entry: the entry is free.
4EDD
Call 4AD6H to write the directory sector at 4200H back as the sector of record Register B of drive Register C.
4EE0
RET NZ C0
If the NZ FLAG is set (error 12H), return with the error code in Register A.
4EE1
Call 4FFDH to read the hash index table of drive Register C into 5100H.
4EE4
RET NZ C0
If the NZ FLAG is set (error 16H), return with the error code in Register A.
4EE5
LD L,B 68
Copy Register B, the record of the freed entry, into Register L: Register Pair HL is its place at 5100H.
4EE6
LD (HL),00H 36 00
Store 00H at Register Pair HL: the place in the hash index table is free.
4EE8
Call 500CH to write the hash index table at 5100H back to drive Register C.
4EEB
RET NZ C0
If the NZ FLAG is set (error 17H), return with the error code in Register A.
4EEC
LD A,B 78
Copy Register B, the record of the freed entry, into Register A.
4EED
AND E0H E6 E0
AND Register A with E0H to keep bits 7-5, the entry in its sector: Register A is its offset in the sector.
4EEF
ADD A,01H C6 01
Add 01H to Register A, the offset of the link back in an extra entry.
4EF1
LD L,A 6F
Copy Register A, the offset of the link back, into Register L.
4EF2
LD H,42H 26 42
Load Register H with 42H: Register Pair HL is entry +01H in the sector buffer at 4200H.
4EF4
LD A,B 78
Copy Register B, the record of the freed entry, into Register A.
4EF5
LD B,(HL) 46
Load Register B with the record of the entry before it from entry +01H at Register Pair HL.
4EF6
XOR B A8
Exclusive OR Register A with Register B: the low five bits differ when the two entries are in different sectors.
4EF7
AND 1FH E6 1F
AND Register A with 1FH to keep the difference of the sectors.
4EF9
If the NZ FLAG is set (another sector), call 4AC1H to read the sector of record Register B into 4200H.
4EFC
RET NZ C0
If the NZ FLAG is set (error 11H), return with the error code in Register A.
4EFD
LD A,B 78
Copy Register B, the record of the entry before, into Register A.
4EFE
AND E0H E6 E0
AND Register A with E0H to keep bits 7-5: Register A is the entry's offset in the sector.
4F00
ADD A,1FH C6 1F
Add 1FH to Register A, the offset of the last byte of the entry.
4F02
LD L,A 6F
Copy Register A into Register L: Register Pair HL is entry +1FH, the record after FEH.
4F03
LD (HL),FFH 36 FF
Store FFH at Register Pair HL, entry +1FH, where the record of the freed entry was.
4F05
DEC L 2D
Decrement Register L to entry +1EH, the FEH that linked the freed entry.
4F06
LD (HL),FFH 36 FF
Store FFH at Register Pair HL, entry +1EH: the extents of the file end in this entry.
4F08
Call 5040H to step Register Pair HL back to the granule byte at entry +1DH and write the sector of record Register B.
4F0B
RET NZ C0
If the NZ FLAG is set (error 12H), return with the error code in Register A.
4F0C
Call 4B03H to write the GAT at 4D00H back to drive Register C.
4F0F
RET NZ C0
If the NZ FLAG is set (error 15H), return with the error code in Register A.
4F10
DEC DE 1B
Decrement Register Pair DE, the granules still to give back.
4F11
LD A,D 7A
Copy Register D, the high byte of the count, into Register A.
4F12
OR E B3
OR Register A with Register E: the Z FLAG is set when Register Pair DE is 0000H.
4F13
If the NZ FLAG is set (more granules to give back), jump back to 4E96H.
4F15
Call 4AD6H to write the directory sector at 4200H back as the sector of record Register B of drive Register C.
4F18
RET NZ C0
If the NZ FLAG is set (error 12H), return with the error code in Register A.
4F19
Call 4B03H to write the GAT at 4D00H back to drive Register C.
4F1C
RET NZ C0
If the NZ FLAG is set (error 15H), return with the error code in Register A.

4F1DH - Put the Specification Back in the FCB

Reached when the directory and the GAT are up to date. The name and extension of the file's first entry and its drive are written into the FCB as NAME/EXT:D and 03H; the password is not. The first byte, a letter, clears bit 7 of FCB+00H, so the FCB is no longer open, and it can be opened again as it is. When the file has an extra entry in another sector than its first, the sector read is that of Register B, the last entry read, and the name copied is the bytes at the first entry's place in that sector.

4F1D
LD A,(IX+07H) DD 7E 07
Load Register A with the record of the file's first entry from FCB+07H through Index Register IX.
4F20
XOR B A8
Exclusive OR Register A with Register B, the record of the entry last read: the low five bits differ when they are in different sectors.
4F21
AND 1FH E6 1F
AND Register A with 1FH to keep the difference of the sectors.
4F23
If the NZ FLAG is set (another sector), call 4AC1H to read the sector of record Register B, the entry last read, into 4200H.
4F26
RET NZ C0
If the NZ FLAG is set (error 11H), return with the error code in Register A.
4F27
LD A,(IX+06H) DD 7E 06
Load Register A with the drive of the file from FCB+06H through Index Register IX.
4F2A
AND 03H E6 03
AND Register A with 03H to keep the drive number 0-3.
4F2C
OR 30H F6 30
OR Register A with 30H: the digit of the drive.
4F2E
LD (4F6AH),A 32 6A 4F
Store Register A, the drive's digit, at 4F6AH, the operand of LD A,nn at 4F69H.
4F31
LD H,42H 26 42
Load Register H with 42H, the page of the sector buffer at 4200H.
4F33
LD A,(IX+07H) DD 7E 07
Load Register A with the record of the file's first entry from FCB+07H through Index Register IX.
4F36
AND E0H E6 E0
AND Register A with E0H to keep bits 7-5: the entry's offset in its sector.
4F38
OR 05H F6 05
OR Register A with 05H, the offset of the name in a directory entry.
4F3A
LD L,A 6F
Copy Register A into Register L: Register Pair HL is the name at entry +05H.
4F3B
PUSH HL E5
Save Register Pair HL, the address of the name, on the stack.
4F3C
PUSH IX DD E5
Save Index Register IX, the FCB, on the stack.
4F3E
POP DE D1
Restore it into Register Pair DE: Register Pair DE is the FCB, where the text goes.
4F3F
LD B,08H 06 08
Load Register B with 08H, the eight characters of the name.
4F41
LD A,(HL) 7E
Load Register A with the character of the name at Register Pair HL.
4F42
CP 20H FE 20
Compare Register A with 20H, a space: the name is padded with spaces.
4F44
If the Z FLAG is set (a space), jump to 4F4BH: the name has ended.
4F46
LD (DE),A 12
Store Register A, the character, at Register Pair DE in the FCB.
4F47
INC HL 23
Increment Register Pair HL to the next character of the name.
4F48
INC DE 13
Increment Register Pair DE to the next byte of the FCB.
4F49
Decrement Register B and jump back to 4F41H while it is not 00H.
4F4B
POP HL E1
Restore Register Pair HL, the address of the name at entry +05H, from the stack.
4F4C
LD A,L 7D
Copy Register L, the low byte of the name's address, into Register A.
4F4D
ADD A,08H C6 08
Add 08H to Register A, the length of the name.
4F4F
LD L,A 6F
Copy Register A into Register L: Register Pair HL is the extension at entry +0DH.
4F50
LD A,(HL) 7E
Load Register A with the first character of the extension at Register Pair HL.
4F51
CP 20H FE 20
Compare Register A with 20H, a space: the file has no extension.
4F53
If the Z FLAG is set (no extension), jump to 4F65H to add the drive.
4F55
LD A,2FH 3E 2F
Load Register A with 2FH, a slash, the start of the extension in the text.
4F57
LD (DE),A 12
Store Register A, the slash, at Register Pair DE in the FCB.
4F58
INC DE 13
Increment Register Pair DE to the next byte of the FCB.
4F59
LD B,03H 06 03
Load Register B with 03H, the three characters of the extension.
4F5B
LD A,(HL) 7E
Load Register A with the character of the extension at Register Pair HL.
4F5C
CP 20H FE 20
Compare Register A with 20H, a space: the extension is padded with spaces.
4F5E
If the Z FLAG is set (a space), jump to 4F65H: the extension has ended.
4F60
LD (DE),A 12
Store Register A, the character, at Register Pair DE in the FCB.
4F61
INC HL 23
Increment Register Pair HL to the next character of the extension.
4F62
INC DE 13
Increment Register Pair DE to the next byte of the FCB.
4F63
Decrement Register B and jump back to 4F5BH while it is not 00H.
4F65
LD A,3AH 3E 3A
Load Register A with 3AH, a colon, the start of the drive in the text.
4F67
LD (DE),A 12
Store Register A, the colon, at Register Pair DE in the FCB.
4F68
INC DE 13
Increment Register Pair DE to the next byte of the FCB.
4F69
LD A,00H 3E 00
Load Register A with the drive's digit: the operand at 4F6AH is stored by 4F2EH (00H in the file).
4F6B
LD (DE),A 12
Store Register A, the drive's digit, at Register Pair DE in the FCB.
4F6C
INC DE 13
Increment Register Pair DE to the next byte of the FCB.
4F6D
LD A,03H 3E 03
Load Register A with 03H, the byte that ends a specification.
4F6F
LD (DE),A 12
Store Register A (03H) at Register Pair DE in the FCB.
4F70
XOR A AF
Clear Register A to 00H and set the Z FLAG: the file is closed.
4F71
RET C9
Return with Register A 00H and the Z FLAG set.

4F72H - Kill a File

Reached for request code A5H (442CH) with Register Pair DE the FCB of an open file. The access level must be 0 or 1. The granules of every extent of the file's first entry and of its extra entries are marked free in the GAT, each entry is freed (attribute 00H) and its place in the hash index table cleared; then the GAT and the hash index table are written and the 32 bytes of the FCB cleared. Returns Register A 00H and the Z FLAG, or the NZ FLAG and an error code: 26H the FCB is not open, 25H access denied, 11H, 12H, 14H, 15H, 16H or 17H a read or write error.

4F72
Call 4892H, the common start of SYS0/SYS's file routines: error 26H when the FCB at Register Pair DE is not open, else Index Register IX becomes the FCB.
4F75
LD A,(IX+01H) DD 7E 01
Load Register A with the access level and flags from FCB+01H through Index Register IX.
4F78
AND 07H E6 07
AND Register A with 07H to keep bits 2-0, the access level (SYS2/SYS always gives 00H).
4F7A
CP 02H FE 02
Compare Register A, the access level, with 02H: the C FLAG is set for levels 0 and 1.
4F7C
If the C FLAG is set (the file may be killed), jump to 4F82H.
4F7E
LD A,25H 3E 25
Load Register A with 25H, the error code for an access that the access level does not allow.
4F80
OR A B7
Set the flags from Register A (25H): the NZ FLAG is set.
4F81
RET C9
Return with error 25H in Register A and the NZ FLAG set.
4F82
LD C,(IX+06H) DD 4E 06
Load Register C with the drive of the file from FCB+06H through Index Register IX.
4F85
LD B,(IX+07H) DD 46 07
Load Register B with the record of the file's first directory entry from FCB+07H through Index Register IX.
4F88
Call 4FFDH to read the hash index table of drive Register C into 5100H.
4F8B
RET NZ C0
If the NZ FLAG is set (error 16H), return with the error code in Register A.
4F8C
Call 4AF0H to read the GAT of drive Register C into 4D00H.
4F8F
RET NZ C0
If the NZ FLAG is set (error 14H), return with the error code in Register A.
4F90
Call 4AC1H to read the directory sector of record Register B into 4200H: Register Pair HL returns the address of the entry.
4F93
RET NZ C0
If the NZ FLAG is set (error 11H), return with the error code in Register A.
4F94
LD A,16H 3E 16
Load Register A with 16H, the offset of the extents in a directory entry.
4F96
ADD A,L 85
Add Register L, the low byte of the entry's address, to Register A.
4F97
LD L,A 6F
Copy Register A into Register L: Register Pair HL is the first extent at entry +16H.
4F98
LD E,(HL) 5E
Load Register E with the block of the extent at Register Pair HL.
4F99
INC L 2C
Increment Register L to the granule byte of the extent.
4F9A
LD D,(HL) 56
Load Register D with the granule byte of the extent at Register Pair HL: Register Pair DE is the extent.
4F9B
LD A,E 7B
Copy Register E, the block of the extent, into Register A for the test of the end.
4F9C
CP FEH FE FE
Compare Register A with FEH: the NC FLAG is set for FEH (the extents go on in another entry) and FFH (the end).
4F9E
If the NC FLAG is set (FEH or FFH), jump to 4FA6H to free the entry.
4FA0
INC L 2C
Increment Register L to the next extent of the entry.
4FA1
Call 4FCEH to mark the granules of the extent Register Pair DE free in the GAT at 4D00H.
4FA4
Jump back to 4F98H for the next extent of the entry.
4FA6
LD A,L 7D
Copy Register L, the low byte of the address in the entry, into Register A.
4FA7
AND E0H E6 E0
AND Register A with E0H: Register A is the low byte of the entry's start.
4FA9
LD L,A 6F
Copy Register A into Register L: Register Pair HL is the entry at +00H.
4FAA
LD (HL),00H 36 00
Store 00H at Register Pair HL, the attribute byte: the entry is free.
4FAC
Call 4AD6H to write the directory sector at 4200H back as the sector of record Register B of drive Register C.
4FAF
RET NZ C0
If the NZ FLAG is set (error 12H), return with the error code in Register A.
4FB0
LD H,51H 26 51
Load Register H with 51H, the page of the hash index table read by 4FFDH.
4FB2
LD L,B 68
Copy Register B, the record of the entry, into Register L: Register Pair HL is its place in the table at 5100H.
4FB3
LD (HL),00H 36 00
Store 00H at Register Pair HL: the place in the hash index table is free.
4FB5
LD B,D 42
Copy Register D, the byte after the FEH or FFH, into Register B: after FEH the record of the next entry.
4FB6
LD A,E 7B
Copy Register E, the FEH or FFH, into Register A.
4FB7
CP FEH FE FE
Compare Register A with FEH, the link to another entry of the file.
4FB9
If the Z FLAG is set (FEH), jump back to 4F90H to free the entry of record Register B as well.
4FBB
Call 4B03H to write the GAT at 4D00H back to drive Register C.
4FBE
RET NZ C0
If the NZ FLAG is set (error 15H), return with the error code in Register A.
4FBF
Call 500CH to write the hash index table at 5100H back to drive Register C.
4FC2
RET NZ C0
If the NZ FLAG is set (error 17H), return with the error code in Register A.
4FC3
PUSH IX DD E5
Save Index Register IX, the FCB, on the stack.
4FC5
POP HL E1
Restore it into Register Pair HL: Register Pair HL is the FCB.
4FC6
LD B,20H 06 20
Load Register B with 20H, the 32 bytes of the FCB.
4FC8
XOR A AF
Clear Register A to 00H and set the Z FLAG: the value stored and the result returned.
4FC9
LD (HL),A 77
Store Register A (00H) at Register Pair HL in the FCB.
4FCA
INC HL 23
Increment Register Pair HL to the next byte of the FCB.
4FCB
Decrement Register B and jump back to 4FC9H while it is not 00H.
4FCD
RET C9
Return with Register A 00H and the Z FLAG set: the file is killed and the FCB cleared.

4FCEH - Free the Granules of an Extent

Called from 4FA1H with Register E the block and Register D the granule byte of an extent (bits 7-5 the first granule in the block, bits 4-0 the count less 1). Each granule's bit is reset in the GAT at 4D00H, two granules a block.

4FCE
PUSH HL E5
Save Register Pair HL, the address in the directory entry, on the stack.
4FCF
PUSH BC C5
Save Register Pair BC, the record and the drive, on the stack.
4FD0
LD L,E 6B
Copy Register E, the block of the extent, into Register L.
4FD1
LD H,4DH 26 4D
Load Register H with 4DH: Register Pair HL is the block's byte in the GAT.
4FD3
LD A,D 7A
Copy Register D, the granule byte, into Register A.
4FD4
AND 1FH E6 1F
AND Register A with 1FH to keep bits 4-0, the count of granules less 1.
4FD6
LD C,A 4F
Copy the count less 1 from Register A into Register C.
4FD7
INC C 0C
Increment Register C: the granules of the extent.
4FD8
XOR D AA
Exclusive OR Register A with Register D: Register A keeps bits 7-5 of the granule byte, the first granule.
4FD9
RLCA 07
Rotate Register A left, the first of three turns that bring bits 7-5 to bits 2-0.
4FDA
RLCA 07
Rotate Register A left, the second of the three turns.
4FDB
RLCA 07
Rotate Register A left, the third turn: Register A is the first granule in the block.
4FDC
PUSH AF F5
Save Register Pair AF, the granule in the block in Register A, on the stack.
4FDD
LD B,(HL) 46
Load Register B with the GAT byte at Register Pair HL.
4FDE
Call 4FF0H to reset bit Register A of Register B: the granule is free.
4FE1
LD (HL),B 70
Store Register B, the GAT byte, back at Register Pair HL.
4FE2
POP AF F1
Restore Register Pair AF: Register A the granule in the block.
4FE3
INC A 3C
Increment Register A to the next granule of the extent in the block.
4FE4
CP 02H FE 02
Compare Register A with 02H, the granules of a block.
4FE6
If the NZ FLAG is set (the same block), jump to 4FEAH.
4FE8
XOR A AF
Clear Register A to 00H, the first granule of the next block.
4FE9
INC L 2C
Increment Register L to the GAT byte of the next block.
4FEA
DEC C 0D
Decrement Register C, the granules of the extent still to free.
4FEB
If the NZ FLAG is set (more granules), jump back to 4FDCH.
4FED
POP BC C1
Restore Register Pair BC, the record and the drive, from the stack.
4FEE
POP HL E1
Restore Register Pair HL, the address in the directory entry, from the stack.
4FEF
RET C9
Return with the extent's granules free in the GAT at 4D00H.

4FF0H - Reset a Bit of Register B

Called with Register B a GAT byte and Register A the number of the bit (the low three bits). The routine writes the instruction RES n,B at 4FFAH and runs it.

4FF0
AND 07H E6 07
AND Register A with 07H to keep the bit number 0-7.
4FF2
RLCA 07
Rotate Register A left, the first of three turns that bring the bit number to bits 5-3.
4FF3
RLCA 07
Rotate Register A left, the second of the three turns.
4FF4
RLCA 07
Rotate Register A left, the third turn: Register A is the bit number times 8.
4FF5
OR 80H F6 80
OR Register A with 80H: Register A is the second byte of RES n,B (80H plus 8 times n).
4FF7
LD (4FFBH),A 32 FB 4F
Store Register A at 4FFBH, the second byte of the RES instruction at 4FFAH.
4FFA
RES 0,B CB 80
Reset bit n of Register B: the second byte of this instruction (80H, RES 0,B, in the file) is stored by 4FF7H.
4FFC
RET C9
Return with the bit reset in Register B, the GAT byte of the caller.

4FFDH - Read the Hash Index Table

Called with Register C the drive. Sector 1 of the drive's directory block, the hash index table, is read into 5100H, after SYS3/SYS, since the GAT is at 4D00H. 5033H keeps Register Pairs BC and DE for it. Returns the Z FLAG, or error 16H.

4FFD
Call 5033H, which saves Register Pairs BC and DE, loads Register D with the directory block of drive Register C and runs the rest of this routine as its own.
5000
LD E,01H 1E 01
Load Register E with 01H, the sector of the hash index table in the directory block.
5002
LD HL,5100H 21 00 51
Load Register Pair HL with 5100H, the buffer of the hash index table.
5005
Call 4B35H to read sector Register E of block Register D on drive Register C into Register Pair HL (5100H).
5008
RET Z C8
Return to 5039H if the Z FLAG is set, with Register A 00H: the table is at 5100H.
5009
LD A,16H 3E 16
Load Register A with 16H, the error code for a hash index table that cannot be read.
500B
RET C9
Return to 5039H with error 16H in Register A and the NZ FLAG set by 4B35H.

500CH - Write the Hash Index Table

Called with Register C the drive. The table at 5100H is written back as sector 1 of the drive's directory block with the deleted data mark and read back. Returns the Z FLAG, or error 17H.

500C
Call 5033H, which saves Register Pairs BC and DE, loads Register D with the directory block of drive Register C and runs the rest of this routine as its own.
500F
LD E,01H 1E 01
Load Register E with 01H, the sector of the hash index table in the directory block.
5011
LD HL,5100H 21 00 51
Load Register Pair HL with 5100H, the hash index table to write.
5014
Call 45CFH to write the buffer at Register Pair HL (5100H) as sector Register E of block Register D on drive Register C and read it back.
5017
RET Z C8
Return to 5039H if the Z FLAG is set: the table has been written.
5018
LD A,17H 3E 17
Load Register A with 17H, the error code for a hash index table that cannot be written.
501A
RET C9
Return to 5039H with error 17H in Register A and the NZ FLAG set by 45CFH.

501BH - Divide, Rounded Down When Exact

Called from 4E80H with Register Pair HL the number of sectors and Register A 05H. Returns Register Pair HL the quotient, or the quotient less 1 when the remainder is 0, so that one more is the number of granules needed.

501B
Call 4B84H to divide Register Pair HL by Register A: the quotient in Register Pair HL, the remainder in Register A.
501E
OR A B7
Set the flags from Register A, the remainder: the Z FLAG is set for 00H.
501F
RET NZ C0
Return if the NZ FLAG is set (a remainder), with the quotient in Register Pair HL.
5020
DEC HL 2B
Decrement Register Pair HL: the sectors fill the granules exactly.
5021
RET C9
Return with the quotient less 1 in Register Pair HL.

5022H - The Number of Sectors, Then Read the Entry

Called from 4E19H with Register B the record and Register C the drive. FCB+0CH-+0DH, the end of file sector, is made the number of sectors again when the last sector is partly filled (SYS2/SYS made it one less, 5180H there). Then the directory entry is read.

5022
LD A,(IX+08H) DD 7E 08
Load Register A with the end of file offset from FCB+08H through Index Register IX.
5025
OR A B7
Set the flags from Register A: the Z FLAG is set when the file ends at the start of a sector.
5026
If the Z FLAG is set (no partly filled sector), jump to 5030H.
5028
INC (IX+0CH) DD 34 0C
Increment the low byte of the end of file sector at FCB+0CH through Index Register IX.
502B
If the NZ FLAG is set (no carry), jump to 5030H.
502D
INC (IX+0DH) DD 34 0D
Increment the high byte of the end of file sector at FCB+0DH through Index Register IX for the carry.
5030
Jump to 4AC1H to read the directory sector of record Register B of drive Register C into 4200H; it returns to 4E1CH with Register Pair HL the entry.

5033H - Keep Register Pairs BC and DE Around the Rest of a Routine

Called as the first instruction of 4FFDH and 500CH. The return address, the rest of the routine, is taken off the stack; Register Pairs DE and BC are saved; the rest of the routine is called through 4B55H, which loads Register D with the drive's directory block; when it returns, Register Pairs BC and DE are restored and 5033H returns to the routine's caller.

5033
POP HL E1
Take the return address off the stack into Register Pair HL: the rest of the routine that called 5033H (5000H or 500FH).
5034
PUSH DE D5
Save Register Pair DE on the stack, the caller's, restored at 503AH.
5035
PUSH BC C5
Save Register Pair BC on the stack, the caller's, restored at 5039H.
5036
Call 503CH to run the rest of the routine: it returns to 5039H.
5039
POP BC C1
Restore Register Pair BC, the caller's, from the stack.
503A
POP DE D1
Restore Register Pair DE, the caller's, from the stack.
503B
RET C9
Return to the caller of 4FFDH or 500CH with the result in Register A and the flags.
503C
PUSH HL E5
Push Register Pair HL, the rest of the routine, as the address that 4B55H returns to.
503D
Jump to 4B55H to load Register D with the directory block of drive Register C; it returns to Register Pair HL, the rest of the routine.

5040H - Step Back and Write the Entry

Called from 4F08H with Register Pair HL entry +1EH of the entry before a freed extra entry. Register Pair HL is made entry +1DH, the granule byte of that entry's last extent, and the sector is written.

5040
DEC HL 2B
Decrement Register Pair HL to entry +1DH, the granule byte of the extent before the FFH.
5041
PUSH HL E5
Save Register Pair HL, the address of entry +1DH, on the stack.
5042
Call 4AD6H to write the directory sector at 4200H back as the sector of record Register B of drive Register C.
5045
POP HL E1
Restore Register Pair HL, the address of entry +1DH, from the stack.
5046
RET C9
Return with Register Pair HL entry +1DH, and error 12H with the NZ FLAG if the write failed.

5047H - Read the GAT, Then Give Back Granules

Reached from 4E92H with Register Pair HL the granule byte of the last extent and Register Pair DE the granules to give back.

5047
Call 4AF0H to read the GAT of drive Register C into 4D00H.
504A
RET NZ C0
If the NZ FLAG is set (error 14H), return with the error code in Register A.
504B
INC DE 13
Increment Register Pair DE: 4F10H takes one off before the first granule is given back.
504C
Jump to 4ECEH, which goes on to 4F10H with Register Pair HL inside the entry's extents.