TRS-80 DOS - NEWDOS/80 v2.0 for the Model III - SYS16/SYS Disassembled
Page Customization
Page Index
SYS16/SYS
Other Navigation
Introduction/Summary
NEWDOS/80 v2.0 SYS16/SYS Disassembly - PDRIVE (Model III)
SYS16/SYS does the PDRIVE command after SYS7/SYS has read its password and first drive number. Its five load records fill 4D00H-51E7H of the overlay area (1,256 bytes) and its transfer address is 4D00H. The code fills 4D00H-50C2H and 51C6H-51E7H; the data in between holds the texts, the FCB of the system data sector and the keyword table, with runs of 00H.
The page shows every byte of the file once, in address order.
PDRIVE
PDRIVE [password:]dn1[,dn2[=dn3]][,TI=letters][,TD=letter][,TC=n][,SPT=n][,TSR=n][,GPL=n][,DDSL=n][,DDGA=n][,A]. SYS7/SYS calls SYS16/SYS with RST 28H code 32H (function 1 of directory slot 12H) and Register B = dn1; any other code gives error 2AH.
| Step | What is done |
|---|---|
| 4D00H | Sector 2 of drive dn1, the system data sector, is read into 4300H through the FCB at 510EH. |
| 4D19H | dn2 (0-9, else error 20H) is the record to change; dn2=dn3 first copies record dn3 over it; each keyword then sets one field (4D46H). |
| 4DA4H | All ten records are checked and their derived bytes worked out (4EB0H), byte +06H is set, and the sector is written back with a verify (443CH). |
| 4DDAH | The ten records are shown, each followed by an error mark if it is unusable; a mix of interface letters shows a message. Any error ends the command through 4030H. |
| 4DF5H | With the A option (dn1 = 0) the records of the drives in use (option AL, 1-4) are copied, 10 bytes each, into SYS0/SYS's PDRIVE table at 4291H. |
PDRIVE,dn1 alone, or PDRIVE,dn1,dn2 with nothing after dn2, shows the records without writing. The A option is taken only for dn1 = 0, by 4FCCH at any separator. The code also takes a B option: it copies the records into SYS0/SYS's table like A, but first fills 4DD3H-4DD9H with 00H, so that the sector is not written (51C6H).
Drive Records
The system data sector holds ten 16-byte records at 00H-9FH (one for each drive 0-9) and option AL at byte A0H. SYS0/SYS keeps bytes +00H to +09H of the records of the drives in use at 4291H (its 4280H-4287H then hold the current drive's).
| Byte | Contents |
|---|---|
| +00H | The directory lump (DDSL, copied by 4EF7H) |
| +01H | The number of lumps: (TC x SPT / sectors per granule) / GPL, rounded up, at most 192 |
| +02H | Bits 1-0 TSR, bits 4-2 the interface code (1 for TI A, 2 for TI D; 0 = unusable), bit 5 TI M, bit 6 TI K, bit 7 TI H (head settle delay) |
| +03H, +04H, +05H | TC (tracks), SPT (sectors per track, at most 10, 17, 20, 34, 18, 26, 36 or 52 for TD A-H), GPL (granules per lump, 1-8; 6 with TI M) |
| +06H | The value written to the controller's sector register at drive select: 00H, or FCH plus bit 1 (double density) and bit 0 (8 inch) when any record uses TI D |
| +07H | Disk I/O flags: bit 0 double density, bit 1 tracks numbered from 1 (TI J or K), bit 2 double step (TI L), bit 4 sectors numbered from 1 (TI I or M), bit 6 two sides, bit 7 an 8 inch drive |
| +08H, +09H | DDSL (the lump where the directory starts), DDGA (the directory's granules, 2-6) |
| +0CH | TSR, the step rate code 0-3 |
| +0DH, +0EH | TI letters: A-H in bits 0-7 of +0DH, I-P in bits 0-7 of +0EH. Exactly one of A and D is needed; B, C, E, F, G, N, O and P make the record unusable |
| +0FH | TD, the drive type A-H as 0-7: bit 0 an 8 inch drive, bit 1 two sides, bit 2 double density; TI A allows only the 5 inch types A, C, E and G |
With TI M a granule is 3 sectors instead of 5. The directory (DDSL x GPL plus DDGA granules) must end inside the diskette.
Variables
Memory Outside SYS16/SYS
| Address Size | Contents |
|---|---|
| 4291H-42B8H 40 bytes | PDRIVE Table SYS0/SYS's in-memory records of drives 0-3, 10 bytes each; the A option copies 1-4 records into it (4DFCH-4E13H). |
| 4300H-439FH 160 bytes | Drive Records The ten 16-byte records of the system data sector read into SYS0/SYS's buffer (4D0EH), changed, written back (4DD6H) and shown. |
| 43A0H 1 byte | Option AL Byte A0H of the system data sector, the number of drives in use (4DFFH, 4E22H). |
| 4302H 1 byte | Record 0 Byte +02H Set to 00H when any record is unusable or the interface letters are mixed (4E8FH, 500BH), which ends the command through 4030H (4DEEH). |
SYS16/SYS Data
| Address Size | Contents |
|---|---|
| 50CBH-5105H 59 bytes | Texts The error mark of an unusable record and the mixed interface message. |
| 5106H-510DH 8 bytes | Sectors per Track The most sectors per track for TD A-H. |
| 510EH-511BH 14 bytes | FCB The FCB of the system data sector: drive at 5114H, NEXT at 5118H-5119H, buffer 4300H. |
| 511CH-514BH 48 bytes | Keyword Table TI=, TD=, TC=, SPT=, TSR=, GPL=, DDSL=, DDGA= with their attribute bytes. |
Operands Changed at Run Time
| Address Size | Contents |
|---|---|
| 4DD3H-4DD9H 7 bytes | Sector Write CALL 4FC3H, CALL 443CH, RET NZ; filled with 00H by the B option (51DFH). |
| 4DF6H 1 byte | A/B Option The operand of LD A at 4DF5H: 00H in the file, the option letter after 51C8H, 41H after 51D5H. |
| 4EA2H 1 byte | Record Number The operand of LD A at 4EA1H: FFH in the file, stored at 4D1CH, 4DA5H and 4E16H. |
| 5114H 1 byte | Drive FCB+6: dn1, stored at 4D08H. |
| 5118H 1 byte | Sector FCB+10: 02H, stored again at 4FC5H. |
Outside Routines and Addresses
| Address | Contents |
|---|---|
| 0033H | ROM: display a character (5011H). |
| 4030H | SYS0/SYS: end the command as one whose error is already displayed (4DF2H). |
| 4409H | SYS0/SYS: the DOS error exit (503CH). |
| 4436H, 443CH | SYS0/SYS: read the sector at NEXT (4D0EH), write it with a verify (4DD6H). |
| 4467H | SYS0/SYS: display a message (4DEBH, 4E8BH). |
| 4C37H, 4C59H | SYS0/SYS: multiply Register L by Register A (4ED9H, 4F03H), divide Register Pair HL by Register A (4EE6H, 4F10H). |
| 4C6AH, 4C7AH | SYS0/SYS: compare a word (5017H), test for the end of the line or a separator (4FCCH, 4FE3H). |
Disassembly
4D00H - PDRIVE Command
SYS7/SYS handles the start of PDRIVE [password:]dn1[,dn2[=dn3]][,keyword=value]...[,A]: it reads the diskette's password and drive and calls SYS16/SYS (directory slot 12H) with RST 28H code 32H (function 1), Register B = dn1 and Register Pair HL = the command line after it; 4BC5H (the dispatcher's tail) is on top of the stack. SYS16/SYS reads sector 2 of drive dn1 (the system data sector, whose first 160 bytes are ten 16-byte PDRIVE records, one for each drive 0-9, and whose byte A0H is option AL) into 4300H, changes record dn2, works out the derived bytes of all ten records, writes the sector back, shows all ten records and, with the A option, copies the records of the drives in use into SYS0/SYS's PDRIVE table at 4291H.
Store Register A (dn1) at 5114H, FCB+6 (the drive number) of the FCB at 510EH.
Store Register A (dn2) at 4EA2H, the operand of the LD A,FFH at 4EA1H, the record number 4E9AH works on.
Keyword Loop
Register Pair HL = the command line; the record being changed is the one in the operand 4EA2H.
4D5EH - Read a Drive Number
Reads a number at Register Pair HL into Register A; it must be 0-9 (a record of the system data sector), else error 20H (ILLEGAL OR MISSING DRIVE #).
4D69H - TI= and TD=
TI= is a list of letters A-P; each sets one bit: A-H bits 0-7 of record byte +0DH, I-P bits 0-7 of record byte +0EH. The list ends at the first character that is not A-P. TD= is one letter A-Z, stored at record byte +0FH as 0-25 (only A-H are accepted later by 4EB0H).
Letter Loop
Register Pair HL = the command line at the next letter of TI=.
4DA4H - Work Out and Write the Records
The command line has been used up. 4EB0H works out the derived bytes of all ten records; 4FECH checks the interface letters of all ten; byte +6 of every record is set; the sector is written back to drive dn1 (unless option B removed the write at 4DD3H-4DD9H).
Record Loop
Register A = the record number, kept on the stack while 4EB0H works.
Store Register A (the record number) at 4EA2H, the operand of the LD A,FFH at 4EA1H. 4DB0H comes back here.
Select Byte Loop
Index Register IX = the record, Register B = the records left, Register C = the letters B-G in use.
4DDAH - Show the Records
One line per record 0-9 (4E16H), each checked again by 4EB0H; an unusable record gets a line ending in Error and makes record 0's byte +02H 00H. A mix of interface letters shows the message at 50DCH. If record 0's byte +02H (4302H) is then 00H the command ends through 4030H (error already shown); otherwise, with option A or B, the records of the drives in use are copied into SYS0/SYS's PDRIVE table at 4291H.
Show Loop
Register A = the record number, kept on the stack.
Load Register A with the A/B option flag: the operand 4DF6H is 00H in the file and 41H (ASCII A) after 51C8H or 51D5H has taken an A or B option.
Copy Loop
Register Pair HL = the record in the sector, Register Pair DE = SYS0/SYS's table, Register A = the records left.
4E16H - Show One Record
Register A = the record number. The line is the number, an asterisk if the drive is in use (below option AL at 43A0H), spaces to column 4, then every keyword of the table at 511CH with its value, separated by commas. The record is then checked by 4EB0H; if it is unusable the text at 50CBH (Error between groups of three asterisks) is added and record 0's byte +02H (4302H) is set to 00H.
Store Register A (the record number) at 4EA2H, the operand of the LD A,FFH at 4EA1H. 4DDCH calls here.
Keyword Loop
Register Pair BC walks the keyword table: the keyword's characters, 00H, the attribute byte.
Letter Loop
Register Pair DE = the letter bits (Register E A-H, Register D I-P), shifted right one bit each pass.
4E97H - Address of a Record Field
4E97H takes the field number from the low four bits of the attribute byte at Register Pair BC; 4E9AH takes it in Register A. Returns Index Register IX = 4300H + 16 x the record number (operand 4EA2H) + the field number. Register Pairs HL and DE are kept.
Load Register A with the record number: the operand 4EA2H is FFH in the file and is stored at 4D1CH, 4DA5H and 4E16H.
4EB0H - Check a Record and Work Out Its Bytes
The record (operand 4EA2H) is first marked unusable by clearing bits 2-4 of byte +02H; any value out of range then returns early and leaves it so. Typed values: +03H TC tracks, +04H SPT sectors per track, +05H GPL granules per lump, +08H DDSL directory lump, +09H DDGA directory granules, +0CH TSR step rate, +0DH TI letters A-H, +0EH TI letters I-P, +0FH TD drive type 0-7. Derived: +00H the directory lump (DDSL), +01H the number of lumps, +02H (bits 1-0 TSR, bits 4-2 the interface code, bit 5 TI M, bit 6 TI K, bit 7 TI H) and +07H, the disk I/O flags (bit 0 double density, bit 1 tracks from 1, bit 2 double step, bit 4 sectors from 1, bit 6 two sides, bit 7 an 8 inch drive).
Directory End Loop
Register B = DDGA, Register Pair HL counts the directory's granules.
Count Loop
Register Pair HL is shifted left 16 times; Register A counts the bits that come out.
4FC3H - Point the FCB at Sector 2
Sets FCB+10 (5118H) of the FCB at 510EH to 02H, so that NEXT is sector 2 of the diskette (the system data sector), and returns Register Pair DE = 510EH for the read (4436H) or the write (443CH).
Store Register A (02H) at 5118H, FCB+10 of the FCB at 510EH: the middle byte of NEXT, so that NEXT = sector 2.
4FCCH - Separator and the A or B Option
Calls SYS0/SYS 4C7AH for the separator at Register Pair HL: the CARRY FLAG for a bad character, the Z FLAG at the end of the line. When a parameter follows, dn1 is 0 and no A or B option has been taken yet, a parameter that is A or B on its own is taken (51C6H): A stores 41H at 4DF6H (copy into SYS0/SYS's table), B does the same and also stores 00H over 4DD3H-4DD9H, so that the sector is not written. Returns the flags of 4C7AH for whatever follows.
4FECH - Check the Mix of Interface Letters
ORs bits 1-6 (the letters B-G) of byte +0DH of all ten records into Register C and counts them. With two or more different letters, record 0's byte +02H (4302H) is set to 00H and the NO CARRY FLAG is returned; otherwise the CARRY FLAG. Register C returns the letters in use.
Collect Loop
Register Pair HL = byte +0DH of the record, Register C = the letters B-G found so far.
Count Loop
Register C is rotated eight times; Register A counts its set bits.
500FH - Show a Character
Shows the character in Register A through the ROM routine 0033H, keeping Register Pairs AF and DE.
5017H - Look Up a Keyword
Register Pair BC = a table of words, each ended by 00H and followed by the number of bytes in Register D; a 00H ends the table. Returns the Z FLAG with Register Pair BC after the matching word's 00H and Register Pair HL past the word in the command line; a word not in the table is error 34H.
Search Loop
Register Pair BC = the table entry, Register Pair HL = the word in the command line, Register D = the bytes after each 00H.
502EH - Read a Number 0-255
Reads a number at Register Pair HL (decimal, or hexadecimal ended by H) and returns it in Register A, with the Z FLAG; a number above 255 is error 2FH. 5033H, an entry for decimal digits only, is never used.
503FH - Read a Number
Reads a number at Register Pair HL into Register Pair DE: decimal digits, or hexadecimal digits ended by H. The digits are first read as decimal; if a letter A-H follows them, the number is read again from its start as hexadecimal and must then end with H. No digit or a missing H is error 2FH. A value above FFFFH stops the reading at the digit that caused it (5095H), so the caller's separator check then finds that digit.
Digit Loop
Register Pair HL = the next character, Register Pair DE = the value so far, Register B bit 0 = hexadecimal.
5099H - Show a Number
Shows Register Pair DE in decimal without leading zeros, through 500FH.
Digit Loop
Register Pair DE = what is left of the number, Register Pair HL = the next power of ten in the table.
50C3H - Data
The powers of ten, the two texts, the most sectors per track for each drive type, the FCB of the system data sector and the keyword table.
511CH - Keyword Table (Data)
Read by 5017H (lookup) and 4E35H (display). Each entry: the keyword with its = sign, 00H and an attribute byte: bit 7 a number, bit 6 a list of letters (else one letter), bits 3-0 the record byte it sets. The 00H at 514BH ends the table.
51C6H - Take an A or B Option
Register A = the first character of a parameter, Register Pair DE = 4DF6H. The character is stored at 4DF6H. A goes on to 4FE2H. B is changed into A (at 4DF6H and in the command line) and 4DD3H-4DD9H (the CALL 4FC3H, the CALL 443CH and the RET NZ that write the sector) are filled with 00H, then it goes on to 4FE2H. Any other character goes to 4FE8H, which clears 4DF6H again.
Store Register A (the character) at Register Pair DE, 4DF6H, the operand of the LD A at 4DF5H.
Store Register A (41H) at Register Pair DE, 4DF6H: B also copies the records into SYS0/SYS's table.
Store Register C (00H, NOP) at Register Pair HL, one byte of 4DD3H-4DD9H. 51E1H comes back here.