TRS-80 DOS - NEWDOS/80 v2.0 for the Model III - SYS16/SYS Disassembled

Page Customization

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.

StepWhat is done
4D00HSector 2 of drive dn1, the system data sector, is read into 4300H through the FCB at 510EH.
4D19Hdn2 (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).
4DA4HAll 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).
4DDAHThe 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.
4DF5HWith 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).

ByteContents
+00HThe directory lump (DDSL, copied by 4EF7H)
+01HThe number of lumps: (TC x SPT / sectors per granule) / GPL, rounded up, at most 192
+02HBits 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, +05HTC (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)
+06HThe 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
+07HDisk 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, +09HDDSL (the lump where the directory starts), DDGA (the directory's granules, 2-6)
+0CHTSR, the step rate code 0-3
+0DH, +0EHTI 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
+0FHTD, 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

AddressContents
0033HROM: display a character (5011H).
4030HSYS0/SYS: end the command as one whose error is already displayed (4DF2H).
4409HSYS0/SYS: the DOS error exit (503CH).
4436H, 443CHSYS0/SYS: read the sector at NEXT (4D0EH), write it with a verify (4DD6H).
4467HSYS0/SYS: display a message (4DEBH, 4E8BH).
4C37H, 4C59HSYS0/SYS: multiply Register L by Register A (4ED9H, 4F03H), divide Register Pair HL by Register A (4EE6H, 4F10H).
4C6AH, 4C7AHSYS0/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.

4D00
CP 32H FE 32
Compare Register A, the RST 28H code, against 32H, function 1 of directory slot 12H (SYS16/SYS). The Z FLAG is set if Register A = 32H.
4D02
LD A,2AH 3E 2A
Load Register A with 2AH, the DOS error code ILLEGAL DOS FUNCTION. LD does not change the flags of the CP.
4D04
If the NZ FLAG is set (Register A held another code), JUMP to 503CH, which leaves through the SYS0/SYS error exit 4409H with Register A = 2AH.
4D07
LD A,B 78
Load Register A with Register B, dn1: the drive whose system data sector is read and changed, passed by SYS7/SYS.
4D08
LD (5114H),A 32 14 51
Self-Modifying Code
Store Register A (dn1) at 5114H, FCB+6 (the drive number) of the FCB at 510EH.
4D0B
GOSUB to 4FC3H, which sets FCB+10 (5118H) to 02H, so that NEXT is sector 2 of the diskette, and returns Register Pair DE = 510EH, the FCB.
4D0E
GOSUB to SYS0/SYS 4436H, which reads the sector at NEXT of the FCB at Register Pair DE (sector 2, the system data sector of drive dn1) into its buffer at 4300H; the NZ FLAG with an error code in Register A on failure.
4D11
RET NZ C0
If the NZ FLAG is set (a read error), RETURN to the dispatcher's tail 4BC5H with the error code in Register A.
4D12
GOSUB to 4FCCH, which looks at the separator after dn1 at Register Pair HL (the CARRY FLAG for a bad one, the Z FLAG at the end of the line) and, for dn1 = 0, takes an A or B option that stands there.
4D15
RET C D8
If the CARRY FLAG is set (a bad separator), RETURN to the dispatcher's tail 4BC5H with Register A = 34H (ILLEGAL KEYWORD OR SEPARATOR OR TERMINATOR).
4D16
If the Z FLAG is set (nothing more: PDRIVE,dn1 or PDRIVE,0,A), JUMP to 4DDAH to show the ten records.
4D19
GOSUB to 4D5EH, which reads dn2, the record to change, at Register Pair HL into Register A (0-9, else error 20H).
4D1C
LD (4EA2H),A 32 A2 4E
Self-Modifying Code
Store Register A (dn2) at 4EA2H, the operand of the LD A,FFH at 4EA1H, the record number 4E9AH works on.
4D1F
LD A,(HL) 7E
Load Register A with the byte at Register Pair HL, the character after dn2.
4D20
CP 3DH FE 3D
Compare Register A against 3DH (ASCII =). The Z FLAG is set for dn2=dn3.
4D22
If the NZ FLAG is set (no = sign), JUMP to 4D3FH for the keywords.
4D24
INC HL 23
INCrement Register Pair HL past the = to dn3, the record to copy from.
4D25
GOSUB to 4D5EH, which reads dn3 at Register Pair HL into Register A (0-9, else error 20H).
4D28
RLCA 07
Rotate Register A (dn3) left (RLCA): dn3 times 2.
4D29
RLCA 07
Rotate Register A left (RLCA): Register A = dn3 times 4.
4D2A
RLCA 07
Rotate Register A left (RLCA): Register A = dn3 times 8.
4D2B
RLCA 07
Rotate Register A left (RLCA): dn3 times 16, the offset of record dn3 in the sector.
4D2C
PUSH HL E5
Save Register Pair HL (the command line after dn3) onto the stack.
4D2D
LD H,43H 26 43
Load Register H with 43H, the high byte of the sector buffer 4300H.
4D2F
LD L,A 6F
Load Register L with Register A (dn3 times 16): Register Pair HL = 4300H + 16 x dn3, record dn3.
4D30
XOR A AF
Load Register A with 00H (XOR A with itself), the offset of the record's first byte.
4D31
GOSUB to 4E9AH, which returns Index Register IX = 4300H + 16 x dn2 (the operand 4EA2H) + Register A (00H): record dn2.
4D34
PUSH IX DD E5
Save Index Register IX (record dn2) onto the stack.
4D36
POP DE D1
Restore Register Pair DE from the stack: Register Pair DE = record dn2, the destination.
4D37
LD BC,0010H 01 10 00
Load Register Pair BC with 0010H (16), the length of a PDRIVE record.
4D3A
LDIR ED B0
LDIR: copy Register Pair BC (16) bytes from Register Pair HL (record dn3) to Register Pair DE (record dn2), upward. Record dn2 now holds dn3's values; Register Pair BC ends at 0000H.
4D3C
POP HL E1
Restore Register Pair HL from the stack: the command line after dn3.
4D3D
JUMP to 4D9EH to look at the separator after dn3.

Keyword Loop
Register Pair HL = the command line; the record being changed is the one in the operand 4EA2H.

4D3F
GOSUB to 4FCCH, which looks at the separator at Register Pair HL (the CARRY FLAG for a bad one, the Z FLAG at the end) and, for dn1 = 0, takes an A or B option. 4D22H comes here.
4D42
RET C D8
If the CARRY FLAG is set (a bad separator), RETURN to the dispatcher's tail 4BC5H with Register A = 34H.
4D43
If the Z FLAG is set (nothing follows dn2), JUMP to 4DDAH to show the records without changing or writing anything.
4D46
LD BC,511CH 01 1C 51
Load Register Pair BC with 511CH, the keyword table (TI=, TD=, TC=, SPT=, TSR=, GPL=, DDSL=, DDGA=). 4DA2H comes back here.
4D49
LD D,01H 16 01
Load Register D with 01H: one attribute byte follows the 00H of each keyword in the table.
4D4B
GOSUB to 5017H, which finds the keyword at Register Pair HL in the table at Register Pair BC (error 34H if it is not there) and returns Register Pair BC at its attribute byte and Register Pair HL past the keyword and its =.
4D4E
GOSUB to 4E97H, which returns Index Register IX = the field of record dn2 that the keyword sets: 4300H + 16 x dn2 + the attribute's low four bits.
4D51
LD A,(BC) 0A
Load Register A with the byte at Register Pair BC, the keyword's attribute byte (bit 7 a number, bit 6 a list of letters, else one letter; bits 3-0 the field).
4D52
BIT 7,A CB 7F
Test bit 7 of Register A, the attribute byte: set for TC=, SPT=, TSR=, GPL=, DDSL= and DDGA=, which take a number.
4D54
If the Z FLAG is set (TI= or TD=, which take letters), JUMP to 4D69H.
4D56
GOSUB to 502EH, which reads the number at Register Pair HL into Register A (0-255, else error 2FH).
4D59
JUMP to 4D9BH to store Register A in the field at Index Register IX.
4D5B
JUMP to 503AH to leave with error 2FH (BAD PARAMETER(S)): TD= was not followed by a letter. 4D99H comes here.

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 #).

4D5E
GOSUB to 502EH, which reads the number at Register Pair HL into Register A (0-255, else error 2FH). 4D19H and 4D25H call here.
4D61
CP 0AH FE 0A
Compare Register A (the number) against 0AH. The CARRY FLAG is set for 0-9.
4D63
RET C D8
If the CARRY FLAG is set (0-9), RETURN with the drive number in Register A.
4D64
LD A,20H 3E 20
Load Register A with 20H, the DOS error code ILLEGAL OR MISSING DRIVE #.
4D66
JUMP to 503CH to leave through the SYS0/SYS error exit 4409H with Register A = 20H.

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).

4D69
BIT 6,A CB 77
Test bit 6 of Register A, the attribute byte: set only for TI=, a list of letters.
4D6B
If the Z FLAG is set (TD=, one letter), JUMP to 4D93H.
4D6D
XOR A AF
Load Register A with 00H (XOR A with itself): TI= replaces the old letters.
4D6E
LD (IX+00H),A DD 77 00
Store Register A (00H) at Index Register IX+00H, record byte +0DH: none of the letters A-H.
4D71
LD (IX+01H),A DD 77 01
Store Register A (00H) at Index Register IX+01H, record byte +0EH: none of the letters I-P.

Letter Loop
Register Pair HL = the command line at the next letter of TI=.

4D74
PUSH IX DD E5
Save Index Register IX (record byte +0DH) onto the stack. 4D91H comes back here.
4D76
POP DE D1
Restore Register Pair DE from the stack: Register Pair DE = record byte +0DH, the byte for the letters A-H.
4D77
LD A,(HL) 7E
Load Register A with the byte at Register Pair HL, the next character of the list.
4D78
SUB 41H D6 41
SUBtract 41H (ASCII A) from Register A: A becomes 0 and P becomes 15.
4D7A
CP 08H FE 08
Compare Register A against 08H. The CARRY FLAG is set for A-H.
4D7C
If the CARRY FLAG is set (A-H, a bit of byte +0DH), JUMP to 4D85H.
4D7E
INC DE 13
INCrement Register Pair DE to record byte +0EH, the byte for the letters I-P.
4D7F
SUB 08H D6 08
SUBtract 08H from Register A: I becomes 0 and P becomes 7.
4D81
CP 08H FE 08
Compare Register A against 08H. The CARRY FLAG is set for I-P.
4D83
If the NO CARRY FLAG is set (not a letter A-P), JUMP to 4D9EH: the list has ended at Register Pair HL.
4D85
LD B,A 47
Load Register B with Register A, the letter's bit number 0-7. 4D7CH comes here.
4D86
LD A,80H 3E 80
Load Register A with 80H, a single bit that the loop rotates into place.
4D88
INC B 04
INCrement Register B, so that the loop rotates bit number plus 1 times.
4D89
RLCA 07
Rotate Register A left (RLCA): the first rotation turns 80H into 01H (bit 0). 4D8AH comes back here.
4D8A
DECrement Register B and LOOP BACK to 4D89H until it is 0: Register A = the letter's bit.
4D8C
EX DE,HL EB
Exchange Register Pairs DE and HL: Register Pair HL = the record byte (+0DH or +0EH), Register Pair DE = the command line.
4D8D
OR (HL) B6
OR Register A (the letter's bit) with the byte at Register Pair HL, the letters given so far.
4D8E
LD (HL),A 77
Store Register A at Register Pair HL: the letter is added to the record byte.
4D8F
EX DE,HL EB
Exchange Register Pairs DE and HL back: Register Pair HL = the command line.
4D90
INC HL 23
INCrement Register Pair HL to the next character of the list.
4D91
JUMP to 4D74H for the next letter at Register Pair HL.
4D93
LD A,(HL) 7E
TD=: load Register A with the byte at Register Pair HL, the drive type letter. 4D6BH comes here.
4D94
SUB 41H D6 41
SUBtract 41H (ASCII A) from Register A: A becomes 0 and Z becomes 25.
4D96
CP 1AH FE 1A
Compare Register A against 1AH (26). The NO CARRY FLAG is set for a character that is not A-Z.
4D98
INC HL 23
INCrement Register Pair HL past the letter. INC HL does not change the flags.
4D99
If the NO CARRY FLAG is set (not a letter), JUMP to 4D5BH for error 2FH.
4D9B
LD (IX+00H),A DD 77 00
Store Register A (a number from 502EH, or TD's letter number) at Index Register IX+00H, the keyword's field in record dn2. 4D59H comes here.
4D9E
GOSUB to 4FCCH, which looks at the separator at Register Pair HL (the CARRY FLAG for a bad one, the Z FLAG at the end) and, for dn1 = 0, takes an A or B option. 4D3DH and 4D83H come here.
4DA1
RET C D8
If the CARRY FLAG is set (a bad separator), RETURN to the dispatcher's tail 4BC5H with Register A = 34H.
4DA2
If the NZ FLAG is set (another keyword follows), LOOP BACK to 4D46H.

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).

4DA4
XOR A AF
Load Register A with 00H (XOR A with itself), record 0.

Record Loop
Register A = the record number, kept on the stack while 4EB0H works.

4DA5
LD (4EA2H),A 32 A2 4E
Self-Modifying Code
Store Register A (the record number) at 4EA2H, the operand of the LD A,FFH at 4EA1H. 4DB0H comes back here.
4DA8
PUSH AF F5
Save Register Pair AF (Register A = the record number) onto the stack.
4DA9
GOSUB to 4EB0H, which checks the record's values and works out its bytes +00H, +01H, +02H and +07H (bits 2-4 of +02H stay 0 for an unusable record).
4DAC
POP AF F1
Restore Register Pair AF from the stack: Register A = the record number.
4DAD
INC A 3C
INCrement Register A to the next record number.
4DAE
CP 0AH FE 0A
Compare Register A against 0AH. The Z FLAG is set after record 9.
4DB0
If the NZ FLAG is set (records left), LOOP BACK to 4DA5H.
4DB2
GOSUB to 4FECH, which returns Register C = the letters B-G given in TI= of any of the ten records and, if two or more different ones are used, stores 00H at 4302H (record 0 unusable) and returns the NO CARRY FLAG.
4DB5
LD IX,4300H DD 21 00 43
Load Index Register IX with 4300H, record 0 in the sector buffer.
4DB9
LD B,0AH 06 0A
Load Register B with 0AH, the count of the ten records in the sector.

Select Byte Loop
Index Register IX = the record, Register B = the records left, Register C = the letters B-G in use.

4DBB
LD E,(IX+07H) DD 5E 07
Load Register E with the byte at Index Register IX+07H, the record's disk I/O flags (bit 0 double density, bit 7 an 8 inch drive). 4DD1H comes back here.
4DBE
LD D,00H 16 00
Load Register D with 00H, byte +06H when no record uses TI D.
4DC0
BIT 3,C CB 59
Test bit 3 of Register C, the letters B-G in use: TI D, the Apparat controller.
4DC2
If the Z FLAG is set (no record uses TI D), JUMP to 4DC9H with Register D = 00H.
4DC4
LD A,E 7B
Load Register A with Register E, the disk I/O flags.
4DC5
RLCA 07
Rotate Register A left (RLCA): bit 7 (8 inch) goes to bit 0 and bit 0 (double density) to bit 1.
4DC6
OR FCH F6 FC
OR Register A with FCH, setting bits 2-7 above the two drive type bits.
4DC8
LD D,A 57
Load Register D with Register A: FCH plus bit 1 for double density and bit 0 for an 8 inch drive.
4DC9
LD (IX+06H),D DD 72 06
Store Register D at Index Register IX+06H, record byte +06H: the value SYS0/SYS writes to the controller's sector register when it selects the drive (475EH). 4DC2H comes here.
4DCC
LD DE,0010H 11 10 00
Load Register Pair DE with 0010H (16), the length of a record.
4DCF
ADD IX,DE DD 19
ADD Register Pair DE (16) to Index Register IX: Index Register IX = the next record.
4DD1
DECrement Register B and LOOP BACK to 4DBBH for all ten records.
4DD3
GOSUB to 4FC3H, which sets NEXT of the FCB at 510EH to sector 2 again and returns Register Pair DE = 510EH. 51DCH (option B) stores 00H over 4DD3H-4DD9H so that the sector is not written.
4DD6
GOSUB to SYS0/SYS 443CH, which writes the buffer at 4300H as sector 2 of drive dn1 (the FCB at Register Pair DE) and reads it back to verify; the NZ FLAG with an error code in Register A on failure.
4DD9
RET NZ C0
If the NZ FLAG is set (a write error), RETURN to the dispatcher's tail 4BC5H with the error code in Register A; otherwise go on to show the records.

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.

4DDA
XOR A AF
Load Register A with 00H (XOR A with itself), record 0. 4D16H and 4D43H come here.

Show Loop
Register A = the record number, kept on the stack.

4DDB
PUSH AF F5
Save Register Pair AF (Register A = the record number) onto the stack. 4DE3H comes back here.
4DDC
GOSUB to 4E16H, which shows the line of the record in Register A.
4DDF
POP AF F1
Restore Register Pair AF from the stack: Register A = the record number.
4DE0
INC A 3C
INCrement Register A to the next record number.
4DE1
CP 0AH FE 0A
Compare Register A against 0AH. The CARRY FLAG is set while records are left.
4DE3
If the CARRY FLAG is set, LOOP BACK to 4DDBH.
4DE5
GOSUB to 4FECH: if two or more of the letters B-G are used in the ten records, record 0 is made unusable (4302H = 00H) and the NO CARRY FLAG is returned.
4DE8
LD HL,50DCH 21 DC 50
Point Register Pair HL to 50DCH, the message TI= SPEC BETWEEN DRIVES INCOMPATIBLE. LD does not change the flags.
4DEB
If the NO CARRY FLAG is set (a mix of interface letters), GOSUB to SYS0/SYS 4467H, which displays the message at Register Pair HL (ended by its 0DH).
4DEE
LD A,(4302H) 3A 02 43
Load Register A with the byte at 4302H, record 0's byte +02H: 00H when any record is unusable or the letters are mixed.
4DF1
OR A B7
OR Register A with itself to set the flags: the Z FLAG is set for 00H.
4DF2
If the Z FLAG is set (an error was shown), JUMP to SYS0/SYS 4030H, which ends the command as one whose error is already displayed. SYS0/SYS's table is not changed.
4DF5
LD A,00H 3E 00
Self-Modifying Code
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.
4DF7
OR A B7
OR Register A with itself to set the flags: the Z FLAG is set if no A or B option was given.
4DF8
RET Z C8
If the Z FLAG is set (no option), RETURN to the dispatcher's tail 4BC5H with Register A = 00H, no error.
4DF9
LD HL,4300H 21 00 43
Point Register Pair HL to 4300H, record 0 in the sector buffer.
4DFC
LD DE,4291H 11 91 42
Point Register Pair DE to 4291H, SYS0/SYS's PDRIVE table (10 bytes for each of drives 0-3).
4DFF
LD A,(43A0H) 3A A0 43
Load Register A with the byte at 43A0H, byte A0H of the system data sector: option AL, the number of drives.
4E02
DEC A 3D
DECrement Register A, option AL: 1-4 drives become 0-3.
4E03
CP 04H FE 04
Compare Register A against 04H. The CARRY FLAG is set for 0-3.
4E05
If the CARRY FLAG is set, JUMP to 4E09H with Register A = 0-3.
4E07
LD A,03H 3E 03
Load Register A with 03H: an AL of 0 or above 4 is taken as 4 drives.
4E09
INC A 3C
INCrement Register A: Register A = 1-4, the records to copy. 4E05H comes here.

Copy Loop
Register Pair HL = the record in the sector, Register Pair DE = SYS0/SYS's table, Register A = the records left.

4E0A
LD BC,000AH 01 0A 00
Load Register Pair BC with 000AH (10), the bytes of a record that SYS0/SYS keeps in memory. 4E13H comes back here.
4E0D
LDIR ED B0
LDIR: copy Register Pair BC (10) bytes from Register Pair HL (record bytes +00H-+09H) to Register Pair DE (SYS0/SYS's table), upward; Register Pair BC ends at 0000H.
4E0F
LD C,06H 0E 06
Load Register C with 06H: Register Pair BC = 0006H, the bytes of the record not copied.
4E11
ADD HL,BC 09
ADD Register Pair BC (6) to Register Pair HL: Register Pair HL = the next record in the sector.
4E12
DEC A 3D
DECrement Register A, the records left to copy.
4E13
If the NZ FLAG is set (records left), LOOP BACK to 4E0AH.
4E15
RET C9
RETURN to the dispatcher's tail 4BC5H with Register A = 00H and the Z FLAG: SYS0/SYS's table now holds the new values.

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.

4E16
LD (4EA2H),A 32 A2 4E
Self-Modifying Code
Store Register A (the record number) at 4EA2H, the operand of the LD A,FFH at 4EA1H. 4DDCH calls here.
4E19
PUSH AF F5
Save Register Pair AF (Register A = the record number) onto the stack.
4E1A
ADD A,30H C6 30
ADD 30H to Register A: the record number 0-9 as an ASCII digit.
4E1C
GOSUB to 500FH, which displays the character in Register A.
4E1F
LD B,03H 06 03
Load Register B with 03H, the columns to fill after the digit.
4E21
POP AF F1
Restore Register Pair AF from the stack: Register A = the record number.
4E22
LD HL,43A0H 21 A0 43
Point Register Pair HL to 43A0H, byte A0H of the system data sector: option AL, the number of drives.
4E25
CP (HL) BE
Compare Register A (the record number) against the byte at Register Pair HL (option AL). The CARRY FLAG is set for a drive in use.
4E26
If the NO CARRY FLAG is set (not a drive in use), JUMP to 4E2EH.
4E28
DEC B 05
DECrement Register B: the asterisk takes one of the three columns.
4E29
LD A,2AH 3E 2A
Load Register A with 2AH, an asterisk, marking a drive in use.
4E2B
GOSUB to 500FH, which displays the asterisk in Register A.
4E2E
LD A,20H 3E 20
Load Register A with 20H, a space. 4E26H and 4E33H come here.
4E30
GOSUB to 500FH, which displays the space in Register A.
4E33
DECrement Register B and LOOP BACK to 4E2EH until the columns are filled.
4E35
LD BC,511CH 01 1C 51
Load Register Pair BC with 511CH, the keyword table.

Keyword Loop
Register Pair BC walks the keyword table: the keyword's characters, 00H, the attribute byte.

4E38
LD A,(BC) 0A
Load Register A with the byte at Register Pair BC, a character of the keyword (00H at its end). 4E3EH and 4E7CH come back here.
4E39
OR A B7
OR Register A with itself to set the flags: the Z FLAG is set at the 00H.
4E3A
INC BC 03
INCrement Register Pair BC to the next byte of the table. INC BC does not change the flags.
4E3B
If the NZ FLAG is set (a character of the keyword), GOSUB to 500FH, which displays it in Register A and keeps the flags.
4E3E
If the NZ FLAG is set, LOOP BACK to 4E38H; after the 00H, Register Pair BC points at the attribute byte.
4E40
GOSUB to 4E97H, which returns Index Register IX = the field of the record for this keyword (the attribute's low four bits).
4E43
LD A,(BC) 0A
Load Register A with the byte at Register Pair BC, the keyword's attribute byte.
4E44
INC BC 03
INCrement Register Pair BC to the next keyword of the table.
4E45
LD E,(IX+00H) DD 5E 00
Load Register E with the byte at Index Register IX+00H, the field's value.
4E48
LD D,(IX+01H) DD 56 01
Load Register D with the byte at Index Register IX+01H, the byte after the field (for TI=, the letters I-P).
4E4B
PUSH BC C5
Save Register Pair BC (the table pointer) onto the stack.
4E4C
BIT 7,A CB 7F
Test bit 7 of Register A, the attribute byte: set for a number.
4E4E
If the NZ FLAG is set (a number), JUMP to 4E6DH.
4E50
BIT 6,A CB 77
Test bit 6 of Register A, the attribute byte: set for TI=, a list of letters.
4E52
If the NZ FLAG is set (TI=, a list of letters), JUMP to 4E5CH to show them.
4E54
LD A,E 7B
TD=: load Register A with Register E, the drive type as 0-25.
4E55
ADD A,41H C6 41
ADD 41H (ASCII A) to Register A: the drive type letter.
4E57
GOSUB to 500FH, which displays the letter in Register A.
4E5A
JUMP to 4E72H for the next keyword, with the table pointer on the stack.
4E5C
LD B,10H 06 10
TI=: load Register B with 10H (16), the letters A-P to look at.
4E5E
LD C,41H 0E 41
Load Register C with 41H, ASCII A, the first letter.

Letter Loop
Register Pair DE = the letter bits (Register E A-H, Register D I-P), shifted right one bit each pass.

4E60
RR D CB 1A
Rotate Register D right through the CARRY FLAG (RR): its bit 0 goes to the CARRY FLAG. 4E69H comes back here.
4E62
RR E CB 1B
Rotate Register E right through the CARRY FLAG (RR): Register D's bit 0 enters bit 7 and the next letter's bit falls into the CARRY FLAG.
4E64
LD A,C 79
Load Register A with Register C, the letter for this bit.
4E65
INC C 0C
INCrement Register C to the next letter. INC does not change the CARRY FLAG.
4E66
If the CARRY FLAG is set (the letter is in the list), GOSUB to 500FH, which displays the letter in Register A.
4E69
DECrement Register B and LOOP BACK to 4E60H for all 16 letters.
4E6B
JUMP to 4E72H for the next keyword, with the table pointer on the stack.
4E6D
LD D,00H 16 00
A number: load Register D with 00H, so that Register Pair DE = the field's value in Register E. 4E4EH comes here.
4E6F
GOSUB to 5099H, which displays Register Pair DE in decimal without leading zeros.
4E72
POP BC C1
Restore Register Pair BC from the stack: the table pointer at the next keyword. 4E5AH and 4E6BH come here.
4E73
LD A,(BC) 0A
Load Register A with the byte at Register Pair BC, the next keyword's first character (00H at the end of the table, 514BH).
4E74
OR A B7
OR Register A with itself to set the flags: the Z FLAG is set at the end of the table.
4E75
If the Z FLAG is set (all keywords shown), JUMP to 4E7EH.
4E77
LD A,2CH 3E 2C
Load Register A with 2CH, a comma between two keywords.
4E79
GOSUB to 500FH, which displays the comma in Register A.
4E7C
JUMP to 4E38H for the next keyword at Register Pair BC.
4E7E
GOSUB to 4EB0H, which checks this record and works out its derived bytes; Index Register IX returns pointing at the record. 4E75H comes here.
4E81
LD A,(IX+02H) DD 7E 02
Load Register A with the byte at Index Register IX+02H, record byte +02H as 4EB0H left it (Index Register IX = the record, set at 4EB1H).
4E84
AND 1CH E6 1C
AND Register A with 1CH, keeping bits 2-4, the interface code: 00H for an unusable record.
4E86
If the NZ FLAG is set (an interface code, the record is usable), JUMP to 4E92H to end the line.
4E88
LD HL,50CBH 21 CB 50
Point Register Pair HL to 50CBH, the text Error between groups of three asterisks, ended by 03H.
4E8B
GOSUB to SYS0/SYS 4467H, which displays the text at Register Pair HL up to the 03H.
4E8E
XOR A AF
Load Register A with 00H (XOR A with itself).
4E8F
LD (4302H),A 32 02 43
Store Register A (00H) at 4302H, record 0's byte +02H: any unusable record makes the command end through 4030H at 4DF2H.
4E92
LD A,0DH 3E 0D
Load Register A with 0DH, a carriage return that ends the record's line. 4E86H comes here.
4E94
JUMP to 500FH, which displays the carriage return and returns to 4DDFH.

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.

4E97
LD A,(BC) 0A
Load Register A with the byte at Register Pair BC, the keyword's attribute byte. 4D4EH and 4E40H call here.
4E98
AND 0FH E6 0F
AND Register A with 0FH, keeping bits 3-0: the field's offset in the record.
4E9A
PUSH HL E5
Save Register Pair HL onto the stack; 4EAEH restores it. 4D31H and 4EB1H call here with the offset in Register A.
4E9B
PUSH DE D5
Save Register Pair DE onto the stack; 4EADH restores it.
4E9C
LD HL,4300H 21 00 43
Point Register Pair HL to 4300H, record 0 in the sector buffer.
4E9F
LD D,L 55
Load Register D with Register L (00H), the high byte of the offset.
4EA0
LD E,A 5F
Load Register E with Register A, the field's offset in the record.
4EA1
LD A,FFH 3E FF
Self-Modifying Code
Load Register A with the record number: the operand 4EA2H is FFH in the file and is stored at 4D1CH, 4DA5H and 4E16H.
4EA3
RLCA 07
Rotate Register A (the record number) left (RLCA): times 2.
4EA4
RLCA 07
Rotate Register A left (RLCA): the record number times 4.
4EA5
RLCA 07
Rotate Register A left (RLCA): the record number times 8.
4EA6
RLCA 07
Rotate Register A left (RLCA): times 16, the record's offset in the sector.
4EA7
ADD A,E 83
ADD Register E (the field's offset) to Register A.
4EA8
LD E,A 5F
Load Register E with Register A: Register Pair DE = the field's offset in the sector.
4EA9
ADD HL,DE 19
ADD Register Pair DE to Register Pair HL (4300H): Register Pair HL = the field's address.
4EAA
PUSH HL E5
Save Register Pair HL (the field's address) onto the stack.
4EAB
POP IX DD E1
Restore Index Register IX from the stack: Index Register IX = the field's address.
4EAD
POP DE D1
Restore Register Pair DE from the stack, as the caller had it.
4EAE
POP HL E1
Restore Register Pair HL from the stack, as the caller had it.
4EAF
RET C9
RETURN with Index Register IX = the field's address in the sector buffer.

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).

4EB0
XOR A AF
Load Register A with 00H (XOR A with itself), the offset of the record's first byte. 4DA9H and 4E7EH call here.
4EB1
GOSUB to 4E9AH, which returns Index Register IX = the record (4300H + 16 x the record number).
4EB4
LD A,(IX+02H) DD 7E 02
Load Register A with the byte at Index Register IX+02H, record byte +02H.
4EB7
AND E3H E6 E3
AND Register A with E3H, clearing bits 2-4, the interface code: the record is unusable unless the checks below all pass.
4EB9
LD (IX+02H),A DD 77 02
Store Register A at Index Register IX+02H, record byte +02H.
4EBC
LD A,(IX+04H) DD 7E 04
Load Register A with the byte at Index Register IX+04H, SPT, the sectors per track.
4EBF
OR A B7
OR Register A with itself to set the flags: the Z FLAG is set for 0.
4EC0
LD C,A 4F
Load Register C with Register A, SPT. LD does not change the flags.
4EC1
RET Z C8
If the Z FLAG is set (SPT = 0), RETURN: the record stays unusable.
4EC2
LD A,(IX+0FH) DD 7E 0F
Load Register A with the byte at Index Register IX+0FH, TD, the drive type 0-25.
4EC5
CP 08H FE 08
Compare Register A against 08H. The CARRY FLAG is set for A-H (0-7).
4EC7
LD E,A 5F
Load Register E with Register A, TD. LD does not change the flags.
4EC8
LD D,00H 16 00
Load Register D with 00H: Register Pair DE = TD, an index into the table at 5106H.
4ECA
If the NO CARRY FLAG is set (TD above H), JUMP to 4ED3H; the TD check at 4F6FH makes the record unusable later.
4ECC
LD HL,5106H 21 06 51
Point Register Pair HL to 5106H, the table of the most sectors per track for each drive type A-H.
4ECF
ADD HL,DE 19
ADD Register Pair DE (TD) to Register Pair HL: Register Pair HL = TD's entry.
4ED0
LD A,(HL) 7E
Load Register A with the byte at Register Pair HL, the most sectors per track this drive type can hold.
4ED1
CP C B9
Compare Register A (the most) against Register C (SPT). The CARRY FLAG is set if SPT is higher.
4ED2
RET C D8
If the CARRY FLAG is set (too many sectors per track), RETURN: the record stays unusable.
4ED3
LD L,C 69
Load Register L with Register C, SPT, for the multiplication. 4ECAH comes here.
4ED4
LD A,(IX+03H) DD 7E 03
Load Register A with the byte at Index Register IX+03H, TC, the number of tracks.
4ED7
OR A B7
OR Register A with itself to set the flags: the Z FLAG is set for 0.
4ED8
RET Z C8
If the Z FLAG is set (TC = 0), RETURN: the record stays unusable.
4ED9
GOSUB to SYS0/SYS 4C37H, which multiplies Register L (SPT) by Register A (TC): Register Pair HL = the sectors on the diskette (Register Pair BC is kept).
4EDC
BIT 4,(IX+0EH) DD CB 0E 66
Test bit 4 of the byte at Index Register IX+0EH, record byte +0EH: TI M.
4EE0
LD A,05H 3E 05
Load Register A with 05H, the sectors per granule. LD does not change the flags.
4EE2
If the Z FLAG is set (no TI M), JUMP to 4EE6H with Register A = 5.
4EE4
LD A,03H 3E 03
TI M: load Register A with 03H, three sectors per granule.
4EE6
GOSUB to SYS0/SYS 4C59H, which divides Register Pair HL (the sectors) by Register A: Register Pair HL = the granules on the diskette; Register B returns 00H. 4EE2H comes here.
4EE9
LD A,(IX+09H) DD 7E 09
Load Register A with the byte at Index Register IX+09H, DDGA, the granules of the directory.
4EEC
CP 02H FE 02
Compare Register A against 02H. The CARRY FLAG is set for 0 or 1.
4EEE
LD B,A 47
Load Register B with Register A, DDGA, the count for the loop at 4F06H. LD does not change the flags.
4EEF
RET C D8
If the CARRY FLAG is set (DDGA below 2), RETURN: the record stays unusable.
4EF0
CP 07H FE 07
Compare Register A (DDGA) against 07H. The NO CARRY FLAG is set for 7 or more.
4EF2
RET NC D0
If the NO CARRY FLAG is set (DDGA above 6), RETURN: the record stays unusable.
4EF3
EX DE,HL EB
Exchange Register Pairs DE and HL: Register Pair DE = the granules on the diskette.
4EF4
LD L,(IX+08H) DD 6E 08
Load Register L with the byte at Index Register IX+08H, DDSL, the lump where the directory starts.
4EF7
LD (IX+00H),L DD 75 00
Store Register L (DDSL) at Index Register IX+00H, record byte +00H, the directory lump SYS0/SYS uses.
4EFA
LD A,(IX+05H) DD 7E 05
Load Register A with the byte at Index Register IX+05H, GPL, the granules per lump.
4EFD
OR A B7
OR Register A with itself to set the flags: the Z FLAG is set for 0.
4EFE
LD C,A 4F
Load Register C with Register A, GPL. LD does not change the flags.
4EFF
RET Z C8
If the Z FLAG is set (GPL = 0), RETURN: the record stays unusable.
4F00
CP 09H FE 09
Compare Register A (GPL) against 09H. The NO CARRY FLAG is set for 9 or more.
4F02
RET NC D0
If the NO CARRY FLAG is set (GPL above 8), RETURN: the record stays unusable.
4F03
GOSUB to SYS0/SYS 4C37H, which multiplies Register L (DDSL) by Register A (GPL): Register Pair HL = the directory's first granule (Register Pair BC is kept).

Directory End Loop
Register B = DDGA, Register Pair HL counts the directory's granules.

4F06
INC HL 23
INCrement Register Pair HL, one granule of the directory. 4F07H comes back here.
4F07
DECrement Register B (DDGA) and LOOP BACK to 4F06H: Register Pair HL = the first granule after the directory.
4F09
EX DE,HL EB
Exchange Register Pairs DE and HL: Register Pair DE = the first granule after the directory, Register Pair HL = the granules on the diskette.
4F0A
OR A B7
OR Register A with itself, which clears the CARRY FLAG for the SBC.
4F0B
SBC HL,DE ED 52
SUBtract Register Pair DE from Register Pair HL with the CARRY FLAG: the CARRY FLAG is set if the directory runs past the end of the diskette.
4F0D
RET C D8
If the CARRY FLAG is set (the directory does not fit), RETURN: the record stays unusable.
4F0E
ADD HL,DE 19
ADD Register Pair DE back to Register Pair HL: Register Pair HL = the granules on the diskette again.
4F0F
LD A,C 79
Load Register A with Register C, GPL, the divisor.
4F10
GOSUB to SYS0/SYS 4C59H, which divides Register Pair HL (the granules) by Register A (GPL): Register Pair HL = the whole lumps, Register A = the granules left over, with the Z FLAG if there are none.
4F13
If the Z FLAG is set (no part lump), JUMP to 4F16H.
4F15
INC HL 23
INCrement Register Pair HL: a part lump counts as one more lump.
4F16
LD (IX+01H),L DD 75 01
Store Register L (the number of lumps) at Index Register IX+01H, record byte +01H. 4F13H comes here.
4F19
DEC HL 2B
DECrement Register Pair HL: the number of the last lump.
4F1A
LD DE,00C0H 11 C0 00
Load Register Pair DE with 00C0H (192), the number of lumps a GAT sector can hold.
4F1D
OR A B7
OR Register A with itself, which clears the CARRY FLAG for the SBC.
4F1E
SBC HL,DE ED 52
SUBtract Register Pair DE (192) from Register Pair HL (the last lump) with the CARRY FLAG: the NO CARRY FLAG is set for more than 192 lumps.
4F20
RET NC D0
If the NO CARRY FLAG is set (too many lumps), RETURN: the record stays unusable.
4F21
LD C,(IX+0DH) DD 4E 0D
Load Register C with the byte at Index Register IX+0DH, record byte +0DH: TI letters A-H in bits 0-7.
4F24
LD B,(IX+0EH) DD 46 0E
Load Register B with the byte at Index Register IX+0EH, record byte +0EH: TI letters I-P in bits 0-7.
4F27
LD A,C 79
Load Register A with Register C, the letters A-H.
4F28
AND 7FH E6 7F
AND Register A with 7FH, dropping H (bit 7), which is not an interface letter.
4F2A
LD L,A 6F
Load Register L with Register A, the letters A-G.
4F2B
LD A,B 78
Load Register A with Register B, the letters I-P.
4F2C
AND 00H E6 00
AND Register A with 00H: none of the letters I-P is an interface letter, so Register A = 00H.
4F2E
LD H,A 67
Load Register H with Register A (00H): Register Pair HL = the interface letters A-G as 16 bits.
4F2F
LD D,10H 16 10
Load Register D with 10H (16), the bits of Register Pair HL to count.
4F31
XOR A AF
Load Register A with 00H (XOR A with itself), the count of interface letters.

Count Loop
Register Pair HL is shifted left 16 times; Register A counts the bits that come out.

4F32
ADD HL,HL 29
ADD Register Pair HL to itself: its top bit goes into the CARRY FLAG. 4F36H comes back here.
4F33
ADC A,00H CE 00
ADD 00H with the CARRY FLAG (ADC) to Register A, counting the bit.
4F35
DEC D 15
DECrement Register D, the bits left to count.
4F36
If the NZ FLAG is set (bits left), LOOP BACK to 4F32H.
4F38
DEC A 3D
DECrement Register A, the count of interface letters: the Z FLAG is set if exactly one of A-G was given.
4F39
RET NZ C0
If the NZ FLAG is set (none, or more than one), RETURN: the record stays unusable.
4F3A
LD A,C 79
Load Register A with Register C, the letters A-H.
4F3B
AND 76H E6 76
AND Register A with 76H, keeping B, C, E, F and G (bits 1, 2, 4, 5 and 6): only A and D are interface letters that this DOS accepts.
4F3D
RET NZ C0
If the NZ FLAG is set (B, C, E, F or G given), RETURN: the record stays unusable.
4F3E
LD A,B 78
Load Register A with Register B, the letters I-P.
4F3F
AND E0H E6 E0
AND Register A with E0H, keeping N, O and P (bits 5-7), which have no meaning.
4F41
RET NZ C0
If the NZ FLAG is set (N, O or P given), RETURN: the record stays unusable.
4F42
LD D,14H 16 14
Load Register D with 14H, the interface code 5 in bits 4-2 for TI E.
4F44
LD L,(IX+0FH) DD 6E 0F
Load Register L with the byte at Index Register IX+0FH, TD, the drive type 0-7 (bit 0 an 8 inch drive, bit 1 two sides, bit 2 double density).
4F47
BIT 4,C CB 61
Test bit 4 of Register C, the letters A-H: TI E. It is never set here, since 4F3BH refused it.
4F49
If the NZ FLAG is set (TI E), JUMP to 4F6EH, which allows every drive type.
4F4B
LD D,08H 16 08
Load Register D with 08H, the interface code 2 in bits 4-2 for TI D.
4F4D
BIT 3,C CB 59
Test bit 3 of Register C, the letters A-H: TI D, the Apparat controller.
4F4F
If the NZ FLAG is set (TI D), JUMP to 4F6EH: every drive type A-H is allowed.
4F51
BIT 1,C CB 49
Test bit 1 of Register C, the letters A-H: TI B. It is never set here, since 4F3BH refused it.
4F53
If the Z FLAG is set (no TI B), JUMP to 4F5BH.
4F55
LD D,0CH 16 0C
Load Register D with 0CH, the interface code 3 in bits 4-2 for TI B (never reached).
4F57
BIT 2,L CB 55
Test bit 2 of Register L, TD's double density bit (never reached).
4F59
JUMP to 4F6DH, where the NZ FLAG makes the record unusable (never reached).
4F5B
BIT 2,C CB 51
Test bit 2 of Register C, the letters A-H: TI C. It is never set here, since 4F3BH refused it. 4F53H comes here.
4F5D
If the Z FLAG is set (no TI C), JUMP to 4F65H.
4F5F
LD D,10H 16 10
Load Register D with 10H, the interface code 4 in bits 4-2 for TI C (never reached).
4F61
BIT 0,L CB 45
Test bit 0 of Register L, TD's 8 inch bit (never reached).
4F63
JUMP to 4F6DH, where the NZ FLAG makes the record unusable (never reached).
4F65
BIT 0,C CB 41
Test bit 0 of Register C, the letters A-H: TI A, the standard controller. 4F5DH comes here.
4F67
RET Z C8
If the Z FLAG is set (no TI A), RETURN: the record stays unusable.
4F68
LD D,04H 16 04
Load Register D with 04H, the interface code 1 in bits 4-2 for TI A.
4F6A
LD A,L 7D
Load Register A with Register L, TD, the drive type 0-7 read at 4F44H.
4F6B
AND 01H E6 01
AND Register A with 01H, keeping TD's bit 0: set for the 8 inch types B, D, F and H, which TI A does not allow.
4F6D
RET NZ C0
If the NZ FLAG is set (a drive type the interface does not allow), RETURN: the record stays unusable. 4F59H and 4F63H come here.
4F6E
LD A,L 7D
Load Register A with Register L, TD. 4F49H and 4F4FH come here.
4F6F
CP 08H FE 08
Compare Register A against 08H. The NO CARRY FLAG is set for a drive type above H.
4F71
RET NC D0
If the NO CARRY FLAG is set, RETURN: the record stays unusable.
4F72
LD E,00H 1E 00
Load Register E with 00H, the disk I/O flags being built for byte +07H.
4F74
BIT 2,L CB 55
Test bit 2 of Register L, TD's double density bit (E, F, G, H).
4F76
If the Z FLAG is set (single density), JUMP to 4F7AH.
4F78
SET 0,E CB C3
Set bit 0 of Register E: disk I/O flag bit 0, double density.
4F7A
BIT 0,L CB 45
Test bit 0 of Register L, TD's 8 inch bit (B, D, F, H). 4F76H comes here.
4F7C
If the Z FLAG is set (a 5 inch drive), JUMP to 4F80H.
4F7E
SET 7,E CB FB
Set bit 7 of Register E: disk I/O flag bit 7, an 8 inch drive.
4F80
BIT 1,L CB 4D
Test bit 1 of Register L, TD's two sides bit (C, D, G, H). 4F7CH comes here.
4F82
If the Z FLAG is set (one side), JUMP to 4F86H.
4F84
SET 6,E CB F3
Set bit 6 of Register E: disk I/O flag bit 6, two sides.
4F86
LD A,(IX+0CH) DD 7E 0C
Load Register A with the byte at Index Register IX+0CH, TSR, the step rate code. 4F82H comes here.
4F89
CP 04H FE 04
Compare Register A against 04H. The NO CARRY FLAG is set for 4 or more.
4F8B
RET NC D0
If the NO CARRY FLAG is set (TSR above 3), RETURN: the record stays unusable.
4F8C
OR D B2
OR Register A (TSR) with Register D (the interface code): bits 1-0 the step rate, bits 4-2 the interface.
4F8D
LD D,A 57
Load Register D with Register A, record byte +02H so far.
4F8E
BIT 4,B CB 60
Test bit 4 of Register B, the letters I-P: TI M (three sectors per granule at 4EE4H).
4F90
If the Z FLAG is set (no TI M), JUMP to 4F9CH.
4F92
SET 5,D CB EA
Set bit 5 of Register D: record byte +02H bit 5, TI M.
4F94
SET 4,E CB E3
Set bit 4 of Register E: disk I/O flag bit 4, sectors numbered from 1 (TI M includes TI I).
4F96
LD A,(IX+05H) DD 7E 05
Load Register A with the byte at Index Register IX+05H, GPL, the granules per lump.
4F99
CP 06H FE 06
Compare Register A against 06H. The Z FLAG is set for GPL = 6.
4F9B
RET NZ C0
If the NZ FLAG is set (GPL is not 6), RETURN: TI M needs GPL=6, so the record stays unusable.
4F9C
BIT 3,B CB 58
Test bit 3 of Register B, the letters I-P: TI L, two step pulses per track. 4F90H comes here.
4F9E
If the Z FLAG is set (no TI L), JUMP to 4FA2H.
4FA0
SET 2,E CB D3
Set bit 2 of Register E: disk I/O flag bit 2, double step.
4FA2
BIT 7,C CB 79
Test bit 7 of Register C, the letters A-H: TI H, a head settle delay. 4F9EH comes here.
4FA4
If the Z FLAG is set (no TI H), JUMP to 4FA8H.
4FA6
SET 7,D CB FA
Set bit 7 of Register D: record byte +02H bit 7, the head settle delay SYS0/SYS waits when it changes to this drive.
4FA8
BIT 1,B CB 48
Test bit 1 of Register B, the letters I-P: TI J, tracks numbered from 1. 4FA4H comes here.
4FAA
If the Z FLAG is set (no TI J), JUMP to 4FAEH.
4FAC
SET 1,E CB CB
Set bit 1 of Register E: disk I/O flag bit 1, tracks numbered from 1.
4FAE
BIT 0,B CB 40
Test bit 0 of Register B, the letters I-P: TI I, sectors numbered from 1. 4FAAH comes here.
4FB0
If the Z FLAG is set (no TI I), JUMP to 4FB4H.
4FB2
SET 4,E CB E3
Set bit 4 of Register E: disk I/O flag bit 4, sectors numbered from 1.
4FB4
BIT 2,B CB 50
Test bit 2 of Register B, the letters I-P: TI K, track 0 in the other density. 4FB0H comes here.
4FB6
If the Z FLAG is set (no TI K), JUMP to 4FBCH.
4FB8
SET 6,D CB F2
Set bit 6 of Register D: record byte +02H bit 6, TI K.
4FBA
SET 1,E CB CB
Set bit 1 of Register E: disk I/O flag bit 1, tracks numbered from 1 (TI K includes TI J).
4FBC
LD (IX+07H),E DD 73 07
Store Register E (the disk I/O flags) at Index Register IX+07H, record byte +07H. 4FB6H comes here.
4FBF
LD (IX+02H),D DD 72 02
Store Register D at Index Register IX+02H, record byte +02H: with the interface code in bits 4-2 the record is usable.
4FC2
RET C9
RETURN with the record's derived bytes complete.

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).

4FC3
LD A,02H 3E 02
Load Register A with 02H, the number of the system data sector on the diskette. 4D0BH and 4DD3H call here.
4FC5
LD (5118H),A 32 18 51
Self-Modifying Code
Store Register A (02H) at 5118H, FCB+10 of the FCB at 510EH: the middle byte of NEXT, so that NEXT = sector 2.
4FC8
LD DE,510EH 11 0E 51
Load Register Pair DE with 510EH, the FCB that reads and writes the system data sector.
4FCB
RET C9
RETURN with Register Pair DE = 510EH, the FCB with NEXT at 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.

4FCC
GOSUB to SYS0/SYS 4C7AH, which looks at the character at Register Pair HL: the Z FLAG at the carriage return; a comma or spaces give the NZ FLAG with Register Pair HL past them; anything else gives the CARRY FLAG with Register A = 34H. 4D12H, 4D3FH and 4D9EH call here.
4FCF
RET C D8
If the CARRY FLAG is set (not a separator), RETURN with it and Register A = 34H.
4FD0
RET Z C8
If the Z FLAG is set (the end of the line), RETURN with it.
4FD1
LD A,(5114H) 3A 14 51
Load Register A with the byte at 5114H, FCB+6, dn1 (stored at 4D08H).
4FD4
OR A B7
OR Register A with itself to set the flags: the Z FLAG is set for dn1 = 0.
4FD5
RET NZ C0
If the NZ FLAG is set (dn1 is not 0), RETURN with the NZ FLAG: a parameter follows.
4FD6
LD DE,4DF6H 11 F6 4D
Point Register Pair DE to 4DF6H, the A/B option flag (the operand of the LD A at 4DF5H).
4FD9
LD A,(DE) 1A
Load Register A with the byte at Register Pair DE (4DF6H), the A/B option flag.
4FDA
OR A B7
OR Register A with itself to set the flags: the Z FLAG is set if no option has been taken yet.
4FDB
RET NZ C0
If the NZ FLAG is set (an option was already taken), RETURN with the NZ FLAG: a parameter follows.
4FDC
LD A,(HL) 7E
Load Register A with the byte at Register Pair HL, the first character of the parameter.
4FDD
JUMP to 51C6H, which looks for A or B in Register A and comes back to 4FE2H or 4FE8H.
4FE0-4FE1
DEFB 00H x 2 00 x 2
Two bytes of 00H between the JP at 4FDDH and 4FE2H; nothing jumps to them.
4FE2
INC HL 23
INCrement Register Pair HL past the A (or the B, overwritten with an A at 51D6H). 51CBH and 51E5H jump here.
4FE3
GOSUB to SYS0/SYS 4C7AH, which looks at the character after the letter at Register Pair HL: the NO CARRY FLAG for the end of the line or a separator.
4FE6
RET NC D0
If the NO CARRY FLAG is set (the letter stands alone: the option), RETURN with the flags of 4C7AH (Z at the end of the line, NZ when a parameter follows).
4FE7
DEC HL 2B
The letter begins a longer word: DECrement Register Pair HL back to it.
4FE8
XOR A AF
Load Register A with 00H (XOR A with itself). 51D0H jumps here when the character is neither A nor B.
4FE9
LD (DE),A 12
Store Register A (00H) at Register Pair DE (4DF6H): no A/B option. A B taken at 51CEH has already removed the write at 4DD3H-4DD9H.
4FEA
INC A 3C
INCrement Register A to 01H, which gives the NZ FLAG: a parameter follows.
4FEB
RET C9
RETURN with the NZ FLAG and Register Pair HL at the parameter.

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.

4FEC
LD HL,430DH 21 0D 43
Point Register Pair HL to 430DH, byte +0DH (TI letters A-H) of record 0. 4DB2H and 4DE5H call here.
4FEF
LD BC,A00H 01 00 0A
Load Register Pair BC with 0A00H: Register B = 10 records, Register C = 00H, the letters collected.
4FF2
LD DE,0010H 11 10 00
Load Register Pair DE with 0010H (16), the length of a record.

Collect Loop
Register Pair HL = byte +0DH of the record, Register C = the letters B-G found so far.

4FF5
LD A,(HL) 7E
Load Register A with the byte at Register Pair HL, the record's TI letters A-H. 4FFBH comes back here.
4FF6
AND 7EH E6 7E
AND Register A with 7EH, keeping the letters B-G (bits 1-6).
4FF8
OR C B1
OR Register A with Register C, adding the letters found so far.
4FF9
LD C,A 4F
Load Register C with Register A, the letters B-G of the records looked at.
4FFA
ADD HL,DE 19
ADD Register Pair DE (16) to Register Pair HL: byte +0DH of the next record.
4FFB
DECrement Register B and LOOP BACK to 4FF5H for all ten records.
4FFD
LD B,08H 06 08
Load Register B with 08H, the bits of Register C to count.
4FFF
XOR A AF
Load Register A with 00H (XOR A with itself), the count.

Count Loop
Register C is rotated eight times; Register A counts its set bits.

5000
RLC C CB 01
Rotate Register C left (RLC): its top bit goes into the CARRY FLAG and to bit 0. 5005H comes back here.
5002
If the NO CARRY FLAG is set (that letter is not used), JUMP to 5005H.
5004
INC A 3C
INCrement Register A, the count of different letters.
5005
DECrement Register B and LOOP BACK to 5000H for the eight bits; Register C is back as it was. 5002H comes here.
5007
CP 02H FE 02
Compare Register A (the count) against 02H. The CARRY FLAG is set for 0 or 1.
5009
RET C D8
If the CARRY FLAG is set (at most one kind of interface letter), RETURN with the CARRY FLAG.
500A
XOR A AF
Load Register A with 00H (XOR A with itself).
500B
LD (4302H),A 32 02 43
Store Register A (00H) at 4302H, record 0's byte +02H: the command ends through 4030H at 4DF2H.
500E
RET C9
RETURN with the NO CARRY FLAG (cleared by the XOR): the letters are mixed.

500FH - Show a Character

Shows the character in Register A through the ROM routine 0033H, keeping Register Pairs AF and DE.

500F
PUSH DE D5
Save Register Pair DE onto the stack; the ROM display routine changes it.
5010
PUSH AF F5
Save Register Pair AF (Register A = the character, and the flags) onto the stack.
5011
GOSUB to the ROM routine at 0033H, which displays the character in Register A at the cursor.
5014
POP AF F1
Restore Register Pair AF from the stack: Register A = the character and the flags as they were.
5015
POP DE D1
Restore Register Pair DE from the stack, as it was before the ROM call.
5016
RET C9
RETURN with Register Pairs AF and DE unchanged.

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.

5017
GOSUB to SYS0/SYS 4C6AH, which compares the 00H-ended word at Register Pair BC with the text at Register Pair HL: on a match the Z FLAG, Register Pair BC past the 00H and Register Pair HL past the text; otherwise the NZ FLAG with Register Pair HL unchanged and Register Pair BC inside the word. 4D4BH calls here; 5028H comes back here.
501A
RET Z C8
If the Z FLAG is set (the word matches), RETURN with Register Pair BC at the attribute byte.
501B
LD A,(BC) 0A
Load Register A with the byte at Register Pair BC, a character of the table word (00H at its end). 501FH comes back here.
501C
CP 00H FE 00
Compare Register A against 00H. The Z FLAG is set at the 00H that ends the table word.
501E
INC BC 03
INCrement Register Pair BC to the next byte of the table. INC BC does not change the flags.
501F
If the NZ FLAG is set (still inside the word), LOOP BACK to 501BH.
5021
LD E,D 5A
Load Register E with Register D, the number of bytes to step over after the 00H (01H).
5022
INC BC 03
INCrement Register Pair BC over one byte after the word's 00H. 5024H comes back here.
5023
DEC E 1D
DECrement Register E, the bytes still to step over. The Z FLAG is set when none are left.
5024
If the NZ FLAG is set (bytes left), LOOP BACK to 5022H.
5026
LD A,(BC) 0A
Load Register A with the byte at Register Pair BC, the first byte of the next entry (00H at the end of the table).
5027
OR A B7
OR Register A with itself to set the flags: the Z FLAG is set at the end of the table.
5028
If the NZ FLAG is set (another entry), LOOP BACK to 5017H to compare it.
502A
LD A,34H 3E 34
Load Register A with 34H, the DOS error code ILLEGAL KEYWORD OR SEPARATOR OR TERMINATOR: the word is not in the table.
502C
JUMP to 503CH to leave through the SYS0/SYS error exit with Register A = 34H.

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.

502E
GOSUB to 503FH, which reads the number at Register Pair HL into Register Pair DE. 4D56H and 4D5EH call here.
5031
JUMP to 5036H to check the number's high byte.
5033
Never executed (nothing calls or jumps here): GOSUB to 505DH, which would read decimal digits only into Register Pair DE.
5036
LD A,D 7A
Load Register A with Register D, the high byte of the number. 5031H comes here.
5037
OR A B7
OR Register A with itself to set the flags: the Z FLAG is set if the number is below 256.
5038
LD A,E 7B
Load Register A with Register E, the number's low byte. LD does not change the flags.
5039
RET Z C8
If the Z FLAG is set (0-255), RETURN with the number in Register A.
503A
LD A,2FH 3E 2F
Load Register A with 2FH, the DOS error code BAD PARAMETER(S). 4D5BH, 5055H and 505BH come here.
503C
JUMP to SYS0/SYS 4409H, the DOS error exit, with the error code in Register A. 4D04H, 4D66H and 502CH come here.

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.

503F
PUSH HL E5
Save Register Pair HL (the start of the number) onto the stack, in case it has to be read again as hexadecimal. 502EH calls here.
5040
GOSUB to 5062H, which sets Register B to 00H (decimal) and reads the digits at Register Pair HL into Register Pair DE; Register Pair HL stops at the first character that is not a digit.
5043
LD A,(HL) 7E
Load Register A with the byte at Register Pair HL, the character after the decimal digits.
5044
SUB 41H D6 41
SUBtract 41H (ASCII A) from Register A: the letters A-H become 00H-07H.
5046
CP 08H FE 08
Compare Register A against 08H. The CARRY FLAG is set for a letter A-H: a hexadecimal digit or the closing H follows.
5048
If the NO CARRY FLAG is set (no letter A-H), JUMP to 5057H: the number is decimal.
504A
POP HL E1
Restore Register Pair HL from the stack: the start of the number, to read it again.
504B
LD B,01H 06 01
Load Register B with 01H: bit 0 set, read hexadecimal digits; bit 1 clear, no digit read yet.
504D
PUSH HL E5
Save Register Pair HL (the start of the number) onto the stack again, to be dropped at 5059H.
504E
GOSUB to 5064H, which reads the hexadecimal digits at Register Pair HL into Register Pair DE.
5051
LD A,(HL) 7E
Load Register A with the byte at Register Pair HL, the character after the hexadecimal digits.
5052
CP 48H FE 48
Compare Register A against 48H (ASCII H). The Z FLAG is set for the closing H.
5054
INC HL 23
INCrement Register Pair HL past the H. INC HL does not change the flags.
5055
If the NZ FLAG is set (no closing H), JUMP to 503AH for error 2FH.
5057
BIT 1,B CB 48
Test bit 1 of Register B: set by 507DH once a digit has been read. 5048H comes here, and the RET of 505DH's digit reading.
5059
POP BC C1
Restore Register Pair BC from the stack, dropping the saved start of the number. POP does not change the flags.
505A
RET NZ C0
If the NZ FLAG is set (at least one digit), RETURN with the number in Register Pair DE and Register Pair HL past it.
505B
JUMP to 503AH for error 2FH (BAD PARAMETER(S)): no digit was read.
505D
PUSH HL E5
Never executed (only the unused 5033H calls it): save Register Pair HL (the start of the number) onto the stack.
505E
LD DE,5057H 11 57 50
Never executed: load Register Pair DE with 5057H, the check that follows the reading.
5061
PUSH DE D5
Never executed: save Register Pair DE (5057H) onto the stack as the return address of the digit reading below.
5062
LD B,00H 06 00
Load Register B with 00H: bit 0 clear (decimal), bit 1 clear (no digit read yet). 5040H calls here.
5064
LD DE,0000H 11 00 00
Load Register Pair DE with 0000H, the value before the first digit. 504EH calls here with Register B = 01H.

Digit Loop
Register Pair HL = the next character, Register Pair DE = the value so far, Register B bit 0 = hexadecimal.

5067
LD A,(HL) 7E
Load Register A with the byte at Register Pair HL, the next character of the number. 5097H comes back here.
5068
SUB 30H D6 30
SUBtract 30H (ASCII 0) from Register A: the digits 0-9 become 00H-09H.
506A
CP 0AH FE 0A
Compare Register A against 0AH. The CARRY FLAG is set for a decimal digit.
506C
If the CARRY FLAG is set (0-9), JUMP to 5078H with the digit's value in Register A.
506E
BIT 0,B CB 40
Test bit 0 of Register B: set when hexadecimal digits are being read.
5070
RET Z C8
If the Z FLAG is set (decimal), RETURN: the number ends at this character.
5071
SUB 11H D6 11
SUBtract 11H more from Register A: the letters A-F (41H-46H, now 11H-16H) become 00H-05H.
5073
CP 06H FE 06
Compare Register A against 06H. The NO CARRY FLAG is set for a character that is not A-F.
5075
RET NC D0
If the NO CARRY FLAG is set (not A-F), RETURN: the number ends at this character.
5076
ADD A,0AH C6 0A
ADD 0AH to Register A: the letters A-F become their values 0AH-0FH.
5078
PUSH HL E5
Save Register Pair HL (the position of the digit) onto the stack. 506CH comes here with a decimal digit.
5079
LD H,D 62
Load Register H with Register D, the high byte of the value so far.
507A
LD L,E 6B
Load Register L with Register E: Register Pair HL = the value so far, and Register Pair DE keeps a copy for the times 5 of a decimal number.
507B
LD C,A 4F
Load Register C with Register A, the value of the new digit.
507C
XOR A AF
Load Register A with 00H (XOR A with itself): Register A collects the carries out of Register Pair HL for this digit.
507D
SET 1,B CB C8
Set bit 1 of Register B: a digit has been read.
507F
ADD HL,HL 29
ADD Register Pair HL to itself: the value times 2. A carry out of bit 15 sets the CARRY FLAG.
5080
ADC A,A 8F
ADD Register A to itself with the CARRY FLAG (ADC): a carry makes Register A non-zero.
5081
ADD HL,HL 29
ADD Register Pair HL to itself: the value times 4.
5082
ADC A,A 8F
ADD Register A to itself with the CARRY FLAG (ADC), collecting the carry.
5083
BIT 0,B CB 40
Test bit 0 of Register B: set for hexadecimal digits.
5085
If the Z FLAG is set (decimal), JUMP to 508AH to make times 5.
5087
ADD HL,HL 29
Hexadecimal: ADD Register Pair HL to itself, the value times 8.
5088
JUMP to 508BH with Register Pair HL = the value times 8.
508A
ADD HL,DE 19
Decimal: ADD Register Pair DE (the value) to Register Pair HL (the value times 4): the value times 5.
508B
ADC A,A 8F
ADD Register A to itself with the CARRY FLAG (ADC), collecting the carry. 5088H comes here.
508C
ADD HL,HL 29
ADD Register Pair HL to itself: the value times 16 (hexadecimal) or times 10 (decimal).
508D
ADC A,A 8F
ADD Register A to itself with the CARRY FLAG (ADC), collecting the carry.
508E
LD E,C 59
Load Register E with Register C, the new digit's value.
508F
LD D,00H 16 00
Load Register D with 00H: Register Pair DE = the new digit.
5091
ADD HL,DE 19
ADD Register Pair DE (the digit) to Register Pair HL.
5092
ADC A,A 8F
ADD Register A to itself with the CARRY FLAG (ADC): Register A is not 00H, and the NZ FLAG is set, if the value passed FFFFH at any step of this digit.
5093
EX DE,HL EB
Exchange Register Pairs DE and HL: Register Pair DE = the new value (its low 16 bits).
5094
POP HL E1
Restore Register Pair HL from the stack: the position of the digit. POP does not change the flags.
5095
RET NZ C0
If the NZ FLAG is set (the value passed FFFFH), RETURN with Register Pair HL still at this digit.
5096
INC HL 23
INCrement Register Pair HL to the next character.
5097
LOOP BACK to 5067H for the next digit at Register Pair HL.

5099H - Show a Number

Shows Register Pair DE in decimal without leading zeros, through 500FH.

5099
LD BC,0400H 01 00 04
Load Register Pair BC with 0400H: Register B = 4, the digits above the units; Register C = 00H, no digit shown yet (leading zeros are left out). 4E6FH calls here.
509C
LD HL,50C3H 21 C3 50
Point Register Pair HL to 50C3H, the table of minus 10000, minus 1000, minus 100 and minus 10.

Digit Loop
Register Pair DE = what is left of the number, Register Pair HL = the next power of ten in the table.

509F
PUSH BC C5
Save Register Pair BC (the digit count and the digit-shown flag) onto the stack. 50BBH comes back here.
50A0
LD C,(HL) 4E
Load Register C with the byte at Register Pair HL, the low byte of the negative power of ten.
50A1
INC HL 23
INCrement Register Pair HL to the high byte of the negative power of ten.
50A2
LD B,(HL) 46
Load Register B with the byte at Register Pair HL: Register Pair BC = minus the power of ten.
50A3
INC HL 23
INCrement Register Pair HL to the next table entry.
50A4
EX DE,HL EB
Exchange Register Pairs DE and HL: Register Pair HL = the number, Register Pair DE = the table pointer.
50A5
LD A,2FH 3E 2F
Load Register A with 2FH, one below ASCII 0, the digit before the first count.
50A7
INC A 3C
INCrement Register A, the digit. 50A9H comes back here.
50A8
ADD HL,BC 09
ADD Register Pair BC (minus the power of ten) to Register Pair HL (the number): the CARRY FLAG is set while the number was not below the power of ten.
50A9
If the CARRY FLAG is set (the power fitted once more), LOOP BACK to 50A7H.
50AB
SBC HL,BC ED 42
SUBtract Register Pair BC (minus the power) from Register Pair HL with the CARRY FLAG (clear here): the last subtraction is undone.
50AD
POP BC C1
Restore Register Pair BC from the stack: Register B = the digits left, Register C = the digit-shown flag.
50AE
EX DE,HL EB
Exchange Register Pairs DE and HL: Register Pair DE = the rest of the number, Register Pair HL = the table pointer.
50AF
CP 30H FE 30
Compare Register A (the digit) against 30H, ASCII 0.
50B1
If the NZ FLAG is set (the digit is not 0), JUMP to 50B7H to show it.
50B3
INC C 0C
INCrement Register C, the digit-shown flag, to test it for 00H without changing it.
50B4
DEC C 0D
DECrement Register C back: the Z FLAG is set if no digit has been shown yet.
50B5
If the Z FLAG is set (a leading zero), JUMP to 50BBH without showing it.
50B7
INC C 0C
INCrement Register C: a digit has been shown, so later zeros are shown. 50B1H comes here.
50B8
GOSUB to 500FH, which shows the digit in Register A.
50BB
DECrement Register B and LOOP BACK to 509FH for the next power of ten. 50B5H comes here.
50BD
LD A,E 7B
Load Register A with Register E, the units left in the number (0-9).
50BE
ADD A,30H C6 30
ADD 30H to Register A: the units digit in ASCII, always shown.
50C0
JUMP to 500FH, which shows the units digit and returns to the caller.

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.

50C3-50CA
DEFW D8F0H, FC18H, FF9CH, FFF6H F0 D8 18 FC 9C FF F6 FF
The negative powers of ten used by 509CH: minus 10000, minus 1000, minus 100 and minus 10.
50CB-50DB
DEFM " *** Error ***" / DEFB 03H 20 20 20 2A 2A 2A 20 45 72 72 6F 72 20 2A 2A 2A 03
Added to the line of an unusable record by 4E88H: three spaces, three asterisks, Error and three asterisks, ended by 03H.
50DC-5105
DEFM "**** TI= SPEC BETWEEN DRIVES INCOMPATIBLE" / DEFB 0DH 2A 2A 2A 2A 20 54 49 3D 20 53 50 45 43 20 42 45 54 57 45 45 4E 20 44 52 49 56 45 53 20 49 4E 43 4F 4D 50 41 54 49 42 4C 45 0D
Shown by 4DE8H when the ten records use two or more of the interface letters B-G, ended by a carriage return.
5106-510D
DEFB 0AH, 11H, 14H, 22H, 12H, 1AH, 24H, 34H 0A 11 14 22 12 1A 24 34
The most sectors per track for the drive types A-H (4ECCH): 10, 17, 20, 34, 18, 26, 36 and 52.
510E
DEFB 82H 82
FCB+0 of the FCB that reads and writes the system data sector: bit 7 open, bit 1 NEXT is a sector number of the whole diskette.
510F
DEFB 60H 60
FCB+1: bit 6 (the end of file only moves forward) and bit 5 (the buffer does not hold the sector at NEXT); access level 0, bit 7 clear (whole sectors).
5110
DEFB 00H 00
FCB+2: 00H, no flags (the open would copy FPDE byte 1 here).
5111-5112
DEFW 4300H 00 43
FCB+3 and +4: the address of the sector buffer, 4300H.
5113
DEFB 00H 00
FCB+5: the low byte of NEXT, the byte within the sector.
5114
DEFB 00H 00
FCB+6: the drive; 00H in the file, dn1 after 4D08H stores it.
5115
DEFB FFH FF
FCB+7: the DEC of a directory entry; FFH for none.
5116
DEFB 00H 00
FCB+8: the low byte of the end of file, 00H (not used by the reads).
5117
DEFB 00H 00
FCB+9: the record length; 00H stands for 256 bytes.
5118-5119
DEFW 0002H 02 00
FCB+10 and +11: the middle and high bytes of NEXT, sector 2 (5118H is stored again by 4FC5H).
511A-511B
DEFW FFFFH FF FF
FCB+12 and +13: the end of file, FFFFH, so no read reaches it. The keyword table follows; this FCB has no extent area.

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.

511C-5120
DEFM "TI=" / DEFB 00H, 4DH 54 49 3D 00 4D
TI=: attribute 4DH, a list of letters A-P in record bytes +0DH (A-H) and +0EH (I-P).
5121-5125
DEFM "TD=" / DEFB 00H, 0FH 54 44 3D 00 0F
TD=: attribute 0FH, one letter, stored as 0-25 in record byte +0FH.
5126-512A
DEFM "TC=" / DEFB 00H, 83H 54 43 3D 00 83
TC=: attribute 83H, a number, record byte +03H (the number of tracks).
512B-5130
DEFM "SPT=" / DEFB 00H, 84H 53 50 54 3D 00 84
SPT=: attribute 84H, a number, record byte +04H (sectors per track).
5131-5136
DEFM "TSR=" / DEFB 00H, 8CH 54 53 52 3D 00 8C
TSR=: attribute 8CH, a number, record byte +0CH (the step rate code 0-3).
5137-513C
DEFM "GPL=" / DEFB 00H, 85H 47 50 4C 3D 00 85
GPL=: attribute 85H, a number, record byte +05H (granules per lump).
513D-5143
DEFM "DDSL=" / DEFB 00H, 88H 44 44 53 4C 3D 00 88
DDSL=: attribute 88H, a number, record byte +08H (the lump where the directory starts).
5144-514A
DEFM "DDGA=" / DEFB 00H, 89H 44 44 47 41 3D 00 89
DDGA=: attribute 89H, a number, record byte +09H (the granules of the directory).
514B
DEFB 00H 00
The 00H that ends the keyword table (5026H, 4E73H).
514C-516A
DEFB 00H x 31 00 x 31
31 bytes of 00H after the keyword table; nothing reads them.
516B-5170
DEFM "LLD=" / DEFB 00H, 8AH 4C 4C 44 3D 00 8A
Not reached: a keyword entry for record byte +0AH, past the 00H at 514BH that ends the table, so neither the lookup nor the display sees it.
5171-5176
DEFM "NLD=" / DEFB 00H, 8BH 4E 4C 44 3D 00 8B
Not reached: a keyword entry for record byte +0BH, past the end of the table at 514BH.
5177-51C5
DEFB 00H x 79 00 x 79
79 bytes of 00H before the code at 51C6H; nothing reads them.

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.

51C6
CP 41H FE 41
Compare Register A (the parameter's first character) against 41H (ASCII A). 4FDDH jumps here.
51C8
LD (DE),A 12
Self-Modifying Code
Store Register A (the character) at Register Pair DE, 4DF6H, the operand of the LD A at 4DF5H.
51C9
If the NZ FLAG is set (not A), JUMP to 51CEH.
51CB
JUMP to 4FE2H to check that the A stands alone.
51CE
CP 42H FE 42
Compare Register A (the character) against 42H (ASCII B). 51C9H comes here.
51D0
If the NZ FLAG is set (neither A nor B), JUMP to 4FE8H, which stores 00H at 4DF6H and returns the NZ FLAG.
51D3
LD A,41H 3E 41
Load Register A with 41H (ASCII A), which a B option is changed into.
51D5
LD (DE),A 12
Self-Modifying Code
Store Register A (41H) at Register Pair DE, 4DF6H: B also copies the records into SYS0/SYS's table.
51D6
LD (HL),A 77
Store Register A (41H) at Register Pair HL, over the B in the command line.
51D7
PUSH BC C5
Save Register Pair BC onto the stack while it counts the bytes below.
51D8
PUSH HL E5
Save Register Pair HL (the command line at the letter) onto the stack.
51D9
LD BC,0700H 01 00 07
Load Register Pair BC with 0700H: Register B = 7 bytes, Register C = 00H, the byte to store.
51DC
LD HL,4DD3H 21 D3 4D
Point Register Pair HL to 4DD3H, the CALL 4FC3H, CALL 443CH and RET NZ that write the sector.
51DF
LD (HL),C 71
Self-Modifying Code
Store Register C (00H, NOP) at Register Pair HL, one byte of 4DD3H-4DD9H. 51E1H comes back here.
51E0
INC HL 23
INCrement Register Pair HL to the next byte of 4DD3H-4DD9H.
51E1
DECrement Register B and LOOP BACK to 51DFH for the 7 bytes: the system data sector is not written.
51E3
POP HL E1
Restore Register Pair HL from the stack: the command line at the letter.
51E4
POP BC C1
Restore Register Pair BC from the stack, as it was at 51D7H.
51E5
JUMP to 4FE2H to check that the letter stands alone.