Percom DoubleDOS 4.24 for the Model I - SYS2/SYS Disassembled
Page Customization
Page Index
SYS2/SYS
Other Navigation
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
| Addresses | Contents |
|---|---|
| 4E00H-4E11H | The dispatcher of the request codes 94H, A4H and B4H (4E00H) |
| 4E12H-4ED7H | Open a file: parse, search the hash index tables, compare the entry, the password tests that are never run (4E12H) |
| 4ED8H-4F4FH | Open a file or make it (4ED8H) |
| 4F50H-4FA6H | Give a file another directory entry (4F50H) |
| 4FA7H-5026H | Fill in the FCB from the directory entry (4FA7H) |
| 5027H-509AH | Parse a file specification (5027H) |
| 509BH-50FCH | The hash code of a name, a free place in the hash index table, the hash of a password (509BH) |
| 50FDH-5153H | Wait for a drive's index pulses, read and write the hash index table (50FDH) |
| 5154H | The drive of the specification (5154H) |
| 5180H-51A6H | The end of file sector, and capitals before the parse (5180H) |
The Request Codes
| Code | Entry in SYS0/SYS, job and registers |
|---|---|
| 94H | 4424H, 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 |
| A4H | 4420H, 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 |
| B4H | SYS0/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
| Step | What the code does |
|---|---|
| 1 | The 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. |
| 2 | The 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). |
| 3 | Every 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). |
| 4 | The password is not tested (4EACH), and the FCB is filled in with the access level 00H (4FA7H). |
| 5 | For 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
| Offset | A new file (4F0EH) | An extra entry (4F50H) |
|---|---|---|
| +00H | 10H, the attribute: protection level 0 | 90H: bit 7 marks an extra entry |
| +01H | 00H | The record of the entry before it |
| +02H-+03H | 00H; +03H the end of file offset | 00H |
| +04H | The record length given | 00H |
| +05H-+0FH | The name and extension | 00H |
| +10H-+13H | The update and access password hashes, both the hash of the password given | 00H |
| +14H-+15H | 0000H, the number of sectors | 0000H |
| +16H-+1FH | FFH: no extents | FFH: 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
| Offset | Contents |
|---|---|
| +00H | 80H, open |
| +01H | The access level (00H) with bit 5 and, when the record length is not 256, bit 7 |
| +02H | 00H |
| +03H-+04H | The buffer (Register Pair HL) |
| +05H | 00H, the offset |
| +06H, +07H | The drive, the directory record |
| +08H | The end of file offset, entry +03H |
| +09H | The record length (Register B) |
| +0AH-+0BH | 0000H, the sector |
| +0CH-+0DH | The end of file sector: entry +14H-+15H, less 1 when entry +03H is not 00H (5180H) |
| +0EH-+1FH | The 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
| Code | Meaning (where set) |
|---|---|
| 11H, 12H | Directory read, directory write error (from 4AC1H, 4AD6H) |
| 13H | No name in the specification (504EH) |
| 16H, 17H | Hash index table read, write error (513EH, 5151H) |
| 18H | No drive searched has the file (4E60H) |
| 19H | The password does not open the file (4ECBH, never run) |
| 1AH | No room for a new file on the drives tried (4F0BH) |
| 1EH | No free place for an extra entry (4F5DH) |
| 20H | A drive number that is not 0-3 (5078H) |
Outside Routines
| Address | Use |
|---|---|
| 4600H | SYS0/SYS: Select a Drive 5102H. |
| 45CFH | SYS0/SYS: Write a Directory Sector and Read It Back 514BH. |
| 4896H | SYS0/SYS: The Common Start of the File Routines Entered past its open test (4E12H, 4ED8H). |
| 4AC1H | SYS0/SYS: Read a Directory Record 4E6DH, 4F17H, 4F6FH, 4F96H. |
| 4AD6H | SYS0/SYS: Write a Directory Record 4F46H, 4F8EH, 4FA3H. |
| 4B35H | SYS0/SYS: Read a Directory Sector 5138H. |
| 4B55H | SYS0/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.
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.
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.
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.
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).
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.
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.
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).
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.
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.
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).
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.
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.
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.
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.
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.
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.
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.
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.