DOSPLUS 3.5 for the Model I - SYS4/SYS Disassembled

Page Customization

Introduction/Summary

DOSPLUS 3.5 SYS4/SYS Disassembly - The Granule System (Model I)

SYS4/SYS is the low overlay that the manual calls the granule system: it allocates disk space. It is requested only by SYS0/SYS's record locator (4CFDH), with code 33H (its 4D58H), when the granule of a file that a read or a write needs is not among the five segments kept in the file control block. SYS4/SYS finds the segment in the file's directory entries, adds granules to the file when it ends before that granule, and returns the segment so that the record locator can put it into the control block's list.

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

The Parts of SYS4/SYS

AddressContents
4E00H-4E4BHThe routine table (routines 2 and 3), routine 2, and routine 3, which returns the segment and updates the list (4E00H, 4E04H, 4E06H).
4E4CH-4E99HThe walk through the segments of the file's entries (4E4CH).
4E9AH-4F64HAdding granules: growing the last segment, starting new segments, Disk space full (4E9AH).
4F65H-4F9AHWriting the table and the entry; the self-modified bit test and bit set (4F65H, 4F80H).
4F9BH-500DHMaking an extended entry and finding a free hash index byte (4F9BH, 4FF2H).
500EH-5051HReading and writing the two tables (500EH).

Finding the Segment

The walk (4E4CH) starts at the file's first entry (FCB+07H) and adds up the granules of each segment descriptor (bits 4-0 of the second byte plus 1) until the segment that reaches the granule wanted; FEH links to an extended entry, whose segments are read in turn. Routine 3 (4E06H) then works out the granule's place in the segment and looks for the segment in the control block's list by its cylinder and first granule. A segment that is there (one that has just grown) gets its new granule byte and is returned with the NC FLAG; otherwise the second to fourth elements move one place on, the fifth is dropped, and the segment is returned with the C FLAG for the record locator to store as the second element (its 4D96H).

Adding Granules

When the file's segments end before the granule wanted, the file gets as many granules as it is short (4E9AH). Each one is taken right after the last segment when that granule is free and the segment holds fewer than 32 granules, so a file grows in one piece when it can. Otherwise the next descriptor of the entry starts a new segment, at the first free granule from the cylinder after the last segment to the diskette's last cylinder (the GAT's byte CCH plus 35), then from cylinder 0; no free granule gives error 1BH, Disk space full, after the work done so far is written.

A file whose entry has no segment yet starts its search at a cylinder chosen by the entry's directory sector: the cylinders are divided by the number of directory sectors that hold entries, and the quotient is multiplied by the entry's sector (bits 4-0 of its logical file number). Files whose entries are in different directory sectors therefore start in different parts of the diskette (4EACH-4EC4H).

When the entry's four descriptors are used up, the table and the entry are written and an extended entry is made (4F9BH): a free byte of the hash index table is looked for from the file's first entry on, then from the start (none gives error 1EH, Directory full can't extend file); it gets the hash code of the file's first entry, and the new entry is 90H, the logical file number of the entry before it, twenty bytes 00H and ten FFH (it has no name). The entry before it gets FEH and the new logical file number at +1EH-+1FH, and the walk is made again. The granule tests and sets use BIT n,B and SET n,A instructions whose second byte is stored before they run (4F80H).

Differences from the Manual

The manual does not describe how DOSPLUS 3.5 chooses where a file's space goes; the start cylinder by directory sector, the growth of the last segment and the extended entry without a name are from the bytes. The extended entry gets the hash code of the file's first entry, so it is found under the same code as the file.

Variables

Memory Outside SYS4/SYS

Address
Size
Contents
4200HH-42FFHH
256 bytes
System Sector Buffer
Directory sectors (4E5AH, 4F65H, 4FBAH).

Work Areas

Address
Size
Contents
5100H-51FFH
256 bytes
Table Buffer
The granule allocation table, then the hash index table (5100H).
51CCH
1 byte
Cylinder Count
GAT byte CCH, the cylinders less 35 (4EACH, 4EF4H, 4F1CH).
4E4AH
1 byte
Place in the Segment
The operand of LD A,n (4E11H, 4E49H).
4F66H
1 byte
Entry Logical File Number
The entry the walk is at: the operand of LD A,n (4E54H, 4F65H, 4FC2H, 4FDDH).
4F8BH
1 byte
BIT Opcode
The second byte of BIT n,B (4F87H).
4F99H
1 byte
SET Opcode
The second byte of SET n,A (4F94H).
4FEDH
1 byte
New Logical File Number
The operand of LD (HL),n, the link to the new extended entry (4FADH, 4FECH).

Registers at Routine 3

RegisterContents
IXThe file control block (entry and return).
IYThe drive control table: DCT+0EH the directory length, DCT+10H the granules per cylinder.
BCEntry: the granule of the file wanted. Return with the C FLAG: Register C the cylinder and Register B the granule byte of the segment.
DEReturn with the C FLAG: the file's granules before the segment.
HLReturn with the C FLAG: the second element's last byte (FCB+13H); with the NC FLAG: the descriptor, Register H the granule byte, Register L the cylinder.
AReturn: the granule's place in the segment; an error code with the NZ FLAG (14H-18H, 1BH, 1EH or a disk error).

Outside Routines

AddressContents
4485HSYS0/SYS: DISKIO%, functions 6 (SREAD) and 7 (SWRITE) (500EH).
490CH, 4915HSYS0/SYS: read and write the directory sector of a logical file number.
4934HSYS0/SYS: 8 bit multiply (4EC0H).
4943HSYS0/SYS: 8 bit divide (4EB7H, 4EE7H).

Disassembly

4E00H - The Routine Table

Data: SYS4/SYS's table of routines 2 and 3, one word each, used by SYS0/SYS's overlay request handler (its 49C9H-49DCH) for the request codes 32H and 33H. SYS0/SYS's record locator requests 33H (its 4D58H) when the granule of a file it needs is not in the five segments of the file control block; no file of the diskette requests 32H or any other code 34H-3FH.

4E00-4E01
DEFW 4E04H 04 4E
Routine 2: 4E04H, XOR A and RET, which SYS0/SYS's record locator requests when it loads SYS4/SYS back (its 4D55H-4D62H).
4E02-4E03
DEFW 4E06H 06 4E
Routine 3: 4E06H, which finds the segment holding granule Register Pair BC of the file at Index Register IX, adding granules to the file when it has fewer, and puts the segment into the file control block's list.

4E04H - Routine 2

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

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

4E06H - Routine 3 - The Segment of a Granule

Requested with code 33H by SYS0/SYS's record locator (4D58H) with Index Register IX the file control block, Register Pair BC the granule of the file wanted (counted from 0) and Index Register IY the drive's control table (LOCDCT% at its 4D00H). The file's directory entries are searched for the segment holding the granule (4E4CH); when the file ends before it, granules are added (4E9AH). Register A returns the granule's place in the segment. A segment already in the list (it has grown) gets its new count, and the routine returns the NC FLAG with Register H = the segment's granule byte and Register L its cylinder; a segment not in the list returns the C FLAG with Register C = its cylinder, Register B its granule byte, Register Pair DE the file's granules before it and Register Pair HL the last byte of the list's second element, which the record locator fills (its 4D96H). On an error Register A holds its code with the NZ FLAG.

4E06
GOSUB to 4E4CH to find the segment of granule Register Pair BC: Register Pair HL returns the segment's descriptor (Register L the cylinder, Register H the granule byte) and Register Pair DE the file's granules before it.
4E09
RET NZ C0
If the NZ FLAG is set (an error), RETurn with the error code in Register A.
4E0A
PUSH HL E5
Save Register Pair HL, the segment's descriptor, to the top of the stack.
4E0B
LD H,B 60
Load Register H with Register B, the high byte of the granule wanted.
4E0C
LD L,C 69
Load Register L with Register C: Register Pair HL = the granule wanted.
4E0D
OR A B7
OR Register A with itself to clear the C FLAG for the SBC below (Register A is 00H).
4E0E
SBC HL,DE ED 52
SUBtract Register Pair DE, the granules before the segment, from Register Pair HL: the granule's place in the segment.
4E10
LD A,L 7D
Load Register A with Register L, the place in the segment (0-31).
4E11
LD (4E4AH),A 32 4A 4E
Store Register A to 4E4AH, the operand of the LD A,00H at 4E49H that loads the result.
4E14
POP HL E1
Restore Register Pair HL from the top of the stack: the segment's descriptor.
4E15
PUSH DE D5
Save Register Pair DE, the granules before the segment, to the top of the stack.
4E16
PUSH IX DD E5
Save Index Register IX, the file control block, to the top of the stack.
4E18
EX (SP),HL E3
Exchange the top of the Stack Pointer with Register Pair HL: Register Pair HL = the file control block and the descriptor goes to the stack.
4E19
LD DE,000EH 11 0E 00
Load Register Pair DE with 000EH, the offset of the segment list in a file control block.
4E1C
ADD HL,DE 19
ADD Register Pair DE to Register Pair HL: Register Pair HL = FCB+0EH, the first segment of the list.
4E1D
POP DE D1
Restore Register Pair DE from the top of the stack: Register E = the segment's cylinder, Register D its granule byte.
4E1E
LD B,05H 06 05
Load Register B with 05H, the five segments of the list.
4E20
LD A,(HL) 7E
Load Register A with the cylinder of the list's segment at Register Pair HL.
4E21
INC HL 23
INCrement Register Pair HL by 1 to the list segment's granule byte.
4E22
CP E BB
Compare Register A against Register E, the cylinder of the segment found.
4E23
If the NZ FLAG is set (another cylinder), JUMP to 4E2BH for the next segment of the list.
4E25
LD A,(HL) 7E
Load Register A with the list segment's granule byte at Register Pair HL.
4E26
XOR D AA
XOR Register A with Register D, the granule byte of the segment found.
4E27
AND E0H E6 E0
AND Register A with E0H, the bits of the first granule (7-5).
4E29
If the Z FLAG is set (the same first granule: the segment is in the list, with its old count), JUMP to 4E45H.
4E2B
DEC B 05
DECrement Register B, the segments of the list left, by 1.
4E2C
If the Z FLAG is set (none left), JUMP to 4E33H to put the segment into the list.
4E2E
INC HL 23
INCrement Register Pair HL by 1 to the next element's count of granules.
4E2F
INC HL 23
INCrement Register Pair HL by 1 to the count's high byte.
4E30
INC HL 23
INCrement Register Pair HL by 1 to the next element's cylinder.
4E31
JUMP back to 4E20H to compare the next segment of the list.
4E33
PUSH DE D5
Save Register Pair DE, the segment's descriptor, to the top of the stack.
4E34
EX DE,HL EB
Exchange Register Pairs DE and HL: Register Pair DE = FCB+1FH, the last byte of the list.
4E35
LD HL,FFFCH 21 FC FF
Load Register Pair HL with FFFCH, minus 4, the length of an element.
4E38
ADD HL,DE 19
ADD Register Pair DE to Register Pair HL: Register Pair HL = FCB+1BH, the last byte of the fourth element.
4E39
LD BC,000CH 01 0C 00
Load Register Pair BC with 000CH, the 12 bytes of the second, third and fourth elements.
4E3C
LDDR ED B8
Move Register Pair BC bytes from Register Pair HL down to Register Pair DE, last byte first: the second to fourth elements move one place on and the fifth is dropped.
4E3E
EX DE,HL EB
Exchange Register Pairs DE and HL: Register Pair HL = FCB+13H, the last byte of the second element, now free.
4E3F
POP BC C1
Restore Register Pair BC from the top of the stack: Register C = the cylinder, Register B = the granule byte.
4E40
POP DE D1
Restore Register Pair DE from the top of the stack: the file's granules before the segment.
4E41
XOR A AF
Set Register A to 00H by XORing it with itself, and set the Z FLAG (no error).
4E42
SCF 37
Set the C FLAG: the record locator is to put the segment into the second element.
4E43
JUMP to 4E49H to load Register A with the granule's place in the segment.
4E45
LD (HL),D 72
Store Register D, the segment's new granule byte (its new count), to the list at Register Pair HL.
4E46
EX DE,HL EB
Exchange Register Pairs DE and HL: Register Pair HL = the descriptor (Register H the granule byte, Register L the cylinder).
4E47
POP AF F1
Restore Register Pair AF from the top of the stack: it drops the granules before the segment.
4E48
XOR A AF
Set Register A to 00H by XORing it with itself: the Z FLAG and the NC FLAG.
4E49
LD A,00H 3E 00
Load Register A with the granule's place in the segment (the operand 4E4AH is 00H in the file and is stored at 4E11H).
4E4B
RET C9
RETurn to the record locator with Register A = the place in the segment, the Z FLAG and the C FLAG as set above.

4E4CH - Finding the Segment of a Granule

Walks the segment descriptors of the file's directory entries (the first at FCB+07H, then each extended entry an FEH links to), adding up the granules, until the segment that holds granule Register Pair BC. Register Pair HL returns its descriptor (Register L the cylinder, Register H the granule byte) and Register Pair DE the granules before it, with the Z FLAG. When the list ends first (FFH), granules are added at 4E9AH and the walk is made again. The logical file number of each entry read is kept at 4F66H, the operand of the LD A,n at 4F65H.

4E4C
PUSH BC C5
Save Register Pair BC, the granule wanted, to the top of the stack.
4E4D
LD DE,0000H 11 00 00
Load Register Pair DE with 0000H, the count of the file's granules before the first segment.
4E50
LD B,(IX+07H) DD 46 07
Load Register B with the logical file number of the file's first entry at Index Register IX+07H (FCB+07H).
4E53
LD A,B 78
Load Register A with Register B, the logical file number of the entry to read.
4E54
LD (4F66H),A 32 66 4F
Store Register A to 4F66H, the operand of the LD A,00H at 4F65H: the entry the walk is at.
4E57
LD C,(IX+06H) DD 4E 06
Load Register C with the drive at Index Register IX+06H (FCB+06H).
4E5A
GOSUB to 490CH in SYS0/SYS to read the directory sector of logical file number Register B on drive Register C into 4200H; Register Pair HL returns the entry's address.
4E5D
If the Z FLAG is set (the sector was read), JUMP to 4E61H to go on.
4E5F
POP BC C1
Restore Register Pair BC from the top of the stack: the granule wanted.
4E60
RET C9
RETurn with the read error code in Register A and the NZ FLAG set.
4E61
LD BC,0016H 01 16 00
Load Register Pair BC with 0016H, the offset of the first segment descriptor in an entry.
4E64
ADD HL,BC 09
ADD Register Pair BC to Register Pair HL: Register Pair HL = the entry's +16H.
4E65
EX DE,HL EB
Exchange Register Pairs DE and HL: Register Pair DE = the descriptor, Register Pair HL = the granules counted so far.
4E66
POP BC C1
Restore Register Pair BC from the top of the stack: the granule wanted.
4E67
LD A,(DE) 1A
Load Register A with the descriptor's first byte at Register Pair DE, the cylinder (or FEH, FFH).
4E68
CP FEH FE FE
Compare Register A against FEH: FEH (a link) and FFH (the end) set the NC FLAG.
4E6A
If the NC FLAG is set (FEH or FFH), JUMP to 4E8BH.
4E6C
INC DE 13
INCrement Register Pair DE by 1 to the descriptor's granule byte.
4E6D
LD A,(DE) 1A
Load Register A with the granule byte at Register Pair DE.
4E6E
PUSH HL E5
Save Register Pair HL, the granules before this segment, to the top of the stack.
4E6F
AND 1FH E6 1F
AND Register A with 1FH, the segment's granules less 1.
4E71
INC A 3C
INCrement Register A by 1: Register A = the granules of the segment.
4E72
ADD A,L 85
ADD Register L, the low byte of the count, to Register A.
4E73
LD L,A 6F
Load Register L with Register A, the new low byte of the count.
4E74
If the NC FLAG is set (no carry), JUMP to 4E77H.
4E76
INC H 24
INCrement Register H by 1 for the carry: Register Pair HL = the granules up to the end of this segment.
4E77
PUSH HL E5
Save Register Pair HL, the granules up to the segment's end, to the top of the stack.
4E78
DEC HL 2B
DECrement Register Pair HL by 1: the number of the segment's last granule.
4E79
OR A B7
OR Register A with itself to clear the C FLAG for the SBC below.
4E7A
SBC HL,BC ED 42
SUBtract Register Pair BC, the granule wanted, from Register Pair HL: no borrow when the segment reaches the granule.
4E7C
POP HL E1
Restore Register Pair HL from the top of the stack: the granules up to the segment's end.
4E7D
If the NC FLAG is set (the granule is in this segment), JUMP to 4E83H.
4E7F
INC DE 13
INCrement Register Pair DE by 1 to the next descriptor.
4E80
POP AF F1
Restore Register Pair AF from the top of the stack: it drops the count before this segment.
4E81
JUMP back to 4E67H for the next descriptor, with Register Pair HL the granules counted so far.
4E83
POP HL E1
Restore Register Pair HL from the top of the stack: the granules before the segment.
4E84
EX DE,HL EB
Exchange Register Pairs DE and HL: Register Pair DE = the granules before, Register Pair HL = the descriptor's granule byte.
4E85
LD A,(HL) 7E
Load Register A with the granule byte at Register Pair HL.
4E86
DEC HL 2B
DECrement Register Pair HL by 1 to the descriptor's cylinder.
4E87
LD L,(HL) 6E
Load Register L with the cylinder at Register Pair HL.
4E88
LD H,A 67
Load Register H with Register A, the granule byte: Register Pair HL = the descriptor.
4E89
XOR A AF
Set Register A to 00H by XORing it with itself, and set the Z FLAG: found.
4E8A
RET C9
RETurn with Register Pair HL = the descriptor and Register Pair DE = the granules before it.
4E8B
PUSH BC C5
Save Register Pair BC, the granule wanted, to the top of the stack.
4E8C
EX DE,HL EB
Exchange Register Pairs DE and HL: Register Pair HL = the descriptor, Register Pair DE = the granules the file holds so far.
4E8D
If the NZ FLAG is set (FFH, the end of the file's segments), JUMP to 4E93H.
4E8F
INC HL 23
FEH: INCrement Register Pair HL by 1 to the link's second byte.
4E90
LD B,(HL) 46
Load Register B with the logical file number of the extended entry at Register Pair HL.
4E91
JUMP back to 4E53H to read the extended entry and go on with its segments.
4E93
GOSUB to 4E9AH to add granules to the file from its last segment (Register Pair HL the FFH, Register Pair DE the granules it holds, Register Pair BC the granule wanted).
4E96
POP BC C1
Restore Register Pair BC from the top of the stack: the granule wanted.
4E97
RET NZ C0
If the NZ FLAG is set (an error), RETurn with the error code in Register A.
4E98
JUMP back to 4E4CH to look for the granule again through the larger file.

4E9AH - Adding Granules to a File

Entered with Register Pair HL at the FFH that ends the segments of the file's last entry (in the buffer at 4200H), Register Pair DE the granules the file holds and Register Pair BC the granule wanted: the file gets Register Pair BC less Register Pair DE plus 1 granules. Each granule is taken next to the last segment when that granule is free (the segment grows, up to 32 granules); otherwise a new segment starts in the next descriptor at the first free granule found from that cylinder on, or, for an entry with no segment yet, from a cylinder chosen by the entry's directory sector, so files are spread over the diskette. When the entry has no descriptor left an extended entry is made (4F9BH). The granule allocation table is read into 5100H and written back with the entry at the end (4F65H).

4E9A
PUSH BC C5
Save Register Pair BC, the granule wanted, to the top of the stack.
4E9B
LD C,(IX+06H) DD 4E 06
Load Register C with the drive at Index Register IX+06H (FCB+06H).
4E9E
GOSUB to 500EH to read the granule allocation table of drive Register C into 5100H.
4EA1
POP BC C1
Restore Register Pair BC from the top of the stack: the granule wanted.
4EA2
RET NZ C0
If the NZ FLAG is set (a read error), RETurn with Register A = 14H, Gat read error.
4EA3
PUSH HL E5
Save Register Pair HL, the address of the FFH, to the top of the stack.
4EA4
LD H,B 60
Load Register H with Register B, the high byte of the granule wanted.
4EA5
LD L,C 69
Load Register L with Register C: Register Pair HL = the granule wanted.
4EA6
OR A B7
OR Register A with itself to clear the C FLAG for the SBC below.
4EA7
SBC HL,DE ED 52
SUBtract Register Pair DE, the granules the file holds, from Register Pair HL.
4EA9
LD B,H 44
Load Register B with Register H, the high byte of the difference.
4EAA
LD C,L 4D
Load Register C with Register L, the low byte.
4EAB
INC BC 03
INCrement Register Pair BC by 1: Register Pair BC = the granules to add (the granule wanted is counted from 0).
4EAC
LD A,(51CCH) 3A CC 51
Load Register A with the GAT's byte CCH at 51CCH, the diskette's cylinder count less 35.
4EAF
ADD A,23H C6 23
ADD 23H (35) to Register A: the number of cylinders.
4EB1
LD E,A 5F
Load Register E with Register A, the number of cylinders.
4EB2
LD A,(IY+0EH) FD 7E 0E
Load Register A with the directory's length in sectors at Index Register IY+0EH (DCT+0EH).
4EB5
DEC A 3D
DECrement Register A by 1 (for the granule allocation table).
4EB6
DEC A 3D
DECrement Register A by 1 (for the hash index table): Register A = the directory sectors that hold entries.
4EB7
GOSUB to 4943H in SYS0/SYS: Register A = Register E (the cylinders) divided by Register A (the entry sectors), Register E = the remainder.
4EBA
LD E,A 5F
Load Register E with Register A, the cylinders per directory entry sector.
4EBB
LD A,(IX+07H) DD 7E 07
Load Register A with the logical file number of the file's first entry at Index Register IX+07H.
4EBE
AND 1FH E6 1F
AND Register A with 1FH, bits 4-0: the entry's directory sector less 2.
4EC0
GOSUB to 4934H in SYS0/SYS: Register A = Register A times Register E, the cylinder from which a new file's first segment is looked for.
4EC3
LD L,A 6F
Load Register L with Register A, the cylinder.
4EC4
LD H,51H 26 51
Load Register H with 51H: Register Pair HL = the cylinder's byte in the granule allocation table at 5100H.
4EC6
POP DE D1
Restore Register Pair DE from the top of the stack: the address of the FFH that ends the segments.
4EC7
INC DE 13
INCrement Register Pair DE by 1 to the second byte of that empty descriptor.
4EC8
PUSH BC C5
Save Register Pair BC, the granules to add, to the top of the stack.
4EC9
LD A,E 7B
Load Register A with Register E, the low byte of the descriptor's address.
4ECA
AND 1EH E6 1E
AND Register A with 1EH: the offset of the descriptor in its entry (the low bit dropped).
4ECC
CP 16H FE 16
Compare Register A against 16H, the entry's first descriptor.
4ECE
If the Z FLAG is set (the entry has no segment yet), JUMP to 4F1AH to start one from the cylinder at Register Pair HL.
4ED0
DEC E 1D
DECrement Register E by 1 (towards the descriptor before the empty one).
4ED1
DEC E 1D
DECrement Register E by 1: Register Pair DE = the granule byte of the entry's last segment.
4ED2
LD A,(DE) 1A
Load Register A with the last segment's granule byte at Register Pair DE.
4ED3
AND 1FH E6 1F
AND Register A with 1FH, the segment's granules less 1.
4ED5
INC A 3C
INCrement Register A by 1: Register A = the granules of the segment.
4ED6
LD C,A 4F
Load Register C with Register A, the granules of the segment.
4ED7
CP 20H FE 20
Compare Register A against 20H, the most granules a segment can hold (32).
4ED9
If the Z FLAG is set (the segment is full), JUMP to 4F03H for a new segment.
4EDB
LD A,(DE) 1A
Load Register A with the segment's granule byte at Register Pair DE.
4EDC
AND E0H E6 E0
AND Register A with E0H, the segment's first granule in bits 7-5.
4EDE
RLCA 07
Rotate Register A left one bit (bits 7-5 move towards bits 2-0).
4EDF
RLCA 07
Rotate Register A left one bit (bits 7-5 move towards bits 2-0).
4EE0
RLCA 07
Rotate Register A left one bit: Register A = the first granule, 0-7.
4EE1
ADD A,C 81
ADD Register C, the granules of the segment, to Register A: the granule after the segment, counted from its first cylinder.
4EE2
PUSH DE D5
Save Register Pair DE, the descriptor's granule byte, to the top of the stack.
4EE3
LD E,A 5F
Load Register E with Register A, the granule after the segment.
4EE4
LD A,(IY+10H) FD 7E 10
Load Register A with the granules per cylinder at Index Register IY+10H (DCT+10H).
4EE7
GOSUB to 4943H in SYS0/SYS: Register A = Register E divided by Register A (the cylinders on), Register E = the granule within its cylinder.
4EEA
LD B,A 47
Load Register B with Register A, the cylinders on from the segment's first.
4EEB
LD C,E 4B
Load Register C with Register E, the granule within the cylinder.
4EEC
POP DE D1
Restore Register Pair DE from the top of the stack: the descriptor's granule byte.
4EED
DEC DE 1B
DECrement Register Pair DE by 1 to the descriptor's cylinder.
4EEE
LD A,(DE) 1A
Load Register A with the segment's first cylinder at Register Pair DE.
4EEF
INC DE 13
INCrement Register Pair DE by 1 back to the granule byte.
4EF0
ADD A,B 80
ADD Register B to Register A: the cylinder of the granule after the segment.
4EF1
LD L,A 6F
Load Register L with Register A, the cylinder.
4EF2
LD H,51H 26 51
Load Register H with 51H: Register Pair HL = the cylinder's byte in the allocation table at 5100H.
4EF4
LD A,(51CCH) 3A CC 51
Load Register A with the GAT's byte CCH at 51CCH, the cylinder count less 35.
4EF7
ADD A,22H C6 22
ADD 22H (34) to Register A: the number of the diskette's last cylinder.
4EF9
CP L BD
Compare Register A against Register L, the cylinder.
4EFA
If the C FLAG is set (past the last cylinder), JUMP to 4F03H for a new segment.
4EFC
LD A,C 79
Load Register A with Register C, the granule within the cylinder.
4EFD
LD B,(HL) 46
Load Register B with the cylinder's allocation byte at Register Pair HL.
4EFE
GOSUB to 4F80H to test bit Register A of Register B: the Z FLAG when the granule is free.
4F01
If the Z FLAG is set (free), JUMP to 4F4BH to add it to the segment.
4F03
INC E 1C
INCrement Register E by 1 (towards the descriptor after this one).
4F04
INC E 1C
INCrement Register E by 1: Register Pair DE = the granule byte of the next descriptor.
4F05
LD A,E 7B
Load Register A with Register E, the low byte of its address.
4F06
AND 1EH E6 1E
AND Register A with 1EH: the descriptor's offset in the entry.
4F08
CP 1EH FE 1E
Compare Register A against 1EH, the entry's +1EH, which is the link and not a descriptor.
4F0A
If the NZ FLAG is set (a free descriptor), JUMP to 4F1AH to start a new segment in it.
4F0C
No descriptor left: GOSUB to 4F65H to write the allocation table and the entry.
4F0F
POP BC C1
Restore Register Pair BC from the top of the stack: the granules still to add.
4F10
RET NZ C0
If the NZ FLAG is set (a write error), RETurn with the error code in Register A.
4F11
PUSH BC C5
Save Register Pair BC, the granules still to add, to the top of the stack.
4F12
GOSUB to 4F9BH to make an extended entry and link it to the entry.
4F15
POP BC C1
Restore Register Pair BC from the top of the stack: the granules still to add.
4F16
RET NZ C0
If the NZ FLAG is set (an error), RETurn with the error code in Register A.
4F17
JUMP to 4E4CH to walk the segments again, here with Register Pair BC the granules still to add, not the granule wanted; its return goes to 4E96H, which restores the granule wanted and walks again, now into the new extended entry.
4F1A
LD B,02H 06 02
Load Register B with 02H: two passes, from the cylinder at Register Pair HL to the last, then from cylinder 0.
4F1C
LD A,(51CCH) 3A CC 51
Load Register A with the GAT's byte CCH at 51CCH, the cylinder count less 35.
4F1F
ADD A,22H C6 22
ADD 22H (34) to Register A: the number of the last cylinder.
4F21
CP L BD
Compare Register A against Register L, the cylinder.
4F22
If the C FLAG is set (past the last cylinder), JUMP to 4F2BH.
4F24
LD A,(HL) 7E
Load Register A with the cylinder's allocation byte at Register Pair HL.
4F25
INC A 3C
INCrement Register A by 1: 00H and the Z FLAG when every granule is in use (FFH).
4F26
If the NZ FLAG is set (a free granule), JUMP to 4F38H.
4F28
INC L 2C
INCrement Register L by 1 to the next cylinder's allocation byte.
4F29
JUMP back to 4F1CH to test the next cylinder.
4F2B
LD L,00H 2E 00
Load Register L with 00H: the search goes on from cylinder 0.
4F2D
DECrement Register B and loop back to 4F1CH while Register B is not zero (the second pass).
4F2F
POP BC C1
Restore Register Pair BC from the top of the stack: the granules still to add.
4F30
No free granule: GOSUB to 4F65H to write the allocation table and the entry as far as they were changed.
4F33
RET NZ C0
If the NZ FLAG is set (a write error), RETurn with the error code in Register A.
4F34
LD A,1BH 3E 1B
Load Register A with 1BH, the error code Disk space full.
4F36
OR A B7
OR Register A with itself to set the NZ FLAG.
4F37
RET C9
RETurn with Register A = 1BH and the NZ FLAG set.
4F38
LD A,FFH 3E FF
Load Register A with FFH, the start value of a new segment's granule byte.
4F3A
LD (DE),A 12
Store Register A (FFH) to the new descriptor's granule byte at Register Pair DE: bits 4-0 = 1FH, so the INC at 4F5AH makes the count 0 (one granule) and carries 1 into the first granule.
4F3B
LD C,00H 0E 00
Load Register C with 00H, granule 0 of the cylinder.
4F3D
LD B,(HL) 46
Load Register B with the cylinder's allocation byte at Register Pair HL.
4F3E
LD A,C 79
Load Register A with Register C, the granule to test.
4F3F
GOSUB to 4F80H to test bit Register A of Register B: the Z FLAG when the granule is free.
4F42
If the Z FLAG is set (free), JUMP to 4F4BH to take it.
4F44
LD A,(DE) 1A
Load Register A with the new descriptor's granule byte at Register Pair DE.
4F45
ADD A,20H C6 20
ADD 20H to Register A: one granule further in bits 7-5 (FFH becomes 1FH, 1FH becomes 3FH ...).
4F47
LD (DE),A 12
Store Register A to the descriptor's granule byte at Register Pair DE.
4F48
INC C 0C
INCrement Register C by 1 to the next granule of the cylinder.
4F49
JUMP back to 4F3EH to test the next granule, Register C.
4F4B
LD A,C 79
Load Register A with Register C, the free granule.
4F4C
GOSUB to 4F8DH: Register A = the granule's bit (1 shifted left by Register A).
4F4F
OR (HL) B6
OR Register A with the cylinder's allocation byte at Register Pair HL.
4F50
LD (HL),A 77
Store Register A to the allocation byte at Register Pair HL: the granule is in use.
4F51
DEC E 1D
DECrement Register E by 1 to the descriptor's cylinder.
4F52
LD A,(DE) 1A
Load Register A with the descriptor's cylinder at Register Pair DE.
4F53
INC A 3C
INCrement Register A by 1: 00H and the Z FLAG when it is FFH, a new segment.
4F54
If the NZ FLAG is set (the segment has its cylinder), JUMP to 4F58H.
4F56
LD A,L 7D
Load Register A with Register L, the cylinder of the granule.
4F57
LD (DE),A 12
Store Register A to the new descriptor's cylinder at Register Pair DE.
4F58
INC E 1C
INCrement Register E by 1 to the descriptor's granule byte.
4F59
LD A,(DE) 1A
Load Register A with the granule byte at Register Pair DE.
4F5A
INC A 3C
INCrement Register A by 1: one more granule (a new segment: the first granule in bits 7-5, count 0).
4F5B
LD (DE),A 12
Store Register A to the granule byte at Register Pair DE.
4F5C
POP BC C1
Restore Register Pair BC from the top of the stack: the granules still to add.
4F5D
DEC BC 0B
DECrement Register Pair BC by 1: one granule added.
4F5E
PUSH BC C5
Save Register Pair BC to the top of the stack.
4F5F
LD A,B 78
Load Register A with Register B, the high byte of the granules still to add.
4F60
OR C B1
OR Register A with Register C, the low byte: the Z FLAG when Register Pair BC is 0000H.
4F61
If the NZ FLAG is set (more to add), JUMP back to 4ED2H to try the granule after the segment.
4F64
POP BC C1
Restore Register Pair BC from the top of the stack (0000H).

4F65H - Writing the Table and the Entry

Writes the granule allocation table from 5100H and the directory sector of the entry the walk is at (its logical file number is the operand at 4F66H, stored at 4E54H), after checking that the entry in the buffer at 4200H is active.

4F65
LD A,00H 3E 00
Load Register A with the logical file number of the entry the walk is at (the operand 4F66H, 00H in the file, is stored at 4E54H).
4F67
LD B,A 47
Load Register B with Register A, the logical file number.
4F68
AND E0H E6 E0
AND Register A with E0H, the entry's offset in its sector.
4F6A
LD L,A 6F
Load Register L with Register A, the low byte of the entry's address.
4F6B
LD H,42H 26 42
Load Register H with 42H: Register Pair HL = the entry in the buffer at 4200H.
4F6D
BIT 4,(HL) CB 66
Test bit 4 of the entry's first byte at Register Pair HL, the active flag.
4F6F
If the NZ FLAG is set (active), JUMP to 4F75H.
4F71
LD A,18H 3E 18
Load Register A with 18H, the error code File not in directory.
4F73
OR A B7
OR Register A with itself to set the NZ FLAG.
4F74
RET C9
RETurn with Register A = 18H and the NZ FLAG set.
4F75
LD C,(IX+06H) DD 4E 06
Load Register C with the drive at Index Register IX+06H (FCB+06H).
4F78
GOSUB to 5020H to write the granule allocation table from 5100H.
4F7B
RET NZ C0
If the NZ FLAG is set (a write error), RETurn with Register A = 15H, Gat write error.
4F7C
GOSUB to 4915H in SYS0/SYS to write the directory sector of logical file number Register B from 4200H.
4F7F
RET C9
RETurn with Register A and the flags of the write.

4F80H - The Granule Bits

4F80H tests bit Register A of Register B by storing the second byte of a BIT n,B instruction (40H + n times 8) at 4F8BH; 4F8DH returns Register A = the bit n alone by storing the second byte of SET n,A (C7H + n times 8) at 4F99H.

4F80
AND 07H E6 07
AND Register A with 07H to keep the bit number, 0-7.
4F82
RLCA 07
Rotate Register A left one bit (the bit number moves towards bits 5-3).
4F83
RLCA 07
Rotate Register A left one bit (the bit number moves towards bits 5-3).
4F84
RLCA 07
Rotate Register A left one bit: Register A = the bit number times 8.
4F85
OR 40H F6 40
OR Register A with 40H, the second byte of BIT 0,B.
4F87
LD (4F8BH),A 32 8B 4F
Store Register A to 4F8BH, the second byte of the instruction at 4F8AH.
4F8A
BIT 0,B CB 40
Test bit n of Register B; n is set by the byte 4F87H stores to 4F8BH (40H here is BIT 0,B). The Z FLAG is set when the bit is 0.
4F8C
RET C9
RETurn with the Z FLAG set when the granule is free.
4F8D
AND 07H E6 07
AND Register A with 07H to keep the bit number, 0-7.
4F8F
RLCA 07
Rotate Register A left one bit (the bit number moves towards bits 5-3).
4F90
RLCA 07
Rotate Register A left one bit (the bit number moves towards bits 5-3).
4F91
RLCA 07
Rotate Register A left one bit: Register A = the bit number times 8.
4F92
OR C7H F6 C7
OR Register A with C7H, the second byte of SET 0,A.
4F94
LD (4F99H),A 32 99 4F
Store Register A to 4F99H, the second byte of the instruction at 4F98H.
4F97
XOR A AF
Set Register A to 00H by XORing it with itself.
4F98
SET 0,A CB C7
Set bit n of Register A; n is set by the byte 4F94H stores to 4F99H (C7H here is SET 0,A).
4F9A
RET C9
RETurn with Register A = the granule's bit alone.

4F9BH - Making an Extended Entry

Reads the hash index table into 5100H and looks for a free entry, from the file's first entry on, then from the start (4FF2H); none gives error 1EH. The new entry's hash index byte is the first entry's hash code. The new entry (FXDE) gets 90H (extended, active), the logical file number of the entry before it at +01H, 00H at +02H-+15H and FFH at +16H-+1FH; the entry before it (the one at 4F66H) gets FEH and the new logical file number at +1EH-+1FH.

4F9B
LD C,(IX+06H) DD 4E 06
Load Register C with the drive at Index Register IX+06H (FCB+06H).
4F9E
GOSUB to 5032H to read the hash index table of drive Register C into 5100H.
4FA1
RET NZ C0
If the NZ FLAG is set (a read error), RETurn with Register A = 16H, Hit read error.
4FA2
LD A,(IX+07H) DD 7E 07
Load Register A with the logical file number of the file's first entry at Index Register IX+07H.
4FA5
GOSUB to 4FF2H to find a free hash index byte from that entry on: Register Pair HL returns its address.
4FA8
LD A,1EH 3E 1E
Load Register A with 1EH, the error code Directory full can't extend file (the flags stay).
4FAA
RET NZ C0
If the NZ FLAG is set (no free entry), RETurn with Register A = 1EH.
4FAB
LD B,L 45
Load Register B with Register L, the logical file number of the free entry.
4FAC
LD A,L 7D
Load Register A with Register L, the new logical file number.
4FAD
LD (4FEDH),A 32 ED 4F
Store Register A to 4FEDH, the operand of the LD (HL),00H at 4FECH, for the link.
4FB0
LD D,H 54
Load Register D with Register H (51H), the page of the hash index table.
4FB1
LD E,(IX+07H) DD 5E 07
Load Register E with the logical file number of the first entry at Index Register IX+07H: Register Pair DE = its hash index byte.
4FB4
LD A,(DE) 1A
Load Register A with the first entry's hash code at Register Pair DE.
4FB5
LD (HL),A 77
Store Register A to the free hash index byte at Register Pair HL: the new entry has the file's hash code.
4FB6
GOSUB to 5042H to write the hash index table from 5100H.
4FB9
RET NZ C0
If the NZ FLAG is set (a write error), RETurn with Register A = 17H, Hit write error.
4FBA
GOSUB to 490CH in SYS0/SYS to read the directory sector of the new logical file number Register B into 4200H.
4FBD
RET NZ C0
If the NZ FLAG is set (a read error), RETurn with the error code in Register A.
4FBE
LD (HL),90H 36 90
Store 90H to the new entry's first byte at Register Pair HL: bit 7 an extended entry, bit 4 active.
4FC0
INC L 2C
INCrement Register L by 1 to the entry's +01H.
4FC1
PUSH BC C5
Save Register Pair BC (Register B the new logical file number) to the top of the stack.
4FC2
LD A,(4F66H) 3A 66 4F
Load Register A with the logical file number of the entry before, from 4F66H.
4FC5
LD (HL),A 77
Store Register A to the new entry's +01H at Register Pair HL, the link back.
4FC6
INC L 2C
INCrement Register L by 1 to the entry's +02H.
4FC7
LD B,14H 06 14
Load Register B with 14H, the 20 bytes +02H-+15H.
4FC9
LD (HL),00H 36 00
Store 00H to the byte of the new entry at Register Pair HL.
4FCB
INC L 2C
INCrement Register L by 1 to the next byte of the entry.
4FCC
DECrement Register B and loop back to 4FC9H while Register B is not zero.
4FCE
PUSH HL E5
Save Register Pair HL, the entry's +16H, to the top of the stack.
4FCF
LD B,0AH 06 0A
Load Register B with 0AH, the 10 bytes +16H-+1FH.
4FD1
LD (HL),FFH 36 FF
Store FFH to the entry at Register Pair HL: no segment, no link.
4FD3
INC L 2C
INCrement Register L by 1 to the next byte of the entry.
4FD4
DECrement Register B and loop back to 4FD1H while Register B is not zero.
4FD6
POP DE D1
Restore Register Pair DE from the top of the stack: the new entry's +16H.
4FD7
INC DE 13
INCrement Register Pair DE by 1 to its +17H (Register Pair DE is not used after this).
4FD8
POP BC C1
Restore Register Pair BC from the top of the stack: Register B = the new logical file number.
4FD9
GOSUB to 4915H in SYS0/SYS to write the directory sector of logical file number Register B from 4200H.
4FDC
RET NZ C0
If the NZ FLAG is set (a write error), RETurn with the error code in Register A.
4FDD
LD A,(4F66H) 3A 66 4F
Load Register A with the logical file number of the entry before, from 4F66H.
4FE0
LD B,A 47
Load Register B with Register A, the entry before.
4FE1
GOSUB to 490CH in SYS0/SYS to read the directory sector of logical file number Register B into 4200H.
4FE4
RET NZ C0
If the NZ FLAG is set (a read error), RETurn with the error code in Register A.
4FE5
LD A,L 7D
Load Register A with Register L, the low byte of the entry's address.
4FE6
ADD A,1EH C6 1E
ADD 1EH to Register A, the offset of the link.
4FE8
LD L,A 6F
Load Register L with Register A: Register Pair HL = the entry's +1EH.
4FE9
LD (HL),FEH 36 FE
Store FEH to the entry's +1EH at Register Pair HL: a link to an extended entry.
4FEB
INC L 2C
INCrement Register L by 1 to the entry's +1FH.
4FEC
LD (HL),00H 36 00
Store the new logical file number to the entry's +1FH at Register Pair HL (the operand 4FEDH, 00H in the file, is stored at 4FADH).
4FEE
GOSUB to 4915H in SYS0/SYS to write the directory sector of logical file number Register B from 4200H.
4FF1
RET C9
RETurn with Register A and the flags of the write.

4FF2H - A Free Hash Index Byte

Looks in the hash index table at 5100H for a byte 00H (a free entry), first from logical file number Register A on, then from 0. The search goes through the entries of one directory sector (+20H each), then the next sector, up to the directory's last sector (DCT+0EH less 3). Register Pair HL returns the free byte with the Z FLAG, or the NZ FLAG when there is none.

4FF2
LD L,A 6F
Load Register L with Register A, the logical file number to start from (Register H is 51H).
4FF3
GOSUB to 4FF9H to search from Register Pair HL on.
4FF6
RET Z C8
If the Z FLAG is set (found), RETurn with Register Pair HL = the free byte.
4FF7
LD L,00H 2E 00
Load Register L with 00H: search again from logical file number 0.
4FF9
LD A,(HL) 7E
Load Register A with the hash index byte at Register Pair HL.
4FFA
OR A B7
OR Register A with itself: the Z FLAG when the byte is 00H, a free entry.
4FFB
RET Z C8
If the Z FLAG is set (free), RETurn with Register Pair HL = the byte.
4FFC
LD A,20H 3E 20
Load Register A with 20H, the step to the next entry of the same directory sector.
4FFE
ADD A,L 85
ADD Register L, the logical file number, to Register A.
4FFF
LD L,A 6F
Load Register L with Register A, the next logical file number.
5000
If the NC FLAG is set (still within the 256 bytes), JUMP back to 4FF9H.
5002
LD A,(IY+0EH) FD 7E 0E
Load Register A with the directory's length in sectors at Index Register IY+0EH (DCT+0EH).
5005
SUB 03H D6 03
SUBtract 03H from Register A: the last entry sector less 2 (the sector bits of its logical file numbers).
5007
INC L 2C
INCrement Register L by 1 to the first entry of the next sector.
5008
CP L BD
Compare Register A against Register L, the next logical file number.
5009
If the NC FLAG is set (a sector of the directory), JUMP back to 4FF9H.
500B
OR FFH F6 FF
OR Register A with FFH to set the NZ FLAG: no free entry.
500D
RET C9
RETurn with the NZ FLAG set and Register A = FFH.

500EH - Reading and Writing the Tables

500EH reads and 5020H writes the granule allocation table (directory sector 0), 5032H reads and 5042H writes the hash index table (directory sector 1), all of drive Register C through 5100H. Each returns the Z FLAG when done, or the NZ FLAG with error 14H, 15H, 16H or 17H.

500E
PUSH DE D5
Save Register Pair DE to the top of the stack.
500F
PUSH HL E5
Save Register Pair HL to the top of the stack.
5010
LD E,00H 1E 00
Load Register E with 00H, directory sector 0, the granule allocation table.
5012
LD HL,5100H 21 00 51
Point Register Pair HL to 5100H, the buffer after the end of SYS4/SYS.
5015
LD A,06H 3E 06
Load Register A with 06H, the SREAD function of DISKIO%, which reads sector Register E of the directory cylinder.
5017
GOSUB to 4485H (DISKIO%) in SYS0/SYS to read the table of drive Register C into the buffer at Register Pair HL (5100H).
501A
POP HL E1
Restore Register Pair HL from the top of the stack.
501B
POP DE D1
Restore Register Pair DE from the top of the stack.
501C
RET Z C8
If the Z FLAG is set (read), RETurn with Register A from DISKIO%.
501D
LD A,14H 3E 14
Load Register A with 14H, the error code Gat read error; the NZ FLAG stays set.
501F
RET C9
RETurn with Register A = 14H and the NZ FLAG set.
5020
PUSH DE D5
Save Register Pair DE to the top of the stack.
5021
PUSH HL E5
Save Register Pair HL to the top of the stack.
5022
LD E,00H 1E 00
Load Register E with 00H, directory sector 0, the granule allocation table.
5024
LD HL,5100H 21 00 51
Point Register Pair HL to 5100H, the buffer that holds the table.
5027
LD A,07H 3E 07
Load Register A with 07H, the SWRITE function of DISKIO%, which writes sector Register E of the directory cylinder.
5029
GOSUB to 4485H (DISKIO%) in SYS0/SYS to write the buffer at Register Pair HL (5100H) to the table of drive Register C.
502C
POP HL E1
Restore Register Pair HL from the top of the stack.
502D
POP DE D1
Restore Register Pair DE from the top of the stack.
502E
RET Z C8
If the Z FLAG is set (written), RETurn with Register A from DISKIO%.
502F
LD A,15H 3E 15
Load Register A with 15H, the error code Gat write error; the NZ FLAG stays set.
5031
RET C9
RETurn with Register A = 15H and the NZ FLAG set.
5032
PUSH DE D5
Save Register Pair DE to the top of the stack.
5033
LD E,01H 1E 01
Load Register E with 01H, directory sector 1, the hash index table.
5035
LD HL,5100H 21 00 51
Point Register Pair HL to 5100H, the buffer (the allocation table was written before this is called).
5038
LD A,06H 3E 06
Load Register A with 06H, the SREAD function of DISKIO%.
503A
GOSUB to 4485H (DISKIO%) in SYS0/SYS to read the hash index table of drive Register C into the buffer at Register Pair HL (5100H).
503D
POP DE D1
Restore Register Pair DE from the top of the stack; Register Pair HL stays 5100H.
503E
RET Z C8
If the Z FLAG is set (read), RETurn with Register A from DISKIO%.
503F
LD A,16H 3E 16
Load Register A with 16H, the error code Hit read error; the NZ FLAG stays set.
5041
RET C9
RETurn with Register A = 16H and the NZ FLAG set.
5042
PUSH DE D5
Save Register Pair DE to the top of the stack.
5043
LD E,01H 1E 01
Load Register E with 01H, directory sector 1, the hash index table.
5045
LD HL,5100H 21 00 51
Point Register Pair HL to 5100H, the buffer that holds the table.
5048
LD A,07H 3E 07
Load Register A with 07H, the SWRITE function of DISKIO%.
504A
GOSUB to 4485H (DISKIO%) in SYS0/SYS to write the buffer at Register Pair HL (5100H) to the hash index table of drive Register C.
504D
POP DE D1
Restore Register Pair DE from the top of the stack; Register Pair HL stays 5100H.
504E
RET Z C8
If the Z FLAG is set (written), RETurn with Register A from DISKIO%.
504F
LD A,17H 3E 17
Load Register A with 17H, the error code Hit write error; the NZ FLAG stays set.
5051
RET C9
RETurn with Register A = 17H and the NZ FLAG set. 5051H is the last byte of SYS4/SYS.

5100H - The Table Buffer

Not in the file: the granule allocation table (500EH, 5020H) and then the hash index table (5032H, 5042H) of the drive are read here and written from here.

5100-51FF
DEFS 256
The buffer for directory sector 0 (byte 5100H + the cylinder; 51CCH the cylinder count less 35) or directory sector 1 (byte 5100H + the logical file number).