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

Page Customization

Introduction/Summary

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

SYS17/SYS does the SYSTEM command (after SYS7/SYS has read its password and drive), the WRDIRP command, and the last part of a diskette COPY for SYS6/SYS. Its five load records fill 4D00H-51E7H of the overlay area (1,256 bytes) and its transfer address is 4D00H; 509FH-51E7H are 00H.

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

Functions

CodeFunction
33HSYSTEM [password:]dn1[,xx=value]..., from SYS7/SYS with Register B = dn1, 4D0CH
53HWRDIRP dn1, from SYS1/SYS's command table, 4F6DH
Any other (F3H)Returns at once with error 2AH: SYS6/SYS uses code F3H only to load SYS17/SYS, then jumps to 502CH at the end of a diskette COPY

Both commands read their diskette through an FCB of their own (4F16H, 501EH) with FCB+0 bit 1 set, so that NEXT is a sector number of the whole diskette, and the buffer 4300H. WRDIRP's FCB also has FCB+0 bit 0, which makes SYS0/SYS write every sector with the directory mark. WRDIRP needs option BK (error 37H otherwise), checks the boot sector (bytes 00H FEH) and the entries of BOOT/SYS and DIR/SYS (error 2CH), and then reads and rewrites the GAT, the HIT and every FDE sector. The diskette COPY code at 502CH runs with SYS6/SYS still in memory from 5200H on and uses its routines and variables.

System Options

An option's code is (first letter - A) x 26 + (second letter - A); the table at 4F24H has one byte for each of the codes 0-71. The options live in the system data sector (sector 2): yes/no options as bits of bytes F0H-FFH, numbers as bytes at A0H-AFH or words at D0H-DFH. The reset copies bytes F0H and F1H to SYS0/SYS's 428CH and 428DH.

ByteOptions
F0HBit 7 AA, 6 AB, 5 AG, 1 AR
F1HBit 7 AT, 6 BC, 5 BE, 4 BK
F8HBit 6 AD, 5 AE, 4 AF, 2 AQ, 1 AJ, 0 AU
F9HBit 7 AY, 6 AZ, 5 BA, 4 BB, 3 BD, 1 BG, 0 BH
A0H-A9HAL, AW, AN, AO, (A4H none), BI, AM, AV, AX, BJ
D0H-D1HAP, a 16-bit number

AC, AH, AI, AK, AS, BF, BL, BM and BN are not on this machine (table byte FEH, error 34H); codes from BO on are FFH. After the options, option AL is set to 1 unless it is 1-4, and the sector is written back with a verify. The display shows every option as xx=Y or N, or xx=decimal/hexadecimalH.

Variables

Memory Outside SYS17/SYS

Address
Size
Contents
4285H
1 byte
Granules per Lump
Byte +5 of the selected drive's PDRIVE values: WRDIRP finds the GAT with it (4F9CH).
428DH
1 byte
Options
SYS0/SYS's copy of system data byte F1H: bit 4 option BK allows WRDIRP (4F6DH).
4300H-43FFH
256 bytes
Sector Buffer
The system data sector of SYSTEM (options at 43A0H-43AFH, 43D0H-43DFH and 43F0H-43FFH), WRDIRP's boot and directory sectors, and the destination GAT of a diskette COPY (43CEH password, 43D0H name, 43D8H date).
5956H, 5994H-5995H
3 bytes
SYS6/SYS Control Block and Flags
Used by the diskette COPY code: the destination's control block (5535H), the option flags (5036H).
5981H, 5983H, 598BH
4 bytes
SYS6/SYS Password, Name, Date
The new password code (505BH) and the name and date copied into the GAT (5076H).
59B8H, 59BCH, 59C1H, 59C3H
6 bytes
SYS6/SYS Source Values
Lumps (5049H), granules per lump (508AH), sectors (502FH) and granules (507BH, 5087H) of the source.
59C6H, 59D1H
3 bytes
SYS6/SYS Destination Values
Lumps (5043H) and granules (5078H) of the destination.

SYS17/SYS Data

Address
Size
Contents
4F08H-4F0FH
8 bytes
Powers of Ten
Minus 10000, 1000, 100 and 10 for the decimal display.
4F10H-4F15H
6 bytes
Hexadecimal Text
"00000H"; 44D2H writes four digits at 4F11H.
4F16H-4F23H
14 bytes
SYSTEM FCB
The system data sector of dn1: drive 4F1CH, NEXT 4F20H.
4F24H-4F6CH
73 bytes
Option Table
One byte for each code AA-CT and an extra FFH.
500FH-501DH
15 bytes
Names
BOOT, DIR and four spaces with SYS.
501EH-502BH
14 bytes
WRDIRP FCB
Directory mark writes: drive 5024H, NEXT 5028H-5029H.

Operands Changed at Run Time

Address
Size
Contents
4D74H, 4D7AH
2 bytes
RES and SET Bit
The second bytes of RES 0,(HL) at 4D73H and SET 0,(HL) at 4D79H, stored at 4D5EH and 4D63H.
4E04H
1 byte
BIT Bit
The second byte of BIT 0,(HL) at 4E03H, stored at 4DF6H.
4F1CH, 4F20H
2 bytes
SYSTEM FCB
The drive (4D0DH) and NEXT (4E23H).
5024H, 5028H-5029H
3 bytes
WRDIRP FCB
The drive (4F79H) and NEXT (4FA6H, 4FC5H, 4FCBH).

Outside Routines and Addresses

AddressContents
0033HROM: display a character (4E6DH).
4409HSYS0/SYS: the DOS error exit (4E81H).
4436H, 443CHSYS0/SYS: read the sector at NEXT (4D13H, 4F83H, 4FDEH), write it with a verify (4DBCH, 4FCEH).
44D2HSYS0/SYS: a word as four hexadecimal digits (4E4AH).
48C4HSYS0/SYS: write the directory sector in 4300H (5096H).
4C37H, 4C39H, 4C59HSYS0/SYS: multiply (4F99H, 4F9FH), divide (4DD4H, 508DH).
4C7AHSYS0/SYS: test for the end of the line or a separator (4D17H, 4DA7H, 4F7CH).
5535H, 54CBH, 552DH, 56F9H, 5762H, 5784HSYS6/SYS: switch to the destination, end with an error, end with DONE, read the GAT, free granules, verify the diskette.

Disassembly

4D00H - Function Dispatcher

SYS17/SYS (directory slot 13H) is loaded by the SYS0/SYS RST 28H dispatcher (4B67H) into 4D00H-51E7H and entered at 4D00H by the CALL at 4BC2H, with Register A = the RST 28H code and 4BC5H (the dispatcher's tail) on top of the stack. Code 53H (function 2) is the WRDIRP command (SYS1/SYS's command table, Register Pair HL = the command line at dn1). Code 33H (function 1) is the SYSTEM command, called by SYS7/SYS after it has read the password and the drive, with Register B = the drive and Register Pair HL = the command line after it. Any other code, such as the F3H with which SYS6/SYS only loads SYS17/SYS for its diskette COPY (SYS6/SYS 62ADH, through its 568DH), returns at once with Register A = 2AH; SYS6/SYS then jumps to 502CH.

4D00
CP 53H FE 53
Compare Register A, the RST 28H code, against 53H, function 2 of directory slot 13H. The Z FLAG is set for WRDIRP.
4D02
If the Z FLAG is set (code 53H), JUMP to 4F6DH, the WRDIRP command.
4D05
CP 33H FE 33
Compare Register A, the RST 28H code, against 33H, function 1 of directory slot 13H. The Z FLAG is set for 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 of the CP.
4D09
RET NZ C0
If the NZ FLAG is set (any other code, such as F3H from SYS6/SYS), RETURN to the dispatcher's tail 4BC5H with Register A = 2AH: SYS17/SYS has only been loaded.
4D0A
NOP 00
No operation (NOP): code 33H goes on through this byte to the SYSTEM command.
4D0B
NOP 00
No operation (NOP), the second byte before the SYSTEM command at 4D0CH.

4D0CH - SYSTEM Command

SYSTEM [password:]dn1[,xx=value]... reads sector 2 of drive dn1, the system data sector, into 4300H through the FCB at 4F16H. Each option is two letters; its code (first letter - A) x 26 + (second letter - A) indexes the table at 4F24H. A table byte with bit 7 clear is a yes/no option: bit (byte bits 6-4) of system data byte F0H + (byte bits 3-0), set for Y. A byte with bit 7 set is a number: one byte at A0H + (bits 4-0), or with bit 6 a 16-bit number at D0H + (bits 4-0). FEH is an option this machine does not have (error 34H). After the options, option AL (byte A0H) is set to 1 unless it is 1-4, and the sector is written back with a verify. The options are then shown.

4D0C
LD A,B 78
Load Register A with Register B, dn1: the drive SYS7/SYS read from the command line.
4D0D
LD (4F1CH),A 32 1C 4F
Self-Modifying Code
Store Register A (dn1) at 4F1CH, FCB+6 (the drive number) of the FCB at 4F16H.
4D10
GOSUB to 4E21H, which sets FCB+10 (4F20H) to 02H, so that NEXT is sector 2 of the diskette, and returns Register Pair DE = 4F16H, the FCB.
4D13
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 dn1) into its buffer at 4300H; the NZ FLAG with an error code in Register A on failure.
4D16
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.
4D17
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.
4D1A
RET C D8
If the CARRY FLAG is set (not a separator), RETURN to the dispatcher's tail 4BC5H with Register A = 34H (ILLEGAL KEYWORD OR SEPARATOR OR TERMINATOR).
4D1B
If the Z FLAG is set (no options), JUMP to 4DC0H to show the options without writing.

Option Loop
Register Pair HL = the command line at the next option's first letter.

4D1E
LD A,(HL) 7E
Load Register A with the byte at Register Pair HL, the first letter of the option. 4DABH comes back here.
4D1F
SUB 41H D6 41
SUBtract 41H (ASCII A) from Register A: the letters A-I become 0-8.
4D21
CP 09H FE 09
Compare Register A against 09H. The CARRY FLAG is set for A-I, which keeps the code below 256; 4D3EH then allows only codes 0-71.
4D23
If the CARRY FLAG is set (A-I), JUMP to 4D2AH.
4D25
LD A,34H 3E 34
Load Register A with 34H, the DOS error code ILLEGAL KEYWORD OR SEPARATOR OR TERMINATOR. 4D38H, 4D40H and 4D4CH come here.
4D27
JUMP to 4E81H, which leaves through the SYS0/SYS error exit 4409H with the error code in Register A.
4D2A
LD C,A 4F
Load Register C with Register A, the first letter as 0-8. 4D23H comes here.
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) to Register A. 4D2EH comes back here.
4D2E
DECrement Register B and LOOP BACK to 4D2DH: Register A = 26 x the first letter.
4D30
LD C,A 4F
Load Register C with Register A, 26 x the first letter.
4D31
INC HL 23
INCrement Register Pair HL to the second letter of the option.
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 (ASCII A) from Register A: the letters A-Z become 0-25.
4D35
CP 1AH FE 1A
Compare Register A against 1AH (26). The NO CARRY FLAG is set for a character that is not A-Z.
4D37
INC HL 23
INCrement Register Pair HL past the second letter. INC HL does not change the flags.
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 x the first letter) to Register A: Register A = 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: Register Pair DE = the code, an index into the table at 4F24H.
4D3E
CP 48H FE 48
Compare Register A (the code) against 48H (72). The NO CARRY FLAG is set for a code past the table (CU and up).
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 after the two letters) onto the stack.
4D43
LD HL,4F24H 21 24 4F
Point Register Pair HL to 4F24H, the option table.
4D46
ADD HL,DE 19
ADD Register Pair DE (the code) to Register Pair HL: Register Pair 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 (not on this machine) and FFH (past the defined options).
4D4A
LD B,A 47
Load Register B with Register A, the table byte, kept for the rest of the option. LD does not change the flags.
4D4B
POP HL E1
Restore Register Pair HL from the stack: the command line after the two letters. POP does not change the flags.
4D4C
If the NO CARRY FLAG is set (an option this machine does not have), 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 two letters.
4D4F
CP 3DH FE 3D
Compare Register A against 3DH (ASCII =). The Z FLAG is set for the = sign.
4D51
INC HL 23
INCrement Register Pair HL past it. INC HL does not change the flags.
4D52
If the NZ FLAG is set (no = sign), 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 yes/no option: load Register A with Register B, the table byte (bits 6-4 the bit number, bits 3-0 the byte F0H-FFH).
4D59
RRCA 0F
Rotate Register A right (RRCA): the bit number moves to bits 5-3.
4D5A
AND 38H E6 38
AND Register A with 38H, keeping bits 5-3, the bit number times 8.
4D5C
OR 86H F6 86
OR Register A with 86H: the second byte of a RES n,(HL) instruction for that bit.
4D5E
LD (4D74H),A 32 74 4D
Self-Modifying Code
Store Register A at 4D74H, the second byte of the RES 0,(HL) at 4D73H, which then resets the option's bit.
4D61
ADD A,40H C6 40
ADD 40H to Register A: the second byte of the SET n,(HL) instruction for the same bit.
4D63
LD (4D7AH),A 32 7A 4D
Self-Modifying Code
Store Register A at 4D7AH, the second byte of the SET 0,(HL) at 4D79H, which then sets the option's bit.
4D66
LD A,B 78
Load Register A with Register B, the table byte.
4D67
AND 0FH E6 0F
AND Register A with 0FH, keeping bits 3-0: the option's byte is F0H + this.
4D69
LD E,A 5F
Load Register E with Register A, the byte offset 0-15.
4D6A
LD D,00H 16 00
Load Register D with 00H: Register Pair DE = the byte offset.
4D6C
LD A,(HL) 7E
Load Register A with the byte at Register Pair HL, the value after the = sign (Y or N).
4D6D
INC HL 23
INCrement Register Pair HL past the value letter in the command line.
4D6E
PUSH HL E5
Save Register Pair HL (the command line after the value) onto the stack; 4DA6H takes it back.
4D6F
LD HL,43F0H 21 F0 43
Point Register Pair HL to 43F0H, byte F0H of the system data sector in the buffer.
4D72
ADD HL,DE 19
ADD Register Pair DE (the byte offset) to Register Pair HL: Register Pair HL = the option's byte (43F0H-43FFH).
4D73
RES 0,(HL) CB 86
Self-Modifying Code
Reset the option's bit of the byte at Register Pair HL: the second byte 4D74H (86H, bit 0, in the file) was stored at 4D5EH.
4D75
CP 4EH FE 4E
Compare Register A (the value) against 4EH (ASCII N). The Z FLAG is set for N.
4D77
If the Z FLAG is set (N, the bit stays reset), JUMP to 4DA6H.
4D79
SET 0,(HL) CB C6
Self-Modifying Code
Set the option's bit of the byte at Register Pair HL: the second byte 4D7AH (C6H, bit 0, in the file) was stored at 4D63H.
4D7B
CP 59H FE 59
Compare Register A (the value) against 59H (ASCII Y). The Z FLAG is set for Y.
4D7D
If the Z FLAG is set (Y, the bit stays set), JUMP to 4DA6H.
4D7F
JUMP to 4E7FH for error 2FH (BAD PARAMETER(S)): no = sign, a value that is neither Y nor N (the bit is left set in the buffer, which is not written), or a number above 255. 4D52H and 4DA4H come here.
4D82
PUSH BC C5
A number: save Register Pair BC (Register B = the table byte) onto the stack. 4D56H comes here.
4D83
GOSUB to 4E84H, which reads the 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, keeping bits 4-0: the option's byte offset.
4D8A
PUSH HL E5
Save Register Pair HL (the command line after the number) onto the stack; 4DA6H takes it back.
4D8B
PUSH DE D5
Save Register Pair DE (the number) onto the stack.
4D8C
LD HL,43A0H 21 A0 43
Point Register Pair HL to 43A0H, byte A0H of the system data sector in the buffer.
4D8F
LD E,A 5F
Load Register E with Register A, the byte offset.
4D90
LD D,00H 16 00
Load Register D with 00H: Register Pair DE = the byte offset.
4D92
ADD HL,DE 19
ADD Register Pair DE (the byte offset) to Register Pair HL: Register Pair HL = 43A0H + the offset.
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.
4D96
If the Z FLAG is set (a one-byte number), JUMP to 4DA1H.
4D98
LD A,L 7D
Load Register A with Register L, the low byte of 43A0H + the offset.
4D99
ADD A,30H C6 30
ADD 30H to Register A: 16-bit numbers live at D0H + the offset.
4D9B
LD L,A 6F
Load Register L with Register A: Register Pair HL = 43D0H + the offset.
4D9C
LD (HL),E 73
Store Register E (the number's low byte) at Register Pair HL.
4D9D
INC HL 23
INCrement Register Pair HL to the number's high byte.
4D9E
LD (HL),D 72
Store Register D (the number's high byte) at Register Pair HL.
4D9F
JUMP to 4DA6H to take back the command line and look at the next option.
4DA1
LD (HL),E 73
Store Register E (the number's low byte) at Register Pair HL, the option's byte at 43A0H + the offset. 4D96H comes here.
4DA2
LD A,D 7A
Load Register A with Register D, the number's high byte.
4DA3
OR A B7
OR Register A with itself to set the flags: the NZ FLAG is set for a number above 255.
4DA4
If the NZ FLAG is set (above 255), JUMP to 4D7FH for error 2FH.
4DA6
POP HL E1
Restore Register Pair HL from the stack: the command line after the option. 4D77H, 4D7DH and 4D9FH come here.
4DA7
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.
4DAA
RET C D8
If the CARRY FLAG is set (not a separator), RETURN to the dispatcher's tail 4BC5H with Register A = 34H.
4DAB
If the NZ FLAG is set (another option follows), JUMP to 4D1EH.
4DAE
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.
4DB1
LD A,(HL) 7E
Load Register A with the byte at Register Pair HL, option AL.
4DB2
DEC A 3D
DECrement Register A: an AL of 1-4 becomes 0-3.
4DB3
CP 04H FE 04
Compare Register A against 04H. The CARRY FLAG is set for 0-3.
4DB5
If the CARRY FLAG is set (AL is 1-4), JUMP to 4DB9H.
4DB7
LD (HL),01H 36 01
Store 01H at Register Pair HL (43A0H): an AL of 0 or above 4 is replaced by 1.
4DB9
GOSUB to 4E21H, which sets NEXT of the FCB at 4F16H to sector 2 again and returns Register Pair DE = 4F16H. 4DB5H comes here.
4DBC
GOSUB to SYS0/SYS 443CH, which writes the buffer at 4300H as sector 2 of drive dn1 (the FCB at Register Pair DE) with a verify; the NZ FLAG with an error code in Register A on failure.
4DBF
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 options.

4DC0H - Show the Options

Walks the table at 4F24H; every option this machine has (table byte below FEH) is shown as its two letters, an = sign and its value: Y or N, or a number as decimal/hexadecimal. The first item follows a carriage return, the others a comma; the table ends at its first FFH (4F4CH).

4DC0
LD HL,4F24H 21 24 4F
Point Register Pair HL to 4F24H, the option table. 4D1BH comes here.
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, shown before the first option.
4DC8
JUMP to 4E13H to look at the first table byte.

Show Loop
Register Pair HL = the table byte, Register Pair DE = its code, Register B = the separator to show first.

4DCA
LD A,B 78
Load Register A with Register B, the separator (a carriage return first, then a comma). 4E16H comes here.
4DCB
GOSUB to 4E6BH, which displays the character in Register A.
4DCE
PUSH HL E5
Save Register Pair HL (the table pointer) onto the stack.
4DCF
PUSH DE D5
Save Register Pair DE (the option's code) onto the stack.
4DD0
PUSH BC C5
Save Register Pair BC (Register B = the separator) onto the stack.
4DD1
EX DE,HL EB
Exchange Register Pairs DE and HL: Register Pair HL = the option's code, Register Pair DE = the table pointer.
4DD2
LD A,1AH 3E 1A
Load Register A with 1AH (26), the divisor that splits the code into its two letters.
4DD4
GOSUB to SYS0/SYS 4C59H, which divides Register Pair HL (the code) by Register A (26): Register Pair HL = the first letter as 0-8, Register A = the second letter as 0-25.
4DD7
ADD A,41H C6 41
ADD 41H (ASCII 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 as 0-8.
4DDB
ADD A,41H C6 41
ADD 41H (ASCII A) to Register A: the first letter.
4DDD
GOSUB to 4E6BH, which displays the first letter in Register A.
4DE0
LD A,H 7C
Load Register A with Register H, the second letter.
4DE1
GOSUB to 4E6BH, which displays the second letter in Register A.
4DE4
LD A,3DH 3E 3D
Load Register A with 3DH, ASCII =, shown between the option's letters and its value.
4DE6
GOSUB to 4E6BH, which displays the = 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 of the offsets below.
4DED
BIT 7,A CB 7F
Test bit 7 of Register A, the table byte: set for a number.
4DEF
If the NZ FLAG is set (a number), JUMP to 4E2AH.
4DF1
RRCA 0F
A yes/no option: rotate Register A (the table byte) right (RRCA): the bit number moves to bits 5-3.
4DF2
AND 38H E6 38
AND Register A with 38H, keeping bits 5-3, the bit number times 8.
4DF4
OR 46H F6 46
OR Register A with 46H: the second byte of a BIT n,(HL) instruction for that bit.
4DF6
LD (4E04H),A 32 04 4E
Self-Modifying Code
Store Register A at 4E04H, the second byte of the BIT 0,(HL) at 4E03H, which then tests the option's bit.
4DF9
LD A,B 78
Load Register A with Register B, the table byte.
4DFA
AND 0FH E6 0F
AND Register A with 0FH, keeping bits 3-0: the option's byte is F0H + this.
4DFC
LD E,A 5F
Load Register E with Register A: Register Pair DE = the byte offset.
4DFD
LD HL,43F0H 21 F0 43
Point Register Pair HL to 43F0H, byte F0H of the system data sector in the buffer.
4E00
ADD HL,DE 19
ADD Register Pair DE (the byte offset) to Register Pair HL: Register Pair HL = the option's byte.
4E01
LD A,4EH 3E 4E
Load Register A with 4EH (ASCII N), shown when the bit is clear.
4E03
BIT 0,(HL) CB 46
Self-Modifying Code
Test the option's bit of the byte at Register Pair HL: the second byte 4E04H (46H, bit 0, in the file) was stored at 4DF6H. The Z FLAG is set if the bit is clear.
4E05
If the Z FLAG is set (N), JUMP to 4E09H with Register A = 4EH.
4E07
LD A,59H 3E 59
Load Register A with 59H (ASCII Y): the bit is set.
4E09
GOSUB to 4E6BH, which displays Y or N in Register A. 4E05H comes here.
4E0C
POP BC C1
Restore Register Pair BC from the stack (Register B = the separator). 4E69H comes here.
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, shown before every later option.
4E11
INC DE 13
INCrement Register Pair DE, the code of the next option. 4E18H comes here.
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 option's table byte. 4DC8H comes here.
4E14
CP FEH FE FE
Compare Register A against FEH. The CARRY FLAG is set for an option this machine has, the Z FLAG for FEH.
4E16
If the CARRY FLAG is set (an option to show), JUMP to 4DCAH.
4E18
If the Z FLAG is set (FEH, an option this machine does not have), LOOP BACK to 4E11H to skip it.
4E1A
LD A,0DH 3E 0D
FFH, the end of the table: load Register A with 0DH, a carriage return.
4E1C
GOSUB to 4E6BH, which displays 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 dispatcher's tail 4BC5H with Register A = 00H, no error.

4E21H - Point the FCB at Sector 2

Sets FCB+10 (4F20H) of the FCB at 4F16H to 02H, so that NEXT is sector 2 (the system data sector), and returns Register Pair DE = 4F16H for the read (4436H) or the write (443CH).

4E21
LD A,02H 3E 02
Load Register A with 02H, the number of the system data sector on the diskette. 4D10H and 4DB9H call here.
4E23
LD (4F20H),A 32 20 4F
Self-Modifying Code
Store Register A (02H) at 4F20H, FCB+10 of the FCB at 4F16H: the middle byte of NEXT, so that NEXT = sector 2.
4E26
LD DE,4F16H 11 16 4F
Load Register Pair DE with 4F16H, the FCB that reads and writes the system data sector.
4E29
RET C9
RETURN with Register Pair DE = 4F16H, the FCB with NEXT at sector 2.

4E2AH - Show a Number Option

Register B = the table byte, Register Pair HL = the table pointer on the stack. The value (one byte at 43A0H + offset, or 16 bits at 43D0H + offset) is shown in decimal, a slash, then in hexadecimal with its leading zeros dropped (one 0 is kept before a first digit A-F) and an H.

4E2A
AND 1FH E6 1F
AND Register A (the table byte) with 1FH, keeping bits 4-0: the option's byte offset. 4DEFH comes here.
4E2C
LD E,A 5F
Load Register E with Register A: Register Pair DE = the byte offset (Register D = 00H from 4DEBH).
4E2D
LD HL,43A0H 21 A0 43
Point Register Pair HL to 43A0H, byte A0H of the system data sector in the buffer.
4E30
ADD HL,DE 19
ADD Register Pair DE (the byte offset) to Register Pair HL: Register Pair 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.
4E35
LD A,L 7D
Load Register A with Register L, the low byte of 43A0H + the offset.
4E36
ADD A,31H C6 31
ADD 31H to Register A: the high byte of a 16-bit number lives at D1H + the offset.
4E38
LD L,A 6F
Load Register L with Register A: Register Pair HL = 43D1H + the offset.
4E39
LD D,(HL) 56
Load Register D with the byte at Register Pair HL, the number's high byte.
4E3A
DEC HL 2B
DECrement Register Pair HL to the number's low byte.
4E3B
LD E,(HL) 5E
Load Register E with the byte at Register Pair HL, the number's low byte: Register Pair DE = the value. 4E33H comes here.
4E3C
PUSH DE D5
Save Register Pair DE (the value) onto the stack.
4E3D
GOSUB to 4EDEH, which displays Register Pair DE in decimal without leading zeros.
4E40
LD A,2FH 3E 2F
Load Register A with 2FH, ASCII /, shown between the decimal and the hexadecimal value.
4E42
GOSUB to 4E6BH, which displays 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
Point Register Pair HL to 4F11H, the four digit positions of the text 00000H at 4F10H-4F15H.
4E49
PUSH HL E5
Save Register Pair HL (4F11H) onto the stack.
4E4A
GOSUB to SYS0/SYS 44D2H, 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 four hexadecimal digits. 4E60H-4E61H later add two: one for the H, and one for the 0 shown before a first letter (or for the count taken off at 4E56H).
4E50
LD A,(HL) 7E
Load Register A with the byte at Register Pair HL, the first hexadecimal digit.
4E51
CP 41H FE 41
Compare Register A against 41H (ASCII A). The NO CARRY FLAG is set for a digit A-F.
4E53
DEC HL 2B
DECrement Register Pair HL to 4F10H, the 0 before the digits. DEC HL does not change the flags.
4E54
If the NO CARRY FLAG is set (the first digit is a letter), JUMP to 4E60H to show the 0, the four digits and H.
4E56
DEC B 05
DECrement Register B: at most three leading zeros are dropped.

Leading Zero Loop
Register Pair HL steps over the zeros before the first digit that is not 0.

4E57
INC HL 23
INCrement Register Pair HL to the next hexadecimal digit. 4E5DH comes back here.
4E58
LD A,(HL) 7E
Load Register A with the byte at Register Pair HL, the digit.
4E59
CP 30H FE 30
Compare Register A against 30H (ASCII 0). The Z FLAG is set for a zero.
4E5B
If the NZ FLAG is set (not 0), JUMP to 4E60H to show from here.
4E5D
DECrement Register B and LOOP BACK to 4E57H while zeros may be dropped.
4E5F
INC HL 23
INCrement Register Pair HL to the last digit, which is always shown.
4E60
INC B 04
INCrement Register B: one more character to show. 4E54H and 4E5BH come here.
4E61
INC B 04
INCrement Register B again: Register B = the digits left plus the H.
4E62
LD A,(HL) 7E
Load Register A with the byte at Register Pair HL, the next character of the text. 4E67H comes back here.
4E63
INC HL 23
INCrement Register Pair HL to the following character.
4E64
GOSUB to 4E6BH, which displays the character in Register A.
4E67
DECrement Register B and LOOP BACK to 4E62H until the H has been shown.
4E69
JUMP to 4E0CH to restore the registers and go on to the next option of the table.

4E6BH - Show a Character

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

4E6B
PUSH DE D5
Save Register Pair DE onto the stack; the ROM display routine changes it.
4E6C
PUSH AF F5
Save Register Pair AF (Register A = the character) onto the stack.
4E6D
GOSUB to the ROM routine at 0033H, which displays the character in Register A at the cursor.
4E70
POP AF F1
Restore Register Pair AF from the stack: Register A = the character shown.
4E71
POP DE D1
Restore Register Pair DE from the stack, as it was before the ROM call.
4E72
RET C9
RETURN with Register Pairs AF and DE unchanged.

4E73H - 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. 4E78H, an entry for decimal digits only, is never used. 4E7FH and 4E81H are the error exits.

4E73
GOSUB to 4E84H, which reads the number at Register Pair HL into Register Pair DE. 4F76H calls here.
4E76
JUMP to 4E7BH to check the number's high byte.
4E78
Never executed (nothing calls or jumps here): GOSUB to 4EA2H, which would read decimal digits only into Register Pair DE.
4E7B
LD A,D 7A
Load Register A with Register D, the high byte of the number. 4E76H comes here.
4E7C
OR A B7
OR Register A with itself to set the flags: the Z FLAG is set if the number is below 256.
4E7D
LD A,E 7B
Load Register A with Register E, the number's low byte. 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). 4D7FH, 4E9AH and 4EA0H come here.
4E81
JUMP to SYS0/SYS 4409H, the DOS error exit, with the error code in Register A. 4D27H and 4FD8H come here.

4E84H - 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 (4EDAH), so the caller's separator check then finds that digit.

4E84
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. 4D83H and 4E73H call here.
4E85
GOSUB to 4EA7H, 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.
4E88
LD A,(HL) 7E
Load Register A with the byte at Register Pair HL, the character after the decimal digits.
4E89
SUB 41H D6 41
SUBtract 41H (ASCII A) from Register A: the letters A-H become 00H-07H.
4E8B
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.
4E8D
If the NO CARRY FLAG is set (no letter A-H), JUMP to 4E9CH: the number is decimal.
4E8F
POP HL E1
Restore Register Pair HL from the stack: the start of the number, to read it again.
4E90
LD B,01H 06 01
Load Register B with 01H: bit 0 set, read hexadecimal digits; bit 1 clear, no digit read yet.
4E92
PUSH HL E5
Save Register Pair HL (the start of the number) onto the stack again, to be dropped at 4E9EH.
4E93
GOSUB to 4EA9H, which reads the 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 hexadecimal digits.
4E97
CP 48H FE 48
Compare Register A against 48H (ASCII H). The Z FLAG is set for the closing H.
4E99
INC HL 23
INCrement Register Pair HL past the H. INC HL does not change the flags.
4E9A
If the NZ FLAG is set (no closing H), JUMP to 4E7FH for error 2FH.
4E9C
BIT 1,B CB 48
Test bit 1 of Register B: set by 4EC2H once a digit has been read. 4E8DH comes here.
4E9E
POP BC C1
Restore Register Pair BC from the stack, dropping the saved start of the number. POP does not change the flags.
4E9F
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.
4EA0
JUMP to 4E7FH for error 2FH (BAD PARAMETER(S)): no digit was read.
4EA2
PUSH HL E5
Never executed (only the unused 4E78H calls it): save Register Pair HL (the start of the number) onto the stack.
4EA3
LD DE,4E9CH 11 9C 4E
Never executed: load Register Pair DE with 4E9CH, the check that follows the reading.
4EA6
PUSH DE D5
Never executed: save Register Pair DE (4E9CH) onto the stack as the return address of the digit reading below.
4EA7
LD B,00H 06 00
Load Register B with 00H: bit 0 clear (decimal), bit 1 clear (no digit read yet). 4E85H calls here.
4EA9
LD DE,0000H 11 00 00
Load Register Pair DE with 0000H, the value before the first digit. 4E93H 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.

4EAC
LD A,(HL) 7E
Load Register A with the byte at Register Pair HL, the next character of the number. 4EDCH comes back here.
4EAD
SUB 30H D6 30
SUBtract 30H (ASCII 0) from Register A: the digits 0-9 become 00H-09H.
4EAF
CP 0AH FE 0A
Compare Register A against 0AH. The CARRY FLAG is set for a decimal digit.
4EB1
If the CARRY FLAG is set (0-9), JUMP to 4EBDH with the digit's value in Register A.
4EB3
BIT 0,B CB 40
Test bit 0 of Register B: set when hexadecimal digits are being read.
4EB5
RET Z C8
If the Z FLAG is set (decimal), RETURN: the number ends at this character.
4EB6
SUB 11H D6 11
SUBtract 11H more from Register A: the letters A-F (41H-46H, now 11H-16H) become 00H-05H.
4EB8
CP 06H FE 06
Compare Register A against 06H. The NO CARRY FLAG is set for a character that is not A-F.
4EBA
RET NC D0
If the NO CARRY FLAG is set (not A-F), RETURN: the number ends at this character.
4EBB
ADD A,0AH C6 0A
ADD 0AH to Register A: the letters A-F become their values 0AH-0FH.
4EBD
PUSH HL E5
Save Register Pair HL (the position of the digit) onto the stack. 4EB1H comes here with a decimal digit.
4EBE
LD H,D 62
Load Register H with Register D, the high byte of the value so far.
4EBF
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.
4EC0
LD C,A 4F
Load Register C with Register A, the value of the new digit.
4EC1
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.
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 to itself: the value times 2. A carry out of bit 15 sets the CARRY FLAG.
4EC5
ADC A,A 8F
ADD Register A to itself with the CARRY FLAG (ADC): a carry makes Register A non-zero.
4EC6
ADD HL,HL 29
ADD Register Pair HL to itself: the value times 4.
4EC7
ADC A,A 8F
ADD Register A to itself with the CARRY FLAG (ADC), collecting the carry.
4EC8
BIT 0,B CB 40
Test bit 0 of Register B: set for hexadecimal digits.
4ECA
If the Z FLAG is set (decimal), JUMP to 4ECFH to make times 5.
4ECC
ADD HL,HL 29
Hexadecimal: ADD Register Pair HL to itself, the value times 8.
4ECD
JUMP to 4ED0H with Register Pair HL = the value times 8.
4ECF
ADD HL,DE 19
Decimal: ADD Register Pair DE (the value) to Register Pair HL (the value times 4): the value times 5.
4ED0
ADC A,A 8F
ADD Register A to itself with the CARRY FLAG (ADC), collecting the carry. 4ECDH comes here.
4ED1
ADD HL,HL 29
ADD Register Pair HL to itself: the value times 16 (hexadecimal) or times 10 (decimal).
4ED2
ADC A,A 8F
ADD Register A to itself with the CARRY FLAG (ADC), collecting the carry.
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: Register Pair DE = the new 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 (ADC): Register A is not 00H, and the NZ FLAG is set, if the value passed FFFFH at any step of this digit.
4ED8
EX DE,HL EB
Exchange Register Pairs DE and HL: Register Pair DE = the new value (its low 16 bits).
4ED9
POP HL E1
Restore Register Pair HL from the stack: the position of the digit. POP does not change the flags.
4EDA
RET NZ C0
If the NZ FLAG is set (the value passed FFFFH), RETURN with Register Pair HL still at this digit.
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, through 4E6BH.

4EDE
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). 4E3DH calls here.
4EE1
LD HL,4F08H 21 08 4F
Point Register Pair HL to 4F08H, 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.

4EE4
PUSH BC C5
Save Register Pair BC (the digit count and the digit-shown flag) onto the stack. 4F00H comes back here.
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 table entry.
4EE9
EX DE,HL EB
Exchange Register Pairs DE and HL: Register Pair HL = the number, Register Pair DE = the table pointer.
4EEA
LD A,2FH 3E 2F
Load Register A with 2FH, one below ASCII 0, the digit before the first count.
4EEC
INC A 3C
INCrement Register A, the digit. 4EEEH comes back here.
4EED
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.
4EEE
If the CARRY FLAG is set (the power fitted once more), LOOP BACK to 4EECH.
4EF0
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.
4EF2
POP BC C1
Restore Register Pair BC from the stack: Register B = the digits left, Register C = the digit-shown flag.
4EF3
EX DE,HL EB
Exchange Register Pairs DE and HL: Register Pair DE = the rest of the number, Register Pair HL = the table pointer.
4EF4
CP 30H FE 30
Compare Register A (the digit) against 30H, ASCII 0.
4EF6
If the NZ FLAG is set (the digit is not 0), JUMP to 4EFCH to show it.
4EF8
INC C 0C
INCrement Register C, the digit-shown flag, to test it for 00H without changing it.
4EF9
DEC C 0D
DECrement Register C back: the Z FLAG is set if no digit has been shown yet.
4EFA
If the Z FLAG is set (a leading zero), JUMP to 4F00H without showing it.
4EFC
INC C 0C
INCrement Register C: a digit has been shown, so later zeros are shown. 4EF6H comes here.
4EFD
GOSUB to 4E6BH, which shows the digit in Register A.
4F00
DECrement Register B and LOOP BACK to 4EE4H for the next power of ten. 4EFAH comes here.
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 in ASCII, always shown.
4F05
JUMP to 4E6BH, which shows the units digit and returns to the caller.

4F08H - Data

The powers of ten, the hexadecimal text, the FCB of the system data sector and the option table.

4F08-4F0F
DEFW D8F0H, FC18H, FF9CH, FFF6H F0 D8 18 FC 9C FF F6 FF
The negative powers of ten used by 4EE1H: minus 10000, minus 1000, minus 100 and minus 10.
4F10-4F15
DEFM "00000H" 30 30 30 30 30 48
The hexadecimal text of 4E46H: SYS0/SYS 44D2H writes four digits over 4F11H-4F14H; the 0 at 4F10H is shown before a first digit A-F, and the H at 4F15H ends every number.
4F16
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.
4F17
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).
4F18
DEFB 00H 00
FCB+2: 00H, no flags (the open would copy FPDE byte 1 here).
4F19-4F1A
DEFW 4300H 00 43
FCB+3 and +4: the address of the sector buffer, 4300H.
4F1B
DEFB 00H 00
FCB+5: the low byte of NEXT, the byte within the sector.
4F1C
DEFB 00H 00
FCB+6: the drive; 00H in the file, dn1 after 4D0DH stores it.
4F1D
DEFB FFH FF
FCB+7: the DEC of a directory entry; FFH for none.
4F1E
DEFB 00H 00
FCB+8: the low byte of the end of file, 00H (not used by the reads).
4F1F
DEFB 00H 00
FCB+9: the record length; 00H stands for 256 bytes.
4F20-4F21
DEFW 0002H 02 00
FCB+10 and +11: the middle and high bytes of NEXT, sector 2 (4F20H is stored again by 4E23H).
4F22-4F23
DEFW FFFFH FF FF
FCB+12 and +13: the end of file, FFFFH, so no read reaches it. The option table follows; this FCB has no extent area.

4F24H - Option Table (Data)

One byte per option code (first letter - A) x 26 + (second letter - A), read by 4D43H and 4DC0H. Bit 7 clear: a yes/no option, bit (bits 6-4) of system data byte F0H + (bits 3-0). Bit 7 set: a number at byte A0H + (bits 4-0), or with bit 6 a 16-bit number at D0H + (bits 4-0). FEH: an option this machine does not have. The first FFH (4F4CH) ends the display.

4F24-4F29
DEFB 70H, 60H, FEH, 68H, 58H, 48H 70 60 FE 68 58 48
AA (F0H bit 7), AB (F0H bit 6), AC (not on this machine), AD (F8H bit 6), AE (F8H bit 5), AF (F8H bit 4).
4F2A-4F2F
DEFB 50H, FEH, FEH, 18H, FEH, 80H 50 FE FE 18 FE 80
AG (F0H bit 5), AH and AI (not on this machine), AJ (F8H bit 1), AK (not on this machine), AL (a number at A0H).
4F30-4F35
DEFB 86H, 82H, 83H, C0H, 28H, 10H 86 82 83 C0 28 10
AM (a number at A6H), AN (A2H), AO (A3H), AP (a 16-bit number at D0H-D1H), AQ (F8H bit 2), AR (F0H bit 1).
4F36-4F3B
DEFB FEH, 71H, 08H, 87H, 81H, 88H FE 71 08 87 81 88
AS (not on this machine), AT (F1H bit 7), AU (F8H bit 0), AV (a number at A7H), AW (A1H), AX (A8H).
4F3C-4F41
DEFB 79H, 69H, 59H, 49H, 61H, 39H 79 69 59 49 61 39
AY (F9H bit 7), AZ (F9H bit 6), BA (F9H bit 5), BB (F9H bit 4), BC (F1H bit 6), BD (F9H bit 3).
4F42-4F47
DEFB 51H, FEH, 19H, 09H, 85H, 89H 51 FE 19 09 85 89
BE (F1H bit 5), BF (not on this machine), BG (F9H bit 1), BH (F9H bit 0), BI (a number at A5H), BJ (A9H).
4F48-4F4B
DEFB 41H, FEH, FEH, FEH 41 FE FE FE
BK (F1H bit 4), BL, BM and BN (not on this machine).
4F4C-4F6C
DEFB FFH x 33 FF x 33
Codes 40-71 (BO-CT) and one more byte: FFH, which ends the display at 4F4CH and gives error 34H when such an option is typed.

4F6DH - WRDIRP Command

WRDIRP dn1 rewrites every directory sector of the diskette in drive dn1 with the directory mark. It needs option BK (428DH bit 4, else error 37H). The boot sector (sector 0) must begin with 00H FEH; its byte 2 is the directory lump, so the GAT is sector lump x 5 x GPL (4285H, the drive's granules per lump). The first entry of the first FDE sector must be BOOT/SYS (a system file in use, first lump 0) and that of the second DIR/SYS (first lump = the directory lump), else error 2CH. Then the GAT, the HIT and the 8 + (HIT byte 1FH) FDE sectors are read (with or without the mark) and written back through the FCB at 501EH, whose FCB+0 bit 0 asks SYS0/SYS for the directory mark, with a verify.

4F6D
LD A,(428DH) 3A 8D 42
Load Register A with the byte at 428DH, SYS0/SYS's copy of system data byte F1H (options AT, BC, BE, BK). 4D02H comes here.
4F70
BIT 4,A CB 67
Test bit 4 of Register A: option BK, which allows WRDIRP.
4F72
LD A,37H 3E 37
Load Register A with 37H, the DOS error code DISKETTE ACCESS DENIED. LD does not change the flags.
4F74
If the Z FLAG is set (BK = N), JUMP to 4FD8H to leave with error 37H.
4F76
GOSUB to 4E73H, which reads dn1 at Register Pair HL into Register A (0-255, else error 2FH).
4F79
LD (5024H),A 32 24 50
Self-Modifying Code
Store Register A (dn1) at 5024H, FCB+6 (the drive number) of the FCB at 501EH.
4F7C
GOSUB to SYS0/SYS 4C7AH, which looks at the character after dn1 at Register Pair HL: the Z FLAG only at the carriage return.
4F7F
RET NZ C0
If the NZ FLAG is set (something follows dn1), RETURN to the dispatcher's tail 4BC5H with Register A = 34H (ILLEGAL KEYWORD OR SEPARATOR OR TERMINATOR).
4F80
LD DE,501EH 11 1E 50
Load Register Pair DE with 501EH, the FCB whose NEXT is 0000H in the file: sector 0, the boot sector.
4F83
GOSUB to SYS0/SYS 4436H, which selects drive dn1 (copying its PDRIVE bytes to 4280H-4287H) and reads the sector at NEXT of the FCB at Register Pair DE into 4300H, advancing NEXT; the NZ FLAG with an error code in Register A on failure.
4F86
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.
4F87
LD HL,4300H 21 00 43
Point Register Pair HL to 4300H, byte 0 of the boot sector.
4F8A
LD A,(HL) 7E
Load Register A with the byte at Register Pair HL, boot sector byte 0.
4F8B
OR A B7
OR Register A with itself to set the flags: the Z FLAG is set for 00H.
4F8C
If the NZ FLAG is set (byte 0 is not 00H), JUMP to 4FD6H for error 2CH.
4F8E
INC HL 23
INCrement Register Pair HL to boot sector byte 1.
4F8F
LD A,(HL) 7E
Load Register A with the byte at Register Pair HL, boot sector byte 1.
4F90
CP FEH FE FE
Compare Register A against FEH. The Z FLAG is set for FEH.
4F92
If the NZ FLAG is set (byte 1 is not FEH), JUMP to 4FD6H for error 2CH.
4F94
INC HL 23
INCrement Register Pair HL to boot sector byte 2, the directory lump.
4F95
LD L,(HL) 6E
Load Register L with the byte at Register Pair HL, the directory lump: Register Pair HL = 43xxH with Register L = the lump.
4F96
LD A,05H 3E 05
Load Register A with 05H, the sectors per granule.
4F98
PUSH HL E5
Save Register Pair HL (Register L = the directory lump) onto the stack; 4FA2H takes it back.
4F99
GOSUB to SYS0/SYS 4C37H, which multiplies Register L (the directory lump) by Register A (5): Register Pair HL = the lump x 5.
4F9C
LD A,(4285H) 3A 85 42
Load Register A with the byte at 4285H, byte +5 of the selected drive's PDRIVE values: its granules per lump.
4F9F
GOSUB to SYS0/SYS 4C39H, which multiplies Register Pair HL by Register A: Register Pair HL = the directory lump x 5 x GPL, the GAT's sector number.
4FA2
POP DE D1
Restore Register Pair DE from the stack: Register E = the directory lump (Register D = 43H).
4FA3
PUSH HL E5
Save Register Pair HL (the GAT's sector number) onto the stack; 4FC4H takes it back.
4FA4
PUSH DE D5
Save Register Pair DE (Register E = the directory lump) onto the stack; 4FBCH takes it back.
4FA5
INC HL 23
INCrement Register Pair HL to the HIT's sector number, the sector after the GAT.
4FA6
LD (5028H),HL 22 28 50
Store Register Pair HL (the HIT's sector) at 5028H-5029H, the middle and high bytes of NEXT of the FCB at 501EH.
4FA9
GOSUB to 4FDBH, which reads the sector at NEXT (the HIT) into 4300H, with or without the directory mark; NEXT then points at the first FDE sector.
4FAC
LD A,(431FH) 3A 1F 43
Load Register A with the byte at 431FH, HIT byte 1FH: the number of FDE sectors beyond the first 8.
4FAF
ADD A,0AH C6 0A
ADD 0AH to Register A: the GAT, the HIT and 8 FDE sectors are added, so Register A = the directory's sectors.
4FB1
LD H,A 67
Load Register H with Register A, the directory's sectors.
4FB2
EX (SP),HL E3
Exchange Register Pair HL with the word on top of the stack (at the Stack Pointer): Register H (the count) goes onto the stack, Register Pair HL = the word with the directory lump in Register L.
4FB3
PUSH HL E5
Save Register Pair HL (Register L = the directory lump) back onto the stack for 4FBCH.
4FB4
LD C,00H 0E 00
Load Register C with 00H, the first lump BOOT/SYS must have.
4FB6
LD HL,500FH 21 0F 50
Point Register Pair HL to 500FH, the name BOOT.
4FB9
GOSUB to 4FE7H, which reads the first FDE sector and checks that its first entry is the system file BOOT/SYS in use, with first lump Register C (0); error 2CH otherwise.
4FBC
POP BC C1
Restore Register Pair BC from the stack: Register C = the directory lump, the first lump DIR/SYS must have.
4FBD
LD HL,5013H 21 13 50
Point Register Pair HL to 5013H, the name DIR.
4FC0
GOSUB to 4FE7H, which reads the second FDE sector and checks that its first entry is the system file DIR/SYS in use, with first lump Register C (the directory lump); error 2CH otherwise.
4FC3
POP BC C1
Restore Register Pair BC from the stack: Register B = the directory's sectors (the count from 4FB1H).
4FC4
POP HL E1
Restore Register Pair HL from the stack: the GAT's sector number.

Rewrite Loop
Register Pair HL = the directory sector, Register B = the sectors left.

4FC5
LD (5028H),HL 22 28 50
Store Register Pair HL (the sector) at 5028H-5029H, the middle and high bytes of NEXT. 4FD3H comes back here.
4FC8
GOSUB to 4FDBH, which reads the sector at NEXT into 4300H with or without the directory mark (error 06H is accepted) and returns the Z FLAG; any other error leaves through 4E81H.
4FCB
LD (5028H),HL 22 28 50
Store Register Pair HL (the same sector) at 5028H-5029H again, since the read moved NEXT on.
4FCE
If the Z FLAG is set (always, after 4FDBH), GOSUB to SYS0/SYS 443CH, which writes the buffer at 4300H to the sector at NEXT with a verify; FCB+0 bit 0 of the FCB at 501EH makes it a write with the directory mark.
4FD1
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.
4FD2
INC HL 23
INCrement Register Pair HL to the next directory sector.
4FD3
DECrement Register B and LOOP BACK to 4FC5H for every directory sector.
4FD5
RET C9
RETURN to the dispatcher's tail 4BC5H with Register A = 00H and the Z FLAG from the last write: no error.
4FD6
LD A,2CH 3E 2C
Load Register A with 2CH, the DOS error code BAD DIRECTORY DATA. 4F8CH, 4F92H, 4FF1H, 4FF7H and 500AH come here.
4FD8
JUMP to 4E81H, which leaves through the SYS0/SYS error exit 4409H with the error code in Register A. 4F74H and 4FE4H come here.

4FDBH - Read a Directory Sector

Reads the sector at NEXT of the FCB at 501EH into 4300H. A good read, or error 06H (the sector has the directory mark), returns the Z FLAG; any other error leaves through 4E81H.

4FDB
LD DE,501EH 11 1E 50
Load Register Pair DE with 501EH, the FCB of WRDIRP. 4FA9H, 4FC8H and 4FE7H call here.
4FDE
GOSUB to SYS0/SYS 4436H, which reads the sector at NEXT of the FCB at Register Pair DE into 4300H and advances NEXT; the NZ FLAG with an error code in Register A on failure.
4FE1
RET Z C8
If the Z FLAG is set (read without the directory mark), RETURN with it.
4FE2
CP 06H FE 06
Compare Register A (the error code) against 06H, the error a sector with the directory mark gives. The Z FLAG is set for 06H.
4FE4
If the NZ FLAG is set (another error), JUMP to 4FD8H to leave with it.
4FE6
RET C9
RETURN with the Z FLAG: the sector was read and has the directory mark.

4FE7H - Check a System File's Entry

Reads the next directory sector (an FDE sector) and checks its first entry: byte 0 bits 6 and 4 set (a system file in use), byte 22 (the first lump of its first extent) = Register C, name = the 4 characters at Register Pair HL followed by the 7 characters at 5017H (four spaces and SYS). Any difference is error 2CH.

4FE7
GOSUB to 4FDBH, which reads the sector at NEXT (the next FDE sector) into 4300H. 4FB9H and 4FC0H call here.
4FEA
LD A,(4300H) 3A 00 43
Load Register A with the byte at 4300H, byte 0 of the sector's first entry.
4FED
AND 50H E6 50
AND Register A with 50H, keeping bit 6 (a system file) and bit 4 (the entry in use).
4FEF
CP 50H FE 50
Compare Register A against 50H. The Z FLAG is set if both are set.
4FF1
If the NZ FLAG is set (not a system file in use), JUMP to 4FD6H for error 2CH.
4FF3
LD A,(4316H) 3A 16 43
Load Register A with the byte at 4316H, byte 22 of the entry: the first lump of its first extent.
4FF6
CP C B9
Compare Register A against Register C, the lump the file must start in. The Z FLAG is set if equal.
4FF7
If the NZ FLAG is set (another lump), JUMP to 4FD6H for error 2CH.
4FF9
LD DE,4305H 11 05 43
Point Register Pair DE to 4305H, byte 5 of the entry, the start of its name.
4FFC
LD B,04H 06 04
Load Register B with 04H, the characters at Register Pair HL to compare (BOOT or DIR and a space).
4FFE
GOSUB to 5006H, which compares Register B bytes at Register Pair DE with those at Register Pair HL; error 2CH on a difference.
5001
LD HL,5017H 21 17 50
Point Register Pair HL to 5017H, four spaces and SYS: the rest of the name and the extension.
5004
LD B,07H 06 07
Load Register B with 07H, the characters to compare (entry bytes 9-15).

Compare Loop
Register Pair DE = the entry, Register Pair HL = the text, Register B = the bytes left.

5006
LD A,(DE) 1A
Load Register A with the byte at Register Pair DE, a character of the entry's name. 4FFEH calls here; 500CH comes back here.
5007
CP (HL) BE
Compare Register A against the byte at Register Pair HL, the character it must be.
5008
INC DE 13
INCrement Register Pair DE to the entry's next character. INC DE does not change the flags.
5009
INC HL 23
INCrement Register Pair HL to the text's next character. INC HL does not change the flags.
500A
If the NZ FLAG is set (the characters differ), JUMP to 4FD6H for error 2CH.
500C
DECrement Register B and LOOP BACK to 5006H for all the characters.
500E
RET C9
RETURN to the caller: every compared character of the entry's name matches.
500F-5012
DEFM "BOOT" 42 4F 4F 54
The first four characters of the name BOOT/SYS, compared by 4FB6H with entry bytes 5-8.
5013-5016
DEFM "DIR " 44 49 52 20
The first four characters of the name DIR/SYS (with a space), compared by 4FBDH with entry bytes 5-8.
5017-501D
DEFM " SYS" 20 20 20 20 53 59 53
The last four characters of the name (spaces) and the extension SYS, compared by 5001H with entry bytes 9-15.
501E
DEFB 83H 83
FCB+0 of the FCB of WRDIRP: bit 7 open, bit 1 NEXT is a sector number of the whole diskette, bit 0 the writes use the directory mark (SYS0/SYS 4A32H).
501F
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).
5020
DEFB 00H 00
FCB+2: 00H, no flags (the open would copy FPDE byte 1 here).
5021-5022
DEFW 4300H 00 43
FCB+3 and +4: the address of the sector buffer, 4300H.
5023
DEFB 00H 00
FCB+5: the low byte of NEXT, the byte within the sector.
5024
DEFB 00H 00
FCB+6: the drive; 00H in the file, dn1 after 4F79H stores it.
5025
DEFB FFH FF
FCB+7: the DEC of a directory entry; FFH for none.
5026
DEFB 00H 00
FCB+8: the low byte of the end of file, 00H (not used by the reads).
5027
DEFB 00H 00
FCB+9: the record length; 00H stands for 256 bytes.
5028-5029
DEFW 0000H 00 00
FCB+10 and +11: the middle and high bytes of NEXT, sector 0 (the boot sector) in the file; stored at 4FA6H, 4FC5H and 4FCBH.
502A-502B
DEFW FFFFH FF FF
FCB+12 and +13: the end of file, FFFFH, so no read reaches it.

502CH - End of a Diskette COPY

Not reached through 4D00H: SYS6/SYS loads SYS17/SYS (code F3H, which only returns) and its 54D4H jumps here when a diskette COPY has written every sector. SYS6/SYS stays in memory from 5200H on, so this code uses its routines and variables: the destination is verified from the source's last sector on, and unless BDU was given the destination's GAT gets the new password, name and date and, when the destination is larger than the source, its extra granules freed. It ends in SYS6/SYS at 552DH (DONE) or 54CBH (an error).

502C
GOSUB to SYS6/SYS 5535H, which switches to the destination diskette (control block 5956H) and points Index Register IX at its FCB, 5B17H.
502F
LD DE,(59C1H) ED 5B C1 59
Load Register Pair DE with the word at 59C1H, SYS6/SYS's count of the source's sectors: the first destination sector not written by the COPY.
5033
GOSUB to SYS6/SYS 5784H, which reads every destination sector from Register Pair DE to the end of the diskette (the directory mark is accepted), asking the operator about any error.
5036
LD BC,(5994H) ED 4B 94 59
Load Register Pair BC with the word at 5994H: Register C = SYS6/SYS's 5994H option flags, Register B = its 5995H flags.
503A
BIT 1,C CB 49
Test bit 1 of Register C (the 5994H flags): BDU, the destination's system data is not to be changed.
503C
If the NZ FLAG is set (BDU), JUMP to 509CH, which ends with DONE.
503E
GOSUB to SYS6/SYS 56F9H, which reads directory sector 0 (the GAT) of the destination into 4300H; Register Pair HL returns 4300H.
5041
LD E,61H 1E 61
Load Register E with 61H, one more than 96, the lump count compared below.
5043
LD A,(59C6H) 3A C6 59
Load Register A with the byte at 59C6H, byte +1 of SYS6/SYS's working record of the destination at 59C5H: its number of lumps.
5046
CP E BB
Compare Register A (the destination's lumps) against Register E (61H). The CARRY FLAG is set for 96 lumps or fewer.
5047
If the CARRY FLAG is set (the destination has at most 96 lumps), JUMP to 5057H.
5049
LD A,(59B8H) 3A B8 59
Load Register A with the byte at 59B8H, byte +1 of SYS6/SYS's working record of the source at 59B7H: its number of lumps.
504C
CP E BB
Compare Register A (the source's lumps) against Register E (61H). The NO CARRY FLAG is set for more than 96 lumps.
504D
If the NO CARRY FLAG is set (the source has more than 96 lumps), JUMP to 5057H.
504F
DEC E 1D
DECrement Register E to 60H, lump 96, the first GAT byte to fill.
5050
LD L,E 6B
Load Register L with Register E: Register Pair HL = 4360H, GAT byte 60H in the buffer (Register H = 43H from 56F9H).

Fill Loop
GAT bytes 60H-BFH (lumps 96-191, beyond the source's lumps) are set to FFH, every granule in use, before the destination's real granules past the source are freed below.

5051
LD (HL),FFH 36 FF
Store FFH at Register Pair HL, a GAT byte: every granule of that lump in use. 5055H comes back here.
5053
DEC E 1D
DECrement Register E, the GAT bytes left (60H in all).
5054
INC HL 23
INCrement Register Pair HL to the next GAT byte.
5055
If the NZ FLAG is set (bytes left), LOOP BACK to 5051H: GAT bytes 60H-BFH become FFH.
5057
BIT 5,B CB 68
Test bit 5 of Register B (the 5995H flags): NDPW, a new destination password was given. 5047H and 504DH come here.
5059
If the Z FLAG is set (no new password), JUMP to 5061H.
505B
LD HL,(5981H) 2A 81 59
Load Register Pair HL with the word at 5981H, SYS6/SYS's code of the new password.
505E
LD (43CEH),HL 22 CE 43
Store Register Pair HL (the password code) at 43CEH-43CFH, GAT bytes CEH-CFH, the diskette's password.
5061
LD A,C 79
Load Register A with Register C, the 5994H flags. 5059H comes here.
5062
AND 0CH E6 0C
AND Register A with 0CH, keeping bit 3 (KDN, keep the destination's name) and bit 2 (NDN, a new destination name). The Z FLAG is set if neither was given.
5064
LD BC,0010H 01 10 00
Load Register Pair BC with 0010H (16), the name and the date. LD does not change the flags.
5067
LD DE,43D0H 11 D0 43
Point Register Pair DE to 43D0H, GAT bytes D0H-D7H, the diskette's name.
506A
LD HL,5983H 21 83 59
Point Register Pair HL to 5983H, SYS6/SYS's diskette name (followed by the date at 598BH).
506D
If the NZ FLAG is set (KDN or NDN), JUMP to 5076H to copy the name and the date.
506F
LD HL,598BH 21 8B 59
Point Register Pair HL to 598BH, SYS6/SYS's diskette date only.
5072
LD E,DBH 1E DB
Load Register E with D8H: Register Pair DE = 43D8H, GAT bytes D8H-DFH, the diskette's date.
5074
LD C,08H 0E 08
Load Register C with 08H: Register Pair BC = 0008H, the date only.
5076
LDIR ED B0
LDIR: copy Register Pair BC bytes (16, or 8) from Register Pair HL (5983H or 598BH) to Register Pair DE (43D0H or 43D8H) in the GAT, upward. 506DH comes here.
5078
LD HL,(59D1H) 2A D1 59
Load Register Pair HL with the word at 59D1H, SYS6/SYS's count of the destination's granules.
507B
LD DE,(59C3H) ED 5B C3 59
Load Register Pair DE with the word at 59C3H, SYS6/SYS's count of the source's granules.
507F
OR A B7
OR Register A with itself, which clears the CARRY FLAG for the SBC.
5080
SBC HL,DE ED 52
SUBtract Register Pair DE (the source's granules) from Register Pair HL (the destination's granules) with the CARRY FLAG: the CARRY FLAG if the destination is smaller, the Z FLAG if equal.
5082
EX DE,HL EB
Exchange Register Pairs DE and HL: Register Pair DE = the destination's extra granules. EX does not change the flags.
5083
If the CARRY FLAG is set (the destination is smaller), JUMP to 5096H.
5085
If the Z FLAG is set (the same size), JUMP to 5096H.
5087
LD HL,(59C3H) 2A C3 59
Load Register Pair HL with the word at 59C3H, the source's granules: the first granule past the copied area.
508A
LD A,(59BCH) 3A BC 59
Load Register A with the byte at 59BCH, byte +5 of the source's working record: its granules per lump.
508D
GOSUB to SYS0/SYS 4C59H, which divides Register Pair HL by Register A: Register Pair HL = the lump, Register A = the granule within it.
5090
LD H,43H 26 43
Load Register H with 43H: Register Pair HL = 4300H + the lump, its byte in the GAT.
5092
LD C,A 4F
Load Register C with Register A, the granule within the lump.
5093
GOSUB to SYS6/SYS 5762H, which frees Register Pair DE granules in the GAT from granule Register C of the lump at Register Pair HL on.
5096
GOSUB to SYS0/SYS 48C4H, which writes the GAT sector in 4300H back with the directory mark and a verify; the NZ FLAG with an error code in Register A on failure. 5083H and 5085H come here.
5099
If the NZ FLAG is set (a write error), JUMP to SYS6/SYS 54CBH, which ends the command with the error code in Register A.
509C
JUMP to SYS6/SYS 552DH, which displays DONE and ends the command without an error. 503CH comes here.
509F-51E7
DEFB 00H x 329 00 x 329
329 bytes of 00H at the end of the file (509FH-51E7H); no code reads them.