TRS-80 DOS - NEWDOS/80 v2.0 for the Model I - SYS17/SYS Disassembled

Page Customization

Introduction/Summary

NEWDOS/80 v2.0 SYS17/SYS Disassembly - SYSTEM, WRDIRP and the End of a Diskette COPY (Model I)

SYS17/SYS holds the SYSTEM command (setting and showing the options in a diskette's system data sector), the WRDIRP command (rewriting the directory sectors with the directory data mark) and, since zap 057, the last part of a diskette COPY, which SYS6 calls. It loads into the overlay area at 4D00H-51E7H (1,256 bytes in five load records, transfer address 4D00H); 508FH-51E7H are unused zero bytes.

The page shows every byte of the file once, in address order.

Entry Codes

CodeFromFunction
33HSYS7 (SYSTEM)SYSTEM, with Register B = the drive (4D0CH).
53HSYS1 (WRDIRP)WRDIRP d (4F5DH).
F3H, C = FFHSYS6 62ADHReturns at once (error 2AH, ignored) so that SYS17 is in memory; SYS6 then jumps to 501CH.

Variables

Locations inside SYS17 whose contents change while it runs:

Address RangePurpose
4D74H
1 byte
Second byte of the RES n,(HL) at 4D73H: the bit of the Y/N option being set (written at 4D5EH).
4D7AH
1 byte
Second byte of the SET n,(HL) at 4D79H (written at 4D63H).
4E04H
1 byte
Second byte of the BIT n,(HL) at 4E03H: the bit of the option being shown (written at 4DF6H).
4F10H-4F15H
6 bytes
Hex display buffer: 0, four digits written by SYS0 4063H at 4F11H, H.
4F16H-4F23H
14 bytes
FCB for the system data sector: drive at 4F1CH (written at 4D0DH), NEXT at 4F20H (sector 2, written at 4E23H).
500EH-501BH
14 bytes
WRDIRP's FCB, writing with the directory data mark: drive at 5014H (written at 4F69H), NEXT at 5018H-5019H (written at 4F96H, 4FB5H and 4FBBH).

Locations outside SYS17 that it reads or writes:

Address RangePurpose
4200H-42FFH
256 bytes
Sector buffer: the system data sector (options at 42A0H-42A9H, 42D0H-42D1H and 42F0H-42FAH), the boot sector, the directory sectors, the GAT.
430FH
1 byte
SYS0's granules per lump of the drive just used (4F8CH).
436DH
1 byte
SYS0's copy of SYSTEM option byte F1H; bit 4 = BK, WRDIRP allowed (4F5DH).
5981H-599BH
in SYS6
SYS6's COPY data: password code 5981H, name and date 5983H, option flags 5994H-5995H, source lumps 59B8H, granules per lump 59BCH, source sectors 59C1H, source granules 59C3H, destination lumps 59C6H, destination granules 59D1H.

SYSTEM Options

The table at 4F24H gives, for each option code, where its value lives in the system data sector: Y/N options in the bits of bytes F0H-F1H and F8H-FAH, numbers in A0H-A9H, and AP as a word at D0H-D1H. AH, AK, BB, BL and BM are not options. After the options are set AL (the number of drives) is forced into 1-4. The settings are shown as XY=Y/N or XY=decimal/hexH.

Disassembly

4D00H - Function Dispatcher

SYS17 is entered by the SYS0 RST 28H dispatcher (4BC2H) with Register A = the RST 28H code. 33H (function 1 of directory slot 13H) is SYSTEM, from SYS7 with Register B = the drive; 53H (function 2) is WRDIRP, from SYS1's command table. Any other code returns error 2AH: SYS6 uses this to load SYS17 (code F3H with Register C = FFH, SYS6 62A7H) and then jumps to 501CH, the end of a diskette COPY. Register Pair HL points at the command line after the command word.

4D00
CP 53H FE 53
Compare Register A (the RST 28H code) against 53H, function 2: WRDIRP.
4D02
If the Z FLAG is set (WRDIRP), JUMP to 4F5DH.
4D05
CP 33H FE 33
Compare Register A (the RST 28H code) against 33H, function 1: SYSTEM.
4D07
LD A,2AH 3E 2A
Load Register A with 2AH, the DOS error code ILLEGAL DOS FUNCTION. LD does not change the flags.
4D09
RET NZ C0
If the NZ FLAG is set (neither code), RETURN to the dispatcher with Register A = 2AH and NZ.
4D0A
NOP 00
NOP: no operation (a byte left over in the file); execution goes on to 4D0BH.
4D0B
NOP 00
NOP: no operation (a byte left over in the file); execution goes on to SYSTEM at 4D0CH.

4D0CH - SYSTEM

SYSTEM password:d[,XY=value...]. SYS7 has selected drive d and checked its password; Register B holds the drive and Register Pair HL the command line after the drive. The drive's system data sector (sector 2) is read into 4200H through the FCB at 4F16H. Each option XY (two letters; its code = 26 times the first letter's number plus the second's, A = 0) is looked up in the table at 4F24H and set: Y or N into a bit of 42F0H-42FAH, a number into 42A0H-42A9H or, for AP, the word at 42D0H. The sector is then written back. Without options the settings are shown.

4D0C
LD A,B 78
Load Register A with Register B, the drive number from SYS7.
4D0D
LD (4F1CH),A 32 1C 4F
Self-Modifying Code
Store Register A (the drive) at 4F1CH, byte 6 of the FCB at 4F16H (the drive), inside this overlay.
4D10
GOSUB to 4E21H, which sets the FCB's NEXT to sector 2 and returns Register Pair DE = 4F16H, the FCB.
4D13
GOSUB to SYS0 4436H, which reads the sector at NEXT (the system data sector) into the FCB's buffer at 4200H; the NZ FLAG is set on an error, with the code in Register A.
4D16
RET NZ C0
If the NZ FLAG is set (a read error), RETURN with it.
4D17
GOSUB to SYS0 4CD5H, which checks the separator at Register Pair HL: the CARRY FLAG is set for a bad one, the Z FLAG at the end of the command, otherwise HL moves past a comma or space to the next item.
4D1A
RET C D8
If the CARRY FLAG is set (a bad separator), RETURN with it (error 34H).
4D1B
If the Z FLAG is set (no options), JUMP to 4DC0H to show the settings.

OPTION LOOP
Register Pair HL = the command line at the next option.

4D1E
LD A,(HL) 7E
Load Register A with the byte at Register Pair HL, the option's first letter.
4D1F
SUB 41H D6 41
Subtract 41H (the letter A) from Register A: A = 0, B = 1 ...
4D21
CP 09H FE 09
Compare Register A against 09H: the CARRY FLAG is set for A to I (the only first letters in use are A and B).
4D23
If the CARRY FLAG is set (a letter A-I), JUMP to 4D2AH with its number in Register A.
4D25
LD A,34H 3E 34
Load Register A with 34H, the DOS error code ILLEGAL KEYWORD OR SEPARATOR OR TERMINATOR.
4D27
JUMP to 4E81H, which leaves through SYS0's error exit 4409H with the code in Register A.
4D2A
LD C,A 4F
Load Register C with Register A, the first letter's number (0-8).
4D2B
LD B,19H 06 19
Load Register B with 19H (25), the times to add it again.
4D2D
ADD A,C 81
Add Register C (the first letter's number) to Register A.
4D2E
Decrement Register B and LOOP back to 4D2DH: Register A = 26 times the first letter's number.
4D30
LD C,A 4F
Load Register C with Register A, 26 times the first letter's number.
4D31
INC HL 23
Increment Register Pair HL to the option's second letter.
4D32
LD A,(HL) 7E
Load Register A with the byte at Register Pair HL, the second letter.
4D33
SUB 41H D6 41
Subtract 41H (the letter A) from Register A, the second letter: A = 0 ... Z = 25.
4D35
CP 1AH FE 1A
Compare Register A against 1AH (26): the NO CARRY FLAG is set if it is not a letter A-Z.
4D37
INC HL 23
Increment Register Pair HL past the second letter (the flags are not changed).
4D38
If the NO CARRY FLAG is set (not a letter), JUMP to 4D25H for error 34H.
4D3A
ADD A,C 81
Add Register C (26 times the first letter) to Register A (the second letter): the option's code.
4D3B
LD E,A 5F
Load Register E with Register A, the option's code.
4D3C
LD D,00H 16 00
Load Register D with 00H, so Register Pair DE = the code as an index.
4D3E
CP 38H FE 38
Compare Register A (the code) against 38H: the NO CARRY FLAG is set past the end of the table (codes above CD).
4D40
If the NO CARRY FLAG is set, JUMP to 4D25H for error 34H.
4D42
PUSH HL E5
Save Register Pair HL (the command line) on the stack.
4D43
LD HL,4F24H 21 24 4F
Load Register Pair HL with 4F24H, the option table.
4D46
ADD HL,DE 19
Add Register Pair DE (the code) to Register Pair HL: HL = the option's table byte.
4D47
LD A,(HL) 7E
Load Register A with the byte at Register Pair HL, the option's table byte.
4D48
CP FEH FE FE
Compare Register A against FEH: the NO CARRY FLAG is set for FEH (no such option) or FFH (past the end).
4D4A
LD B,A 47
Load Register B with Register A, the option's table byte. LD does not change the flags.
4D4B
POP HL E1
Restore Register Pair HL from the stack: the command line after the two letters.
4D4C
If the NO CARRY FLAG is set (not an option), JUMP to 4D25H for error 34H.
4D4E
LD A,(HL) 7E
Load Register A with the byte at Register Pair HL, the character after the letters.
4D4F
CP 3DH FE 3D
Compare Register A against 3DH, an equals sign.
4D51
INC HL 23
Increment Register Pair HL past it (the flags are not changed).
4D52
If the NZ FLAG is set (no =), JUMP to 4D7FH for error 2FH.
4D54
BIT 7,B CB 78
Test bit 7 of Register B (the table byte): set for an option that takes a number.
4D56
If the NZ FLAG is set (a number), JUMP to 4D82H.
4D58
LD A,B 78
A Y/N option: load Register A with Register B, the table byte (bits 4-6 = the bit number, bits 0-3 = the byte's offset from 42F0H).
4D59
RRCA 0F
Rotate Register A right: the bit number moves from bits 4-6 to bits 3-5.
4D5A
AND 38H E6 38
AND Register A with 38H, keeping bits 3-5: 8 times the bit number.
4D5C
OR 86H F6 86
OR Register A with 86H: the second opcode byte of RES n,(HL) (86H + 8 times n).
4D5E
LD (4D74H),A 32 74 4D
Self-Modifying Code
Store Register A at 4D74H, the second byte of the RES n,(HL) at 4D73H.
4D61
ADD A,40H C6 40
Add 40H to Register A: the second opcode byte of SET n,(HL) (C6H + 8 times n).
4D63
LD (4D7AH),A 32 7A 4D
Self-Modifying Code
Store Register A at 4D7AH, the second byte of the SET n,(HL) at 4D79H.
4D66
LD A,B 78
Load Register A with Register B, the table byte.
4D67
AND 0FH E6 0F
AND Register A with 0FH: the offset of the option's byte from 42F0H.
4D69
LD E,A 5F
Load Register E with Register A, the offset of the option's byte from 42F0H.
4D6A
LD D,00H 16 00
Load Register D with 00H, so Register Pair DE = the offset.
4D6C
LD A,(HL) 7E
Load Register A with the byte at Register Pair HL, the value's letter (Y or N).
4D6D
INC HL 23
Increment Register Pair HL past the value's letter (Y or N).
4D6E
PUSH HL E5
Save Register Pair HL (the command line) on the stack.
4D6F
LD HL,42F0H 21 F0 42
Load Register Pair HL with 42F0H, byte F0H of the system data sector in the buffer, the first option byte.
4D72
ADD HL,DE 19
Add Register Pair DE (the offset) to Register Pair HL: HL = the option's byte in the sector.
4D73
RES 0,(HL) CB 86
Self-Modifying Code
RES n,(HL): clear the option's bit in the byte at Register Pair HL; the bit number is in the second byte 4D74H, stored at 4D5EH (86H, bit 0, in the file).
4D75
CP 4EH FE 4E
Compare Register A (the value's letter) against 4EH, the letter N.
4D77
If the Z FLAG is set (N, the bit stays clear), JUMP to 4DA6H.
4D79
SET 0,(HL) CB C6
Self-Modifying Code
SET n,(HL): set the option's bit in the byte at Register Pair HL; the bit number is in the second byte 4D7AH, stored at 4D63H (C6H, bit 0, in the file). SET does not change the flags.
4D7B
CP 59H FE 59
Compare Register A (the value's letter) against 59H, the letter Y.
4D7D
If the Z FLAG is set (Y, the bit is set), JUMP to 4DA6H.
4D7F
JUMP to 4E7FH to leave with error 2FH, BAD PARAMETER(S) (the bit is left set, but the sector is not written).
4D82
PUSH BC C5
A number: save Register Pair BC (Register B = the table byte) on the stack.
4D83
GOSUB to 4E84H, which reads a decimal or hexadecimal number at Register Pair HL into Register Pair DE.
4D86
POP BC C1
Restore Register Pair BC from the stack: Register B = the table byte.
4D87
LD A,B 78
Load Register A with Register B, the table byte.
4D88
AND 1FH E6 1F
AND Register A with 1FH: the option's offset from 42A0H.
4D8A
PUSH HL E5
Save Register Pair HL (the command line) on the stack.
4D8B
PUSH DE D5
Save Register Pair DE (the number) on the stack.
4D8C
LD HL,42A0H 21 A0 42
Load Register Pair HL with 42A0H, byte A0H of the system data sector in the buffer, the first number option.
4D8F
LD E,A 5F
Load Register E with Register A, the offset of the option's byte from 42A0H.
4D90
LD D,00H 16 00
Load Register D with 00H, so Register Pair DE = the offset.
4D92
ADD HL,DE 19
Add Register Pair DE to Register Pair HL: HL = the option's byte in the sector.
4D93
POP DE D1
Restore Register Pair DE from the stack: the number.
4D94
BIT 6,B CB 70
Test bit 6 of Register B (the table byte): set for a 16-bit number (AP).
4D96
If the Z FLAG is set (one byte), JUMP to 4DA1H.
4D98
LD A,L 7D
Load Register A with Register L, the low byte of the option's address.
4D99
ADD A,30H C6 30
Add 30H to Register A (the low byte of the option's address): the word lies 30H higher.
4D9B
LD L,A 6F
Load Register L with Register A: HL = 30H higher, the option's word (42D0H for AP).
4D9C
LD (HL),E 73
Store Register E (the low byte of the number) at Register Pair HL.
4D9D
INC HL 23
Increment Register Pair HL to the word's high byte.
4D9E
LD (HL),D 72
Store Register D (the high byte of the number) at Register Pair HL.
4D9F
JUMP to 4DA6H for the separator and the next option.
4DA1
LD (HL),E 73
Store Register E (the number) at Register Pair HL, the option's byte.
4DA2
LD A,D 7A
Load Register A with Register D, the high byte of the number.
4DA3
OR A B7
OR Register A with itself to set the flags: the Z FLAG is set if the number is 0-255.
4DA4
If the NZ FLAG is set (256 or more), JUMP to 4D7FH for error 2FH.
4DA6
POP HL E1
Restore Register Pair HL from the stack: the command line after the value.
4DA7
GOSUB to SYS0 4CD5H, which checks the separator at Register Pair HL: CARRY for a bad one, Z at the end, otherwise HL moves to the next option.
4DAA
RET C D8
If the CARRY FLAG is set (a bad separator), RETURN with it (error 34H).
4DAB
If the NZ FLAG is set (another option follows), JUMP to 4D1EH.
4DAE
LD HL,42A0H 21 A0 42
Load Register Pair HL with 42A0H, the option AL in the sector: the number of drives.
4DB1
LD A,(HL) 7E
Load Register A with the byte at Register Pair HL, the number of drives.
4DB2
DEC A 3D
Decrement Register A, the number of drives (AL), so 1-4 become 0-3.
4DB3
CP 04H FE 04
Compare Register A against 04H: the CARRY FLAG is set for 1-4 drives.
4DB5
If the CARRY FLAG is set (a valid number), JUMP to 4DB9H.
4DB7
LD (HL),01H 36 01
Store 01H at Register Pair HL (42A0H): any other number of drives becomes 1.
4DB9
GOSUB to 4E21H, which sets the FCB's NEXT back to sector 2 and returns Register Pair DE = 4F16H, the FCB.
4DBC
GOSUB to SYS0 443CH, which writes the buffer at 4200H as the sector at NEXT and reads it back to verify; the NZ FLAG is set on an error.
4DBF
RET NZ C0
If the NZ FLAG is set (a write error), RETURN with it. Otherwise execution goes on to show the new settings.

4DC0H - Show the Settings

Every option in code order: its two letters, =, and Y or N, or the number in decimal and hexadecimal (for example AP=65535/0FFFFH). The first is preceded by a carriage return, the others by a comma. Register Pair HL walks the option table and Register Pair DE holds the code.

4DC0
LD HL,4F24H 21 24 4F
Load Register Pair HL with 4F24H, the option table.
4DC3
LD DE,0000H 11 00 00
Load Register Pair DE with 0000H, the code of the first option (AA).
4DC6
LD B,0DH 06 0D
Load Register B with 0DH, a carriage return, the separator shown before the first option.
4DC8
JUMP to 4E13H to test the first table byte at Register Pair HL.

DISPLAY LOOP
Register Pair HL = the table byte, Register Pair DE = the option's code, Register B = the separator to show.

4DCA
LD A,B 78
Load Register A with Register B, the separator (a carriage return or a comma).
4DCB
GOSUB to 4E6BH, which shows the character in Register A.
4DCE
PUSH HL E5
Save Register Pair HL (the table pointer) on the stack.
4DCF
PUSH DE D5
Save Register Pair DE (the code) on the stack.
4DD0
PUSH BC C5
Save Register Pair BC (Register B = the separator) on the stack.
4DD1
EX DE,HL EB
Exchange Register Pairs DE and HL: HL = the code, DE = the table pointer.
4DD2
LD A,1AH 3E 1A
Load Register A with 1AH (26), the divisor that splits the code into two letters.
4DD4
GOSUB to SYS0 4CB4H, which divides Register Pair HL (the code) by Register A (26): HL = the first letter's number, Register A = the remainder, the second letter's number.
4DD7
ADD A,41H C6 41
Add 41H (the letter A) to Register A: the second letter.
4DD9
LD H,A 67
Load Register H with Register A, the second letter.
4DDA
LD A,L 7D
Load Register A with Register L, the first letter's number.
4DDB
ADD A,41H C6 41
Add 41H (the letter A) to Register A: the option's first letter.
4DDD
GOSUB to 4E6BH to show the first letter in Register A.
4DE0
LD A,H 7C
Load Register A with Register H, the second letter.
4DE1
GOSUB to 4E6BH to show the second letter in Register A.
4DE4
LD A,3DH 3E 3D
Load Register A with 3DH, the equals sign shown after the option's letters.
4DE6
GOSUB to 4E6BH to show the equals sign in Register A.
4DE9
LD A,(DE) 1A
Load Register A with the byte at Register Pair DE, the option's table byte.
4DEA
LD B,A 47
Load Register B with Register A, the table byte.
4DEB
LD D,00H 16 00
Load Register D with 00H, the high byte for the offset below.
4DED
BIT 7,A CB 7F
Test bit 7 of Register A: set for a number option.
4DEF
If the NZ FLAG is set (a number), JUMP to 4E2AH.
4DF1
RRCA 0F
A Y/N option: rotate Register A right, moving the bit number from bits 4-6 to bits 3-5.
4DF2
AND 38H E6 38
AND Register A with 38H: 8 times the bit number.
4DF4
OR 46H F6 46
OR Register A with 46H: the second opcode byte of BIT n,(HL) (46H + 8 times n).
4DF6
LD (4E04H),A 32 04 4E
Self-Modifying Code
Store Register A at 4E04H, the second byte of the BIT n,(HL) at 4E03H.
4DF9
LD A,B 78
Load Register A with Register B, the table byte.
4DFA
AND 0FH E6 0F
AND Register A with 0FH: the offset of the option's byte from 42F0H.
4DFC
LD E,A 5F
Load Register E with Register A, the offset (Register D is 00H).
4DFD
LD HL,42F0H 21 F0 42
Load Register Pair HL with 42F0H, byte F0H of the system data sector in the buffer.
4E00
ADD HL,DE 19
Add Register Pair DE (the offset) to Register Pair HL: HL = the option's byte.
4E01
LD A,4EH 3E 4E
Load Register A with 4EH, the letter N, the value shown if the bit is clear.
4E03
BIT 0,(HL) CB 46
Self-Modifying Code
BIT n,(HL): test the option's bit in the byte at Register Pair HL; the bit number is in the second byte 4E04H, stored at 4DF6H (46H, bit 0, in the file).
4E05
If the Z FLAG is set (the bit is clear), JUMP to 4E09H with Register A = N.
4E07
LD A,59H 3E 59
Load Register A with 59H, the letter Y: the option's bit is set.
4E09
GOSUB to 4E6BH to show Y or N from Register A.
4E0C
POP BC C1
Restore Register Pair BC from the stack (Register B = the old separator).
4E0D
POP DE D1
Restore Register Pair DE from the stack: the option's code.
4E0E
POP HL E1
Restore Register Pair HL from the stack: the table pointer.
4E0F
LD B,2CH 06 2C
Load Register B with 2CH, a comma, the separator before every later option.
4E11
INC DE 13
Increment Register Pair DE, the next option's code.
4E12
INC HL 23
Increment Register Pair HL to the next table byte.
4E13
LD A,(HL) 7E
Load Register A with the byte at Register Pair HL, the table byte for this code.
4E14
CP FEH FE FE
Compare Register A against FEH: the CARRY FLAG is set for an option, the Z FLAG for FEH (no such option).
4E16
If the CARRY FLAG is set (an option), JUMP to 4DCAH to show it.
4E18
If the Z FLAG is set (FEH, no option for this code), JUMP to 4E11H to the next code.
4E1A
LD A,0DH 3E 0D
FFH, the end of the table: load Register A with 0DH, a carriage return.
4E1C
GOSUB to 4E6BH to show the carriage return in Register A.
4E1F
XOR A AF
Load Register A with 00H (XOR A with itself), which also sets the Z FLAG: no error.
4E20
RET C9
RETURN to the caller with Register A = 00H and the Z FLAG set: no error.
4E21
LD A,02H 3E 02
Load Register A with 02H, the system data sector's number.
4E23
LD (4F20H),A 32 20 4F
Self-Modifying Code
Store Register A (2) at 4F20H, the low byte of NEXT (FCB + 10) of the FCB at 4F16H.
4E26
LD DE,4F16H 11 16 4F
Load Register Pair DE with 4F16H, the FCB for the system data sector.
4E29
RET C9
RETURN with Register Pair DE = 4F16H, the FCB, and NEXT = sector 2.
4E2A
AND 1FH E6 1F
A number option: AND Register A (the table byte) with 1FH, the offset from 42A0H.
4E2C
LD E,A 5F
Load Register E with Register A, the offset (Register D is 00H).
4E2D
LD HL,42A0H 21 A0 42
Load Register Pair HL with 42A0H, byte A0H of the system data sector in the buffer.
4E30
ADD HL,DE 19
Add Register Pair DE (the offset) to Register Pair HL: HL = the option's byte.
4E31
BIT 6,B CB 70
Test bit 6 of Register B (the table byte): set for a 16-bit number.
4E33
If the Z FLAG is set (one byte), JUMP to 4E3BH with Register D = 0.
4E35
LD A,L 7D
Load Register A with Register L, the low byte of the option's address.
4E36
ADD A,31H C6 31
Add 31H to Register A: the high byte of the word 30H higher.
4E38
LD L,A 6F
Load Register L with Register A: HL = the high byte of the option's word (42D1H for AP).
4E39
LD D,(HL) 56
Load Register D with the byte at Register Pair HL, the high byte of the number.
4E3A
DEC HL 2B
Decrement Register Pair HL to the low byte of the option's word.
4E3B
LD E,(HL) 5E
Load Register E with the byte at Register Pair HL, the low byte (or the whole one-byte number). Register Pair DE now holds the option's value.
4E3C
PUSH DE D5
Save Register Pair DE (the value) on the stack.
4E3D
GOSUB to 4EDEH, which shows Register Pair DE in decimal.
4E40
LD A,2FH 3E 2F
Load Register A with 2FH, the slash between the decimal and the hexadecimal value.
4E42
GOSUB to 4E6BH to show the slash in Register A.
4E45
POP DE D1
Restore Register Pair DE from the stack: the value.
4E46
LD HL,4F11H 21 11 4F
Load Register Pair HL with 4F11H, the four digit places of the hex buffer at 4F10H.
4E49
PUSH HL E5
Save Register Pair HL (4F11H, the first digit place) on the stack.
4E4A
GOSUB to SYS0 4063H, which writes Register Pair DE as four hexadecimal digits at Register Pair HL (4F11H-4F14H).
4E4D
POP HL E1
Restore Register Pair HL from the stack: 4F11H, the first digit.
4E4E
LD B,04H 06 04
Load Register B with 04H, the number of hex digits in the buffer.
4E50
LD A,(HL) 7E
Load Register A with the byte at Register Pair HL, the first digit.
4E51
CP 41H FE 41
Compare Register A against 41H: the NO CARRY FLAG is set if it is a letter A-F.
4E53
DEC HL 2B
Decrement Register Pair HL to 4F10H, the 0 in front of the digits (the flags are not changed).
4E54
If the NO CARRY FLAG is set (a letter), JUMP to 4E60H: the number is shown from the 0, as 0FFFFH.

SKIP LEADING ZEROS
Register Pair HL steps through the digits; Register B counts the digits left, keeping at least one.

4E56
DEC B 05
Decrement Register B, the digits left to show.
4E57
INC HL 23
Increment Register Pair HL to the next digit.
4E58
LD A,(HL) 7E
Load Register A with the byte at Register Pair HL, that digit.
4E59
CP 30H FE 30
Compare Register A (the digit) against 30H, the digit 0.
4E5B
If the NZ FLAG is set (not a leading 0), JUMP to 4E60H.
4E5D
Decrement Register B and LOOP back to 4E57H, skipping at most three leading zeros.
4E5F
INC HL 23
Increment Register Pair HL to the last digit, which is shown even if it is 0.
4E60
INC B 04
Increment Register B: the count includes the digit at Register Pair HL.
4E61
INC B 04
Increment Register B again, for the H after the digits.
4E62
LD A,(HL) 7E
Load Register A with the byte at Register Pair HL, the next character to show.
4E63
INC HL 23
Increment Register Pair HL to the next character in the buffer.
4E64
GOSUB to 4E6BH to show the character in Register A.
4E67
Decrement Register B and LOOP back to 4E62H until the digits and the H are shown.
4E69
JUMP to 4E0CH to restore the registers and go on with the next option.
4E6B
PUSH DE D5
Save Register Pair DE on the stack; the ROM's display routine changes it.
4E6C
PUSH AF F5
Save Register Pair AF (Register A = the character to show) on the stack.
4E6D
GOSUB to the ROM's display routine at 0033H, which shows the character in Register A on the screen.
4E70
POP AF F1
Restore Register Pair AF from the stack: Register A = the character.
4E71
POP DE D1
Restore Register Pair DE from the stack, as it was before the display call.
4E72
RET C9
RETURN to the caller with Register Pairs AF and DE unchanged.

4E73H - Read a Number

A decimal number, or a hexadecimal one ended by H (the same routine as in SYS7, SYS14 and SYS16). 4E73H also requires it to be 0-255 and returns it in Register A. A bad number is error 2FH BAD PARAMETER(S). Register Pair HL is the command line.

4E73
GOSUB to 4E84H, which reads the number at Register Pair HL into Register Pair DE.
4E76
JUMP to 4E7BH to check that it fits in one byte.
4E78
GOSUB to 4EA2H; no code jumps or calls here, so this instruction is never executed.
4E7B
LD A,D 7A
Load Register A with Register D, the high byte of the number.
4E7C
OR A B7
OR Register A with itself to set the flags: the Z FLAG is set if it is 0.
4E7D
LD A,E 7B
Load Register A with Register E, the low byte of the number. LD does not change the flags.
4E7E
RET Z C8
If the Z FLAG is set (0-255), RETURN with the number in Register A.
4E7F
LD A,2FH 3E 2F
Load Register A with 2FH, the DOS error code BAD PARAMETER(S).
4E81
JUMP to SYS0 4409H, the DOS error exit, with the error code in Register A.
4E84
PUSH HL E5
Save Register Pair HL (the start of the number) on the stack.
4E85
GOSUB to 4EA7H, which reads decimal digits at Register Pair HL into Register Pair DE; HL is left on the first character that is not a digit.
4E88
LD A,(HL) 7E
Load Register A with the byte at Register Pair HL, the character after the digits.
4E89
SUB 41H D6 41
Subtract 41H (the letter A) from Register A, the character after the digits.
4E8B
CP 08H FE 08
Compare Register A against 08H: the CARRY FLAG is set for A to H, a hexadecimal digit or the H that ends one.
4E8D
If the NO CARRY FLAG is set (a decimal number), JUMP to 4E9CH.
4E8F
POP HL E1
Restore Register Pair HL from the stack: back to the start of the number.
4E90
LD B,01H 06 01
Load Register B with 01H: bit 0 set, read hexadecimal digits.
4E92
PUSH HL E5
Save Register Pair HL (the start of the number) on the stack again, to be discarded at 4E9EH.
4E93
GOSUB to 4EA9H, which reads hexadecimal digits at Register Pair HL into Register Pair DE.
4E96
LD A,(HL) 7E
Load Register A with the byte at Register Pair HL, the character after the digits.
4E97
CP 48H FE 48
Compare Register A against 48H, the letter H.
4E99
INC HL 23
Increment Register Pair HL past it (the flags are not changed).
4E9A
If the NZ FLAG is set (no H), JUMP to 4E7FH for error 2FH.
4E9C
BIT 1,B CB 48
Test bit 1 of Register B: set once a digit has been read.
4E9E
POP BC C1
Restore Register Pair BC from the stack, discarding the saved start of the number.
4E9F
RET NZ C0
If the NZ FLAG is set (a digit was read), RETURN with the number in Register Pair DE.
4EA0
JUMP to 4E7FH for error 2FH: no digit was read (Register B bit 1 clear).
4EA2
PUSH HL E5
Save Register Pair HL on the stack. Only 4E78H, itself never executed, leads here.
4EA3
LD DE,4E9CH 11 9C 4E
Load Register Pair DE with 4E9CH, the digit check.
4EA6
PUSH DE D5
Push Register Pair DE (4E9CH) as a return address.
4EA7
LD B,00H 06 00
Load Register B with 00H: decimal digits, none read yet.
4EA9
LD DE,0000H 11 00 00
Load Register Pair DE with 0000H, the number so far.

DIGIT LOOP
Register Pair HL = the command line, Register Pair DE = the number so far, Register B = the flags (bit 0 hexadecimal, bit 1 a digit read).

4EAC
LD A,(HL) 7E
Load Register A with the byte at Register Pair HL, the next character.
4EAD
SUB 30H D6 30
Subtract 30H (the digit 0) from Register A, the character: 0-9 become 00H-09H.
4EAF
CP 0AH FE 0A
Compare Register A against 0AH: the CARRY FLAG is set for 0-9.
4EB1
If the CARRY FLAG is set (a digit 0-9), JUMP to 4EBDH with its value in Register A.
4EB3
BIT 0,B CB 40
Test bit 0 of Register B: set when reading hexadecimal digits.
4EB5
RET Z C8
If the Z FLAG is set (decimal), RETURN: the number ends here.
4EB6
SUB 11H D6 11
Subtract 11H more from Register A: the letters A-F become 00H-05H.
4EB8
CP 06H FE 06
Compare Register A against 06H: the NO CARRY FLAG is set if it is not A-F.
4EBA
RET NC D0
If the NO CARRY FLAG is set, RETURN: the number ends here.
4EBB
ADD A,0AH C6 0A
Add 0AH to Register A: the letters A-F become their values 10-15.
4EBD
PUSH HL E5
Save Register Pair HL (the command line) on the stack.
4EBE
LD H,D 62
Load Register H with Register D, the high byte of the number so far.
4EBF
LD L,E 6B
Load Register L with Register E. Register Pair HL = the number so far (Register Pair DE keeps it too, for times 5).
4EC0
LD C,A 4F
Load Register C with Register A, the new digit's value.
4EC1
XOR A AF
Load Register A with 00H (XOR A with itself): Register A collects any overflow.
4EC2
SET 1,B CB C8
Set bit 1 of Register B: a digit has been read.
4EC4
ADD HL,HL 29
Add Register Pair HL (the number so far) to itself: times 2.
4EC5
ADC A,A 8F
Add Register A to itself with the CARRY FLAG: an overflow makes Register A non-zero.
4EC6
ADD HL,HL 29
Add Register Pair HL to itself: the number so far times 4.
4EC7
ADC A,A 8F
Add Register A to itself with the CARRY FLAG, collecting any overflow.
4EC8
BIT 0,B CB 40
Test bit 0 of Register B: set for hexadecimal.
4ECA
If the Z FLAG is set (decimal), JUMP to 4ECFH.
4ECC
ADD HL,HL 29
Hexadecimal: add Register Pair HL to itself, times 8.
4ECD
JUMP to 4ED0H with Register Pair HL = 8 times the number (hexadecimal).
4ECF
ADD HL,DE 19
Decimal: add Register Pair DE (the number) to Register Pair HL (4 times it): times 5.
4ED0
ADC A,A 8F
Add Register A to itself with the CARRY FLAG, collecting any overflow.
4ED1
ADD HL,HL 29
Add Register Pair HL to itself: times 16 (hexadecimal) or 10 (decimal).
4ED2
ADC A,A 8F
Add Register A to itself with the CARRY FLAG, collecting any overflow.
4ED3
LD E,C 59
Load Register E with Register C, the new digit's value.
4ED4
LD D,00H 16 00
Load Register D with 00H, so Register Pair DE = the digit.
4ED6
ADD HL,DE 19
Add Register Pair DE (the digit) to Register Pair HL.
4ED7
ADC A,A 8F
Add Register A to itself with the CARRY FLAG: Register A is non-zero (NZ) if the number passed FFFFH at any step.
4ED8
EX DE,HL EB
Exchange Register Pairs DE and HL: DE = the new number.
4ED9
POP HL E1
Restore Register Pair HL from the stack: the command line at the digit.
4EDA
RET NZ C0
If the NZ FLAG is set (the number passed FFFFH), RETURN early with Register Pair HL on the digit; no error is given for it here.
4EDB
INC HL 23
Increment Register Pair HL to the next character.
4EDC
LOOP back to 4EACH for the next digit at Register Pair HL.

4EDEH - Show a Number in Decimal

Shows Register Pair DE in decimal without leading zeros (the same routine as SYS16 50A8H), using the negative powers of ten at 4F08H.

4EDE
LD BC,0400H 01 00 04
Load Register Pair BC with 0400H: Register B = 4 powers of ten, Register C = 0 (no digit shown yet).
4EE1
LD HL,4F08H 21 08 4F
Load Register Pair HL with 4F08H, the table of negative powers of ten.

DIGIT LOOP
Register Pair DE = the part of the number not shown yet, Register Pair HL = the next power in the table.

4EE4
PUSH BC C5
Save Register Pair BC (the counts) on the stack.
4EE5
LD C,(HL) 4E
Load Register C with the byte at Register Pair HL, the low byte of the negative power of ten.
4EE6
INC HL 23
Increment Register Pair HL to the high byte of the negative power of ten.
4EE7
LD B,(HL) 46
Load Register B with the byte at Register Pair HL. Register Pair BC = minus the power of ten.
4EE8
INC HL 23
Increment Register Pair HL to the next power in the table.
4EE9
EX DE,HL EB
Exchange Register Pairs DE and HL: HL = the number, DE = the table pointer.
4EEA
LD A,2FH 3E 2F
Load Register A with 2FH, one below the character 0.
4EEC
INC A 3C
Increment Register A, counting how often the power goes into the number.
4EED
ADD HL,BC 09
Add Register Pair BC (minus the power) to Register Pair HL: subtract the power; the CARRY FLAG is set while the result is not negative.
4EEE
If the CARRY FLAG is set (it went), LOOP back to 4EECH.
4EF0
SBC HL,BC ED 42
Subtract Register Pair BC with the CARRY FLAG (clear here) from Register Pair HL: add the power back once.
4EF2
POP BC C1
Restore Register Pair BC from the stack: the counts.
4EF3
EX DE,HL EB
Exchange Register Pairs DE and HL: DE = the rest of the number, HL = the table pointer.
4EF4
CP 30H FE 30
Compare Register A (the digit character) against 30H, the digit 0.
4EF6
If the NZ FLAG is set (not 0), JUMP to 4EFCH to show it.
4EF8
INC C 0C
Increment Register C (the digits shown so far)...
4EF9
DEC C 0D
...and decrement Register C again: the Z FLAG is set if no digit has been shown yet (Register C = 0).
4EFA
If the Z FLAG is set (a leading 0), JUMP to 4F00H without showing it.
4EFC
INC C 0C
Increment Register C: a digit has been shown.
4EFD
GOSUB to 4E6BH to show the digit in Register A.
4F00
Decrement Register B (the powers left) and LOOP back to 4EE4H.
4F02
LD A,E 7B
Load Register A with Register E, the units left in the number (0-9).
4F03
ADD A,30H C6 30
Add 30H to Register A: the units digit, always shown.
4F05
JUMP to 4E6BH to show the units digit in Register A and return.
4F08-4F0F
DEFW D8F0H, FC18H, FF9CH, FFF6H F0 D8 18 FC 9C FF F6 FF
DEFW D8F0H, FC18H, FF9CH, FFF6H: the powers of ten 10000, 1000, 100 and 10 as negative numbers, added at 4EEDH.
4F10-4F15
DEFM "00000H" 30 30 30 30 30 48
The hex display buffer: a 0 (shown before a value starting with a letter), the four digits SYS0 4063H writes at 4F11H, and H.
4F16-4F23
DEFB 82H, 60H, 00H, 00H, 42H, 00H, 00H, FFH, 00H, 00H, 02H, 00H, FFH, FFH 82 60 00 00 42 00 00 FF 00 00 02 00 FF FF
The FCB for the system data sector, 14 bytes: open, NEXT/EOF counted in sectors of the diskette (82H), buffer 4200H, the drive at 4F1CH (stored at 4D0DH), NEXT = sector 2 at 4F20H (stored at 4E23H), EOF FFFFH.

4F24H - The Option Table

Data, not code: one byte for each option code (26 times the first letter's number plus the second letter's, A = 0), in code order. FEH = no such option, FFH = the end. Bit 7 clear: a Y/N option, whose bit (bits 4-6) lies in the byte 42F0H + (bits 0-3) of the system data sector. Bit 7 set: a number at 42A0H + (bits 0-4), a 16-bit one 30H higher if bit 6 is set. SYS0's reset code reads the same sector bytes (Part 5, section 3.4).

4F24
DEFB 70H 70
Table byte for option AA (code 00H): Y/N, bit 7 of 42F0H (sector byte F0H).
4F25
DEFB 60H 60
Table byte for option AB (code 01H): Y/N, bit 6 of 42F0H (sector byte F0H).
4F26
DEFB 78H 78
Table byte for option AC (code 02H): Y/N, bit 7 of 42F8H (sector byte F8H).
4F27
DEFB 68H 68
Table byte for option AD (code 03H): Y/N, bit 6 of 42F8H (sector byte F8H).
4F28
DEFB 58H 58
Table byte for option AE (code 04H): Y/N, bit 5 of 42F8H (sector byte F8H).
4F29
DEFB 48H 48
Table byte for option AF (code 05H): Y/N, bit 4 of 42F8H (sector byte F8H).
4F2A
DEFB 50H 50
Table byte for option AG (code 06H): Y/N, bit 5 of 42F0H (sector byte F0H).
4F2B
DEFB FEH FE
Table byte for code 07H (AH): FEH, no such option; SYSTEM gives error 34H for it.
4F2C
DEFB 40H 40
Table byte for option AI (code 08H): Y/N, bit 4 of 42F0H (sector byte F0H).
4F2D
DEFB 18H 18
Table byte for option AJ (code 09H): Y/N, bit 1 of 42F8H (sector byte F8H).
4F2E
DEFB FEH FE
Table byte for code 0AH (AK): FEH, no such option; SYSTEM gives error 34H for it.
4F2F
DEFB 80H 80
Table byte for option AL (code 0BH): a number at 42A0H (sector byte A0H).
4F30
DEFB 86H 86
Table byte for option AM (code 0CH): a number at 42A6H (sector byte A6H).
4F31
DEFB 82H 82
Table byte for option AN (code 0DH): a number at 42A2H (sector byte A2H).
4F32
DEFB 83H 83
Table byte for option AO (code 0EH): a number at 42A3H (sector byte A3H).
4F33
DEFB C0H C0
Table byte for option AP (code 0FH): a 16-bit number at 42D0H-42D1H (system data sector bytes D0H-D1H).
4F34
DEFB 28H 28
Table byte for option AQ (code 10H): Y/N, bit 2 of 42F8H (sector byte F8H).
4F35
DEFB 10H 10
Table byte for option AR (code 11H): Y/N, bit 1 of 42F0H (sector byte F0H).
4F36
DEFB 00H 00
Table byte for option AS (code 12H): Y/N, bit 0 of 42F0H (sector byte F0H).
4F37
DEFB 71H 71
Table byte for option AT (code 13H): Y/N, bit 7 of 42F1H (sector byte F1H).
4F38
DEFB 08H 08
Table byte for option AU (code 14H): Y/N, bit 0 of 42F8H (sector byte F8H).
4F39
DEFB 87H 87
Table byte for option AV (code 15H): a number at 42A7H (sector byte A7H).
4F3A
DEFB 81H 81
Table byte for option AW (code 16H): a number at 42A1H (sector byte A1H).
4F3B
DEFB 88H 88
Table byte for option AX (code 17H): a number at 42A8H (sector byte A8H).
4F3C
DEFB 79H 79
Table byte for option AY (code 18H): Y/N, bit 7 of 42F9H (sector byte F9H).
4F3D
DEFB 69H 69
Table byte for option AZ (code 19H): Y/N, bit 6 of 42F9H (sector byte F9H).
4F3E
DEFB 59H 59
Table byte for option BA (code 1AH): Y/N, bit 5 of 42F9H (sector byte F9H).
4F3F
DEFB FEH FE
Table byte for code 1BH (BB): FEH, no such option; SYSTEM gives error 34H for it.
4F40
DEFB 61H 61
Table byte for option BC (code 1CH): Y/N, bit 6 of 42F1H (sector byte F1H).
4F41
DEFB 39H 39
Table byte for option BD (code 1DH): Y/N, bit 3 of 42F9H (sector byte F9H).
4F42
DEFB 51H 51
Table byte for option BE (code 1EH): Y/N, bit 5 of 42F1H (sector byte F1H).
4F43
DEFB 29H 29
Table byte for option BF (code 1FH): Y/N, bit 2 of 42F9H (sector byte F9H).
4F44
DEFB 19H 19
Table byte for option BG (code 20H): Y/N, bit 1 of 42F9H (sector byte F9H).
4F45
DEFB 09H 09
Table byte for option BH (code 21H): Y/N, bit 0 of 42F9H (sector byte F9H).
4F46
DEFB 85H 85
Table byte for option BI (code 22H): a number at 42A5H (sector byte A5H).
4F47
DEFB 89H 89
Table byte for option BJ (code 23H): a number at 42A9H (sector byte A9H).
4F48
DEFB 41H 41
Table byte for option BK (code 24H): Y/N, bit 4 of 42F1H (sector byte F1H).
4F49
DEFB FEH FE
Table byte for code 25H (BL): FEH, no such option; SYSTEM gives error 34H for it.
4F4A
DEFB FEH FE
Table byte for code 26H (BM): FEH, no such option; SYSTEM gives error 34H for it.
4F4B
DEFB 7AH 7A
Table byte for option BN (code 27H): Y/N, bit 7 of 42FAH (sector byte FAH).
4F4C
DEFB FFH FF
FFH: the end of the table for the display loop (4E14H); code 28H would be BO.
4F4D-4F5C
DEFB FFH, FFH, FFH, FFH, FFH, FFH, FFH, FFH, FFH, FFH, FFH, FFH, FFH, FFH, FFH, FFH FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
Sixteen more FFH bytes, for codes 29H-38H (BP to CE). SYSTEM looks up codes up to 37H (the test at 4D3EH), finds FFH and gives error 34H; the display stops at 4F4CH.

4F5DH - WRDIRP

WRDIRP d (only with the SYSTEM option BK = Y, else error 37H). Reads drive d's boot sector, finds the directory (the lump in boot sector byte 2), checks that the first two directory entries are BOOT/SYS and DIR/SYS, and writes back every directory sector that was read without the directory data mark, now with it (the FCB at 500EH writes with the mark). A wrong boot sector or entry is error 2CH BAD DIRECTORY DATA. Register Pair HL points at the command line after WRDIRP.

4F5D
LD A,(436DH) 3A 6D 43
Load Register A with the byte at 436DH, the second SYSTEM option byte in SYS0 (system data sector byte F1H).
4F60
BIT 4,A CB 67
Test bit 4 of Register A, the SYSTEM option BK (WRDIRP allowed).
4F62
LD A,37H 3E 37
Load Register A with 37H, the DOS error code DISKETTE ACCESS DENIED. LD does not change the flags.
4F64
If the Z FLAG is set (BK = N), JUMP to 4FC8H to leave with error 37H.
4F66
GOSUB to 4E73H, which reads the drive number at Register Pair HL (0-255) into Register A.
4F69
LD (5014H),A 32 14 50
Self-Modifying Code
Store Register A (the drive) at 5014H, byte 6 of the FCB at 500EH (the drive).
4F6C
GOSUB to SYS0 4CD5H, which checks what follows at Register Pair HL: the Z FLAG is set at the end of the command.
4F6F
RET NZ C0
If the NZ FLAG is set (something follows the drive), RETURN with the error from 4CD5H (34H).
4F70
LD DE,500EH 11 0E 50
Load Register Pair DE with 500EH, WRDIRP's FCB (NEXT = sector 0, the boot sector, in the file).
4F73
GOSUB to SYS0 4436H, which reads the sector at NEXT (the boot sector) into 4200H; the NZ FLAG is set on an error.
4F76
RET NZ C0
If the NZ FLAG is set (a read error), RETURN with it.
4F77
LD HL,4200H 21 00 42
Load Register Pair HL with 4200H, the boot sector in the buffer.
4F7A
LD A,(HL) 7E
Load Register A with the byte at Register Pair HL, boot sector byte 0.
4F7B
OR A B7
OR Register A with itself to set the flags: the Z FLAG is set if it is 00H, as on every NEWDOS/80 boot sector.
4F7C
If the NZ FLAG is set (not 00H), JUMP to 4FC6H for error 2CH.
4F7E
INC HL 23
Increment Register Pair HL to boot sector byte 1.
4F7F
LD A,(HL) 7E
Load Register A with the byte at Register Pair HL, boot sector byte 1.
4F80
CP FEH FE FE
Compare Register A against FEH, the value it must have.
4F82
If the NZ FLAG is set (not FEH), JUMP to 4FC6H for error 2CH.
4F84
INC HL 23
Increment Register Pair HL to boot sector byte 2.
4F85
LD L,(HL) 6E
Load Register L with the byte at Register Pair HL, boot sector byte 2: the lump where the directory starts. Register H stays 42H.
4F86
LD A,05H 3E 05
Load Register A with 05H, the sectors per granule.
4F88
PUSH HL E5
Save Register Pair HL (Register H = 42H, Register L = the directory's lump) on the stack.
4F89
GOSUB to SYS0 4C92H, which multiplies Register L (the lump) by Register A (5) into Register Pair HL.
4F8C
LD A,(430FH) 3A 0F 43
Load Register A with the byte at 430FH, SYS0's granules per lump for the drive just used.
4F8F
GOSUB to SYS0 4C94H, which multiplies Register Pair HL by Register A: HL = the directory's first sector (the GAT).
4F92
POP DE D1
Restore Register Pair DE from the stack: Register D = 42H, Register E = the directory's lump.
4F93
PUSH HL E5
Save Register Pair HL (the GAT sector's number) on the stack.
4F94
PUSH DE D5
Save Register Pair DE (the directory's lump in Register E) on the stack.
4F95
INC HL 23
Increment Register Pair HL: the next sector, the HIT.
4F96
LD (5018H),HL 22 18 50
Self-Modifying Code
Store Register Pair HL (the HIT sector's number) at 5018H, NEXT in the FCB at 500EH.
4F99
GOSUB to 4FCBH, which reads the sector at NEXT (the HIT) into 4200H.
4F9C
LD A,(421FH) 3A 1F 42
Load Register A with the byte at 421FH, HIT byte 1FH: the number of FDE sectors beyond the first eight.
4F9F
ADD A,0AH C6 0A
Add 0AH to Register A: plus the GAT, the HIT and eight FDE sectors, the directory's size in sectors.
4FA1
LD H,A 67
Load Register H with Register A, the directory's size.
4FA2
EX (SP),HL E3
Exchange Register Pair HL with the word at the top of the stack (at the Stack Pointer SP): HL = 42H and the directory's lump, and the size (in Register H) is saved.
4FA3
PUSH HL E5
Save Register Pair HL (the directory's lump in Register L) on the stack.
4FA4
LD C,00H 0E 00
Load Register C with 00H: BOOT/SYS must start at lump 0.
4FA6
LD HL,4FFFH 21 FF 4F
Load Register Pair HL with 4FFFH, the text BOOT.
4FA9
GOSUB to 4FD7H, which reads the next directory sector (the first FDE sector) and checks that its first entry is a system file named BOOT/SYS starting at lump Register C (0).
4FAC
POP BC C1
Restore Register Pair BC from the stack: Register C = the directory's lump.
4FAD
LD HL,5003H 21 03 50
Load Register Pair HL with 5003H, the text DIR.
4FB0
GOSUB to 4FD7H, which reads the next FDE sector and checks that its first entry is a system file named DIR/SYS starting at the directory's lump (Register C).
4FB3
POP BC C1
Restore Register Pair BC from the stack: Register B = the directory's size in sectors.
4FB4
POP HL E1
Restore Register Pair HL from the stack: the directory's first sector (the GAT).

MARK THE DIRECTORY SECTORS
Register Pair HL = the sector's number, Register B = the sectors left.

4FB5
LD (5018H),HL 22 18 50
Self-Modifying Code
Store Register Pair HL (the sector's number) at 5018H, NEXT in the FCB.
4FB8
GOSUB to 4FCBH, which reads the sector: the Z FLAG is set if it was read without the directory data mark (the NZ FLAG, error 06H, if it has it).
4FBB
LD (5018H),HL 22 18 50
Self-Modifying Code
Store Register Pair HL (the same sector) at 5018H again, since the read moved NEXT on.
4FBE
If the Z FLAG is set (no mark), GOSUB to SYS0 443CH, which writes the sector back, now with the directory data mark, and verifies it.
4FC1
RET NZ C0
If the NZ FLAG is set (a write error), RETURN with it.
4FC2
INC HL 23
Increment Register Pair HL, the next sector's number.
4FC3
Decrement Register B (the sectors left) and LOOP back to 4FB5H for the whole directory.
4FC5
RET C9
RETURN with no error: every directory sector has the mark.
4FC6
LD A,2CH 3E 2C
Load Register A with 2CH, the DOS error code BAD DIRECTORY DATA.
4FC8
JUMP to 4E81H, which leaves through SYS0's error exit 4409H with the code in Register A.
4FCB
LD DE,500EH 11 0E 50
Load Register Pair DE with 500EH, WRDIRP's FCB.
4FCE
GOSUB to SYS0 4436H, which reads the sector at the FCB's NEXT into 4200H.
4FD1
RET Z C8
If the Z FLAG is set (read without error), RETURN with Z.
4FD2
CP 06H FE 06
Compare Register A (the error code) against 06H, the error the read gives when the sector has the directory data mark.
4FD4
If the NZ FLAG is set (another error), JUMP to 4FC8H to leave with it.
4FD6
RET C9
RETURN with NZ: the sector already has the directory data mark.
4FD7
GOSUB to 4FCBH to read the next directory sector (NEXT moves on after each read) into 4200H.
4FDA
LD A,(4200H) 3A 00 42
Load Register A with the byte at 4200H, byte 0 of the sector's first directory entry (its attributes).
4FDD
AND 50H E6 50
AND Register A with 50H, keeping bit 6 (system file) and bit 4 (entry in use).
4FDF
CP 50H FE 50
Compare Register A against 50H: both must be set.
4FE1
If the NZ FLAG is set (not a system file in use), JUMP to 4FC6H for error 2CH.
4FE3
LD A,(4216H) 3A 16 42
Load Register A with the byte at 4216H, entry byte 16H: the lump of the file's first extent.
4FE6
CP C B9
Compare Register A with Register C, the lump expected.
4FE7
If the NZ FLAG is set (it differs), JUMP to 4FC6H for error 2CH.
4FE9
LD DE,4205H 11 05 42
Load Register Pair DE with 4205H, entry byte 5: the file's name.
4FEC
LD B,04H 06 04
Load Register B with 04H, the characters of the name to compare with the text at Register Pair HL (BOOT or DIR and a space).
4FEE
GOSUB to 4FF6H to compare Register B characters at Register Pairs DE and HL.
4FF1
LD HL,5007H 21 07 50
Load Register Pair HL with 5007H, the text of four spaces and SYS, the rest of the name and the extension.
4FF4
LD B,07H 06 07
Load Register B with 07H, the characters to compare; execution falls into the compare loop.

COMPARE LOOP
Register Pair DE = the entry's name, Register Pair HL = the text expected, Register B = the characters left.

4FF6
LD A,(DE) 1A
Load Register A with the byte at Register Pair DE, a character of the entry's name.
4FF7
CP (HL) BE
Compare Register A with the byte at Register Pair HL, the character expected.
4FF8
INC DE 13
Increment Register Pair DE (the flags are not changed).
4FF9
INC HL 23
Increment Register Pair HL to the next character expected.
4FFA
If the NZ FLAG is set (it differs), JUMP to 4FC6H for error 2CH.
4FFC
Decrement Register B (the characters left) and LOOP back to 4FF6H.
4FFE
RET C9
RETURN: all Register B characters of the name match.
4FFF-5002
DEFM "BOOT" 42 4F 4F 54
DEFM "BOOT", the first four characters of BOOT/SYS, compared at 4FEEH.
5003-5006
DEFM "DIR " 44 49 52 20
DEFM "DIR ", the first four characters of DIR/SYS (with a space), compared at 4FEEH.
5007-500D
DEFM " SYS" 20 20 20 20 53 59 53
DEFM " SYS", four spaces and SYS: the rest of both names and their extension, compared at 4FF4H.
500E-501B
DEFB 83H, 60H, 00H, 00H, 42H, 00H, 00H, FFH, 00H, 00H, 00H, 00H, FFH, FFH 83 60 00 00 42 00 00 FF 00 00 00 00 FF FF
WRDIRP's FCB, 14 bytes: open, NEXT/EOF counted in sectors of the diskette and written with the directory data mark (83H), buffer 4200H, the drive at 5014H (stored at 4F69H), NEXT at 5018H-5019H (sector 0 in the file), EOF FFFFH.

501CH - The End of a Diskette COPY (Zap 057)

Zap 057 moved this code out of SYS6. SYS6 loads SYS17 at 62ADH and jumps here from 54D4H when a diskette COPY has written all sectors; Index Register IX is SYS6's FCB. It verifies the rest of the destination diskette and, unless SYS6's option flag 5994H bit 1 is set, brings the destination's GAT up to date: allocation bytes where a larger destination has them, the password, the name and date, and the granules beyond the source's size made free. Every call goes to SYS6 (or SYS0).

501C
GOSUB to SYS6 5535H, which switches to the destination diskette and opens its FCB (Index Register IX).
501F
LD DE,(59C1H) ED 5B C1 59
Load Register Pair DE with the 16-bit value at 59C1H in SYS6, the source diskette's number of sectors.
5023
GOSUB to SYS6 5784H, which verifies the destination from the sector in Register Pair DE to its last sector.
5026
LD BC,(5994H) ED 4B 94 59
Load Register Pair BC with the 16-bit value at 5994H in SYS6: Register C = the option flags at 5994H, Register B = those at 5995H.
502A
BIT 1,C CB 49
Test bit 1 of Register C (5994H bit 1): set when the directory must not be changed.
502C
If the NZ FLAG is set, JUMP to 508CH to finish without touching the GAT.
502E
GOSUB to SYS6 56F9H, which reads the destination's GAT sector into 4200H.
5031
LD E,61H 1E 61
Load Register E with 61H (97), one more than the lumps whose bits fit before the GAT's lockout table.
5033
LD A,(59C6H) 3A C6 59
Load Register A with the byte at 59C6H in SYS6, the destination's number of lumps.
5036
CP E BB
Compare Register A with Register E (97): the NO CARRY FLAG is set if the destination has more than 96 lumps.
5037
If the CARRY FLAG is set (96 or fewer), JUMP to 5047H.
5039
LD A,(59B8H) 3A B8 59
Load Register A with the byte at 59B8H in SYS6, the source's number of lumps.
503C
CP E BB
Compare Register A with Register E (97): the CARRY FLAG is set if the source has 96 or fewer.
503D
If the NO CARRY FLAG is set (the source is large too), JUMP to 5047H.
503F
DEC E 1D
Decrement Register E to 60H, the count of bytes to fill.
5040
LD L,E 6B
Load Register L with Register E (60H). The fill below treats Register Pair HL as 4260H, GAT byte 60H, but Register H is not loaded in SYS17: it holds whatever SYS6 56F9H (the GAT read) left there. On a large destination bytes 60H-BFH are allocation bytes, while the small source's copy holds its lockout table there.

FILL LOOP
Register Pair HL = the GAT byte, Register E = the bytes left.

5041
LD (HL),FFH 36 FF
Store FFH at Register Pair HL: every granule of that lump in use, until 5068H frees the ones past the source's size.
5043
DEC E 1D
Decrement Register E, the GAT bytes left to fill.
5044
INC HL 23
Increment Register Pair HL to the next GAT byte (the flags are not changed).
5045
If the NZ FLAG is set (bytes left), LOOP back to 5041H; it fills 4260H-42BFH.
5047
BIT 5,B CB 68
Test bit 5 of Register B (5995H bit 5): set when a new password was given for the destination.
5049
If the Z FLAG is set (no new password), JUMP to 5051H.
504B
LD HL,(5981H) 2A 81 59
Load Register Pair HL with the 16-bit value at 5981H in SYS6, the new password's hash code.
504E
LD (42CEH),HL 22 CE 42
Store Register Pair HL at 42CEH-42CFH, GAT bytes CEH-CFH: the diskette's password code.
5051
LD A,C 79
Load Register A with Register C, the option flags from 5994H.
5052
AND 0CH E6 0C
AND Register A with 0CH, keeping bits 2 and 3: set when a new diskette name was given.
5054
LD BC,0010H 01 10 00
Load Register Pair BC with 0010H (16), the bytes of name and date. LD does not change the flags.
5057
LD DE,42D0H 11 D0 42
Load Register Pair DE with 42D0H, GAT byte D0H: the diskette's name and date.
505A
LD HL,5983H 21 83 59
Load Register Pair HL with 5983H in SYS6, the new name and date.
505D
If the NZ FLAG is set (a new name), JUMP to 5066H to copy all 16 bytes.
505F
LD HL,598BH 21 8B 59
Load Register Pair HL with 598BH in SYS6, the date alone.
5062
LD E,D8H 1E D8
Load Register E with D8H: DE = 42D8H, GAT byte D8H, the diskette's date.
5064
LD C,08H 0E 08
Load Register C with 08H: Register Pair BC = 8, the date's length.
5066
LDIR ED B0
LDIR: copy BC bytes (16 or 8) from Register Pair HL (SYS6's name and date) to Register Pair DE (the GAT).
5068
LD HL,(59D1H) 2A D1 59
Load Register Pair HL with the 16-bit value at 59D1H in SYS6, the destination's number of granules.
506B
LD DE,(59C3H) ED 5B C3 59
Load Register Pair DE with the 16-bit value at 59C3H in SYS6, the source's number of granules.
506F
OR A B7
OR Register A with itself to clear the CARRY FLAG for the subtraction.
5070
SBC HL,DE ED 52
Subtract Register Pair DE from Register Pair HL: HL = how many more granules the destination has.
5072
EX DE,HL EB
Exchange Register Pairs DE and HL: DE = that difference. EX does not change the flags.
5073
If the CARRY FLAG is set (the destination has fewer), JUMP to 5086H.
5075
If the Z FLAG is set (the same number), JUMP to 5086H.
5077
LD HL,(59C3H) 2A C3 59
Load Register Pair HL with the 16-bit value at 59C3H, the source's number of granules: the first granule beyond the source's size.
507A
LD A,(59BCH) 3A BC 59
Load Register A with the byte at 59BCH in SYS6, the source's granules per lump.
507D
GOSUB to SYS0 4CB4H, which divides Register Pair HL by Register A: HL = that granule's lump, Register A = its granule within the lump.
5080
LD H,42H 26 42
Load Register H with 42H: HL = the lump's allocation byte in the GAT at 4200H.
5082
LD C,A 4F
Load Register C with Register A, the granule within the lump.
5083
GOSUB to SYS6 5762H, which frees Register Pair DE granules in the GAT from the lump at Register Pair HL, granule Register C on.
5086
GOSUB to SYS0 491FH, which writes the GAT sector back to the destination.
5089
If the NZ FLAG is set (a write error), JUMP to SYS6 54CBH, which ends the COPY with the error.
508C
JUMP to SYS6 552DH, which shows DONE and ends the COPY.

508FH - Unused Bytes

508FH-51E7H fill the last load record; nothing reads or executes them.

508F-51E7
NOP x 345 00 x 345
345 zero bytes that fill the end of the file (up to 51E7H). No code jumps, calls or reads here.