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

Page Customization

Introduction/Summary

Percom DoubleDOS 4.24 SYS2/SYS Disassembly (Model I)

SYS2/SYS is the overlay of DoubleDOS (DBLDOS in Percom's manual) that finds a file in the directory and opens it, makes a new file, and gives a growing file another directory entry. It is overlay 4 (directory record 04H): the overlay dispatcher of SYS0/SYS loads it at 4E00H when a request code with the low four bits 4 is given and calls its transfer address 4E00H with the code in Register A.

The file is 1099 bytes: a name record, the copyright record of 169 bytes, two load blocks, 4E00H-5154H and 5180H-51A6H (892 bytes), and the transfer address 4E00H. Every loaded byte is on exactly one row below; the 43 bytes 5155H-517FH between the blocks hold the parsed password, name and extension and the password hash, and are not in the file. SYS2/SYS is the same in DoubleDOS 4.20, 4.23 (all three sets) and 4.24.

Load Map

AddressesContents
4E00H-4E11HThe dispatcher of the request codes 94H, A4H and B4H (4E00H)
4E12H-4ED7HOpen a file: parse, search the hash index tables, compare the entry, the password tests that are never run (4E12H)
4ED8H-4F4FHOpen a file or make it (4ED8H)
4F50H-4FA6HGive a file another directory entry (4F50H)
4FA7H-5026HFill in the FCB from the directory entry (4FA7H)
5027H-509AHParse a file specification (5027H)
509BH-50FCHThe hash code of a name, a free place in the hash index table, the hash of a password (509BH)
50FDH-5153HWait for a drive's index pulses, read and write the hash index table (50FDH)
5154HThe drive of the specification (5154H)
5180H-51A6HThe end of file sector, and capitals before the parse (5180H)

The Request Codes

CodeEntry in SYS0/SYS, job and registers
94H4424H, open the file named by the specification text in the FCB at Register Pair DE, with Register Pair HL the buffer and Register B the record length (00H for 256). @LOAD (SYS0/SYS 4C16H) calls it with Register Pair HL 4200H and Register B 00H: 4E12H
A4H4420H, the same, but a file that no drive has is made; the C FLAG is returned set for a new file (BASIC/CMD, COPY/CMD, SYS6/SYS): 4ED8H
B4HSYS0/SYS 4A6BH, when the directory entry being extended has no free extent place left but its last: give the file of Index Register IX an extra entry (4F50H)

How a File Is Opened

StepWhat the code does
1The 32 bytes of the FCB are made capitals and parsed as NAME/EXT.PASSWORD:D into 515DH, 5165H, 5155H and 5154H (5194H, 5027H). The name's hash code (509BH) and the password's hash (50D1H) are worked out.
2The drive named, or each of drives 0-3 in turn, is selected and must show index pulses (50FDH); its hash index table, sector 1 of the directory block, is read into 4D00H (512EH).
3Every byte of the table equal to the hash code names a directory record by its place; the entry is read and its eleven characters of name and extension compared, an extra entry being passed over (4E6AH).
4The password is not tested (4EACH), and the FCB is filled in with the access level 00H (4FA7H).
5For request code A4H, a file that is not found is made on the drive named, or on the first of drives 0-3 that is ready, not write protected and has a free place: the hash index table, the new entry and the FCB are written (4F0EH).

The Hash Index Table

Sector 1 of the directory block, read into 4D00H, has a byte for each directory record: its place is the record number (bits 7-5 the entry in its sector, bits 4-0 the sector of entries, 0-7), its value the hash code of the entry's name and extension, or 00H for a free entry. The hash code (509BH) is never 00H. Entries 0 and 1 of the sectors are where the system files are (SYS0/SYS's dispatcher reads records 03H-07H, 20H and 21H), and a new entry is never put in entry 0 or 1 of a sector: the search for a free place (50ABH) starts at a place taken from the tick count at 4040H, in entries 2-7, so that new files are spread over the sectors.

The Directory Entry as SYS2/SYS Writes It

OffsetA new file (4F0EH)An extra entry (4F50H)
+00H10H, the attribute: protection level 090H: bit 7 marks an extra entry
+01H00HThe record of the entry before it
+02H-+03H00H; +03H the end of file offset00H
+04HThe record length given00H
+05H-+0FHThe name and extension00H
+10H-+13HThe update and access password hashes, both the hash of the password given00H
+14H-+15H0000H, the number of sectors0000H
+16H-+1FHFFH: no extentsFFH: no extents

When an extra entry is made, the last extent place of the entry before it, +1EH-+1FH, becomes FEH and the new entry's record: SYS0/SYS follows that link when it counts the extents (SYS0/SYS 49F5H).

Differences From the Manual

Percom's manual has nothing on passwords or on the directory; it refers to the TRSDOS manual for the commands. What the bytes show, below, is a matter of the bytes alone.

Notes

Passwords are never tested. The jump at 4EACH passes over the tests at 4EAEH-4ECEH, which would refuse a file of protection level 7, give every access for the update password and the file's protection level for the access password, and return error 19H for any other password. Every file is opened with the access level 00H, which allows every access. The comparison with 61A2H just before the jump has no effect, since nothing tests its result.

When request code A4H finds no room on drives 0-3 (no drive named), it returns error 1AH with the Z FLAG of the compare at 4F07H still set (4F0DH). A caller that tests the Z FLAG takes the open as good, with an FCB still holding the specification text. With a drive named, the NZ FLAG is returned as it should be.

The record length of the directory entry (+04H) is not used when a file is opened: the FCB gets the record length the caller gives in Register B (4FD6H). FCB+01H gets bit 7 when the record length is not 256 and bit 5 always.

The test of a drive (50FDH) waits for index pulses and uses the write protect bit only when a file is made: a file is opened on a write protected diskette, but not made on one.

The FCB holds only the first five extents of the entry; an extent byte FEH ends them as FFH does, and SYS0/SYS reads the directory entry when it needs a granule beyond them.

The words at 4FC0H, 4FAFH, 4FB2H, 4E4EH, 4F1DH and 4FA2H are operands written while SYS2/SYS runs (the Variables below).

Variables

SYS2/SYS's Own Bytes

Address
Size
Contents
4E4EH
1 byte
Hash Code of the Name
Operand of CP nn at 4E4DH, stored by 4E29H; also put in a new entry's place in the hash index table (4F0FH).
4F1DH
1 byte
Attribute of a New File
Operand of LD (HL),nn at 4F1CH: 10H, stored by 4EE4H.
4FA2H
1 byte
Record of the Extra Entry
Operand of LD (HL),nn at 4FA1H, stored by 4F62H.
4FAFH
1 byte
Record Length
Operand of LD A,nn at 4FAEH, from Register B (4E16H); read at 4F28H and 4FD6H.
4FB2H
1 byte
Access Level
Operand of LD A,nn at 4FB1H, from Register B (4ED1H): always 00H.
4FC0H-4FC1H
2 bytes
Buffer
Operand of LD DE,nnnn at 4FBFH, from Register Pair HL (4E19H).
5154H
1 byte
Drive
FFH when none is named (503DH), 0-3 (507CH), the drive where the file was found (4E8EH).
5155H-515CH
8 bytes
Password
Not in the file; padded with spaces (5032H, 5068H).
515DH-5164H
8 bytes
Name
Not in the file (5045H).
5165H-5167H
3 bytes
Extension
Not in the file (505CH).
5168H-516BH
4 bytes
Password Hash, Twice
Not in the file: the update and the access password of a new entry (4E32H, 4E35H, 4F35H); 516AH is compared at 4EA0H.

Memory Outside SYS2/SYS

Address
Size
Contents
4040H
1 byte
Tick Count
The start of the search for a free place (50ABH).
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.
4ABEH
1 byte
Record of the Entry Being Extended
SYS0/SYS's operand, stored at 49BDH; read at 4F77H and 4F92H.
4D00H-4DFFH
256 bytes
Hash Index Table
Read by 512EH, written by 5141H.
37ECH
1 byte
Controller Command and Status
Force Interrupt D0H (50FFH); the index bit 1 and write protect bit 6 (5123H).

The FCB as SYS2/SYS Fills It In

OffsetContents
+00H80H, open
+01HThe access level (00H) with bit 5 and, when the record length is not 256, bit 7
+02H00H
+03H-+04HThe buffer (Register Pair HL)
+05H00H, the offset
+06H, +07HThe drive, the directory record
+08HThe end of file offset, entry +03H
+09HThe record length (Register B)
+0AH-+0BH0000H, the sector
+0CH-+0DHThe end of file sector: entry +14H-+15H, less 1 when entry +03H is not 00H (5180H)
+0EH-+1FHThe first extent, then four extents each after the count of granules before it; FFH for those the entry does not have

Error Codes Returned by SYS2/SYS

CodeMeaning (where set)
11H, 12HDirectory read, directory write error (from 4AC1H, 4AD6H)
13HNo name in the specification (504EH)
16H, 17HHash index table read, write error (513EH, 5151H)
18HNo drive searched has the file (4E60H)
19HThe password does not open the file (4ECBH, never run)
1AHNo room for a new file on the drives tried (4F0BH)
1EHNo free place for an extra entry (4F5DH)
20HA drive number that is not 0-3 (5078H)

Outside Routines

AddressUse
4600HSYS0/SYS: Select a Drive
5102H.
45CFHSYS0/SYS: Write a Directory Sector and Read It Back
514BH.
4896HSYS0/SYS: The Common Start of the File Routines
Entered past its open test (4E12H, 4ED8H).
4AC1HSYS0/SYS: Read a Directory Record
4E6DH, 4F17H, 4F6FH, 4F96H.
4AD6HSYS0/SYS: Write a Directory Record
4F46H, 4F8EH, 4FA3H.
4B35HSYS0/SYS: Read a Directory Sector
5138H.
4B55HSYS0/SYS: The Directory Block of a Drive
5130H, 5143H.

Disassembly

4E00H - The Request Code Dispatcher

The transfer address of SYS2/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 (4) name SYS2/SYS. 94H opens a file that exists, A4H opens a file and makes it when it is not found, B4H gives an open file another directory entry.

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 94H, 20H for A4H, 30H for B4H.
4E02
CP 10H FE 10
Compare Register A, the job, with 10H, the job of request code 94H, which 4424H passes to open a file.
4E04
If the Z FLAG is set (request code 94H), jump to 4E12H to open 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 A4H, which 4420H passes.
4E09
If the Z FLAG is set (request code A4H), jump to 4ED8H to open the file, or make it when no drive has it.
4E0C
CP 30H FE 30
Compare Register A, the job, with 30H, the job of request code B4H, which SYS0/SYS issues at 4A6BH.
4E0E
If the Z FLAG is set (request code B4H), jump to 4F50H to give the file of Index Register IX another directory entry.
4E11
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 SYS2/SYS has a job.

4E12H - Open a File

Reached for request code 94H (4424H) with Register Pair DE the FCB, which holds the file specification as text, Register Pair HL the buffer and Register B the record length (00H for 256). @LOAD calls 4424H with Register B 00H and Register Pair HL 4200H (SYS0/SYS 4C16H). The specification is parsed, the name looked up in the hash index table of the drive named or of drives 0-3 in turn, and the FCB filled in from the directory entry. Returns Register A 00H and the Z FLAG, or the NZ FLAG and an error code: 13H a bad name, 20H a bad drive, 11H or 16H a read error, 18H no drive has the file.

4E12
Call 4896H, the common start of SYS0/SYS's file routines past its test that the FCB at Register Pair DE is open: Index Register IX becomes the FCB, and the file routine returns through 48B3H.
4E15
LD A,B 78
Load Register A with Register B, the record length the caller gave (00H for 256). 4EDBH calls here as well.
4E16
LD (4FAFH),A 32 AF 4F
Store Register A, the record length, at 4FAFH, the operand of LD A,nn at 4FAEH, for FCB+01H and FCB+09H (4FA7H) and for a new entry (4F28H).
4E19
LD (4FC0H),HL 22 C0 4F
Store Register Pair HL, the buffer the caller gave, at 4FC0H, the operand of LD DE,nnnn at 4FBFH, for FCB+03H-+04H.
4E1C
PUSH IX DD E5
Save Index Register IX, the FCB, on the stack.
4E1E
POP HL E1
Restore it into Register Pair HL: Register Pair HL is the FCB, which holds the file specification as text.
4E1F
Call 5194H to make small letters capitals in the 32 bytes at Register Pair HL and parse the specification into the name at 515DH, the extension at 5165H, the password at 5155H and the drive at 5154H.
4E22
RET NZ C0
If the NZ FLAG is set (error 13H for a bad name or 20H for a bad drive), return with the error code in Register A.
4E23
LD HL,515DH 21 5D 51
Load Register Pair HL with 515DH, the name and extension, eleven characters padded with spaces.
4E26
Call 509BH to work out the hash code in Register A of the eleven characters at Register Pair HL (515DH): never 00H, the mark of a free place.
4E29
LD (4E4EH),A 32 4E 4E
Store Register A, the hash code, at 4E4EH, the operand of CP nn at 4E4DH, the compare of the search below.
4E2C
LD DE,5155H 11 55 51
Load Register Pair DE with 5155H, the password, eight characters padded with spaces.
4E2F
Call 50D1H to work out the password hash in Register Pair HL of the eight characters at Register Pair DE (5155H).
4E32
LD (5168H),HL 22 68 51
Store Register Pair HL, the password hash, at 5168H, the update password of a new entry (4F35H).
4E35
LD (516AH),HL 22 6A 51
Store Register Pair HL, the password hash, at 516AH as well, the access password of a new entry and the hash compared at 4EA0H.
4E38
LD A,(5154H) 3A 54 51
Load Register A with the drive of the specification from 5154H: FFH when none was named.
4E3B
LD C,A 4F
Copy Register A, the drive, into Register C, the drive number used by SYS0/SYS's routines.
4E3C
INC A 3C
Increment Register A: the Z FLAG is set when the drive byte was FFH.
4E3D
If the NZ FLAG is set (a drive was named), jump to 4E40H to search that drive alone.
4E3F
LD C,A 4F
Copy Register A (00H) into Register C: with no drive named the search starts at drive 0.
4E40
Call 50FDH to select drive Register C and wait for its index pulses: the NZ FLAG is set when the drive gives none (no diskette or no drive).
4E43
If the NZ FLAG is set (the drive is not ready), jump to 4E54H to go on to the next drive.
4E45
Call 512EH to read the hash index table of drive Register C into 4D00H: Register Pair HL is 4D00H.
4E48
RET NZ C0
If the NZ FLAG is set (error 16H, the table could not be read), return with the error code in Register A.
4E49
LD A,(HL) 7E
Load Register A with the byte of the hash index table at Register Pair HL: the hash code of the entry whose record is Register L, or 00H.
4E4A
OR A B7
Set the flags from Register A: the Z FLAG is set for 00H, a free place.
4E4B
If the Z FLAG is set (a free place), jump to 4E51H to go on to the next byte.
4E4D
CP 00H FE 00
Compare Register A with the hash code of the name: the operand at 4E4EH is stored by 4E29H (00H in the file).
4E4F
If the Z FLAG is set (the hash codes agree), jump to 4E6AH to read the entry and compare its name.
4E51
INC L 2C
Increment Register L to the next byte of the hash index table; 4E68H comes back here after an entry that is not the file.
4E52
If the NZ FLAG is set (Register L has not come round to 00H), jump back to 4E49H to test the next of the 256 bytes.
4E54
LD A,(5154H) 3A 54 51
Load Register A with the drive of the specification from 5154H: the name is not on drive Register C.
4E57
INC A 3C
Increment Register A: the Z FLAG is set when no drive was named (FFH).
4E58
If the NZ FLAG is set (a drive was named), jump to 4E60H to return error 18H.
4E5A
INC C 0C
Increment Register C, the drive number, to the next drive of the search.
4E5B
LD A,C 79
Copy the drive number from Register C into Register A.
4E5C
CP 04H FE 04
Compare Register A with 04H: DoubleDOS has drives 0-3.
4E5E
If the C FLAG is set (drive 3 or below), jump back to 4E40H to search drive Register C.
4E60
LD A,18H 3E 18
Load Register A with 18H, the error code for a file that is not in the directory of any drive searched.
4E62
OR A B7
Set the flags from Register A (18H): the NZ FLAG is set.
4E63
RET C9
Return with error 18H in Register A and the NZ FLAG set.
4E64
POP BC C1
Restore Register Pair BC, the record and the drive, saved at 4E76H: the entry is not the file.
4E65
POP HL E1
Restore Register Pair HL, the address of the entry, saved at 4E75H.
4E66
POP BC C1
Restore Register Pair BC, the drive in Register C, saved at 4E6BH.
4E67
POP HL E1
Restore Register Pair HL, the place in the hash index table, saved at 4E6AH.
4E68
Jump to 4E51H to go on with the next byte of the hash index table.

4E6AH - Compare the Entry With the Name

Reached from 4E4FH when the hash code of the place Register L in the hash index table agrees. The record number of a directory entry is the place in the table: bits 7-5 the entry in its sector, bits 4-0 the sector after the hash index table. The entry is read; a file's extra entry (attribute bit 7) is passed over, and the eleven characters at +05H-+0FH are compared with the name.

4E6A
PUSH HL E5
Save Register Pair HL, the place in the hash index table, on the stack.
4E6B
PUSH BC C5
Save Register Pair BC, the drive in Register C, on the stack.
4E6C
LD B,L 45
Copy Register L, the place in the hash index table, into Register B: the record number of the entry.
4E6D
Call 4AC1H to read the directory sector of record Register B of drive Register C into 4200H: Register Pair HL returns the address of the entry.
4E70
If the Z FLAG is set (the sector was read), jump to 4E75H to look at the entry.
4E72
POP BC C1
Restore Register Pair BC, the drive, from the stack.
4E73
POP HL E1
Restore Register Pair HL, the place in the hash index table, from the stack.
4E74
RET C9
Return with error 11H in Register A, the directory read error of 4AC1H, and the NZ FLAG set.
4E75
PUSH HL E5
Save Register Pair HL, the address of the entry in 4200H, on the stack.
4E76
PUSH BC C5
Save Register Pair BC, the record in Register B and the drive in Register C, on the stack.
4E77
BIT 7,(HL) CB 7E
Test bit 7 of the attribute byte at Register Pair HL, entry +00H: it is set in an extra entry of a file (90H, 4F73H).
4E79
If the NZ FLAG is set (an extra entry), jump to 4E64H: it holds no name of its own.
4E7B
LD A,05H 3E 05
Load Register A with 05H, the offset of the name in a directory entry.
4E7D
ADD A,L 85
Add Register L, the low byte of the entry's address, to Register A.
4E7E
LD L,A 6F
Copy Register A into Register L: Register Pair HL is the name at entry +05H.
4E7F
LD DE,515DH 11 5D 51
Load Register Pair DE with 515DH, the name and extension of the specification.
4E82
LD B,0BH 06 0B
Load Register B with 0BH, the eleven characters of the name and the extension.
4E84
LD A,(DE) 1A
Load Register A with the character of the specification at Register Pair DE.
4E85
CP (HL) BE
Compare Register A with the character of the entry at Register Pair HL.
4E86
If the NZ FLAG is set (a character differs), jump to 4E64H: this entry is not the file.
4E88
INC HL 23
Increment Register Pair HL to the next character of the entry.
4E89
INC DE 13
Increment Register Pair DE to the next character of the specification.
4E8A
Decrement Register B and jump back to 4E84H while it is not 00H.
4E8C
POP BC C1
Restore Register Pair BC: Register B the record of the entry, Register C the drive.
4E8D
LD A,C 79
Copy the drive from Register C into Register A.
4E8E
LD (5154H),A 32 54 51
Store Register A, the drive where the file was found, at 5154H.
4E91
POP HL E1
Restore Register Pair HL, the address of the entry, from the stack.
4E92
POP AF F1
Take the word saved at 4E6BH off the stack into Register Pair AF: it is not needed.
4E93
POP AF F1
Take the word saved at 4E6AH off the stack into Register Pair AF: it is not needed either.
4E94
PUSH BC C5
Save Register Pair BC, the record and the drive, on the stack for the FCB.
4E95
PUSH HL E5
Save Register Pair HL, the address of the entry, on the stack.
4E96
LD A,(HL) 7E
Load Register A with the attribute byte at Register Pair HL, entry +00H.
4E97
AND 07H E6 07
AND Register A with 07H to keep bits 2-0, the protection level of the file.
4E99
LD C,A 4F
Copy the protection level from Register A into Register C, for the password test that is passed over at 4EACH.
4E9A
LD B,00H 06 00
Load Register B with 00H, the access level given to the FCB: 00H allows everything.
4E9C
LD A,10H 3E 10
Load Register A with 10H, the offset of the update password hash in a directory entry.
4E9E
ADD A,L 85
Add Register L, the low byte of the entry's address, to Register A.
4E9F
LD L,A 6F
Copy Register A into Register L: Register Pair HL is the update password hash at entry +10H.
4EA0
LD DE,(516AH) ED 5B 6A 51
Load Register Pair DE with the password hash of the specification from 516AH, stored at 4E35H.
4EA4
PUSH HL E5
Save Register Pair HL, the address of entry +10H, on the stack.
4EA5
LD HL,61A2H 21 A2 61
Load Register Pair HL with 61A2H, a hash that the subtraction below compares with the password's.
4EA8
XOR A AF
Clear Register A to 00H and the C FLAG for the subtraction.
4EA9
SBC HL,DE ED 52
Subtract Register Pair DE, the password hash, from Register Pair HL (61A2H): the result is not tested, since the jump at 4EACH always goes.
4EAB
POP HL E1
Restore Register Pair HL, the address of entry +10H, from the stack.
4EAC
Jump to 4ECFH: the password tests at 4EAEH-4ECEH are passed over, and every file is opened with Register B 00H, the access level that allows everything.

4EAEH - The Password Tests, Never Run

The jump at 4EACH passes over these 33 bytes and nothing else reaches them. They would refuse a file of protection level 7, give the access level 00H for the update password (entry +10H-+11H) and the file's protection level for the access password (entry +12H-+13H), and return error 19H for any other password.

4EAE
LD A,C 79
Load Register A with Register C, the protection level of the file (never run: the jump at 4EACH passes over it).
4EAF
CP 07H FE 07
Compare Register A, the protection level, with 07H, the level that allows nothing (never run).
4EB1
If the Z FLAG is set (level 7), jump to 4EC9H to return error 19H (never run).
4EB3
LD A,(HL) 7E
Load Register A with the low byte of the update password hash at Register Pair HL, entry +10H (never run).
4EB4
INC HL 23
Increment Register Pair HL to the high byte of the update password hash, entry +11H (never run).
4EB5
PUSH HL E5
Save Register Pair HL, the address of entry +11H, on the stack (never run).
4EB6
LD H,(HL) 66
Load Register H with the high byte of the update password hash at Register Pair HL (never run).
4EB7
LD L,A 6F
Copy Register A, the low byte, into Register L: Register Pair HL is the update password hash (never run).
4EB8
XOR A AF
Clear Register A to 00H and the C FLAG for the subtraction (never run).
4EB9
SBC HL,DE ED 52
Subtract Register Pair DE, the password hash of the specification, from Register Pair HL, the update password hash (never run).
4EBB
POP HL E1
Restore Register Pair HL, the address of entry +11H, from the stack (never run).
4EBC
If the Z FLAG is set (the update password), jump to 4ECFH with Register B 00H, every access (never run).
4EBE
INC HL 23
Increment Register Pair HL to the access password hash at entry +12H (never run).
4EBF
LD B,C 41
Copy Register C, the protection level of the file, into Register B, the access level (never run).
4EC0
LD A,(HL) 7E
Load Register A with the low byte of the access password hash at Register Pair HL (never run).
4EC1
INC HL 23
Increment Register Pair HL to the high byte of the access password hash, entry +13H (never run).
4EC2
LD H,(HL) 66
Load Register H with the high byte of the access password hash at Register Pair HL (never run).
4EC3
LD L,A 6F
Copy Register A, the low byte, into Register L: Register Pair HL is the access password hash (never run).
4EC4
XOR A AF
Clear Register A to 00H and the C FLAG for the subtraction (never run).
4EC5
SBC HL,DE ED 52
Subtract Register Pair DE, the password hash of the specification, from Register Pair HL, the access password hash (never run).
4EC7
If the Z FLAG is set (the access password), jump to 4ECFH with Register B the protection level (never run).
4EC9
POP HL E1
Restore Register Pair HL, the address of the entry, from the stack (never run: 4EB1H and 4EC7H are never reached).
4ECA
POP BC C1
Restore Register Pair BC, the record and the drive, from the stack (never run).
4ECB
LD A,19H 3E 19
Load Register A with 19H, the error code for a password that does not open the file (never run).
4ECD
OR A B7
Set the flags from Register A (19H): the NZ FLAG is set (never run).
4ECE
RET C9
Return with error 19H in Register A and the NZ FLAG set (never run).
4ECF
POP HL E1
Restore Register Pair HL, the address of the entry, from the stack: the jump at 4EACH comes here.
4ED0
LD A,B 78
Copy Register B, the access level (00H), into Register A.
4ED1
LD (4FB2H),A 32 B2 4F
Store Register A, the access level, at 4FB2H, the operand of LD A,nn at 4FB1H, for FCB+01H.
4ED4
POP BC C1
Restore Register Pair BC: Register B the record of the entry, Register C the drive.
4ED5
Jump to 4FA7H to fill in the FCB of Index Register IX from the entry at Register Pair HL; it returns Register A 00H and the Z FLAG to the caller.

4ED8H - Open a File or Make It

Reached for request code A4H (4420H) with the same registers as 4E12H. The file is opened when a drive has it. When none has it, a new entry is made on the drive named, or on the first of drives 0-3 that is ready, not write protected and has a free place in its hash index table: the hash index table, the directory entry and the FCB are written, and the C FLAG is returned set to tell a new file. Returns Register A 00H and the Z FLAG, or the NZ FLAG and an error code: those of 4E12H, 12H or 17H a write error, 1AH no drive has room (returned with the Z FLAG when no drive was named, 4F0DH).

4ED8
Call 4896H, the common start of SYS0/SYS's file routines past its test that the FCB at Register Pair DE is open: Index Register IX becomes the FCB.
4EDB
Call 4E15H, the open of request code 94H after its own call of 4896H, with Register B the record length and Register Pair HL the buffer.
4EDE
RET Z C8
Return if the Z FLAG is set (the file was found and the FCB filled in), with Register A 00H and the C FLAG clear.
4EDF
CP 18H FE 18
Compare Register A, the error code, with 18H, the code for a file that no drive searched has.
4EE1
RET NZ C0
Return if the NZ FLAG is set (another error), with the error code in Register A.
4EE2
LD A,10H 3E 10
Load Register A with 10H, the attribute byte of a new file: bit 4 set, protection level 0.
4EE4
LD (4F1DH),A 32 1D 4F
Store Register A (10H) at 4F1DH, the operand of LD (HL),nn at 4F1CH that writes entry +00H.
4EE7
LD A,(5154H) 3A 54 51
Load Register A with the drive of the specification from 5154H: FFH when none was named.
4EEA
LD C,A 4F
Copy Register A, the drive, into Register C, the drive number used by SYS0/SYS's routines.
4EEB
INC A 3C
Increment Register A: the Z FLAG is set when the drive byte was FFH.
4EEC
If the NZ FLAG is set (a drive was named), jump to 4EEFH to make the file on that drive alone.
4EEE
LD C,A 4F
Copy Register A (00H) into Register C: with no drive named drive 0 is tried first.
4EEF
Call 50FDH to select drive Register C and wait for its index pulses: the NZ FLAG when the drive is not ready, the C FLAG when the diskette is write protected.
4EF2
If the NZ FLAG is set (the drive is not ready), jump to 4EFFH to try the next drive.
4EF4
If the C FLAG is set (the diskette is write protected), jump to 4EFFH to try the next drive.
4EF6
Call 512EH to read the hash index table of drive Register C into 4D00H.
4EF9
RET NZ C0
If the NZ FLAG is set (error 16H, the table could not be read), return with the error code in Register A.
4EFA
Call 50ABH to find a free place in the hash index table, starting at a place taken from the tick count at 4040H: Register L returns the place.
4EFD
If the Z FLAG is set (a free place), jump to 4F0EH to make the entry.
4EFF
LD A,(5154H) 3A 54 51
Load Register A with the drive of the specification from 5154H: drive Register C has no room.
4F02
INC A 3C
Increment Register A: the Z FLAG is set when no drive was named (FFH).
4F03
If the NZ FLAG is set (a drive was named), jump to 4F0BH to return error 1AH.
4F05
INC C 0C
Increment Register C to the next drive, of 0-3, that may hold the new file.
4F06
LD A,C 79
Copy the drive number from Register C into Register A.
4F07
CP 04H FE 04
Compare Register A with 04H: DoubleDOS has drives 0-3.
4F09
If the C FLAG is set (drive 3 or below), jump back to 4EEFH to try drive Register C.
4F0B
LD A,1AH 3E 1A
Load Register A with 1AH, the error code for no room in the directory of any drive tried.
4F0D
RET C9
Return with error 1AH in Register A and the flags of the last test: NZ after 4F03H when a drive was named, but the Z FLAG of the compare at 4F07H (Register A was 04H) when drives 0-3 were tried, so the caller sees no error.
4F0E
LD B,L 45
Copy Register L, the free place, into Register B: the record number of the new entry.
4F0F
LD A,(4E4EH) 3A 4E 4E
Load Register A with the hash code of the name from 4E4EH, stored by 4E29H.
4F12
LD (HL),A 77
Store Register A, the hash code, at Register Pair HL, the free place in the hash index table at 4D00H.
4F13
Call 5141H to write the hash index table at 4D00H back to drive Register C.
4F16
RET NZ C0
If the NZ FLAG is set (error 17H, the table could not be written), return with the error code in Register A.
4F17
Call 4AC1H to read the directory sector of record Register B into 4200H: Register Pair HL returns the address of the entry.
4F1A
RET NZ C0
If the NZ FLAG is set (error 11H), return with the error code in Register A.
4F1B
PUSH HL E5
Save Register Pair HL, the address of the new entry, on the stack.
4F1C
LD (HL),00H 36 00
Store the attribute byte at Register Pair HL, entry +00H: the operand at 4F1DH is stored by 4EE4H (10H; 00H in the file).
4F1E
INC HL 23
Increment Register Pair HL to entry +01H, the first of three bytes cleared.
4F1F
LD (HL),00H 36 00
Store 00H at Register Pair HL, entry +01H of the new directory entry.
4F21
INC HL 23
Increment Register Pair HL to entry +02H of the new directory entry.
4F22
LD (HL),00H 36 00
Store 00H at Register Pair HL, entry +02H of the new directory entry.
4F24
INC HL 23
Increment Register Pair HL to entry +03H, the end of file offset.
4F25
LD (HL),00H 36 00
Store 00H at Register Pair HL, entry +03H: the file ends at the start of a sector.
4F27
INC HL 23
Increment Register Pair HL to entry +04H, the record length.
4F28
LD A,(4FAFH) 3A AF 4F
Load Register A with the record length from 4FAFH, stored by 4E16H.
4F2B
LD (HL),A 77
Store Register A, the record length, at Register Pair HL, entry +04H.
4F2C
INC HL 23
Increment Register Pair HL to entry +05H, the name.
4F2D
PUSH BC C5
Save Register Pair BC, the record and the drive, on the stack.
4F2E
LD BC,000FH 01 0F 00
Load Register Pair BC with 000FH, the fifteen bytes of entry +05H-+13H.
4F31
EX DE,HL EB
Exchange Register Pairs DE and HL: Register Pair DE is entry +05H.
4F32
LD HL,515DH 21 5D 51
Load Register Pair HL with 515DH: the name (515DH), the extension (5165H) and the two password hashes (5168H, 516AH).
4F35
LDIR ED B0
Copy Register Pair BC (15) bytes from Register Pair HL (515DH) to Register Pair DE: entry +05H-+13H, the update and the access password both the password's hash.
4F37
EX DE,HL EB
Exchange Register Pairs DE and HL: Register Pair HL is entry +14H.
4F38
LD (HL),00H 36 00
Store 00H at Register Pair HL, entry +14H, the low byte of the number of sectors.
4F3A
INC HL 23
Increment Register Pair HL to entry +15H, the high byte of the number of sectors.
4F3B
LD (HL),00H 36 00
Store 00H at Register Pair HL, entry +15H, the high byte of the number of sectors: the file is empty.
4F3D
INC HL 23
Increment Register Pair HL to entry +16H, the first extent.
4F3E
LD B,0AH 06 0A
Load Register B with 0AH, the ten bytes of the five extents at entry +16H-+1FH.
4F40
LD (HL),FFH 36 FF
Store FFH at Register Pair HL: the extents of the new entry are all unused.
4F42
INC HL 23
Increment Register Pair HL to the next byte of the extents.
4F43
Decrement Register B and jump back to 4F40H while it is not 00H.
4F45
POP BC C1
Restore Register Pair BC, the record in Register B and the drive in Register C.
4F46
Call 4AD6H to write the directory sector at 4200H back as the sector of record Register B of drive Register C.
4F49
POP HL E1
Restore Register Pair HL, the address of the new entry, from the stack.
4F4A
RET NZ C0
If the NZ FLAG is set (error 12H, the sector could not be written), return with the error code in Register A.
4F4B
Call 4FA7H to fill in the FCB of Index Register IX from the entry at Register Pair HL: Register A returns 00H with the Z FLAG.
4F4E
SCF 37
Set the C FLAG to tell the caller of 4420H that the file is new.
4F4F
RET C9
Return with Register A 00H, the Z FLAG and the C FLAG: the file was made and opened.

4F50H - Give a File Another Directory Entry

Reached for request code B4H from SYS0/SYS (4A6BH) with Index Register IX the FCB, when the directory entry being extended has no free extent place but its last, +1EH-+1FH. A free place in the hash index table gets the hash code of the file's first entry, the new entry is written as an extra entry (attribute 90H, +01H the record of the entry before it, no extents), and the last extent place of the entry before it gets FEH and the new record. Returns Register A 00H and the Z FLAG, or the NZ FLAG and an error code: 16H, 17H, 11H or 12H a read or write error, 1EH no free place.

4F50
LD C,(IX+06H) DD 4E 06
Load Register C with the drive of the file from FCB+06H through Index Register IX.
4F53
Call 512EH to read the hash index table of drive Register C into 4D00H.
4F56
RET NZ C0
If the NZ FLAG is set (error 16H, the table could not be read), return with the error code in Register A.
4F57
LD A,(IX+07H) DD 7E 07
Load Register A with the record of the file's first directory entry from FCB+07H through Index Register IX.
4F5A
Call 50B6H to find a free place in the hash index table, starting after the place Register A: Register L returns the place.
4F5D
LD A,1EH 3E 1E
Load Register A with 1EH, the error code for no free place; the LD leaves the flags of 50B6H.
4F5F
RET NZ C0
If the NZ FLAG is set (no free place), return with error 1EH in Register A.
4F60
LD B,L 45
Copy Register L, the free place, into Register B: the record number of the new entry.
4F61
LD A,L 7D
Copy Register L, the free place, into Register A.
4F62
LD (4FA2H),A 32 A2 4F
Store Register A, the new record, at 4FA2H, the operand of LD (HL),nn at 4FA1H that links the entry before it to this one.
4F65
LD D,H 54
Copy Register H (4DH) into Register D, the page of the hash index table.
4F66
LD E,(IX+07H) DD 5E 07
Load Register E with the record of the file's first entry from FCB+07H through Index Register IX: Register Pair DE is its place in the hash index table.
4F69
LD A,(DE) 1A
Load Register A with the hash code of the file's first entry at Register Pair DE.
4F6A
LD (HL),A 77
Store Register A, the hash code, at Register Pair HL, the new entry's place in the hash index table.
4F6B
Call 5141H to write the hash index table at 4D00H back to drive Register C.
4F6E
RET NZ C0
If the NZ FLAG is set (error 17H, the table could not be written), return with the error code in Register A.
4F6F
Call 4AC1H to read the directory sector of record Register B into 4200H: Register Pair HL returns the address of the new entry.
4F72
RET NZ C0
If the NZ FLAG is set (error 11H), return with the error code in Register A.
4F73
LD (HL),90H 36 90
Store 90H, the attribute of an extra entry (bit 7 set), at Register Pair HL, entry +00H.
4F75
INC L 2C
Increment Register L to entry +01H, the link back to the entry before it.
4F76
PUSH BC C5
Save Register Pair BC, the new record in Register B and the drive in Register C, on the stack.
4F77
LD A,(4ABEH) 3A BE 4A
Load Register A with the record of the entry being extended from 4ABEH, the operand stored by SYS0/SYS at 49BDH.
4F7A
LD (HL),A 77
Store Register A, the record of the entry before this one, at Register Pair HL, entry +01H.
4F7B
INC L 2C
Increment Register L to entry +02H, the first of the bytes cleared.
4F7C
LD B,14H 06 14
Load Register B with 14H, the twenty bytes of entry +02H-+15H.
4F7E
LD (HL),00H 36 00
Store 00H at Register Pair HL, one of the bytes +02H-+15H of the new entry.
4F80
INC L 2C
Increment Register L to the next byte of the entry.
4F81
Decrement Register B and jump back to 4F7EH while it is not 00H.
4F83
PUSH HL E5
Save Register Pair HL, the address of entry +16H, the extents, on the stack.
4F84
LD B,0AH 06 0A
Load Register B with 0AH, the ten bytes of the five extents at entry +16H-+1FH.
4F86
LD (HL),FFH 36 FF
Store FFH at Register Pair HL: the extents of the extra entry are all unused.
4F88
INC L 2C
Increment Register L to the next byte of the extents.
4F89
Decrement Register B and jump back to 4F86H while it is not 00H.
4F8B
POP DE D1
Restore Register Pair DE with the address of entry +16H: nothing after this uses it, since SYS0/SYS loads Register Pair DE again at 49B6H.
4F8C
INC DE 13
Increment Register Pair DE to entry +17H, which nothing then reads.
4F8D
POP BC C1
Restore Register Pair BC, the new record in Register B and the drive in Register C.
4F8E
Call 4AD6H to write the directory sector at 4200H back as the sector of record Register B of drive Register C.
4F91
RET NZ C0
If the NZ FLAG is set (error 12H), return with the error code in Register A.
4F92
LD A,(4ABEH) 3A BE 4A
Load Register A with the record of the entry being extended from 4ABEH.
4F95
LD B,A 47
Copy the record from Register A into Register B.
4F96
Call 4AC1H to read the directory sector of record Register B into 4200H: Register Pair HL returns the address of the entry.
4F99
RET NZ C0
If the NZ FLAG is set (error 11H), return with the error code in Register A.
4F9A
LD A,L 7D
Copy Register L, the low byte of the entry's address, into Register A.
4F9B
ADD A,1EH C6 1E
Add 1EH to Register A, the offset of the last extent place.
4F9D
LD L,A 6F
Copy Register A into Register L: Register Pair HL is entry +1EH, still FFH.
4F9E
LD (HL),FEH 36 FE
Store FEH at Register Pair HL, entry +1EH: the extents go on in another entry.
4FA0
INC L 2C
Increment Register L to entry +1FH, the byte after the FEH.
4FA1
LD (HL),00H 36 00
Store the record of the new entry at Register Pair HL, entry +1FH: the operand at 4FA2H is stored by 4F62H (00H in the file).
4FA3
Call 4AD6H to write the directory sector at 4200H back as the sector of record Register B of drive Register C.
4FA6
RET C9
Return to SYS0/SYS (4A66H) with Register A 00H and the Z FLAG, or error 12H.

4FA7H - Fill In the FCB

Reached from 4ED5H and 4F4BH with Register Pair HL the directory entry in 4200H, Register B its record and Register C the drive. The 32 bytes of the FCB at Index Register IX are written over the specification text: the open flag, the access level and flags, the buffer, the drive and record, the end of file, the record length and the first five extents of the entry. Returns Register A 00H and the Z FLAG.

4FA7
EX DE,HL EB
Exchange Register Pairs DE and HL: Register Pair DE is the directory entry.
4FA8
PUSH IX DD E5
Save Index Register IX, the FCB, on the stack.
4FAA
POP HL E1
Restore it into Register Pair HL: Register Pair HL is FCB+00H.
4FAB
LD (HL),80H 36 80
Store 80H at Register Pair HL, FCB+00H: bit 7 set, the FCB is open.
4FAD
INC HL 23
Increment Register Pair HL to FCB+01H, the access level and flags.
4FAE
LD A,00H 3E 00
Load Register A with the record length: the operand at 4FAFH is stored by 4E16H (00H in the file).
4FB0
OR A B7
Set the flags from Register A: the Z FLAG is set for 00H, records of 256 bytes.
4FB1
LD A,00H 3E 00
Load Register A with the access level: the operand at 4FB2H is stored by 4ED1H (00H in the file). The LD leaves the flags.
4FB3
If the Z FLAG is set (records of 256 bytes), jump to 4FB7H.
4FB5
OR 80H F6 80
OR Register A with 80H: bit 7 set, the file is read and written a record at a time through the buffer.
4FB7
OR 20H F6 20
OR Register A with 20H: bit 5 set, the buffer must be read before it is used.
4FB9
LD (HL),A 77
Store Register A, the access level and flags, at Register Pair HL, FCB+01H.
4FBA
INC HL 23
Increment Register Pair HL to FCB+02H, the byte after the access level.
4FBB
LD (HL),00H 36 00
Store 00H at Register Pair HL, FCB+02H, a byte of the FCB that SYS2/SYS clears.
4FBD
INC HL 23
Increment Register Pair HL to FCB+03H, the buffer address.
4FBE
PUSH DE D5
Save Register Pair DE, the directory entry, on the stack.
4FBF
LD DE,0000H 11 00 00
Load Register Pair DE with the buffer: the operand at 4FC0H-4FC1H is stored by 4E19H (0000H in the file).
4FC2
LD (HL),E 73
Store Register E, the low byte of the buffer, at Register Pair HL, FCB+03H.
4FC3
INC HL 23
Increment Register Pair HL to FCB+04H, the high byte of the buffer.
4FC4
LD (HL),D 72
Store Register D, the high byte of the buffer, at Register Pair HL, FCB+04H.
4FC5
INC HL 23
Increment Register Pair HL to FCB+05H, the byte offset in the buffer.
4FC6
POP DE D1
Restore Register Pair DE, the directory entry, from the stack.
4FC7
LD (HL),00H 36 00
Store 00H at Register Pair HL, FCB+05H: the offset is at the start of the buffer.
4FC9
INC HL 23
Increment Register Pair HL to FCB+06H, the drive.
4FCA
LD (HL),C 71
Store Register C, the drive, at Register Pair HL, FCB+06H.
4FCB
INC HL 23
Increment Register Pair HL to FCB+07H, the directory record.
4FCC
LD (HL),B 70
Store Register B, the record of the directory entry, at Register Pair HL, FCB+07H.
4FCD
INC HL 23
Increment Register Pair HL to FCB+08H, the end of file offset.
4FCE
LD A,03H 3E 03
Load Register A with 03H, the offset of the end of file byte in a directory entry.
4FD0
ADD A,E 83
Add Register E, the low byte of the entry's address, to Register A.
4FD1
LD E,A 5F
Copy Register A into Register E: Register Pair DE is entry +03H.
4FD2
LD A,(DE) 1A
Load Register A with the end of file offset at Register Pair DE, entry +03H.
4FD3
LD (HL),A 77
Store Register A, the end of file offset, at Register Pair HL, FCB+08H.
4FD4
INC HL 23
Increment Register Pair HL to FCB+09H, the record length.
4FD5
INC DE 13
Increment Register Pair DE to entry +04H, the record length of the entry, which is not used.
4FD6
LD A,(4FAFH) 3A AF 4F
Load Register A with the record length the caller gave from 4FAFH, stored by 4E16H.
4FD9
LD (HL),A 77
Store Register A, the record length, at Register Pair HL, FCB+09H.
4FDA
INC HL 23
Increment Register Pair HL to FCB+0AH, the sector.
4FDB
LD (HL),00H 36 00
Store 00H at Register Pair HL, FCB+0AH, the low byte of the sector.
4FDD
INC HL 23
Increment Register Pair HL to FCB+0BH, the high byte of the sector.
4FDE
LD (HL),00H 36 00
Store 00H at Register Pair HL, FCB+0BH: the file starts at its sector 0.
4FE0
INC HL 23
Increment Register Pair HL to FCB+0CH, the end of file sector.
4FE1
LD A,10H 3E 10
Load Register A with 10H, the distance from entry +04H to entry +14H, the number of sectors.
4FE3
ADD A,E 83
Add Register E, the low byte of the entry's address, to Register A.
4FE4
LD E,A 5F
Copy Register A into Register E: Register Pair DE is entry +14H.
4FE5
LD A,(DE) 1A
Load Register A with the low byte of the number of sectors at Register Pair DE, entry +14H.
4FE6
LD (HL),A 77
Store Register A at Register Pair HL, FCB+0CH, the low byte of the end of file sector.
4FE7
INC HL 23
Increment Register Pair HL to FCB+0DH, the high byte of the end of file sector.
4FE8
Call 5180H to copy entry +15H, the high byte, to FCB+0DH and count one sector less when the last sector is partly filled.
4FEB
INC HL 23
Increment Register Pair HL to FCB+0EH, the block of the first extent.
4FEC
INC DE 13
Increment Register Pair DE to entry +16H, the block of the entry's first extent.
4FED
LD A,(DE) 1A
Load Register A with the block of the first extent at Register Pair DE.
4FEE
LD (HL),A 77
Store Register A, the block, at Register Pair HL, FCB+0EH.
4FEF
INC HL 23
Increment Register Pair HL to FCB+0FH, the granule byte of the first extent.
4FF0
INC DE 13
Increment Register Pair DE to entry +17H, the granule byte of the first extent.
4FF1
LD A,(DE) 1A
Load Register A with the granule byte of the first extent at Register Pair DE.
4FF2
LD (HL),A 77
Store Register A, the granule byte, at Register Pair HL, FCB+0FH.
4FF3
INC HL 23
Increment Register Pair HL to FCB+10H, the second extent of the FCB.
4FF4
AND 1FH E6 1F
AND Register A with 1FH to keep bits 4-0 of the granule byte, the count of granules less 1.
4FF6
INC A 3C
Increment Register A: the granules of the first extent.
4FF7
LD C,A 4F
Copy Register A into Register C: Register Pair BC counts the granules before the next extent.
4FF8
LD B,00H 06 00
Load Register B with 00H, the high byte of the count of granules.
4FFA
LD A,04H 3E 04
Load Register A with 04H, the four more extents that the FCB holds.
4FFC
PUSH AF F5
Save Register Pair AF, the extents still to copy in Register A, on the stack.
4FFD
INC DE 13
Increment Register Pair DE to the block of the entry's next extent.
4FFE
LD A,(DE) 1A
Load Register A with the block of the next extent at Register Pair DE.
4FFF
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).
5001
If the NC FLAG is set (no more extents in this entry), jump to 501CH to fill the rest of the FCB with FFH.
5003
LD (HL),C 71
Store Register C, the low byte of the granules before the extent, at Register Pair HL.
5004
INC HL 23
Increment Register Pair HL to the next byte of the FCB's extent.
5005
LD (HL),B 70
Store Register B, the high byte of the granules before the extent, at Register Pair HL.
5006
INC HL 23
Increment Register Pair HL to the byte for the block of the extent.
5007
LD A,(DE) 1A
Load Register A with the block of the extent at Register Pair DE.
5008
LD (HL),A 77
Store Register A, the block, at Register Pair HL.
5009
INC HL 23
Increment Register Pair HL to the byte for the granule byte of the extent.
500A
INC DE 13
Increment Register Pair DE to the granule byte of the entry's extent.
500B
LD A,(DE) 1A
Load Register A with the granule byte of the extent at Register Pair DE.
500C
LD (HL),A 77
Store Register A, the granule byte, at Register Pair HL.
500D
INC HL 23
Increment Register Pair HL to the next extent of the FCB.
500E
AND 1FH E6 1F
AND Register A with 1FH to keep bits 4-0 of the granule byte, the count of granules less 1.
5010
INC A 3C
Increment Register A: the granules of the extent.
5011
ADD A,C 81
Add Register C, the low byte of the granules counted, to Register A.
5012
LD C,A 4F
Copy Register A into Register C, the low byte of the granules before the next extent.
5013
LD A,B 78
Copy Register B, the high byte of the granules counted, into Register A.
5014
ADC A,00H CE 00
Add 00H and the carry to Register A: the high byte of the count.
5016
LD B,A 47
Copy Register A into Register B: Register Pair BC is the granules before the next extent.
5017
POP AF F1
Restore Register Pair AF: Register A the extents still to copy.
5018
DEC A 3D
Decrement Register A, the extents still to copy.
5019
If the NZ FLAG is set (more extents to copy), jump back to 4FFCH.
501B
RET C9
Return with Register A 00H and the Z FLAG: the FCB holds five extents of the entry.
501C
POP AF F1
Restore Register Pair AF: Register A the extents of the FCB left empty.
501D
RLCA 07
Rotate Register A left: twice the extents left.
501E
RLCA 07
Rotate Register A left again: four times the extents left, the bytes to fill.
501F
LD B,A 47
Copy Register A, the bytes to fill, into Register B.
5020
LD (HL),FFH 36 FF
Store FFH at Register Pair HL: the place of an extent the FCB does not have.
5022
INC HL 23
Increment Register Pair HL to the next byte of the FCB's extents.
5023
Decrement Register B and jump back to 5020H while it is not 00H.
5025
XOR A AF
Clear Register A to 00H and set the Z FLAG: the extents of the FCB are complete.
5026
RET C9
Return with Register A 00H and the Z FLAG: the FCB is filled in.

5027H - Parse the File Specification

Reached from 51A4H with Register Pair HL the specification in capitals. The name goes to 515DH (eight characters, the first a letter), the extension after a slash to 5165H (three), the password after a period to 5155H (eight) and the drive after a colon to 5154H (0-3; FFH when none is named), each padded with spaces. Returns Register A 00H and the Z FLAG, or the NZ FLAG with error 13H (no name) or 20H (a bad drive).

5027
LD B,0BH 06 0B
Load Register B with 0BH, the eleven characters of the name and the extension.
5029
LD DE,515DH 11 5D 51
Load Register Pair DE with 515DH, the name and the extension.
502C
LD A,20H 3E 20
Load Register A with 20H, a space, the padding of every part of the specification.
502E
LD (DE),A 12
Store Register A, a space, at Register Pair DE.
502F
INC DE 13
Increment Register Pair DE to the next character of the name or extension.
5030
Decrement Register B and jump back to 502EH while it is not 00H.
5032
LD B,08H 06 08
Load Register B with 08H, the eight characters of the password.
5034
LD DE,5155H 11 55 51
Load Register Pair DE with 5155H, the password.
5037
LD (DE),A 12
Store Register A, a space, at Register Pair DE.
5038
INC DE 13
Increment Register Pair DE to the next character of the password.
5039
Decrement Register B and jump back to 5037H while it is not 00H.
503B
LD A,FFH 3E FF
Load Register A with FFH, the mark of no drive named.
503D
LD (5154H),A 32 54 51
Store Register A (FFH) at 5154H, the drive of the specification.
5040
LD DE,515DH 11 5D 51
Load Register Pair DE with 515DH, where the name goes.
5043
LD B,08H 06 08
Load Register B with 08H, the most characters of a name.
5045
Call 5081H to copy the name from Register Pair HL to Register Pair DE: Register A returns the character after it and Register B the characters not used.
5048
LD C,A 4F
Copy Register A, the character after the name, into Register C.
5049
LD A,B 78
Copy Register B, the characters not used, into Register A.
504A
CP 08H FE 08
Compare Register A with 08H: the Z FLAG is set when no character was copied.
504C
If the NZ FLAG is set (the name has a character), jump to 5052H.
504E
LD A,13H 3E 13
Load Register A with 13H, the error code for a specification with no name.
5050
OR A B7
Set the flags from Register A (13H): the NZ FLAG is set.
5051
RET C9
Return with error 13H in Register A and the NZ FLAG set.
5052
LD A,C 79
Copy Register C, the character after the name, into Register A.
5053
CP 2FH FE 2F
Compare Register A with 2FH, a slash, the start of an extension.
5055
If the NZ FLAG is set (no slash), jump to 505FH.
5057
LD DE,5165H 11 65 51
Load Register Pair DE with 5165H, where the extension goes.
505A
LD B,03H 06 03
Load Register B with 03H, the most characters of an extension.
505C
Call 5081H to copy the extension from Register Pair HL to Register Pair DE: Register A returns the character after it.
505F
CP 2EH FE 2E
Compare Register A with 2EH, a period, the start of a password.
5061
If the NZ FLAG is set (no period), jump to 506BH.
5063
LD DE,5155H 11 55 51
Load Register Pair DE with 5155H, where the password goes.
5066
LD B,08H 06 08
Load Register B with 08H, the most characters of a password.
5068
Call 5081H to copy the password from Register Pair HL to Register Pair DE: Register A returns the character after it.
506B
CP 3AH FE 3A
Compare Register A with 3AH, a colon, the start of a drive number.
506D
If the NZ FLAG is set (no colon), jump to 507FH to return: anything else ends the specification.
506F
LD A,(HL) 7E
Load Register A with the character after the colon at Register Pair HL.
5070
SUB 30H D6 30
Subtract 30H, the digit 0, from Register A: the drive number.
5072
If the C FLAG is set (below the digit 0), jump to 5078H to return error 20H.
5074
CP 04H FE 04
Compare Register A, the drive number, with 04H.
5076
If the C FLAG is set (drive 0-3), jump to 507CH to keep it.
5078
LD A,20H 3E 20
Load Register A with 20H, the error code for a drive number that is not 0-3.
507A
OR A B7
Set the flags from Register A (20H): the NZ FLAG is set.
507B
RET C9
Return with error 20H in Register A and the NZ FLAG set.
507C
LD (5154H),A 32 54 51
Store Register A, the drive number, at 5154H.
507F
XOR A AF
Clear Register A to 00H and set the Z FLAG: the specification is parsed.
5080
RET C9
Return with Register A 00H and the Z FLAG set.

5081H - Copy a Part of the Specification

Called with Register Pair HL the text, Register Pair DE the place for the part and Register B the most characters. The first character must be a letter, the others letters or digits; up to Register B of them are copied. Returns Register A the character that ended the part (when Register B characters were copied, the character after them), Register Pair HL past it and Register B the characters not used.

5081
LD A,(HL) 7E
Load Register A with the first character of the part at Register Pair HL.
5082
INC HL 23
Increment Register Pair HL past the character.
5083
Jump to 508EH: the first character must be a letter.
5085
LD A,(HL) 7E
Load Register A with the next character of the part at Register Pair HL.
5086
INC HL 23
Increment Register Pair HL past the character.
5087
CP 30H FE 30
Compare Register A with 30H, the digit 0, the lowest character a part may hold after its first.
5089
RET C D8
Return if the C FLAG is set (below 0): the character ends the part.
508A
CP 3AH FE 3A
Compare Register A with 3AH, the character after the digit 9.
508C
If the C FLAG is set (a digit), jump to 5094H to copy it.
508E
CP 41H FE 41
Compare Register A with 41H, the letter A: 3AH-40H end the part as well.
5090
RET C D8
Return if the C FLAG is set (below A, not a letter): the character ends the part.
5091
CP 5BH FE 5B
Compare Register A with 5BH, the character after the letter Z.
5093
RET NC D0
Return if the NC FLAG is set (not a letter): the character ends the part.
5094
LD (DE),A 12
Store Register A, the letter or digit, at Register Pair DE.
5095
INC DE 13
Increment Register Pair DE to the next place of the part.
5096
Decrement Register B and jump back to 5085H while it is not 00H.
5098
LD A,(HL) 7E
Load Register A with the character after the last one copied at Register Pair HL.
5099
INC HL 23
Increment Register Pair HL past the character.
509A
RET C9
Return with Register A the character after the part and Register B 00H.

509BH - The Hash Code of a Name

Called from 4E26H with Register Pair HL the eleven characters of the name and the extension. Each character is combined with an exclusive OR and a turn to the left. The result is kept in the hash index table at the record's place; 00H, the mark of a free place, becomes 01H.

509B
LD B,0BH 06 0B
Load Register B with 0BH, the eleven characters of the name and the extension.
509D
LD C,00H 0E 00
Load Register C with 00H, the start of the hash code.
509F
LD A,(HL) 7E
Load Register A with the character at Register Pair HL.
50A0
INC HL 23
Increment Register Pair HL to the next character.
50A1
XOR C A9
Exclusive OR Register A with Register C, the hash code so far.
50A2
RLCA 07
Rotate Register A left, bit 7 going round to bit 0: the hash code so far.
50A3
LD C,A 4F
Copy Register A into Register C, the hash code so far.
50A4
Decrement Register B and jump back to 509FH while it is not 00H.
50A6
LD A,C 79
Copy Register C, the hash code, into Register A.
50A7
OR A B7
Set the flags from Register A: the Z FLAG is set for 00H.
50A8
RET NZ C0
Return if the NZ FLAG is set, with the hash code in Register A.
50A9
INC A 3C
Increment Register A: a hash code of 00H becomes 01H, since 00H marks a free place.
50AA
RET C9
Return with the hash code 01H in Register A and the NZ FLAG set by the INC.

50ABH - Find a Free Place in the Hash Index Table

Called from 4EFAH with the hash index table at 4D00H. The search starts at a place taken from the tick count at 4040H, always in entries 2-7 of a sector (entries 0 and 1 hold the system files). From the place Register L it looks at the later entries of the same sector, then at entries 2-7 of the sectors after it; when none is free it starts again at entry 2 of sector 0 (place 40H). Returns the Z FLAG and Register L the free place, or the NZ FLAG when the table has none. 50B6H is the entry with Register A the starting place (4F5AH).

50AB
LD A,(4040H) 3A 40 40
Load Register A with the tick count at 4040H, counted by SYS0/SYS's interrupt routine every 25 milliseconds.
50AE
AND E7H E6 E7
AND Register A with E7H to keep bits 7-5, the entry, and bits 2-0, the sector 0-7.
50B0
CP 40H FE 40
Compare Register A with 40H: the C FLAG is set for entries 0 and 1.
50B2
If the NC FLAG is set (entry 2-7), jump to 50B6H to start there.
50B4
OR 80H F6 80
OR Register A with 80H: entry 0 becomes entry 4 and entry 1 entry 5.
50B6
LD L,A 6F
Copy Register A, the starting place, into Register L: Register Pair HL is its byte in the table at 4D00H.
50B7
Call 50BDH to look from the place Register L: the Z FLAG is set when it finds a free place.
50BA
RET Z C8
Return if the Z FLAG is set, with the free place in Register L.
50BB
LD L,40H 2E 40
Load Register L with 40H, entry 2 of sector 0, to look through the whole table once more.
50BD
LD A,(HL) 7E
Load Register A with the byte of the hash index table at Register Pair HL.
50BE
OR A B7
Set the flags from Register A: the Z FLAG is set for 00H, a free place.
50BF
RET Z C8
Return if the Z FLAG is set, with the free place in Register L.
50C0
LD A,L 7D
Copy Register L, the place just tested and found in use, into Register A.
50C1
ADD A,20H C6 20
Add 20H to Register A: the next entry of the same sector.
50C3
LD L,A 6F
Copy Register A into Register L, the next place.
50C4
If the NC FLAG is set (entry 7 not passed), jump back to 50BDH to test it.
50C6
ADD A,41H C6 41
Add 41H to Register A: the next sector, entry 2.
50C8
LD L,A 6F
Copy Register A into Register L, the next place.
50C9
AND E7H E6 E7
AND Register A with E7H to drop bits 4-3: they are set only past sector 7.
50CB
CP L BD
Compare Register A with Register L: the Z FLAG is set when the place is in sectors 0-7.
50CC
If the Z FLAG is set (a sector of the directory), jump back to 50BDH to test it.
50CE
OR 01H F6 01
OR Register A with 01H so that the NZ FLAG is set whatever Register A held.
50D0
RET C9
Return with the NZ FLAG set: no free place from the place where the search started.

50D1H - The Hash of a Password

Called from 4E2FH with Register Pair DE the eight characters of the password. Register Pair HL starts at FFFFH and takes in each character from the last to the first with shifts and exclusive ORs. The password of eight spaces gives 4296H.

50D1
LD HL,FFFFH 21 FF FF
Load Register Pair HL with FFFFH, the start of the hash.
50D4
LD B,08H 06 08
Load Register B with 08H, the eight characters of the password.
50D6
LD A,E 7B
Copy Register E, the low byte of the password's address, into Register A.
50D7
ADD A,07H C6 07
Add 07H to Register A: the address of the last character.
50D9
LD E,A 5F
Copy Register A into Register E: Register Pair DE is the last character of the password.
50DA
If the NC FLAG is set (no carry), jump to 50DDH.
50DC
INC D 14
Increment Register D for the carry: Register Pair DE is the last character.
50DD
LD A,(DE) 1A
Load Register A with the character of the password at Register Pair DE.
50DE
PUSH DE D5
Save Register Pair DE, the address of the character, on the stack.
50DF
LD D,A 57
Copy Register A, the character, into Register D.
50E0
LD E,H 5C
Copy Register H, the high byte of the hash, into Register E.
50E1
LD A,L 7D
Copy Register L, the low byte of the hash, into Register A.
50E2
AND 07H E6 07
AND Register A with 07H to keep bits 2-0 of the low byte.
50E4
RRCA 0F
Rotate Register A right, the first of three turns that bring bits 2-0 to bits 7-5.
50E5
RRCA 0F
Rotate Register A right, the second of the three turns.
50E6
RRCA 0F
Rotate Register A right, the third turn: bits 2-0 are now bits 7-5.
50E7
XOR L AD
Exclusive OR Register A with Register L, the low byte of the hash.
50E8
LD L,A 6F
Copy Register A into Register L, the new low byte of the working value.
50E9
LD H,00H 26 00
Load Register H with 00H: Register Pair HL is the new low byte.
50EB
ADD HL,HL 29
Add Register Pair HL to itself: shifted left once.
50EC
ADD HL,HL 29
Add Register Pair HL to itself: shifted left twice.
50ED
ADD HL,HL 29
Add Register Pair HL to itself: shifted left three times.
50EE
ADD HL,HL 29
Add Register Pair HL to itself: shifted left four times.
50EF
XOR H AC
Exclusive OR Register A, the new low byte, with Register H, its bits 7-4.
50F0
XOR D AA
Exclusive OR Register A with Register D, the character.
50F1
LD D,A 57
Copy Register A into Register D, the high byte of the next hash.
50F2
LD A,L 7D
Copy Register L, the new low byte shifted left four times, into Register A.
50F3
ADD HL,HL 29
Add Register Pair HL to itself: shifted left five times.
50F4
XOR H AC
Exclusive OR Register A with Register H, bits 7-3 of the new low byte.
50F5
XOR E AB
Exclusive OR Register A with Register E, the high byte of the hash before.
50F6
LD E,A 5F
Copy Register A into Register E, the low byte of the next hash.
50F7
EX DE,HL EB
Exchange Register Pairs DE and HL: Register Pair HL is the hash.
50F8
POP DE D1
Restore Register Pair DE, the address of the character, from the stack.
50F9
DEC DE 1B
Decrement Register Pair DE to the character before.
50FA
Decrement Register B and jump back to 50DDH while it is not 00H.
50FC
RET C9
Return with the hash of the password in Register Pair HL.

50FDH - Wait for a Drive's Index Pulses

Called from 4E40H and 4EEFH with Register C the drive. The controller is stopped with Force Interrupt D0H, so that its status shows the index pulse in bit 1, and the drive is selected. The routine waits for the end of an index pulse, a whole pulse and its end, with one count of 3155H turns of 511EH for all three waits, about 0.58 seconds at the Model I's 1.77 MHz. Returns the NZ FLAG when the count runs out (no diskette or no drive), else the Z FLAG with the C FLAG set when the diskette is write protected.

50FD
LD A,D0H 3E D0
Load Register A with D0H, the Force Interrupt command of the controller with no condition.
50FF
LD (37ECH),A 32 EC 37
Store Register A (D0H) at 37ECH, the command register: the status register then shows the drive's index, write protect and ready lines.
5102
Call 4600H to select drive Register C, giving it time to come up to speed when it was not running.
5105
PUSH BC C5
Save Register Pair BC, the drive in Register C, on the stack: 5129H takes it off when the count runs out.
5106
LD BC,3155H 01 55 31
Load Register Pair BC with 3155H, the count of turns shared by the three waits.
5109
Call 511EH to count one turn and test the index bit: the NZ FLAG is set while the index hole is under the sensor.
510C
If the NZ FLAG is set (in the index pulse), jump back to 5109H until it ends.
510E
Call 511EH to count one turn and test the index bit, waiting for the next index pulse.
5111
If the Z FLAG is set (no index pulse), jump back to 510EH until one comes.
5113
Call 511EH to count one turn and test the index bit, waiting for the end of that pulse.
5116
If the NZ FLAG is set (in the index pulse), jump back to 5113H until it ends.
5118
POP BC C1
Restore Register Pair BC, the drive in Register C, from the stack.
5119
RLCA 07
Rotate Register A, the status, left: bit 6, write protected, moves to bit 7.
511A
AND 80H E6 80
AND Register A with 80H to keep the write protect bit.
511C
ADD A,A 87
Add Register A to itself: 80H gives 00H and the C FLAG, 00H gives 00H; the Z FLAG is set either way.
511D
RET C9
Return with the Z FLAG set and the C FLAG set when the diskette is write protected.

511EH - Count a Turn and Test the Index Bit

Called from the three waits of 50FDH with Register Pair BC the count. Returns the status in Register A and bit 1, the index pulse, in the Z FLAG; when the count runs out it takes its own return address and the saved Register Pair BC off the stack and returns from 50FDH with the NZ FLAG set.

511E
DEC BC 0B
Decrement Register Pair BC, the turns left of the count set at 5106H.
511F
LD A,B 78
Copy Register B, the high byte of the turns left, into Register A.
5120
OR C B1
OR Register A with Register C, the low byte: the Z FLAG is set when Register Pair BC is 0000H.
5121
If the Z FLAG is set (the count has run out), jump to 5129H.
5123
LD A,(37ECH) 3A EC 37
Load Register A with the status of the controller from 37ECH.
5126
BIT 1,A CB 4F
Test bit 1 of Register A, the index pulse: the NZ FLAG is set while the index hole is under the sensor.
5128
RET C9
Return to the wait in 50FDH with the status in Register A and the index bit in the Z FLAG.
5129
POP BC C1
Take the return address into 50FDH off the stack into Register Pair BC: the wait is given up.
512A
POP BC C1
Restore Register Pair BC, the drive in Register C, saved at 5105H.
512B
OR 01H F6 01
OR Register A with 01H: the NZ FLAG is set, the drive is not ready.
512D
RET C9
Return to the caller of 50FDH with the NZ FLAG set.

512EH - Read the Hash Index Table

Called with Register C the drive. Sector 1 of the drive's directory block, the hash index table (sector 0 is the GAT), is read into 4D00H. Returns Register Pair HL 4D00H and the Z FLAG, or error 16H.

512E
PUSH BC C5
Save Register Pair BC, the drive in Register C, on the stack.
512F
PUSH DE D5
Save Register Pair DE on the stack: 4B55H loads Register D.
5130
Call 4B55H to load Register D with the directory block of drive Register C from 4304H-4307H.
5133
LD E,01H 1E 01
Load Register E with 01H, the sector of the hash index table in the directory block.
5135
LD HL,4D00H 21 00 4D
Load Register Pair HL with 4D00H, the buffer of the hash index table.
5138
Call 4B35H to read sector Register E of block Register D on drive Register C into Register Pair HL (4D00H), with the deleted data mark of the directory.
513B
POP DE D1
Restore Register Pair DE, the caller's, from the stack.
513C
POP BC C1
Restore Register Pair BC, the drive in Register C, from the stack.
513D
RET Z C8
Return if the Z FLAG is set, with Register A 00H: the table is at 4D00H.
513E
LD A,16H 3E 16
Load Register A with 16H, the error code for a hash index table that cannot be read.
5140
RET C9
Return with error 16H in Register A and the NZ FLAG set by 4B35H.

5141H - Write the Hash Index Table

Called with Register C the drive. The table at 4D00H 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.

5141
PUSH BC C5
Save Register Pair BC, the drive in Register C, on the stack.
5142
PUSH DE D5
Save Register Pair DE on the stack: 4B55H loads Register D.
5143
Call 4B55H to load Register D with the directory block of drive Register C from 4304H-4307H.
5146
LD E,01H 1E 01
Load Register E with 01H, the sector of the hash index table in the directory block.
5148
LD HL,4D00H 21 00 4D
Load Register Pair HL with 4D00H, the hash index table to write.
514B
Call 45CFH to write the buffer at Register Pair HL (4D00H) as sector Register E of block Register D on drive Register C and read it back.
514E
POP DE D1
Restore Register Pair DE, the caller's, from the stack.
514F
POP BC C1
Restore Register Pair BC, the drive in Register C, from the stack.
5150
RET Z C8
Return if the Z FLAG is set: the table has been written.
5151
LD A,17H 3E 17
Load Register A with 17H, the error code for a hash index table that cannot be written.
5153
RET C9
Return with error 17H in Register A and the NZ FLAG set by 45CFH.

5154H - The Parsed Specification

The drive byte is the last byte of the first load block; the rest of the parsed specification, at 5155H-516BH, is not in the file.

5154
DEFB 00H 00
The drive of the specification at 5154H: FFH when none is named (503DH), else 0-3 (507CH), and the drive where the file was found (4E8EH).
5155-517F
DEFS 43
Not in the file: the 43 bytes between the load blocks 4E00H-5154H and 5180H-51A6H. 5155H-515CH the password, 515DH-5164H the name, 5165H-5167H the extension, 5168H-5169H and 516AH-516BH the password hash twice (4E32H, 4E35H); 516CH-517FH are not used.

5180H - The Rest of the End of File Sector

Called from 4FE8H with Register Pair DE entry +14H and Register Pair HL FCB+0DH. When the end of file offset is not 00H, the last sector is partly filled and the end of file sector is one less than the number of sectors.

5180
INC DE 13
Increment Register Pair DE to entry +15H, the high byte of the number of sectors.
5181
LD A,(DE) 1A
Load Register A with the high byte of the number of sectors at Register Pair DE.
5182
LD (HL),A 77
Store Register A at Register Pair HL, FCB+0DH, the high byte of the end of file sector.
5183
LD A,(IX+08H) DD 7E 08
Load Register A with the end of file offset at FCB+08H through Index Register IX.
5186
OR A B7
Set the flags from Register A: the Z FLAG is set when the file ends at the start of a sector.
5187
RET Z C8
Return if the Z FLAG is set: the end of file sector is the number of sectors.
5188
LD A,(IX+0CH) DD 7E 0C
Load Register A with the low byte of the end of file sector from FCB+0CH through Index Register IX.
518B
DEC (IX+0CH) DD 35 0C
Decrement the low byte of the end of file sector at FCB+0CH through Index Register IX.
518E
OR A B7
Set the flags from Register A, the low byte before the decrement: the Z FLAG is set for 00H.
518F
RET NZ C0
Return if the NZ FLAG is set: no borrow from the high byte.
5190
DEC (IX+0DH) DD 35 0D
Decrement the high byte of the end of file sector at FCB+0DH through Index Register IX for the borrow.
5193
RET C9
Return with the end of file sector at FCB+0CH-+0DH.

5194H - Capitals, Then Parse

Called from 4E1FH with Register Pair HL the FCB. The small letters of its 32 bytes are made capitals in place, then the specification is parsed by 5027H.

5194
PUSH HL E5
Save Register Pair HL, the FCB, on the stack.
5195
LD B,20H 06 20
Load Register B with 20H, the 32 bytes of the FCB.
5197
LD A,(HL) 7E
Load Register A with the byte at Register Pair HL.
5198
SUB 61H D6 61
Subtract 61H, the letter a, from Register A: a small letter becomes 00H-19H.
519A
CP 1AH FE 1A
Compare Register A with 1AH, the number of letters.
519C
If the NC FLAG is set (not a small letter), jump to 51A0H to leave the byte as it is.
519E
RES 5,(HL) CB AE
Reset bit 5 of the byte at Register Pair HL: the small letter becomes a capital.
51A0
INC HL 23
Increment Register Pair HL to the next byte of the FCB.
51A1
Decrement Register B and jump back to 5197H while it is not 00H.
51A3
POP HL E1
Restore Register Pair HL, the FCB, from the stack.
51A4
Jump to 5027H to parse the specification at Register Pair HL; it returns to 4E22H.