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

Page Customization

Introduction/Summary

NEWDOS/80 v2.0 SYS7/SYS Disassembly - SYSTEM, HIMEM, PDRIVE, AUTO, ATTRIB, PROT, DUMP, PURGE, TIME and DATE (Model I)

SYS7/SYS holds ten library commands. It loads into the overlay area at 4D00H-51E7H (1,256 bytes in five load records, transfer address 4D00H). SYS1 calls it with LD A,E9H / RST 28H (function 7) and the sub-function from its command table in Register C; the SYS0 dispatcher (4BC2H) loads SYS7 when 4317H does not already hold its slot number (09H). SYSTEM, PDRIVE and PURGE are only started here: SYS7 reads the drive and checks the diskette password, then passes the rest of the command line to SYS17, SYS16 or SYS3.

The page shows every byte of the file once, in address order. Each row says what every register and address it uses holds at that moment.

Sub-Functions of Code E9H

CCommandWhat SYS7 does
1SYSTEMReads [password]:d, then RST 28H 33H (SYS17 function 1) with Register B = the drive (4D61H).
2HIMEMDisplays HIMEM (4049H) in hexadecimal, or sets it: at least 7000H, at most the top of memory found at reset (4D76H).
3PDRIVEReads [password]:d, then RST 28H 32H (SYS16 function 1) with Register B = the drive (4D65H).
4AUTOStores the rest of the line in GAT bytes E0H-FFH of drive 0 (4DD4H).
5ATTRIBChanges a file's FPDE: INV, VIS, PROT=, ACC=, UPD=, ASE=, ASC=, UDF=, LRL= (4DF3H).
6PROTChanges a diskette's GAT (PW=, NAME=, DATE=) and all its files (LOCK, UNLOCK, RUF) (4EC5H).
7DUMPWrites memory to a file in load module format (50EDH).
8(DUMP)The second half of DUMP, reached through the SYS0 49D3H chain after the first write (5142H). Not in SYS1's table.
9PURGEReads [password]:d, then RST 28H E5H with Register C = 06H (SYS3 function 7 sub-function 6) and Register B = the drive (4D69H).
0AHTIMEDisplays HH:MM:SS, or sets the clock at 4041H-4043H (4D32H).
0BHDATEDisplays MM/DD/YY, or sets the date at 4044H-4046H.
othernoneError 2AH. Any code other than E9H also gives 2AH.

Parameters and Passwords

  • Numbers (HIMEM, LRL=, DUMP, drive numbers) are decimal, or hexadecimal with a trailing H (4F9EH); a value over FFFFH gives error 2FH. TIME and DATE take exactly two decimal digits per field and do not check the ranges.
  • Keywords are separated by commas or spaces and looked up in the tables at 504DH (ATTRIB), 508CH (access levels) and 50C0H (PROT). The text only has to start with a keyword. A wrong keyword or separator gives error 34H, a bad value 2FH.
  • Passwords are encoded into 16-bit codes (501CH, the same steps as SYS2 5155H; a blank password is 4296H). A password is a letter followed by up to seven letters or digits; the eight-byte buffer at 51E8H is blanked again while the code is made.
  • ATTRIB needs the file to be open with full access (access level 0 in FCB+1); with option AA on, that means it was named with its update password. Otherwise error 19H.
  • PROT, SYSTEM, PDRIVE and PURGE compare the code of the password given before the drive number (password:d), or the blank code 4296H when none is given, with the diskette password code in GAT bytes CEH-CFH. A mismatch gives error 37H, but only when option AA is on (4E89H); so with option AA on, a diskette that has a password needs it even when none is typed.
  • PROT LOCK gives every file that is neither a system file nor invisible the diskette password code (the new one when PW= is also given) as both its update and access password; UNLOCK gives them the blank code and wins when both are given. RUF clears the updated flag of every file.

DUMP

DUMP filespec,start,end[,entry[,load]]. The file gets load module records: type 01H, length (data + 2, 00H = 256), load address, up to 254 data bytes; then the transfer record 02H 02H and the entry address (default 402DH). Addresses from start to end are written as load + (address - start), so a program can be saved from one place and loaded at another; the entry address is translated the same way when it is inside that range. With entry = FFFFH only two address bytes (the start) and the data are written, without records.

The file's sector buffer is 4D61H-4E60H, inside SYS7 itself. DUMP first positions the file at relative sector (count + 4) / 252 and writes one sector there so that all its space is allocated at once; because that write can load SYS2, it goes through the SYS0 chain at 49D3H with the word E908H, which comes back into SYS7 as sub-function 8 (5142H). The bytes are then sent one at a time through ROM 001BH with Register Pair DE = the FCB: SYS0 (4033H, 4ADBH) turns a device call on an FCB into a byte write. The file is closed through SYS0 4428H, which loads SYS3.

Variables

Self-Modified Operands

Address
Size
Contents
4DCBH
1 byte
TIME/DATE Separator
Operand of the CP at 4DCAH: 3AH (colon) for TIME or 2FH (slash) for DATE, stored by 4D3BH; 00H in the file.
4F13H
1 byte
PROT File Flags
Operand of the LD A,nn at 4F12H: bit 0 UNLOCK, bit 1 LOCK, bit 2 RUF, ORed in by 4EF9H; 00H in the file.
4F66H
1 byte
FDE Sector Count
Operand of the CP at 4F65H: 8 plus HIT byte 1FH, stored by 4F2CH; 00H in the file.
51B7H-51B8H
2 bytes
DUMP End Address
Operand of the LD HL,nnnn at 51B6H, stored by 5150H.
51BEH-51BFH
2 bytes
DUMP Start Address
Operand of the LD DE,nnnn at 51BDH, stored by 5154H.
51C5H-51C6H
2 bytes
DUMP Load Address
Operand of the LD HL,nnnn at 51C4H, stored by 514CH.

Work Areas

Address
Size
Contents
4D61H-4E60H
256 bytes
DUMP Sector Buffer
SYS7's own code for SYSTEM to ATTRIB, made the FCB's buffer by 50EDH.
51E8H-51EFH
8 bytes
Password Buffer
Not in the file. The name read by 4FFEH, padded with spaces and blanked again by 5046H.
51E8H-51F0H
9 bytes
Display Text
Not in the file. HH:MM:SS or MM/DD/YY (44ACH) or four hexadecimal digits (4063H), ended by 0DH at 4D86H.
4200H-42FFH
256 bytes
Directory Sector Buffer
The GAT for AUTO and PROT (42CEH password code, 42D0H name, 42D8H date, 42E0H AUTO command), the FPDE's sector for ATTRIB, the HIT (421FH) and the FDE sectors for LOCK, UNLOCK and RUF.

SYS0 Locations Used

Address
Size
Contents
4041H-4043H
3 bytes
Clock
Seconds, minutes, hours in binary; read by TIME (4D29H), set by 4DA7H.
4044H-4046H
3 bytes
Date
Year, day, month in binary; read by DATE (4D36H), set by 4DA7H.
4049H-404AH
2 bytes
HIMEM
Displayed by 4D7BH, set by 4DA2H.
4308H
1 byte
Current Drive
Read as IY-78H (Index Register IY = 4380H) at 4D72H.
436CH
1 byte
Option Flags
Bit 7 = option AA (passwords checked), tested at 4EBBH.
43A9H-43AAH
2 bytes
Top of Memory
Found at reset; the upper limit for HIMEM (4D98H).
4480H-449FH
32 bytes
DOS FCB
The DUMP file opened by SYS1; 4483H (buffer) set at 50F0H, 448AH (NEXT middle and high) at 5131H.

Outside Routines Called

AddressContents
0018HROM RST 18H: compare Register Pair HL with Register Pair DE (4E96H, 51B9H, 51C0H).
001BHROM output of one byte to a control block; on an FCB SYS0 writes it to the file (51D4H).
4063HSYS0: Register Pair DE as four hexadecimal digits (4D83H).
4409HSYS0: DOS error exit (4D5EH).
4428HSYS0: close (519AH).
4439H / 443FHSYS0: write / rewind (513FH; 5143H, 5195H).
4467HSYS0: display a message (4D89H).
44ACHSYS0: three bytes as two-digit fields with a separator (4D47H).
4776H / 47ECHSYS0: select a drive / select it and check for a diskette (4DD6H; 4EA7H).
490AH / 491FH / 4936H / 494BHSYS0: read a directory sector / write it back / read an FDE sector / read a file's FPDE.
49D3HSYS0: return point that turns a pushed word into RST 28H (5137H).
4CB4HSYS0: Register Pair HL divided by Register A (512EH).
4CC5H / 4CD5H / 4CD9HSYS0: compare a table name with the text / end of line or separator / separator.

Disassembly

4D00H - Function Dispatcher

SYS7 is entered from the SYS0 RST 28H dispatcher at 4BC2H, which has loaded SYS7 into 4D00H-51FFH and CALLs 4D00H with Register A = the RST 28H code, Register C = the sub-function and Register Pair HL = the rest of the command line, all as SYS1 left them. Only function 7 (code E9H) exists. Register C comes from byte 1 of SYS1's command table entry (4F58H): 1 SYSTEM, 2 HIMEM, 3 PDRIVE, 4 AUTO, 5 ATTRIB, 6 PROT, 7 DUMP, 8 the second half of DUMP (reached only through the 49D3H chain set up at 5137H), 9 PURGE, 0AH TIME, 0BH DATE. Any other code or sub-function returns error 2AH.

4D00
LD IY,4380H FD 21 80 43
Load Index Register IY with 4380H, the base address SYS0 and every overlay use for the SYS0 variables around 4300H; with it IY-78H is 4308H, the current drive number, which 4D72H reads.
4D04
CP E9H FE E9
Compare Register A, the RST 28H code passed by the dispatcher from SYS1, against E9H (SYS7 slot 09H, function 7): the Z FLAG is set only for the one function SYS7 has.
4D06
If the NZ FLAG is set (Register A holds some other code), JUMP to 4D32H, which returns error 2AH ILLEGAL DOS FUNCTION.
4D08
DEC C 0D
Decrement Register C, the sub-function number taken from SYS1's command table; the Z FLAG is set if Register C was 1 (SYSTEM).
4D09
If the Z FLAG is set (Register C was 1, the SYSTEM command), JUMP to 4D61H to read the drive and pass the command on to SYS17.
4D0B
DEC C 0D
Decrement Register C, the sub-function number (now 1 lower than SYS1 passed); the Z FLAG is set if Register C was 2 (HIMEM).
4D0C
If the Z FLAG is set (Register C was 2, the HIMEM command), JUMP to 4D76H to display or set HIMEM (4049H).
4D0F
DEC C 0D
Decrement Register C, the sub-function number (now 2 lower than SYS1 passed); the Z FLAG is set if Register C was 3 (PDRIVE).
4D10
If the Z FLAG is set (Register C was 3, the PDRIVE command), JUMP to 4D65H to read the drive and pass the command on to SYS16.
4D12
DEC C 0D
Decrement Register C, the sub-function number (now 3 lower than SYS1 passed); the Z FLAG is set if Register C was 4 (AUTO).
4D13
If the Z FLAG is set (Register C was 4, the AUTO command), JUMP to 4DD4H to store the AUTO command line in the GAT of drive 0.
4D16
DEC C 0D
Decrement Register C, the sub-function number (now 4 lower than SYS1 passed); the Z FLAG is set if Register C was 5 (ATTRIB).
4D17
If the Z FLAG is set (Register C was 5, the ATTRIB command), JUMP to 4DF3H to change the attributes of the file SYS1 has opened.
4D1A
DEC C 0D
Decrement Register C, the sub-function number (now 5 lower than SYS1 passed); the Z FLAG is set if Register C was 6 (PROT).
4D1B
If the Z FLAG is set (Register C was 6, the PROT command), JUMP to 4EC5H to change a diskette's GAT and the passwords of its files.
4D1E
DEC C 0D
Decrement Register C, the sub-function number (now 6 lower than SYS1 passed); the Z FLAG is set if Register C was 7 (DUMP).
4D1F
If the Z FLAG is set (Register C was 7, the DUMP command), JUMP to 50EDH to read the addresses and allocate the file's space.
4D22
DEC C 0D
Decrement Register C, the sub-function number (now 7 lower than SYS1 passed); the Z FLAG is set if Register C was 8 (DUMP's second half).
4D23
If the Z FLAG is set (Register C was 8, which only the SYS0 49D3H chain started at 5137H passes), JUMP to 5142H to write the memory to the file.
4D26
DEC C 0D
Decrement Register C, the sub-function number (now 8 lower than SYS1 passed); the Z FLAG is set if Register C was 9 (PURGE).
4D27
If the Z FLAG is set (Register C was 9, the PURGE command), JUMP to 4D69H to read the drive and pass the command on to SYS3.
4D29
LD DE,4043H 11 43 40
Prepare TIME: load Register Pair DE with 4043H, the hours byte of the SYS0 clock (seconds, minutes and hours are kept in binary at 4041H, 4042H and 4043H); the fields are handled from 4043H downward.
4D2C
LD B,3AH 06 3A
Load Register B with 3AH, the colon that separates the TIME fields (HH:MM:SS); 4D3AH stores it as the CP operand at 4DCBH and SYS0 44ACH writes it between the digits.
4D2E
DEC C 0D
Decrement Register C, the sub-function number (now 9 lower than SYS1 passed); the Z FLAG is set if Register C was 0AH (TIME).
4D2F
If the Z FLAG is set (Register C was 0AH, the TIME command), JUMP to 4D3AH with Register Pair DE = 4043H and Register B = 3AH.
4D31
DEC C 0D
Decrement Register C, the sub-function number (now 10 lower than SYS1 passed); the Z FLAG is set if Register C was 0BH (DATE), and 4D32H falls through to DATE with it.

4D32H - Error 2AH, and the TIME and DATE Commands

4D32H is reached from 4D06H for a code that is not E9H (NZ FLAG) and falls through from 4D31H, where the Z FLAG says whether the sub-function was 0BH (DATE). TIME and DATE without a parameter display the clock as HH:MM:SS or the date as MM/DD/YY through SYS0 44ACH; with a parameter they set it at 4DA7H.

4D32
LD A,2AH 3E 2A
Load Register A with 2AH, the error code ILLEGAL DOS FUNCTION, in case the next instruction leaves; LD does not change the flags, so the Z FLAG from 4D31H (or the NZ FLAG from 4D04H) is still the one tested.
4D34
If the NZ FLAG is set (the code was not E9H, or Register C was not 0BH after all the DEC C steps), JUMP to 4D5EH, the error exit, with Register A = 2AH.
4D36
LD E,46H 1E 46
DATE: load Register E with 46H, so that Register Pair DE (still 40xxH from 4D29H) = 4046H, the month byte of the SYS0 date (year, day and month are kept in binary at 4044H, 4045H and 4046H).
4D38
LD B,2FH 06 2F
Load Register B with 2FH, the slash that separates the DATE fields (MM/DD/YY); it replaces the colon put in Register B at 4D2CH.
4D3A
LD A,B 78
TIME and DATE: load Register A with Register B, the field separator (3AH colon for TIME from 4D2CH, 2FH slash for DATE from 4D38H).
4D3B
LD (4DCBH),A 32 CB 4D
Self-Modifying Code
Store Register A, the separator, at 4DCBH, the operand of the CP at 4DCAH, so that the setting loop at 4DAAH checks for the right separator between the fields.
4D3E
LD A,(HL) 7E
Load Register A with the byte at Register Pair HL, the next character of the command line after TIME or DATE (SYS1 left Register Pair HL there).
4D3F
CP 0DH FE 0D
Compare Register A, the next command line character, against 0DH, the carriage return that ends the line; the Z FLAG is set when nothing follows the command.
4D41
If the NZ FLAG is set (Register A is not the carriage return, so a time or date follows), JUMP to 4DA7H to set the clock or date from the text at Register Pair HL.
4D43
LD HL,51E8H 21 E8 51
No parameter: load Register Pair HL with 51E8H, a text buffer just past the end of SYS7's file (51E8H-51FFH is in the overlay area but not in the file).
4D46
PUSH HL E5
Save Register Pair HL, 51E8H (the start of the text to be built), on the stack for 4D88H, which takes it back to display the text.
4D47
GOSUB to SYS0 44ACH, which writes the three binary bytes from Register Pair DE (4043H or 4046H) downward to Register Pair HL (51E8H) as two decimal digits each, with the separator in Register B between them; Register Pair HL comes back past the last digit.
4D4A
JUMP to 4D86H to put a carriage return at Register Pair HL (after the last digit) and display the text from 51E8H.

4D4CH - Unreferenced Error Exit

Nothing in SYS7, and no other module, reaches 4D4CH: no branch, table entry or pushed address names it.

4D4C
LD A,2CH 3E 2C
Load Register A with 2CH, the error code BAD DIRECTORY DATA. No instruction in SYS7 branches here, so this row is never executed.
4D4E
JUMP to 4D5EH, the error exit, with Register A = 2CH; like 4D4CH, never executed because nothing reaches 4D4CH.

4D50H - Error Exits and the End of the Command

4D50H returns error 20H (from 4EA2H, a drive number of 256 or more). 4D54H accepts the end of the line (Z FLAG) or a separator (NZ FLAG, Register Pair HL past it) and gives error 34H for anything else; 4D58H accepts only the end of the line. 4D5EH is the common error exit through SYS0 4409H, which displays the error and ends the command.

4D50
LD A,20H 3E 20
Load Register A with 20H, the error code ILLEGAL OR MISSING DRIVE #, for a drive number of 256 or more found at 4EA2H.
4D52
JUMP to 4D5EH, the error exit, with Register A = 20H.
4D54
GOSUB to SYS0 4CD5H with Register Pair HL = the command line: at the carriage return it returns the Z FLAG (and NO CARRY); after stepping Register Pair HL over a comma or spaces it returns the NZ FLAG and NO CARRY; before any other character it returns the CARRY FLAG with Register Pair HL unchanged. Register A comes back as 34H except at the carriage return.
4D57
RET NC D0
If the NO CARRY FLAG is set (Register Pair HL is at the end of the line, Z FLAG, or past a separator, NZ FLAG), RETURN to the caller with those flags.
4D58
LD A,(HL) 7E
Load Register A with the byte at Register Pair HL, the next command line character (the caller wants nothing more on the line).
4D59
CP 0DH FE 0D
Compare Register A, that character, against 0DH, the carriage return that ends the line; the Z FLAG is set at the end.
4D5B
RET Z C8
If the Z FLAG is set (Register A is the carriage return: the line has ended as required), RETURN with the Z FLAG set and Register A = 0DH.
4D5C
LD A,34H 3E 34
Load Register A with 34H, the error code ILLEGAL KEYWORD OR SEPARATOR OR TERMINATOR: the character at Register Pair HL is not allowed here (also reached from 4F90H when no keyword matched).
4D5E
JUMP to SYS0 4409H, the DOS error exit, with the error code in Register A; 4409H displays the message and returns to DOS READY (or to the DOS-CALL caller).

4D61H - SYSTEM, PDRIVE and PURGE Commands

These three read only [password]:d or d and check the diskette password at 4E89H; then they pass the rest of the command line to another overlay with Register B = the drive: SYSTEM to SYS17 function 1 (code 33H), PDRIVE to SYS16 function 1 (code 32H), PURGE to SYS3 function 7 sub-function 6 (code E5H, Register C = 06H).

4D61
LD B,33H 06 33
SYSTEM: load Register B with 33H, the RST 28H code of SYS17 function 1 (slot 13H, function 1), which performs the SYSTEM command.
4D63
JUMP to 4D6CH with Register B = 33H, the SYS17 code; Register C is not used by SYS17 function 1.
4D65
LD B,32H 06 32
PDRIVE: load Register B with 32H, the RST 28H code of SYS16 function 1 (slot 12H, function 1), which performs the PDRIVE command.
4D67
JUMP to 4D6CH with Register B = 32H, the SYS16 code; Register C is not used by SYS16 function 1.
4D69
LD BC,E506H 01 06 E5
PURGE: load Register Pair BC with E506H: Register B = E5H, the RST 28H code of SYS3 function 7, and Register C = 06H, SYS3's PURGE sub-function.
4D6C
PUSH BC C5
Save Register Pair BC (Register B = the RST 28H code, Register C = the sub-function for PURGE) on the stack, because 4E89H uses Register Pair BC.
4D6D
GOSUB to 4E89H to read [password]:d at Register Pair HL, select the drive, read its GAT into 4200H and check the diskette password; Register Pair HL comes back after the drive number.
4D70
POP BC C1
Restore Register Pair BC from the stack: Register B = the RST 28H code (33H, 32H or E5H) and Register C = 06H for PURGE.
4D71
LD A,B 78
Load Register A with Register B, the RST 28H code of the overlay that does the work.
4D72
LD B,(IY-78H) FD 46 88
Load Register B with the byte at Index Register IY-78H, which is 4308H (Index Register IY = 4380H from 4D00H): the drive number 4E89H just selected.
4D75
RST 28H EF
RST 28H with Register A = the code: the SYS0 dispatcher loads the other overlay over SYS7 and runs it with Register B = the drive, Register C = the sub-function and Register Pair HL = the rest of the command line; that overlay returns to SYS1.

4D76H - HIMEM Command

Without a parameter HIMEM displays the address held in 4049H (HIMEM) as four hexadecimal digits. With one it stores the value, which may be decimal or hexadecimal with a trailing H (4F9EH); it must be 7000H or higher, and it is lowered to the top of memory found at reset (43A9H) if it is above it.

4D76
LD A,(HL) 7E
Load Register A with the byte at Register Pair HL, the next command line character after HIMEM (SYS1 left Register Pair HL there).
4D77
CP 0DH FE 0D
Compare Register A, that character, against 0DH, the carriage return that ends the line; the Z FLAG is set when no value follows.
4D79
If the NZ FLAG is set (Register A is not the carriage return, so a value follows), JUMP to 4D8CH to set HIMEM.
4D7B
LD DE,(4049H) ED 5B 49 40
Load Register Pair DE with the 16-bit value at 4049H, HIMEM: the highest address free for programs, set at reset and by HIMEM.
4D7F
LD HL,51E8H 21 E8 51
Load Register Pair HL with 51E8H, a text buffer just past the end of SYS7's file, where the four hexadecimal digits are built.
4D82
PUSH HL E5
Save Register Pair HL, 51E8H (the start of the text), on the stack for 4D88H, which takes it back to display the text.
4D83
GOSUB to SYS0 4063H to write Register Pair DE (HIMEM) as four hexadecimal digits at Register Pair HL (51E8H-51EBH); Register Pair HL comes back past the last digit.
4D86
LD (HL),0DH 36 0D
Store 0DH (a carriage return) at Register Pair HL, the byte after the last digit, to end the text (TIME and DATE also arrive here from 4D4AH).
4D88
POP HL E1
Restore Register Pair HL from the stack: 51E8H, the start of the text saved at 4D46H or 4D82H.
4D89
JUMP to SYS0 4467H to display the text at Register Pair HL up to the carriage return; 4467H returns to SYS1 with no error.
4D8C
GOSUB to 4F9EH to read the number at Register Pair HL (decimal, or hexadecimal with a trailing H) into Register Pair DE; a bad number gives error 2FH there.
4D8F
GOSUB to 4D58H: the line must end after the number at Register Pair HL, else error 34H.
4D92
LD A,D 7A
Load Register A with Register D, the high byte of the new HIMEM value in Register Pair DE.
4D93
CP 70H FE 70
Compare Register A, the high byte of the value, against 70H: the CARRY FLAG is set if the value in Register Pair DE is below 7000H.
4D95
If the CARRY FLAG is set (the value in Register Pair DE is below 7000H), JUMP to 4DD0H for error 2FH BAD PARAMETER(S).
4D98
LD HL,(43A9H) 2A A9 43
Load Register Pair HL with the 16-bit value at 43A9H, the top of memory that the SYS0 reset code found (HIMEM may not be set above it).
4D9B
OR A B7
OR Register A with itself to clear the CARRY FLAG before the SBC; Register A (the value's high byte) is not changed.
4D9C
SBC HL,DE ED 52
Subtract Register Pair DE (the new value) from Register Pair HL (the top of memory from 43A9H): the CARRY FLAG is set if the value is above the top of memory.
4D9E
ADD HL,DE 19
Add Register Pair DE (the new value) back to Register Pair HL, which is the top of memory again; the ADD carries exactly when the SBC borrowed, so the CARRY FLAG still says whether the value was above the top.
4D9F
If the CARRY FLAG is set (the value in Register Pair DE is above the top of memory), JUMP to 4DA2H to store the top of memory in Register Pair HL instead.
4DA1
EX DE,HL EB
Exchange Register Pairs DE and HL: Register Pair HL = the new value (accepted as it is) and Register Pair DE = the top of memory.
4DA2
LD (4049H),HL 22 49 40
Store Register Pair HL (the accepted value, or the top of memory from 43A9H) at 4049H, HIMEM.
4DA5
XOR A AF
Load Register A with 00H (XOR A with itself), which also sets the Z FLAG: no error for SYS1.
4DA6
RET C9
RETURN to SYS1 through the dispatcher with Register A = 00H and the Z FLAG set: HIMEM has been set.

4DA7H - TIME and DATE: Set the Clock or Date

Three fields of two decimal digits, separated by the character stored at 4DCBH (: or /), are stored downward from Register Pair DE: hours, minutes and seconds at 4043H-4041H, or month, day and year at 4046H-4044H. The values are not range-checked. Interrupts are off while the fields are stored, so the clock does not tick in between. A field that is not two digits, or a wrong separator, gives error 2FH; anything but the end of the line after the third field gives error 34H, after the values are already stored.

4DA7
DI F3
Disable interrupts, so that the SYS0 timer interrupt (which counts the seconds at 4041H) cannot change the clock while it is being set.
4DA8
LD B,03H 06 03
Load Register B with 03H, the number of two-digit fields to read (hours, minutes, seconds or month, day, year).

Field Loop
Register Pair HL = the command line, Register Pair DE = the clock or date byte for this field, Register B = the fields left.

4DAA
LD A,(HL) 7E
Load Register A with the byte at Register Pair HL, the first (tens) digit of the field.
4DAB
SUB 30H D6 30
Subtract 30H from Register A, the character: the digits 0-9 become 00H-09H, anything else a value of 0AH or more (or a borrow).
4DAD
CP 0AH FE 0A
Compare Register A, the converted character, against 0AH: the CARRY FLAG is set only for a digit 0-9.
4DAF
INC HL 23
Increment Register Pair HL past the tens digit in the command line; INC HL does not change the flags.
4DB0
If the NO CARRY FLAG is set (Register A was not a digit), JUMP to 4DCFH to enable interrupts and give error 2FH.
4DB2
LD C,A 4F
Load Register C with Register A, the tens digit (00H-09H), to be multiplied by 10.
4DB3
RLCA 07
Rotate Register A (the tens digit, 00H-09H) left: Register A = the digit times 2; no bit leaves the byte for values this small.
4DB4
RLCA 07
Rotate Register A left again: Register A = the tens digit times 4.
4DB5
ADD A,C 81
Add Register C (the tens digit) to Register A (the digit times 4): Register A = the tens digit times 5.
4DB6
ADD A,A 87
Add Register A to itself: Register A = the tens digit times 10, the value of the tens place.
4DB7
LD C,A 4F
Load Register C with Register A, the tens place value (0-90), to add the units digit to it.
4DB8
LD A,(HL) 7E
Load Register A with the byte at Register Pair HL, the second (units) digit of the field.
4DB9
SUB 30H D6 30
Subtract 30H from Register A, the character: the digits 0-9 become 00H-09H.
4DBB
CP 0AH FE 0A
Compare Register A, the converted character, against 0AH: the CARRY FLAG is set only for a digit 0-9.
4DBD
INC HL 23
Increment Register Pair HL past the units digit in the command line; INC HL does not change the flags.
4DBE
If the NO CARRY FLAG is set (Register A was not a digit), JUMP to 4DCFH to enable interrupts and give error 2FH.
4DC0
ADD A,C 81
Add Register C (the tens place value) to Register A (the units digit): Register A = the field's binary value, 0-99.
4DC1
LD (DE),A 12
Store Register A, the field's value, at Register Pair DE, the clock or date byte (4043H/4046H first, then the lower ones).
4DC2
DEC DE 1B
Decrement Register Pair DE to the next clock or date byte down (minutes then seconds, or day then year).
4DC3
Decrement Register B, the fields left; if Register B is not 0, JUMP to 4DC9H to check the separator before the next field.
4DC5
EI FB
All three fields are stored: enable interrupts again, so the SYS0 timer interrupt resumes counting from the new clock values.
4DC6
JUMP to SYS0 4CD5H with Register Pair HL after the third field: at the carriage return it returns the Z FLAG (no error); otherwise it returns the NZ FLAG with Register A = 34H, which SYS1 reports as an error.
4DC9
LD A,(HL) 7E
Load Register A with the byte at Register Pair HL, the character after the field, which must be the separator.
4DCA
CP 00H FE 00
Self-Modifying Code
Compare Register A, that character, against the separator in the operand at 4DCBH (00H in the file; 4D3BH stores 3AH for TIME or 2FH for DATE); the Z FLAG is set if it matches.
4DCC
INC HL 23
Increment Register Pair HL past the separator; INC HL does not change the flags.
4DCD
If the Z FLAG is set (Register A was the right separator), LOOP back to 4DAAH for the next field, with Register Pair DE at the next byte down.
4DCF
EI FB
Enable interrupts again before reporting the error (a field that was not two digits, or a wrong separator); fields already read stay stored.
4DD0
LD A,2FH 3E 2F
Load Register A with 2FH, the error code BAD PARAMETER(S); also the error entry for every other bad value in SYS7 (HIMEM below 7000H, AUTO too long, LRL=, Y/N, numbers, DUMP addresses).
4DD2
JUMP to 4D5EH, the error exit, with Register A = 2FH.

4DD4H - AUTO Command

Stores the rest of the command line, up to and including its carriage return, in bytes E0H-FFH of the GAT of drive 0: the command the reset code runs automatically. At most 31 characters fit with the carriage return; longer text gives error 2FH and nothing is written. AUTO with nothing after it stores only the carriage return, which removes the AUTO command.

4DD4
EX DE,HL EB
Exchange Register Pairs DE and HL: Register Pair DE = the command line after AUTO (from SYS1), because Register Pair HL is needed for the GAT.
4DD5
XOR A AF
Load Register A with 00H (XOR A with itself): drive 0, the system diskette whose GAT holds the AUTO command.
4DD6
GOSUB to SYS0 4776H to select the drive in Register A (drive 0); it returns the NZ FLAG with an error code in Register A if the drive cannot be used.
4DD9
RET NZ C0
If the NZ FLAG is set (drive 0 could not be selected), RETURN to SYS1 with the error code in Register A.
4DDA
XOR A AF
Load Register A with 00H (XOR A with itself): directory sector 0 of the diskette, the GAT.
4DDB
GOSUB to SYS0 490AH to read directory sector Register A (the GAT) into the buffer at 4200H; Register Pair HL comes back as 4200H.
4DDE
RET NZ C0
If the NZ FLAG is set (the GAT could not be read), RETURN to SYS1 with the error code in Register A.
4DDF
LD B,20H 06 20
Load Register B with 20H, the 32 bytes of GAT E0H-FFH: room for 31 characters and the carriage return.
4DE1
LD L,E0H 2E E0
Load Register L with E0H: Register Pair HL (4200H from 490AH) becomes 42E0H, GAT byte E0H, where the AUTO command starts.

Copy Loop
Register Pair DE = the command line, Register Pair HL = the GAT byte (42E0H-42FFH), Register B = the bytes of room left.

4DE3
LD A,(DE) 1A
Load Register A with the byte at Register Pair DE, the next character of the AUTO text.
4DE4
CP 0DH FE 0D
Compare Register A, that character, against 0DH, the carriage return that ends the line; the Z FLAG is set at the end.
4DE6
LD (HL),A 77
Store Register A (the character, or the final carriage return) at Register Pair HL in the GAT copy at 42E0H-42FFH; LD does not change the flags.
4DE7
INC DE 13
Increment Register Pair DE to the next character of the command line.
4DE8
INC HL 23
Increment Register Pair HL to the next GAT byte.
4DE9
If the Z FLAG is set (the carriage return in Register A has been stored), JUMP to 4DF0H to write the GAT back.
4DEB
Decrement Register B, the bytes of room left; if Register B is not 0, LOOP back to 4DE3H for the next character.
4DED
The 32 bytes are used and no carriage return was stored: JUMP to 4DD0H for error 2FH BAD PARAMETER(S); the GAT in 4200H is not written.
4DF0
JUMP to SYS0 491FH to write the directory sector in 4200H (the GAT here, the FPDE's sector for ATTRIB from 4E61H) back with the directory mark and verify; it returns the result to SYS1.

4DF3H - ATTRIB Command

SYS1 has opened the file (FCB at Register Pair DE) and, because the command table entry has bit 3 of byte 3 set, left the command line pointer on the stack under the dispatcher's return address. The file must have been opened with full access (access level 0: its update password, or any password when option AA is off), otherwise error 19H. Its FPDE is read and changed by the keywords in the table at 504DH, separated by commas or spaces; then the directory sector is written back. Keywords: INV and VIS (invisible bit), PROT=level (508CH), ACC=password, UPD=password, ASE=Y/N, ASC=Y/N, UDF=Y/N and LRL=n.

4DF3
POP AF F1
Restore Register Pair AF from the stack, discarding the dispatcher's return address (4C20H), so that the command line pointer SYS1 left is on top.
4DF4
POP HL E1
Restore Register Pair HL from the stack: the command line pointer left by SYS1, at the character after the filespec.
4DF5
GOSUB to 4F6BH: a comma or spaces must follow the filespec at Register Pair HL (else error 34H); Register Pair HL comes back past them, at the first keyword.
4DF8
PUSH DE D5
Save Register Pair DE, the FCB address from SYS1, on the stack to move it into Index Register IX.
4DF9
POP IX DD E1
Restore Index Register IX from the stack: Index Register IX = the FCB, which SYS0 494BH (4E03H) needs.
4DFB
INC DE 13
Increment Register Pair DE (the FCB address) to FCB+1, which holds the access level granted when the file was opened.
4DFC
LD A,(DE) 1A
Load Register A with the byte at Register Pair DE, FCB+1: bit 7 record mode, bits 5-3 buffer flags, bits 0-2 the access level.
4DFD
AND 07H E6 07
Mask Register A (FCB+1) against 07H (0000 0111) to keep bits 0-2, the access level; the Z FLAG is set for level 0, FULL access.
4DFF
LD A,19H 3E 19
Load Register A with 19H, the error code FILE ACCESS DENIED, in case the next instruction leaves; LD does not change the flags.
4E01
RET NZ C0
If the NZ FLAG is set (the file was opened with a level other than FULL), RETURN to SYS1 with error 19H in Register A.
4E02
PUSH HL E5
Save Register Pair HL, the command line pointer at the first keyword, on the stack (494BH uses Register Pair HL).
4E03
GOSUB to SYS0 494BH to read the file's FPDE (using the FCB at Index Register IX): Register Pair HL comes back pointing at the entry in the directory sector at 4200H-42FFH.
4E06
If the NZ FLAG is set (the FPDE could not be read or does not match the FCB), JUMP to 4D5EH, the error exit, with the error code in Register A.
4E09
EX (SP),HL E3
Exchange Register Pair HL with the word at the top of the stack (at the Stack Pointer SP): Register Pair HL = the command line pointer again, and the FPDE's address is kept on the stack for the keyword handlers.
4E0A
LD BC,504DH 01 4D 50
Load Register Pair BC with 504DH, the ATTRIB keyword table (4E5EH loops back here for each further keyword).
4E0D
JUMP to 4F71H to find the keyword at Register Pair HL in the table at Register Pair BC and jump to its handler with Register Pair HL past the keyword.

4E10H - ATTRIB LRL=

LRL=n sets the record length (FPDE byte 4) to n, 1-256; 256 is stored as 00H. Other values give error 2FH.

4E10
GOSUB to 4F9EH to read the number after LRL= at Register Pair HL into Register Pair DE (decimal, or hexadecimal with a trailing H).
4E13
DEC DE 1B
Decrement Register Pair DE, the record length: 1-256 become 0000H-00FFH, so a valid length has Register D = 00H.
4E14
LD A,D 7A
Load Register A with Register D, the high byte of the record length minus 1.
4E15
OR A B7
OR Register A (the high byte) with itself: the Z FLAG is set only if Register D is 00H, that is for a record length of 1-256.
4E16
If the NZ FLAG is set (the number in Register Pair DE was 0 or above 256), JUMP to 4DD0H for error 2FH BAD PARAMETER(S).
4E18
EX (SP),HL E3
Exchange Register Pair HL with the word at the top of the stack (at the Stack Pointer SP): Register Pair HL = the FPDE's address, and the command line pointer is kept on the stack.
4E19
PUSH HL E5
Save Register Pair HL, the FPDE's address (byte 0 of the entry), on the stack again.
4E1A
INC HL 23
Increment Register Pair HL, the FPDE pointer, to byte 1 of the entry (the second flag byte).
4E1B
INC HL 23
Increment Register Pair HL, the FPDE pointer, to byte 2 of the entry.
4E1C
INC HL 23
Increment Register Pair HL, the FPDE pointer, to byte 3 of the entry (the EOF low byte).
4E1D
INC HL 23
Increment Register Pair HL, the FPDE pointer, to byte 4 of the entry, the record length (LRL).
4E1E
INC E 1C
Increment Register E, the record length minus 1: the 1 is added back, and a length of 256 becomes 00H.
4E1F
LD (HL),E 73
Store Register E, the record length (00H for 256), at Register Pair HL, byte 4 of the FPDE.
4E20
POP HL E1
Restore Register Pair HL from the stack: the FPDE's address (byte 0 of the entry).
4E21
JUMP to 4E4AH to put the FPDE's address back on the stack and look for the next keyword.

4E23H - ATTRIB UDF=, ASE= and ASC=

Each changes one bit of FPDE byte 1: UDF (bit 5, the file has been updated) is set by Y and cleared by N; ASE (bit 7, the file may not be extended) and ASC (bit 6, CLOSE keeps the space beyond EOF) are cleared by Y and set by N, because the bits stand for the opposite of the keyword. Anything but Y or N gives error 2FH.

4E23
LD C,20H 0E 20
UDF=: load Register C with 20H (0010 0000), bit 5 of FPDE byte 1, the bit that says the file has been updated.
4E25
LD DE,FF00H 11 00 FF
Load Register Pair DE with FF00H: Register D = FFH (the bit is set) for Y, Register E = 00H (the bit is cleared) for N.
4E28
JUMP to 4E33H to read the Y or N with Register C = 20H and Register Pair DE = FF00H.
4E2A
LD C,80H 0E 80
ASE=: load Register C with 80H (1000 0000), bit 7 of FPDE byte 1, the bit that stops the file from being extended.
4E2C
JUMP to 4E30H to load the Y/N values for an inverted bit, with Register C = 80H.
4E2E
LD C,40H 0E 40
ASC=: load Register C with 40H (0100 0000), bit 6 of FPDE byte 1, the bit that stops CLOSE from releasing the space beyond EOF.
4E30
LD DE,00FFH 11 FF 00
Load Register Pair DE with 00FFH: Register D = 00H (the bit is cleared) for Y, Register E = FFH (the bit is set) for N.
4E33
LD A,(HL) 7E
Load Register A with the byte at Register Pair HL, the character after the = of the keyword.
4E34
CP 59H FE 59
Compare Register A, that character, against 59H, the letter Y; the Z FLAG is set for Y.
4E36
INC HL 23
Increment Register Pair HL past the Y or N in the command line; INC HL does not change the flags.
4E37
If the Z FLAG is set (Register A was Y), JUMP to 4E3EH with the Y value already in Register D.
4E39
LD D,E 53
Load Register D with Register E, the N value, in case the character is N.
4E3A
CP 4EH FE 4E
Compare Register A, the character, against 4EH, the letter N; the Z FLAG is set for N.
4E3C
If the NZ FLAG is set (Register A is neither Y nor N), JUMP to 4DD0H for error 2FH BAD PARAMETER(S).
4E3E
EX (SP),HL E3
Exchange Register Pair HL with the word at the top of the stack (at the Stack Pointer SP): Register Pair HL = the FPDE's address, and the command line pointer is kept on the stack.
4E3F
INC HL 23
Increment Register Pair HL, the FPDE pointer, to byte 1 of the entry, the flag byte with bits 7, 6 and 5.
4E40
LD A,C 79
Load Register A with Register C, the single bit to change (80H, 40H or 20H).
4E41
AND D A2
AND Register A (the bit) with Register D, the value FFH or 00H chosen by the Y or N: Register A = the bit if it is to be set, else 00H.
4E42
LD B,A 47
Load Register B with Register A, the new state of the bit (the bit itself or 00H).
4E43
LD A,FFH 3E FF
Load Register A with FFH, all bits set, to build the mask that keeps the other bits of byte 1.
4E45
XOR C A9
XOR Register A (FFH) with Register C, the bit: Register A = every bit except that one, the mask that keeps the other bits.
4E46
AND (HL) A6
AND Register A (the mask) with the byte at Register Pair HL, FPDE byte 1: Register A = byte 1 with the bit cleared.
4E47
OR B B0
OR Register A (byte 1 with the bit cleared) with Register B, the new state of the bit: Register A = the new byte 1.
4E48
LD (HL),A 77
Store Register A, the new flag byte, at Register Pair HL, byte 1 of the FPDE.
4E49
DEC HL 2B
Decrement Register Pair HL, the FPDE pointer, back to byte 0 of the entry, the address kept on the stack.
4E4A
EX (SP),HL E3
Exchange Register Pair HL with the word at the top of the stack (at the Stack Pointer SP): Register Pair HL = the command line pointer again, and the FPDE's address is kept on the stack.
4E4B
JUMP to 4E5BH to look for a separator and the next keyword at Register Pair HL, or the end of the line.

4E4DH - ATTRIB INV, VIS and PROT=

INV sets and VIS clears bit 3 of FPDE byte 0 (invisible). PROT=level stores the access level (LOCK 7, EXEC 6, READ 5, WRITE 4, RENAME or NAME 2, KILL 1, FULL 0; table 508CH) in bits 0-2 of byte 0. 4E5BH then continues with the next keyword, or at the end of the line writes the directory sector.

4E4D
LD C,08H 0E 08
INV: load Register C with 08H (0000 1000), bit 3 of FPDE byte 0 set: the file becomes invisible to DIR without the I option.
4E4F
JUMP to 4E53H with the new bit in Register C (08H).
4E51
LD C,00H 0E 00
VIS: load Register C with 00H, bit 3 of FPDE byte 0 clear: the file becomes visible.
4E53
LD B,F7H 06 F7
Load Register B with F7H (1111 0111), the mask that keeps every bit of FPDE byte 0 except bit 3.
4E55
POP DE D1
Restore Register Pair DE from the stack: the FPDE's address, kept there since 4E09H (4E6FH also enters here for PROT= with Register B = F8H and Register C = the level).
4E56
LD A,(DE) 1A
Load Register A with the byte at Register Pair DE, byte 0 of the FPDE (bit 7 FXDE, 6 system, 4 in use, 3 invisible, 2-0 access level).
4E57
AND B A0
AND Register A (FPDE byte 0) with Register B, the mask: the bits being replaced are cleared, the others kept.
4E58
OR C B1
OR Register A with Register C, the new bits (08H or 00H for INV/VIS, the level 0-7 for PROT=): Register A = the new byte 0.
4E59
LD (DE),A 12
Store Register A, the new flag byte, at Register Pair DE, byte 0 of the FPDE.
4E5A
PUSH DE D5
Save Register Pair DE (the FPDE's address) on the stack again for the next keyword.
4E5B
GOSUB to 4D54H with Register Pair HL = the command line: the Z FLAG at the end of the line, the NZ FLAG with Register Pair HL past a comma or spaces; any other character gives error 34H.
4E5E
If the NZ FLAG is set (a separator was passed, so another keyword follows), LOOP back to 4E0AH for the next keyword at Register Pair HL.
4E60
POP AF F1
The end of the line: restore Register Pair AF from the stack, discarding the FPDE's address; the sector in 4200H already holds every change.
4E61
JUMP to 4DF0H, which jumps to SYS0 491FH to write the directory sector in 4200H back.
4E63
LD BC,508CH 01 8C 50
PROT=: load Register Pair BC with 508CH, the access level table (level names, each followed by 00H and the level byte).
4E66
LD D,01H 16 01
Load Register D with 01H: one byte, the level, follows each name in that table (4F7DH skips Register D bytes after a name).
4E68
GOSUB to 4F7DH to find the level name at Register Pair HL in the table at Register Pair BC; error 34H if none matches, else Register Pair BC comes back at the name's level byte and Register Pair HL past the name.
4E6B
LD A,(BC) 0A
Load Register A with the byte at Register Pair BC, the access level 0-7 for the name found.
4E6C
LD C,A 4F
Load Register C with Register A, the level, for bits 0-2 of FPDE byte 0.
4E6D
LD B,F8H 06 F8
Load Register B with F8H (1111 1000), the mask that keeps bits 3-7 of FPDE byte 0.
4E6F
JUMP to 4E55H to merge Register C (the level) into byte 0 of the FPDE with the mask in Register B.

4E71H - ATTRIB ACC= and UPD=

ACC=password stores the password's code at FPDE bytes 18-19 (the access password), UPD=password at bytes 16-17 (the update password). A blank password (nothing after the =) gives the code 4296H.

4E71
LD A,12H 3E 12
ACC=: load Register A with 12H, the offset of the access password code (bytes 18-19) in the FPDE.
4E73
JUMP to 4E77H with the offset 12H in Register A.
4E75
LD A,10H 3E 10
UPD=: load Register A with 10H, the offset of the update password code (bytes 16-17) in the FPDE.
4E77
PUSH AF F5
Save Register Pair AF (Register A = the offset 10H or 12H) on the stack, because 4FFEH uses Register A.
4E78
GOSUB to 4FFEH to read the password at Register Pair HL and return its 16-bit code in Register Pair DE, with Register Pair HL after the password.
4E7B
PUSH HL E5
Save Register Pair HL, the command line pointer after the password, on the stack to move it into Register Pair BC.
4E7C
POP BC C1
Restore Register Pair BC from the stack: Register Pair BC = the command line pointer, kept there while Register Pair HL addresses the FPDE.
4E7D
POP AF F1
Restore Register Pair AF from the stack: Register A = the offset of the password field (10H or 12H).
4E7E
POP HL E1
Restore Register Pair HL from the stack: the FPDE's address (byte 0 of the entry), kept there since 4E09H.
4E7F
PUSH HL E5
Save Register Pair HL, the FPDE's address, on the stack again for the next keyword.
4E80
ADD A,L 85
Add Register L (the low byte of the FPDE's address) to Register A (the offset): Register A = the low byte of the password field's address. An entry starts at a multiple of 20H, so this cannot carry.
4E81
LD L,A 6F
Load Register L with Register A: Register Pair HL = the password code field in the FPDE (byte 16 or 18).
4E82
LD (HL),E 73
Store Register E, the low byte of the password code, at Register Pair HL.
4E83
INC HL 23
Increment Register Pair HL to the high byte of the password code field (byte 17 or 19).
4E84
LD (HL),D 72
Store Register D, the high byte of the password code, at Register Pair HL.
4E85
LD H,B 60
Load Register H with Register B, the high byte of the command line pointer.
4E86
LD L,C 69
Load Register L with Register C, the low byte: Register Pair HL = the command line pointer after the password.
4E87
JUMP to 4E5BH to look for a separator and the next keyword at Register Pair HL, or the end of the line.

4E89H - Read a Drive and Check the Diskette Password

Used by PROT, SYSTEM, PDRIVE and PURGE. The text is password:d, :d or d. The drive is selected (SYS0 47ECH, error 08H if no diskette turns) and its GAT is read into 4200H. The password code read (4296H, the blank code, when no password was typed) is then compared with the diskette password code in GAT bytes CEH-CFH; when they differ the result is error 37H, but only while option AA (bit 7 of 436CH) is on. So with option AA on, a diskette that has a password needs it even when none is typed. Returns with Register Pair HL after the drive number.

4E89
GOSUB to 4FFEH to read a name at Register Pair HL and return its password code in Register Pair DE; if the text does not start with a letter nothing is taken and Register Pair DE = 4296H, the blank code.
4E8C
LD A,(HL) 7E
Load Register A with the byte at Register Pair HL, the character after the name (or the first character when there was no name).
4E8D
CP 3AH FE 3A
Compare Register A, that character, against 3AH, a colon; the Z FLAG is set when a colon separates the password from the drive number.
4E8F
INC HL 23
Increment Register Pair HL past the character; INC HL does not change the flags.
4E90
If the Z FLAG is set (Register A was a colon), JUMP to 4E9CH to read the drive number after it.
4E92
PUSH HL E5
No colon: save Register Pair HL, the command line pointer one past the character, on the stack (RST 18H needs Register Pair HL).
4E93
LD HL,4296H 21 96 42
Load Register Pair HL with 4296H, the code of a blank password, to find out whether a name was read.
4E96
RST 18H DF
RST 18H: compare Register Pair HL (4296H) with Register Pair DE (the code read at 4E89H); the Z FLAG is set if they are equal, that is if no name was given.
4E97
POP HL E1
Restore Register Pair HL from the stack: the command line pointer one past the character; POP does not change the flags.
4E98
DEC HL 2B
Decrement Register Pair HL back to the character, which is the drive number; DEC HL does not change the flags.
4E99
If the NZ FLAG is set (Register Pair DE holds the code of a name, but no colon followed it), JUMP to 4DD0H for error 2FH BAD PARAMETER(S).
4E9C
PUSH DE D5
Save Register Pair DE, the password code (4296H if none was typed), on the stack, because 4F9EH returns the drive number in Register Pair DE.
4E9D
GOSUB to 4F9EH to read the drive number at Register Pair HL into Register Pair DE (decimal, or hexadecimal with a trailing H); error 2FH if there is no number.
4EA0
LD A,D 7A
Load Register A with Register D, the high byte of the drive number.
4EA1
OR A B7
OR Register A (the high byte) with itself: the NZ FLAG is set for a drive number of 256 or more.
4EA2
If the NZ FLAG is set (Register Pair DE is 256 or more), JUMP to 4D50H for error 20H ILLEGAL OR MISSING DRIVE #.
4EA5
LD A,E 7B
Load Register A with Register E, the drive number (0-255; SYS0 checks it against option AL).
4EA6
POP DE D1
Restore Register Pair DE from the stack: the password code saved at 4E9CH.
4EA7
GOSUB to SYS0 47ECH to select the drive in Register A and wait for the index hole to show that a diskette turns; it returns the NZ FLAG with error 20H (drive too high) or 08H (no diskette) in Register A.
4EAA
If the NZ FLAG is set (the drive cannot be used), JUMP to 4EC2H to give the error in Register A.
4EAC
PUSH HL E5
Save Register Pair HL, the command line pointer after the drive number, on the stack (490AH returns Register Pair HL = 4200H).
4EAD
XOR A AF
Load Register A with 00H (XOR A with itself): directory sector 0, the GAT.
4EAE
GOSUB to SYS0 490AH to read directory sector Register A (the GAT) of the selected drive into 4200H.
4EB1
If the NZ FLAG is set (the GAT could not be read), JUMP to 4EC2H to give the error code in Register A.
4EB3
LD HL,(42CEH) 2A CE 42
Load Register Pair HL with the 16-bit value at 42CEH, GAT bytes CEH-CFH: the diskette password code (4296H when the diskette has no password).
4EB6
OR A B7
OR Register A with itself to clear the CARRY FLAG before the SBC (Register A, 00H after the good read, is not changed).
4EB7
SBC HL,DE ED 52
Subtract Register Pair DE (the code typed, or 4296H) from Register Pair HL (the diskette's code): the Z FLAG is set if they match.
4EB9
POP HL E1
Restore Register Pair HL from the stack: the command line pointer after the drive number; POP does not change the flags.
4EBA
RET Z C8
If the Z FLAG is set (the codes match), RETURN to the caller with Register Pair HL after the drive number.
4EBB
LD A,(436CH) 3A 6C 43
Load Register A with the byte at 436CH, the copy of system data sector byte F0H made at reset: bit 7 is option AA (passwords are checked).
4EBE
RLCA 07
Rotate Register A (the 436CH flags) left: bit 7, option AA, goes into the CARRY FLAG.
4EBF
RET NC D0
If the NO CARRY FLAG is set (option AA is off), RETURN with Register Pair HL after the drive number: the password is not checked. The NZ FLAG from 4EB7H is still set and Register A holds the rotated flags, but neither caller tests them.
4EC0
LD A,37H 3E 37
Load Register A with 37H, the error code DISKETTE ACCESS DENIED: option AA is on and the password code does not match the diskette's.
4EC2
JUMP to 4D5EH, the error exit, with the error code in Register A.

4EC5H - PROT Command

PROT [password]:d,keyword,... changes the diskette's GAT: PW=password (a new diskette password), NAME=name and DATE=date (8 characters each); and it applies LOCK, UNLOCK and RUF to all the diskette's files after the last keyword (4F09H). The keywords are in the table at 50C0H.

4EC5
GOSUB to 4E89H to read [password]:d at Register Pair HL, select the drive, read its GAT into 4200H and check the diskette password; Register Pair HL comes back after the drive number.
4EC8
GOSUB to 4F6BH: a comma or spaces must follow the drive number at Register Pair HL (else error 34H); Register Pair HL comes back at the first keyword.
4ECB
LD BC,50C0H 01 C0 50
Load Register Pair BC with 50C0H, the PROT keyword table (4F0CH loops back here for each further keyword).
4ECE
JUMP to 4F71H to find the keyword at Register Pair HL in the table at Register Pair BC and jump to its handler with Register Pair HL past the keyword.

4ED1H - PROT DATE= and NAME=

Copies up to 8 characters, up to a comma, a space or the end of the line, to GAT bytes D8H-DFH (DATE=) or D0H-D7H (NAME=), padded with spaces. Characters after the eighth are left in the line, where 4F09H finds them and gives error 34H.

4ED1
LD DE,42D8H 11 D8 42
DATE=: load Register Pair DE with 42D8H, GAT bytes D8H-DFH in the sector buffer: the diskette's date.
4ED4
JUMP to 4ED9H with the field address 42D8H in Register Pair DE.
4ED6
LD DE,42D0H 11 D0 42
NAME=: load Register Pair DE with 42D0H, GAT bytes D0H-D7H in the sector buffer: the diskette's name.
4ED9
LD B,08H 06 08
Load Register B with 08H, the eight characters of the name or date field.

Field Loop
Register Pair HL = the command line, Register Pair DE = the GAT byte, Register B = the field positions left.

4EDB
GOSUB to SYS0 4CD5H with Register Pair HL = the command line: the NO CARRY FLAG at the end of the line (Z FLAG) or after stepping over a comma or spaces (NZ FLAG); the CARRY FLAG before any other character.
4EDE
If the NO CARRY FLAG is set (the field text has ended), JUMP to 4EE4H to pad the rest of the field with spaces.
4EE0
LD A,(HL) 7E
An ordinary character: load Register A with the byte at Register Pair HL, the next character of the field.
4EE1
INC HL 23
Increment Register Pair HL past that character in the command line.
4EE2
JUMP to 4EE9H to store the character in Register A.
4EE4
If the Z FLAG is set (Register Pair HL is at the carriage return), JUMP to 4EE7H; Register Pair HL stays at the carriage return.
4EE6
DEC HL 2B
A separator: decrement Register Pair HL back one character, so that 4D54H at 4F09H finds a separator again and reads the next keyword.
4EE7
LD A,20H 3E 20
Load Register A with 20H, a space, to pad the field.
4EE9
LD (DE),A 12
Store Register A (the character, or a space) at Register Pair DE, the field in the GAT copy at 4200H.
4EEA
INC DE 13
Increment Register Pair DE to the next GAT byte of the field.
4EEB
Decrement Register B, the field positions left; if Register B is not 0, LOOP back to 4EDBH.
4EED
JUMP to 4F09H to look for the next keyword at Register Pair HL, or the end of the line.

4EEFH - PROT RUF, UNLOCK and LOCK

These only set a bit in the operand at 4F13H; the files are changed after the last keyword (4F12H). Bit 2 RUF, bit 0 UNLOCK, bit 1 LOCK. When both LOCK and UNLOCK are given, UNLOCK wins (4F1BH).

4EEF
LD A,04H 3E 04
RUF: load Register A with 04H (0000 0100), bit 2 of the PROT file flags: reset the updated flag of every file.
4EF1
JUMP to 4EF9H to merge the bit in Register A (04H) into the flags at 4F13H.
4EF3
LD A,01H 3E 01
UNLOCK: load Register A with 01H (0000 0001), bit 0 of the PROT file flags: give every file blank passwords.
4EF5
JUMP to 4EF9H to merge the bit in Register A (01H) into the flags at 4F13H.
4EF7
LD A,02H 3E 02
LOCK: load Register A with 02H (0000 0010), bit 1 of the PROT file flags: give every file the diskette password.
4EF9
PUSH HL E5
Save Register Pair HL, the command line pointer after the keyword, on the stack.
4EFA
LD HL,4F13H 21 13 4F
Load Register Pair HL with 4F13H, the operand of the LD A,nn at 4F12H, which collects the PROT file flags.
4EFD
OR (HL) B6
OR Register A (the new bit) with the byte at Register Pair HL, the flags collected so far.
4EFE
LD (HL),A 77
Self-Modifying Code
Store Register A, the updated flags, at Register Pair HL (4F13H), the operand that 4F12H loads after the last keyword.
4EFF
POP HL E1
Restore Register Pair HL from the stack: the command line pointer after the keyword.
4F00
JUMP to 4F09H to look for the next keyword at Register Pair HL, or the end of the line.

4F02H - PROT PW=

PW=password stores the new password's code in GAT bytes CEH-CFH. A later LOCK uses the new code, because 4F17H reads it from the GAT copy after every keyword has been handled.

4F02
GOSUB to 4FFEH to read the password at Register Pair HL and return its 16-bit code in Register Pair DE (4296H for a blank password), with Register Pair HL after it.
4F05
LD (42CEH),DE ED 53 CE 42
Store Register Pair DE, the new password code, at 42CEH, GAT bytes CEH-CFH in the sector buffer: the diskette password.

4F09H - PROT: Next Keyword, Then Change the Files

After the last keyword the GAT is written back. Then, if LOCK, UNLOCK or RUF was given, every FDE sector of the directory (8 plus the extra sectors counted in HIT byte 1FH) is read and each FPDE in use is changed: RUF clears the updated bit (byte 1 bit 5) of every file; LOCK sets both password codes of every file that is neither a system file nor invisible to the diskette password, UNLOCK sets them to the blank code 4296H. Each sector is written back.

4F09
GOSUB to 4D54H with Register Pair HL = the command line: the Z FLAG at the end of the line, the NZ FLAG with Register Pair HL past a comma or spaces; any other character gives error 34H.
4F0C
If the NZ FLAG is set (a separator was passed, so another keyword follows), LOOP back to 4ECBH for the next keyword at Register Pair HL.
4F0E
GOSUB to SYS0 491FH to write the GAT in 4200H (with any PW=, NAME= and DATE= changes) back to directory sector 0, with the directory mark and verify.
4F11
RET NZ C0
If the NZ FLAG is set (the GAT could not be written), RETURN to SYS1 with the error code in Register A.
4F12
LD A,00H 3E 00
Self-Modifying Code
Load Register A with the PROT file flags, the operand at 4F13H: 00H in the file, ORed with 01H (UNLOCK), 02H (LOCK) and 04H (RUF) by 4EF9H.
4F14
OR A B7
OR Register A (the file flags) with itself: the Z FLAG is set if none of LOCK, UNLOCK or RUF was given.
4F15
LD B,A 47
Load Register B with Register A, the file flags, for the entry loop; LD does not change the flags.
4F16
RET Z C8
If the Z FLAG is set (no file flags), RETURN to SYS1 with the Z FLAG set and Register A = 00H: no error.
4F17
LD DE,(42CEH) ED 5B CE 42
Load Register Pair DE with the 16-bit value at 42CEH, GAT bytes CEH-CFH: the diskette password code, the code LOCK gives every file (already the new one if PW= was given).
4F1B
RRCA 0F
Rotate Register A (the file flags) right: bit 0, UNLOCK, goes into the CARRY FLAG.
4F1C
If the NO CARRY FLAG is set (no UNLOCK), JUMP to 4F21H with Register Pair DE = the diskette password code.
4F1E
LD DE,4296H 11 96 42
UNLOCK: load Register Pair DE with 4296H, the code of a blank password, which the files get instead.
4F21
LD A,01H 3E 01
Load Register A with 01H: directory sector 1, the HIT, which tells how many FDE sectors the directory has.
4F23
GOSUB to SYS0 490AH to read directory sector Register A (the HIT) into 4200H.
4F26
RET NZ C0
If the NZ FLAG is set (the HIT could not be read), RETURN to SYS1 with the error code in Register A.
4F27
LD A,(421FH) 3A 1F 42
Load Register A with the byte at 421FH, HIT byte 1FH: the number of extra FDE sectors (0, 5, 10, 15 or 20).
4F2A
ADD A,08H C6 08
Add 08H to Register A (the extra FDE sectors): Register A = the number of FDE sectors in the directory.
4F2C
LD (4F66H),A 32 66 4F
Self-Modifying Code
Store Register A, the number of FDE sectors, at 4F66H, the operand of the CP at 4F65H that ends the sector loop.
4F2F
XOR A AF
Load Register A with 00H (XOR A with itself): FDE sector 0, the first.

Sector Loop
Register C = the FDE sector (0 up), Register B = the file flags, Register Pair DE = the password code for LOCK or UNLOCK.

4F30
LD C,A 4F
Load Register C with Register A, the FDE sector number (0 up), to keep it for 4F63H; as a DEC (bits 0-4 the FDE sector, bits 5-7 entry 0) Register A names the sector's first entry.
4F31
GOSUB to SYS0 4936H to read the FDE sector of the DEC in Register A (directory sector Register A + 2) into 4200H and point Register Pair HL to its first entry (4200H).
4F34
RET NZ C0
If the NZ FLAG is set (the sector could not be read), RETURN to SYS1 with the error code in Register A.

Entry Loop
Register Pair HL = byte 0 of the entry (4200H, 4220H, ... 42E0H).

4F35
LD A,(HL) 7E
Load Register A with the byte at Register Pair HL, byte 0 of the directory entry (bit 7 FXDE, bit 6 system, bit 4 in use, bit 3 invisible).
4F36
AND 90H E6 90
Mask Register A (byte 0) against 90H (1001 0000) to keep bit 7 (an extension entry, FXDE) and bit 4 (the entry is in use).
4F38
CP 10H FE 10
Compare Register A, those two bits, against 10H: the Z FLAG is set only for a primary entry (FPDE) in use.
4F3A
If the NZ FLAG is set (the entry is free, or an FXDE), JUMP to 4F57H for the next entry.
4F3C
BIT 2,B CB 50
Test bit 2 of Register B, the file flags: bit 2 is RUF.
4F3E
If the Z FLAG is set (bit 2 of Register B clear, no RUF), JUMP to 4F44H.
4F40
INC HL 23
Increment Register Pair HL, the entry pointer, to byte 1 of the entry (the second flag byte).
4F41
RES 5,(HL) CB AE
Clear bit 5 of the byte at Register Pair HL, entry byte 1: the file is no longer marked as updated.
4F43
DEC HL 2B
Decrement Register Pair HL, the entry pointer, back to byte 0 of the entry.
4F44
LD A,B 78
Load Register A with Register B, the file flags (bit 0 UNLOCK, bit 1 LOCK, bit 2 RUF).
4F45
AND 03H E6 03
Mask Register A (the file flags) against 03H (0000 0011) to keep UNLOCK (bit 0) and LOCK (bit 1); the Z FLAG is set if neither was given.
4F47
If the Z FLAG is set (no LOCK or UNLOCK), JUMP to 4F57H for the next entry.
4F49
LD A,(HL) 7E
Load Register A with the byte at Register Pair HL, byte 0 of the entry.
4F4A
AND 48H E6 48
Mask Register A (byte 0) against 48H (0100 1000) to keep bit 6 (a system file) and bit 3 (an invisible file).
4F4C
If the NZ FLAG is set (Register A shows a system or invisible file), JUMP to 4F57H: its passwords are left alone.
4F4E
SET 4,L CB E5
Set bit 4 of Register L: Register Pair HL (an entry start, a multiple of 20H) now points at byte 16 of the entry (entry + 10H), the update password code.
4F50
LD (HL),E 73
Store Register E, the low byte of the password code (the diskette's, or 4296H for UNLOCK), at Register Pair HL, entry byte 16.
4F51
INC HL 23
Increment Register Pair HL, the entry pointer, to byte 17, the high byte of the update password code.
4F52
LD (HL),D 72
Store Register D, the high byte of the password code, at Register Pair HL, entry byte 17.
4F53
INC HL 23
Increment Register Pair HL, the entry pointer, to byte 18, the access password code.
4F54
LD (HL),E 73
Store Register E, the low byte of the password code, at Register Pair HL, entry byte 18.
4F55
INC HL 23
Increment Register Pair HL, the entry pointer, to byte 19, the high byte of the access password code.
4F56
LD (HL),D 72
Store Register D, the high byte of the password code, at Register Pair HL, entry byte 19.
4F57
LD A,L 7D
Load Register A with Register L, the low byte of the entry pointer (somewhere inside the current 32-byte entry).
4F58
AND E0H E6 E0
Mask Register A (the low byte) against E0H (1110 0000): Register A = the low byte of the entry's start.
4F5A
ADD A,20H C6 20
Add 20H to Register A: the low byte of the next entry; the CARRY FLAG is set after the eighth entry (E0H + 20H).
4F5C
LD L,A 6F
Load Register L with Register A: Register Pair HL = the next entry in 4200H-42FFH.
4F5D
If the NO CARRY FLAG is set (Register Pair HL is still inside the sector), LOOP back to 4F35H for the next entry.
4F5F
GOSUB to SYS0 491FH to write the changed FDE sector in 4200H back with the directory mark and verify.
4F62
RET NZ C0
If the NZ FLAG is set (the sector could not be written), RETURN to SYS1 with the error code in Register A.
4F63
INC C 0C
Increment Register C, the FDE sector number, to the next FDE sector.
4F64
LD A,C 79
Load Register A with Register C, the next FDE sector number.
4F65
CP 00H FE 00
Self-Modifying Code
Compare Register A, the next FDE sector number, against the number of FDE sectors in the operand at 4F66H (00H in the file, stored at 4F2CH): the CARRY FLAG is set while sectors remain.
4F67
If the CARRY FLAG is set (Register A is below the number of FDE sectors), LOOP back to 4F30H for the next FDE sector.
4F69
XOR A AF
Load Register A with 00H (XOR A with itself), which also sets the Z FLAG: no error.
4F6A
RET C9
RETURN to SYS1 with Register A = 00H and the Z FLAG set: PROT has finished.

4F6BH - A Separator Must Follow

Steps Register Pair HL over a comma or spaces; any other character, or the end of the line, gives error 34H.

4F6B
GOSUB to SYS0 4CD9H with Register Pair HL = the command line: the NO CARRY FLAG with Register Pair HL past a comma or spaces; the CARRY FLAG (Register Pair HL unchanged) before any other character, the carriage return included.
4F6E
RET NC D0
If the NO CARRY FLAG is set (a separator was passed), RETURN with Register Pair HL at the next keyword or value.
4F6F
No separator: JUMP to 4F90H, which jumps to 4D5CH for error 34H ILLEGAL KEYWORD OR SEPARATOR OR TERMINATOR.

4F71H - Find a Keyword

4F71H searches a table of keyword entries (the name, 00H, and a two-byte handler address) and jumps to the handler of the keyword at Register Pair HL, with Register Pair HL past the keyword. 4F7DH does the search for any table with Register D bytes after each name and returns Register Pair BC pointing at them. No match gives error 34H. The text only has to start with the keyword, so anything typed after it is read by the handler.

4F71
LD D,02H 16 02
Load Register D with 02H: two bytes, the handler's address, follow each name in the ATTRIB and PROT keyword tables.
4F73
GOSUB to 4F7DH to find the keyword at Register Pair HL in the table at Register Pair BC: Register Pair BC comes back at the handler address and Register Pair HL past the keyword (no match: error 34H).
4F76
LD A,(BC) 0A
Load Register A with the byte at Register Pair BC, the low byte of the keyword's handler address.
4F77
LD E,A 5F
Load Register E with Register A, the handler's low byte.
4F78
INC BC 03
Increment Register Pair BC, the table pointer, to the high byte of the handler address.
4F79
LD A,(BC) 0A
Load Register A with the byte at Register Pair BC, the high byte of the handler address.
4F7A
LD D,A 57
Load Register D with Register A, the handler's high byte: Register Pair DE = the handler's address.
4F7B
PUSH DE D5
Push Register Pair DE, the handler's address, on the stack as a return address.
4F7C
RET C9
RETURN, which pops the handler's address and jumps to it with Register Pair HL past the keyword (the FPDE's address or the caller's return is the next word on the stack).

Table Loop
Register Pair BC = the table entry, Register Pair HL = the command line, Register D = the bytes after each name.

4F7D
GOSUB to SYS0 4CC5H to compare the name at Register Pair BC (ending in 00H) with the text at Register Pair HL: on a match it returns the Z FLAG with Register Pair HL past the name in the text and Register Pair BC past the name's 00H; otherwise the NZ FLAG with Register Pair HL unchanged and Register Pair BC one past the byte that differed.
4F80
RET Z C8
If the Z FLAG is set (the text starts with this name), RETURN with Register Pair BC at the bytes after the name (the handler address or the level).
4F81
LD A,(BC) 0A
Load Register A with the byte at Register Pair BC, the next byte of the name that did not match.
4F82
CP 00H FE 00
Compare Register A, that byte, against 00H, the byte that ends every name in the table.
4F84
INC BC 03
Increment Register Pair BC, the table pointer, to the next byte; INC BC does not change the flags.
4F85
If the NZ FLAG is set (Register A was not the 00H), LOOP back to 4F81H; when it was, Register Pair BC is past the 00H, at the bytes after the name.
4F87
LD E,D 5A
Load Register E with Register D, the number of bytes after each name (2 for the keyword tables, 1 for the level table).
4F88
INC BC 03
Increment Register Pair BC, the table pointer, past one of the bytes that follow the name.
4F89
DEC E 1D
Decrement Register E, the bytes still to skip after the name.
4F8A
If the NZ FLAG is set (Register E is not 0, more bytes to skip), LOOP back to 4F88H.
4F8C
LD A,(BC) 0A
Load Register A with the byte at Register Pair BC, the first byte of the next entry, or the 00H that ends the table.
4F8D
OR A B7
OR Register A with itself: the Z FLAG is set for the 00H that ends the table.
4F8E
If the NZ FLAG is set (Register A starts another name), LOOP back to 4F7DH to compare it.
4F90
No keyword matched (also reached from 4F6FH and 4F9CH when a separator is missing): JUMP to 4D5CH for error 34H ILLEGAL KEYWORD OR SEPARATOR OR TERMINATOR.

4F93H - Read an Optional Number

4F93H: at the end of the line RETURN with Register Pair DE unchanged (the default the caller put there); after a separator read a number. 4F99H: a separator and a number must follow. 4F9EH reads a number: decimal, or hexadecimal with a trailing H (a letter A-H after the decimal digits makes the reading start again as hexadecimal). Returns Register Pair DE = the value; no digit, a missing H or a value over FFFFH gives error 2FH.

4F93
GOSUB to SYS0 4CD5H with Register Pair HL = the command line: the Z FLAG at the end of the line; the NZ FLAG and NO CARRY after stepping over a separator; the CARRY FLAG before another character.
4F96
If the NZ FLAG is set (not the end of the line), JUMP to 4F9CH, which reads a number after a separator or gives error 34H.
4F98
RET C9
The end of the line: RETURN with Register Pair DE unchanged, the default the caller loaded (402DH for the entry, the start for the load address).
4F99
GOSUB to SYS0 4CD9H with Register Pair HL = the command line: the NO CARRY FLAG with Register Pair HL past a comma or spaces; the CARRY FLAG otherwise (the end of the line included).
4F9C
If the CARRY FLAG is set (no separator before the number), JUMP to 4F90H for error 34H.
4F9E
PUSH HL E5
Save Register Pair HL, the start of the number in the command line, on the stack, to read it a second time as hexadecimal if needed.
4F9F
LD B,00H 06 00
Load Register B with 00H, the reading flags: bit 0 clear (decimal) and bit 1 clear (no digit read yet).
4FA1
GOSUB to 4FBFH to read the digits at Register Pair HL into Register Pair DE with the flags in Register B; Register Pair HL comes back at the first character that is not a digit.
4FA4
LD A,(HL) 7E
Load Register A with the byte at Register Pair HL, the character that ended the decimal digits.
4FA5
SUB 41H D6 41
Subtract 41H from Register A, that character: the letters A-H become 00H-07H.
4FA7
CP 08H FE 08
Compare Register A, the converted character, against 08H: the CARRY FLAG is set for a letter A-H (a hexadecimal digit, or the H suffix).
4FA9
If the NO CARRY FLAG is set (no letter A-H: a decimal number), JUMP to 4FB8H with the value in Register Pair DE.
4FAB
POP HL E1
Restore Register Pair HL from the stack: the start of the number, to read it again.
4FAC
LD B,01H 06 01
Load Register B with 01H, the reading flags: bit 0 set (hexadecimal), bit 1 clear (no digit read yet).
4FAE
PUSH HL E5
Save Register Pair HL, the start of the number, on the stack again (4FBAH drops it).
4FAF
GOSUB to 4FBFH to read the hexadecimal digits at Register Pair HL into Register Pair DE with the flags in Register B; Register Pair HL comes back at the first character that is not one.
4FB2
LD A,(HL) 7E
Load Register A with the byte at Register Pair HL, the character that ended the hexadecimal digits.
4FB3
CP 48H FE 48
Compare Register A, that character, against 48H, the letter H that must end a hexadecimal number.
4FB5
INC HL 23
Increment Register Pair HL past the H; INC HL does not change the flags.
4FB6
If the NZ FLAG is set (Register A was not H), JUMP to 4FBCH for error 2FH BAD PARAMETER(S).
4FB8
BIT 1,B CB 48
Test bit 1 of Register B, the reading flags: bit 1 is set once a digit has been read.
4FBA
POP BC C1
Restore Register Pair BC from the stack, discarding the saved start of the number; POP does not change the flags.
4FBB
RET NZ C0
If the NZ FLAG is set (at least one digit was read), RETURN with the value in Register Pair DE and Register Pair HL after the number.
4FBC
No digit, or no H: JUMP to 4DD0H for error 2FH BAD PARAMETER(S).
4FBF
LD DE,0000H 11 00 00
Load Register Pair DE with 0000H, the value of the number so far.

Digit Loop
Register Pair HL = the command line, Register Pair DE = the value, Register B = the reading flags (bit 0 hexadecimal, bit 1 a digit has been read).

4FC2
LD A,(HL) 7E
Load Register A with the byte at Register Pair HL, the next character of the number.
4FC3
SUB 30H D6 30
Subtract 30H from Register A, the character: the digits 0-9 become 00H-09H.
4FC5
CP 0AH FE 0A
Compare Register A, the converted character, against 0AH: the CARRY FLAG is set for a digit 0-9.
4FC7
If the CARRY FLAG is set (a digit 0-9 in Register A), JUMP to 4FD3H to add it to the value.
4FC9
BIT 0,B CB 40
Test bit 0 of Register B, the reading flags: bit 0 is set when reading hexadecimal.
4FCB
RET Z C8
If the Z FLAG is set (decimal: Register A is not a digit), RETURN with the value in Register Pair DE and Register Pair HL at the character.
4FCC
SUB 11H D6 11
Subtract 11H from Register A (the character minus 30H): the letters A-F become 00H-05H.
4FCE
CP 06H FE 06
Compare Register A, the converted character, against 06H: the CARRY FLAG is set for a letter A-F.
4FD0
RET NC D0
If the NO CARRY FLAG is set (Register A is not A-F), RETURN with the value in Register Pair DE and Register Pair HL at the character.
4FD1
ADD A,0AH C6 0A
Add 0AH to Register A: the letters A-F become the digit values 10-15.
4FD3
PUSH HL E5
Save Register Pair HL, the command line pointer, on the stack while Register Pair HL does the arithmetic.
4FD4
LD H,D 62
Load Register H with Register D, the high byte of the value so far.
4FD5
LD L,E 6B
Load Register L with Register E, the low byte: Register Pair HL = the value so far (Register Pair DE keeps a copy for the times-5 step).
4FD6
LD C,A 4F
Load Register C with Register A, the new digit (0-15), to add after the multiplication.
4FD7
XOR A AF
Load Register A with 00H (XOR A with itself): Register A collects the bits carried out of Register Pair HL (any overflow).
4FD8
SET 1,B CB C8
Set bit 1 of Register B, the reading flags: a digit has been read.
4FDA
ADD HL,HL 29
Add Register Pair HL to itself: Register Pair HL = the value times 2; the CARRY FLAG is set on overflow.
4FDB
ADC A,A 8F
Add Register A to itself with the CARRY FLAG: an overflow bit is shifted into Register A, which stays 00H only while nothing overflows.
4FDC
ADD HL,HL 29
Add Register Pair HL to itself: Register Pair HL = the value times 4.
4FDD
ADC A,A 8F
Add Register A to itself with the CARRY FLAG: an overflow bit is kept in Register A.
4FDE
BIT 0,B CB 40
Test bit 0 of Register B, the reading flags: bit 0 is set for hexadecimal.
4FE0
If the Z FLAG is set (decimal), JUMP to 4FE5H to make the value times 5.
4FE2
ADD HL,HL 29
Hexadecimal: add Register Pair HL to itself, Register Pair HL = the value times 8.
4FE3
JUMP to 4FE6H to keep the overflow bit and double once more (times 16).
4FE5
ADD HL,DE 19
Decimal: add Register Pair DE (the value before this digit) to Register Pair HL (the value times 4): Register Pair HL = the value times 5.
4FE6
ADC A,A 8F
Add Register A to itself with the CARRY FLAG: an overflow bit is kept in Register A.
4FE7
ADD HL,HL 29
Add Register Pair HL to itself: Register Pair HL = the value times 16 (hexadecimal) or times 10 (decimal).
4FE8
ADC A,A 8F
Add Register A to itself with the CARRY FLAG: an overflow bit is kept in Register A.
4FE9
LD E,C 59
Load Register E with Register C, the new digit.
4FEA
LD D,00H 16 00
Load Register D with 00H: Register Pair DE = the new digit (0-15).
4FEC
ADD HL,DE 19
Add Register Pair DE (the digit) to Register Pair HL: Register Pair HL = the new value.
4FED
ADC A,A 8F
Add Register A to itself with the CARRY FLAG: the NZ FLAG is set if any step carried out of Register Pair HL (a value over FFFFH).
4FEE
EX DE,HL EB
Exchange Register Pairs DE and HL: Register Pair DE = the new value.
4FEF
POP HL E1
Restore Register Pair HL from the stack: the command line pointer at the digit; POP does not change the flags.
4FF0
If the NZ FLAG is set (the number is over FFFFH), JUMP to 4FBCH for error 2FH BAD PARAMETER(S).
4FF2
INC HL 23
Increment Register Pair HL, the command line pointer, past the digit.
4FF3
LOOP back to 4FC2H for the next digit with the value in Register Pair DE.

4FF5H - Read a Password and Encode It

4FFEH copies a name of up to 8 characters (a letter, then letters and digits) to 51E8H-51EFH, padded with spaces, and leaves Register Pair HL after it. If the text does not start with a letter nothing is taken and the name is blank. 501CH then encodes the 8 characters into a 16-bit code in Register Pair DE with the same steps as SYS2 5155H (a blank name gives 4296H, PASSWORD 42E0H). The buffer is blank again afterwards.

Copy Loop
Register Pair HL = the command line, Register Pair DE = the buffer position before the next character, Register B = the characters left (from 8).

4FF5
LD A,(HL) 7E
Load Register A with the byte at Register Pair HL, the next character of the name (the second or a later one).
4FF6
CP 30H FE 30
Compare Register A, that character, against 30H, the digit 0: the CARRY FLAG is set for anything below it.
4FF8
If the CARRY FLAG is set (Register A is below 0, so not a letter or digit), JUMP to 500FH: the name ends here.
4FFA
CP 3AH FE 3A
Compare Register A, the character, against 3AH, one above the digit 9: the CARRY FLAG is set for a digit 0-9.
4FFC
JUMP to 5004H with that CARRY FLAG: a digit is stored there, anything else is checked for a letter.
4FFE
LD DE,51E7H 11 E7 51
Entry: load Register Pair DE with 51E7H, one below the eight-byte buffer at 51E8H-51EFH (the store at 5017H increments first).
5001
LD B,08H 06 08
Load Register B with 08H, the eight characters of a name.
5003
OR A B7
OR Register A with itself to clear the CARRY FLAG: for the first character a digit is not allowed, so 5004H always goes on to the letter test.
5004
If the CARRY FLAG is set (Register A is a digit, and not the first character), JUMP to 5017H to store it.
5006
LD A,(HL) 7E
Load Register A with the byte at Register Pair HL, the character, again (for the first character it has not been read yet).
5007
CP 41H FE 41
Compare Register A, the character, against 41H, the letter A: the CARRY FLAG is set for anything below it.
5009
If the CARRY FLAG is set (Register A is not a letter), JUMP to 500FH: the name ends here (with no character taken, for the first).
500B
CP 5BH FE 5B
Compare Register A, the character, against 5BH, one above the letter Z: the CARRY FLAG is set for a letter A-Z.
500D
If the CARRY FLAG is set (Register A is a letter), JUMP to 5017H to store it.
500F
INC DE 13
Increment Register Pair DE to the next buffer position, which gets a space.

Pad Loop
Register Pair DE = the buffer position, Register B = the positions left.

5010
LD A,20H 3E 20
Load Register A with 20H, a space, to fill the rest of the eight-byte buffer.
5012
LD (DE),A 12
Store Register A (a space) at Register Pair DE in the buffer at 51E8H-51EFH.
5013
Decrement Register B, the positions left; if Register B is not 0, LOOP back to 500FH for the next position.
5015
JUMP to 501CH to encode the eight characters now in 51E8H-51EFH.
5017
INC DE 13
Increment Register Pair DE to the next buffer position.
5018
LD (DE),A 12
Store Register A, the letter or digit, at Register Pair DE in the buffer at 51E8H-51EFH.
5019
INC HL 23
Increment Register Pair HL, the command line pointer, past the character.
501A
Decrement Register B, the characters left; if Register B is not 0, LOOP back to 4FF5H for the next character. After the eighth the name ends without looking at what follows.
501C
PUSH HL E5
Save Register Pair HL, the command line pointer after the name, on the stack.
501D
EX DE,HL EB
Exchange Register Pairs DE and HL: Register Pair HL = 51EFH, the last byte of the buffer (Register Pair DE was left there by the copy or the padding).
501E
LD DE,FFFFH 11 FF FF
Load Register Pair DE with FFFFH, the starting value of the password code.
5021
LD B,08H 06 08
Load Register B with 08H: eight characters, taken from the last (51EFH) down to the first (51E8H).

Encode Loop
Register Pair DE = the code so far, Register Pair HL = the character, Register B = the characters left (kept on the stack while Register Pair BC is work space).

5023
PUSH BC C5
Save Register Pair BC (Register B = the characters left) on the stack, because Registers B and C are used for the mixing steps.
5024
LD A,E 7B
Load Register A with Register E, the low byte of the code so far.
5025
AND 07H E6 07
Mask Register A (the code's low byte) against 07H (0000 0111) to keep its bits 0-2.
5027
LD C,A 4F
Load Register C with Register A, bits 0-2 of the code's low byte.
5028
LD A,E 7B
Load Register A with Register E, the low byte of the code so far, again.
5029
RLCA 07
Rotate Register A (the code's low byte) left by one bit.
502A
RLCA 07
Rotate Register A left again: the code's low byte rotated left by two bits.
502B
RLCA 07
Rotate Register A left a third time: the code's low byte rotated left by three bits.
502C
XOR C A9
XOR Register A (the rotated low byte) with Register C, the low byte's original bits 0-2.
502D
RLCA 07
Rotate Register A left once more: Register A = the mixed value used for both new bytes.
502E
LD C,A 4F
Load Register C with Register A, the mixed value.
502F
AND F0H E6 F0
Mask Register A (the mixed value) against F0H (1111 0000) to keep its high four bits.
5031
LD B,A 47
Load Register B with Register A, the high four bits of the mixed value.
5032
LD A,C 79
Load Register A with Register C, the mixed value, again.
5033
RLCA 07
Rotate Register A (the mixed value) left by one bit.
5034
AND 1FH E6 1F
Mask Register A against 1FH (0001 1111) to keep its low five bits.
5036
XOR B A8
XOR Register A with Register B, the high four bits of the mixed value.
5037
XOR D AA
XOR Register A with Register D, the high byte of the code so far.
5038
LD E,A 5F
Load Register E with Register A: the new low byte of the code.
5039
LD A,C 79
Load Register A with Register C, the mixed value, again.
503A
AND 0FH E6 0F
Mask Register A (the mixed value) against 0FH (0000 1111) to keep its low four bits.
503C
LD B,A 47
Load Register B with Register A, the low four bits of the mixed value.
503D
LD A,C 79
Load Register A with Register C, the mixed value, again.
503E
RLCA 07
Rotate Register A (the mixed value) left by one bit.
503F
RLCA 07
Rotate Register A (the mixed value) left again: two bits so far.
5040
RLCA 07
Rotate Register A left a third time (three bits).
5041
RLCA 07
Rotate Register A left a fourth time: the two halves of the mixed value are swapped.
5042
XOR B A8
XOR Register A (the swapped mixed value) with Register B, its low four bits.
5043
POP BC C1
Restore Register Pair BC from the stack: Register B = the characters left.
5044
XOR (HL) AE
XOR Register A with the byte at Register Pair HL, the character from the buffer at 51E8H-51EFH.
5045
LD D,A 57
Load Register D with Register A: the new high byte of the code.
5046
LD (HL),20H 36 20
Store 20H (a space) at Register Pair HL: the buffer is blanked as it is used, so no password stays in memory.
5048
DEC HL 2B
Decrement Register Pair HL to the character before, in the buffer at 51E8H-51EFH.
5049
Decrement Register B, the characters left; if Register B is not 0, LOOP back to 5023H.
504B
POP HL E1
Restore Register Pair HL from the stack: the command line pointer after the name.
504C
RET C9
RETURN with the password code in Register Pair DE and Register Pair HL after the name.

504DH - ATTRIB Keyword Table

Data. Searched by 4F71H (loaded into Register Pair BC at 4E0AH): each entry is the keyword in ASCII, a 00H that ends it, and the two-byte address of its handler (low byte first). A 00H in place of a keyword ends the table. The text only has to start with the keyword.

504D-5052
DEFM "INV", 00H / DEFW 4E4DH 49 4E 56 00 4D 4E
Data: the keyword INV, its 00H end, and the handler address 4E4DH, which sets bit 3 (invisible) of FPDE byte 0.
5053-5058
DEFM "VIS", 00H / DEFW 4E51H 56 49 53 00 51 4E
Data: the keyword VIS, its 00H end, and the handler address 4E51H, which clears bit 3 (invisible) of FPDE byte 0.
5059-5060
DEFM "PROT=", 00H / DEFW 4E63H 50 52 4F 54 3D 00 63 4E
Data: the keyword PROT=, its 00H end, and the handler address 4E63H, which looks the level name up at 508CH and stores the level in FPDE byte 0 bits 0-2.
5061-5067
DEFM "ACC=", 00H / DEFW 4E71H 41 43 43 3D 00 71 4E
Data: the keyword ACC=, its 00H end, and the handler address 4E71H, which stores the access password code at FPDE bytes 18-19.
5068-506E
DEFM "UPD=", 00H / DEFW 4E75H 55 50 44 3D 00 75 4E
Data: the keyword UPD=, its 00H end, and the handler address 4E75H, which stores the update password code at FPDE bytes 16-17.
506F-5075
DEFM "ASE=", 00H / DEFW 4E2AH 41 53 45 3D 00 2A 4E
Data: the keyword ASE=, its 00H end, and the handler address 4E2AH: Y clears and N sets bit 7 of FPDE byte 1 (the file may not be extended).
5076-507C
DEFM "ASC=", 00H / DEFW 4E2EH 41 53 43 3D 00 2E 4E
Data: the keyword ASC=, its 00H end, and the handler address 4E2EH: Y clears and N sets bit 6 of FPDE byte 1 (CLOSE keeps the space beyond EOF).
507D-5083
DEFM "UDF=", 00H / DEFW 4E23H 55 44 46 3D 00 23 4E
Data: the keyword UDF=, its 00H end, and the handler address 4E23H: Y sets and N clears bit 5 of FPDE byte 1 (the file has been updated).
5084-508A
DEFM "LRL=", 00H / DEFW 4E10H 4C 52 4C 3D 00 10 4E
Data: the keyword LRL=, its 00H end, and the handler address 4E10H, which stores the record length 1-256 in FPDE byte 4.
508B
DEFB 00H 00
Data: the 00H that ends the ATTRIB keyword table; 4F8DH finds it after the LRL= entry and gives error 34H.

508CH - Access Level Table

Data. Searched by 4F7DH for PROT= (loaded into Register Pair BC at 4E63H, with Register D = 01H): each entry is the level name in ASCII, a 00H that ends it, and the access level for bits 0-2 of FPDE byte 0. A 00H in place of a name ends the table.

508C-5091
DEFM "LOCK", 00H, 07H 4C 4F 43 4B 00 07
Data: the level name LOCK, its 00H end, and level 07H: a file opened at this level cannot be read, written or loaded (SYS2 refuses to load it with error 25H).
5092-5097
DEFM "EXEC", 00H, 06H 45 58 45 43 00 06
Data: the level name EXEC, its 00H end, and level 06H: the file may be loaded and run but not read (SYS0 49B9H needs a level below 6 to read).
5098-509D
DEFM "READ", 00H, 05H 52 45 41 44 00 05
Data: the level name READ, its 00H end, and level 05H: the file may be read and run but not written (SYS0 49B7H needs a level below 5 to write).
509E-50A4
DEFM "WRITE", 00H, 04H 57 52 49 54 45 00 04
Data: the level name WRITE, its 00H end, and level 04H: the file may also be written.
50A5-50AC
DEFM "RENAME", 00H, 02H 52 45 4E 41 4D 45 00 02
Data: the level name RENAME, its 00H end, and level 02H: the file may also be renamed.
50AD-50B2
DEFM "NAME", 00H, 02H 4E 41 4D 45 00 02
Data: the level name NAME, its 00H end, and level 02H, the same as RENAME.
50B3-50B8
DEFM "KILL", 00H, 01H 4B 49 4C 4C 00 01
Data: the level name KILL, its 00H end, and level 01H: the file may also be killed.
50B9-50BE
DEFM "FULL", 00H, 00H 46 55 4C 4C 00 00
Data: the level name FULL, its 00H end, and level 00H: full access, which ATTRIB itself needs (4DFDH).
50BF
DEFB 00H 00
Data: the 00H that ends the access level table; 4F8DH finds it after the FULL entry and gives error 34H.

50C0H - PROT Keyword Table

Data. Searched by 4F71H (loaded into Register Pair BC at 4ECBH): each entry is the keyword in ASCII, a 00H that ends it, and the two-byte address of its handler (low byte first). A 00H in place of a keyword ends the table.

50C0-50C5
DEFM "PW=", 00H / DEFW 4F02H 50 57 3D 00 02 4F
Data: the keyword PW=, its 00H end, and the handler address 4F02H, which stores the new diskette password code in GAT bytes CEH-CFH.
50C6-50CE
DEFM "UNLOCK", 00H / DEFW 4EF3H 55 4E 4C 4F 43 4B 00 F3 4E
Data: the keyword UNLOCK, its 00H end, and the handler address 4EF3H, which sets bit 0 of the PROT file flags at 4F13H (blank passwords for the files).
50CF-50D5
DEFM "LOCK", 00H / DEFW 4EF7H 4C 4F 43 4B 00 F7 4E
Data: the keyword LOCK, its 00H end, and the handler address 4EF7H, which sets bit 1 of the PROT file flags at 4F13H (the diskette password for the files).
50D6-50DD
DEFM "NAME=", 00H / DEFW 4ED6H 4E 41 4D 45 3D 00 D6 4E
Data: the keyword NAME=, its 00H end, and the handler address 4ED6H, which copies the diskette name to GAT bytes D0H-D7H.
50DE-50E5
DEFM "DATE=", 00H / DEFW 4ED1H 44 41 54 45 3D 00 D1 4E
Data: the keyword DATE=, its 00H end, and the handler address 4ED1H, which copies the diskette date to GAT bytes D8H-DFH.
50E6-50EB
DEFM "RUF", 00H / DEFW 4EEFH 52 55 46 00 EF 4E
Data: the keyword RUF, its 00H end, and the handler address 4EEFH, which sets bit 2 of the PROT file flags at 4F13H (reset the updated flags).
50EC
DEFB 00H 00
Data: the 00H that ends the PROT keyword table; 4F8DH finds it after the RUF entry and gives error 34H.

50EDH - DUMP Command

DUMP filespec,start,end[,entry[,load]] writes memory from start to end to the file (opened by SYS1 in the DOS FCB at 4480H) in load module format. Numbers are decimal or hexadecimal with H. The entry address defaults to 402DH (DOS READY); the load address, where the data will be loaded later, defaults to start. With entry = FFFFH the file is written without records instead (two address bytes, then the data) and no load address is read. The file's sector buffer is set to 4D61H, inside SYS7 itself (over the code for SYSTEM to ATTRIB, which DUMP does not need). Before the dump one sector is written at relative sector (count + 4) / 252 of the file, so that all the space the file needs is allocated at once; the 49D3H chain then brings DUMP back as sub-function 8.

50ED
LD HL,4D61H 21 61 4D
Load Register Pair HL with 4D61H, the 256 bytes 4D61H-4E60H of SYS7's own code (SYSTEM to ATTRIB, not needed by DUMP), used as the file's sector buffer.
50F0
LD (4483H),HL 22 83 44
Store Register Pair HL, 4D61H, at 4483H, bytes 3-4 of the DOS FCB at 4480H: the buffer address for every read and write of the file.
50F3
POP AF F1
Restore Register Pair AF from the stack, discarding the dispatcher's return address (4C20H), so that the command line pointer SYS1 left is on top.
50F4
POP HL E1
Restore Register Pair HL from the stack: the command line pointer left by SYS1, at the character after the filespec.
50F5
GOSUB to 4F99H: a separator must follow at Register Pair HL, then the start address is read into Register Pair DE.
50F8
PUSH DE D5
Save Register Pair DE, the start address, on the stack.
50F9
GOSUB to 4F99H: a separator must follow at Register Pair HL, then the end address is read into Register Pair DE.
50FC
EX DE,HL EB
Exchange Register Pairs DE and HL: Register Pair HL = the end address and Register Pair DE = the command line pointer.
50FD
EX (SP),HL E3
Exchange Register Pair HL with the word at the top of the stack (at the Stack Pointer SP): the end address is kept on the stack and Register Pair HL = the start address.
50FE
EX DE,HL EB
Exchange Register Pairs DE and HL: Register Pair DE = the start address and Register Pair HL = the command line pointer.
50FF
PUSH DE D5
Save Register Pair DE, the start address, on the stack above the end address.
5100
LD DE,402DH 11 2D 40
Load Register Pair DE with 402DH, the default entry address (the DOS READY jump), used when no entry address is typed.
5103
GOSUB to 4F93H: at the end of the line Register Pair DE keeps 402DH; after a separator the entry address is read into Register Pair DE.
5106
LD A,D 7A
Load Register A with Register D, the high byte of the entry address.
5107
AND E A3
AND Register A (the high byte) with Register E, the low byte: Register A = FFH only if the entry address is FFFFH.
5108
INC A 3C
Increment Register A: the Z FLAG is set if the entry address in Register Pair DE is FFFFH (write without records).
5109
EX DE,HL EB
Exchange Register Pairs DE and HL: Register Pair HL = the entry address and Register Pair DE = the command line pointer; EX does not change the flags.
510A
EX (SP),HL E3
Exchange Register Pair HL with the word at the top of the stack (at the Stack Pointer SP): the entry address is kept on the stack and Register Pair HL = the start address.
510B
EX DE,HL EB
Exchange Register Pairs DE and HL: Register Pair DE = the start address (the default load address) and Register Pair HL = the command line pointer.
510C
PUSH DE D5
Save Register Pair DE, the start address, on the stack; PUSH does not change the flags.
510D
If the NZ FLAG is set (the entry address is not FFFFH), GOSUB to 4F93H to read a load address into Register Pair DE after a separator; at the end of the line Register Pair DE stays the start address.
5110
GOSUB to 4D58H: the line must end at Register Pair HL, else error 34H.
5113
POP BC C1
Restore Register Pair BC from the stack: the start address (the word pushed at 510CH).
5114
POP AF F1
Restore Register Pair AF from the stack: the entry address (Register A = its high byte, the flags its low byte).
5115
POP HL E1
Restore Register Pair HL from the stack: the end address.
5116
PUSH AF F5
Save Register Pair AF, the entry address, on the stack (popped into Register Pair BC at 5157H).
5117
PUSH BC C5
Save Register Pair BC, the start address, on the stack (popped at 5153H).
5118
PUSH HL E5
Save Register Pair HL, the end address, on the stack (popped at 514FH).
5119
PUSH DE D5
Save Register Pair DE, the load address, on the stack (popped at 514AH).
511A
OR A B7
OR Register A with itself to clear the CARRY FLAG before the SBC; Register A (the entry's high byte) is not changed.
511B
SBC HL,BC ED 42
Subtract Register Pair BC (the start address) from Register Pair HL (the end address): Register Pair HL = the byte count minus 1; the CARRY FLAG is set if the end is below the start.
511D
PUSH HL E5
Save Register Pair HL, the byte count minus 1, on the stack (popped at 5149H); PUSH does not change the flags.
511E
If the CARRY FLAG is set (the end address is below the start), JUMP to 4DD0H for error 2FH BAD PARAMETER(S).
5121
LD BC,0005H 01 05 00
Load Register Pair BC with 0005H, to turn the count minus 1 in Register Pair HL into the count plus 4.
5124
ADD HL,BC 09
Add Register Pair BC (5) to Register Pair HL: Register Pair HL = the byte count plus 4; the CARRY FLAG is set if that passes FFFFH.
5125
If the NO CARRY FLAG is set (the sum fits in 16 bits), JUMP to 512CH to divide it.
5127
LD HL,0104H 21 04 01
A count of FFFCH or more: load Register Pair HL with 0104H (260), the relative sector to write, the quotient a count near 65536 would give.
512A
JUMP to 5131H with the relative sector number in Register Pair HL.
512C
LD A,FCH 3E FC
Load Register A with FCH, 252: the bytes reckoned per sector of the file, leaving room for the record headers.
512E
GOSUB to SYS0 4CB4H to divide Register Pair HL (the count plus 4) by Register A (252): Register Pair HL = the quotient, the relative sector at which the file's data will end.
5131
LD (448AH),HL 22 8A 44
Store Register Pair HL, the relative sector number, at 448AH, bytes 10-11 of the DOS FCB (NEXT middle and high): the file is positioned at that sector.
5134
LD DE,4480H 11 80 44
Load Register Pair DE with 4480H, the DOS FCB holding the open DUMP file.
5137
LD BC,E908H 01 08 E9
Load Register Pair BC with E908H: Register B = E9H (the RST 28H code of SYS7 function 7) and Register C = 08H (sub-function 8, DUMP's second half).
513A
LD HL,49D3H 21 D3 49
Load Register Pair HL with 49D3H, the SYS0 return point that pops a word into Registers A and C and does RST 28H with it.
513D
PUSH BC C5
Push Register Pair BC (E908H, the code and sub-function) on the stack for 49D3H.
513E
PUSH HL E5
Push Register Pair HL (49D3H) on the stack, as the return address of the write.
513F
JUMP to SYS0 4439H to write the buffer through the FCB at Register Pair DE at the sector set at 448AH; this allocates the file's space up to that sector, and SYS2 may be loaded over SYS7 for it. The write returns to 49D3H, which goes to the error exit 4409H on an error, or reloads SYS7 with code E9H and sub-function 8.

5142H - DUMP, Sub-Function 8: Write the Data

Entered through 49D3H with Register Pair DE = the FCB and the values pushed at 5116H-511DH still on the stack. The file is rewound and the bytes are sent one at a time through the ROM output routine at 001BH with Register Pair DE = the FCB (SYS0 4ADBH writes them to the file). Load module records are type 01H, a length byte (the data length plus 2; 00H means 256), the two-byte load address (51B4H translates it) and up to 254 data bytes; the last record is the transfer record 02H 02H and the entry address. Finally the file is rewound again and closed through SYS0 4428H.

5142
POP AF F1
Restore Register Pair AF from the stack, discarding the dispatcher's return address (4C20H), so that the values pushed at 5116H-511DH are on top.
5143
GOSUB to SYS0 443FH to rewind the file at Register Pair DE (the DOS FCB at 4480H, which 49D3H passed on): NEXT = 0.
5146
If the NZ FLAG is set (the rewind failed), JUMP to 5198H, whose JR NZ goes on to the error exit with the error code in Register A.
5148
EXX D9
Exchange Register Pairs BC, DE and HL with the alternate set: the alternate Register Pair DE keeps the FCB address (4480H) for the output routine at 51D3H.
5149
POP DE D1
Restore Register Pair DE from the stack: the byte count minus 1, pushed at 511DH.
514A
POP HL E1
Restore Register Pair HL from the stack: the load address, pushed at 5119H.
514B
INC DE 13
Increment Register Pair DE: the byte count (0000H stands for 65536 bytes).
514C
LD (51C5H),HL 22 C5 51
Self-Modifying Code
Store Register Pair HL, the load address, at 51C5H, the operand of the LD HL,nnnn at 51C4H used to translate addresses.
514F
POP HL E1
Restore Register Pair HL from the stack: the end address, pushed at 5118H.
5150
LD (51B7H),HL 22 B7 51
Self-Modifying Code
Store Register Pair HL, the end address, at 51B7H, the operand of the LD HL,nnnn at 51B6H.
5153
POP HL E1
Restore Register Pair HL from the stack: the start address, pushed at 5117H.
5154
LD (51BEH),HL 22 BE 51
Self-Modifying Code
Store Register Pair HL, the start address, at 51BEH, the operand of the LD DE,nnnn at 51BDH.
5157
POP BC C1
Restore Register Pair BC from the stack: the entry address, pushed as Register Pair AF at 5116H.
5158
EX DE,HL EB
Exchange Register Pairs DE and HL: Register Pair HL = the byte count and Register Pair DE = the start address, the first byte to write.
5159
LD A,B 78
Load Register A with Register B, the high byte of the entry address.
515A
AND C A1
AND Register A (the high byte) with Register C, the low byte: Register A = FFH only if the entry address is FFFFH.
515B
INC A 3C
Increment Register A: the Z FLAG is set if the entry address in Register Pair BC is FFFFH.
515C
If the Z FLAG is set (entry FFFFH: no records), JUMP to 519DH to write the address and the raw data.
515E
PUSH BC C5
Save Register Pair BC, the entry address, on the stack for the transfer record (popped at 518DH).
515F
LD A,H 7C
Load Register A with Register H, the high byte of the byte count.
5160
OR L B5
OR Register A (the high byte) with Register L, the low byte: the Z FLAG is set for a count of 0000H, meaning 65536 bytes.
5161
If the NZ FLAG is set (a count below 65536 in Register Pair HL), JUMP to 516BH to start the records.
5163
LD BC,00FEH 01 FE 00
65536 bytes: load Register Pair BC with 00FEH, the 254 data bytes of the first full record.
5166
OR A B7
OR Register A with itself to clear the CARRY FLAG before the SBC.
5167
SBC HL,BC ED 42
Subtract Register Pair BC (254) from Register Pair HL (0000H): Register Pair HL = FF02H, the bytes left after the first record.
5169
JUMP to 5173H to write the first full record, without the borrow test of 5171H (which the 0000H count would fail).

Record Loop
Register Pair HL = the bytes left, Register Pair DE = the next memory byte, Register C = the record's data length.

516B
LD BC,00FEH 01 FE 00
Load Register Pair BC with 00FEH, the 254 data bytes of a full record.
516E
OR A B7
OR Register A with itself to clear the CARRY FLAG before the SBC.
516F
SBC HL,BC ED 42
Subtract Register Pair BC (254) from Register Pair HL (the bytes left): the CARRY FLAG is set if fewer than 254 bytes are left.
5171
If the CARRY FLAG is set (fewer than 254 bytes left), JUMP to 5186H for the last, short record or the transfer record.
5173
INC C 0C
Increment Register C, the record's data length (FEH for a full record): the length byte is the data length plus 2.
5174
INC C 0C
Increment Register C again: Register C = the length byte (FEH + 2 wraps to 00H, which stands for 256).
5175
LD B,01H 06 01
Load Register B with 01H, record type 01H: a block of data with its load address.
5177
GOSUB to 51ACH to write the type (Register B), the length byte (Register C) and the load address of Register Pair DE (translated to the load address).
517A
DEC C 0D
Decrement Register C, the length byte, to take the 2 off again.
517B
DEC C 0D
Decrement Register C again: Register C = the number of data bytes in this record (00H stands for 256, FEH for a full record).

Data Loop
Register Pair DE = the next memory byte, Register C = the bytes left in the record.

517C
LD A,(DE) 1A
Load Register A with the byte at Register Pair DE, the next byte of the memory being dumped.
517D
INC DE 13
Increment Register Pair DE, the memory pointer, to the next byte to dump.
517E
GOSUB to 51D3H to write the byte in Register A to the file through the FCB in the alternate Register Pair DE.
5181
DEC C 0D
Decrement Register C, the data bytes left in this record.
5182
If the NZ FLAG is set (Register C is not 0, more data in the record), LOOP back to 517CH.
5184
LOOP back to 516BH for the next record, with Register Pair HL = the bytes left.
5186
OR A B7
OR Register A with itself to clear the CARRY FLAG before the ADC.
5187
ADC HL,BC ED 4A
Add Register Pair BC (254) back to Register Pair HL: Register Pair HL = the bytes left (0-253), and the Z FLAG is set if none are left.
5189
LD C,L 4D
Load Register C with Register L, the bytes left (0-253), the data length of the last record.
518A
LD L,H 6C
Load Register L with Register H (00H, since fewer than 254 are left): Register Pair HL = 0000H, nothing left after this record. LD does not change the flags.
518B
If the NZ FLAG is set (bytes are left), JUMP to 5173H for a short record of Register C bytes; 516BH then finds Register Pair HL = 0000H and comes back here with the Z FLAG.
518D
POP DE D1
Restore Register Pair DE from the stack: the entry address, pushed at 515EH.
518E
LD B,02H 06 02
Load Register B with 02H, record type 02H: the transfer address.
5190
LD C,B 48
Load Register C with Register B: the length byte 02H, for the two address bytes.
5191
GOSUB to 51ACH to write the transfer record: the type in Register B, the length in Register C and the entry address in Register Pair DE (translated if it lies in the dumped range).
5194
EXX D9
Exchange Register Pairs BC, DE and HL with the alternate set again: the main Register Pair DE = the FCB address 4480H again.
5195
GOSUB to SYS0 443FH to rewind the file at Register Pair DE (NEXT = 0), which also writes the last buffer if it was changed.
5198
If the NZ FLAG is set (an error, here or from 5146H), JUMP to 51D9H to give the error code in Register A.
519A
JUMP to SYS0 4428H to close the file at Register Pair DE (SYS3 is loaded for it); it returns to SYS1 with the result.
519D
Without records: GOSUB to 51B4H to write the address in Register Pair DE (the start, translated: the load address, which is the start itself since no load address was read) as two bytes.

Raw Data Loop
Register Pair DE = the next memory byte, Register Pair HL = the bytes left.

51A0
LD A,(DE) 1A
Load Register A with the byte at Register Pair DE, the next byte of the memory being dumped.
51A1
INC DE 13
Increment Register Pair DE, the memory pointer, to the next byte to dump.
51A2
GOSUB to 51D3H to write the byte in Register A to the file through the FCB in the alternate Register Pair DE.
51A5
DEC HL 2B
Decrement Register Pair HL, the bytes left to write.
51A6
LD A,H 7C
Load Register A with Register H, the high byte of the bytes left, to test Register Pair HL for zero.
51A7
OR L B5
OR Register A (the high byte) with Register L, the low byte: the Z FLAG is set when no bytes are left.
51A8
If the NZ FLAG is set (Register Pair HL is not 0), LOOP back to 51A0H for the next byte.
51AA
JUMP to 5194H to switch back to the FCB in Register Pair DE, rewind and close the file.

51ACH - DUMP: Write a Record Header and an Address

51ACH writes Register B (the record type) and Register C (the length byte). 51B4H writes the address in Register Pair DE as two bytes, translated when it lies between start and end: address - start + load. 51D3H writes the byte in Register A through ROM 001BH with the FCB in the alternate Register Pair DE, and ends DUMP with the error on a write error.

51AC
LD A,B 78
Load Register A with Register B, the record type (01H data or 02H transfer).
51AD
GOSUB to 51D3H to write the record type in Register A to the file.
51B0
LD A,C 79
Load Register A with Register C, the record's length byte (data length plus 2, or 02H).
51B1
GOSUB to 51D3H to write the length byte in Register A to the file.
51B4
PUSH HL E5
Save Register Pair HL, the caller's count of bytes left, on the stack.
51B5
PUSH DE D5
Save Register Pair DE, the address to write (the record's first memory byte or the entry address), on the stack.
51B6
LD HL,0000H 21 00 00
Self-Modifying Code
Load Register Pair HL with the end address of the dump, the operand at 51B7H (0000H in the file, stored at 5150H).
51B9
RST 18H DF
RST 18H: compare Register Pair HL (the end address) with Register Pair DE (the address to write); the CARRY FLAG is set if the address is past the end.
51BA
EX DE,HL EB
Exchange Register Pairs DE and HL: Register Pair HL = the address to write and Register Pair DE = the end address; EX does not change the flags.
51BB
If the CARRY FLAG is set (the address is past the end), JUMP to 51CCH to write it unchanged.
51BD
LD DE,0000H 11 00 00
Self-Modifying Code
Load Register Pair DE with the start address of the dump, the operand at 51BEH (0000H in the file, stored at 5154H).
51C0
RST 18H DF
RST 18H: compare Register Pair HL (the address to write) with Register Pair DE (the start address); the CARRY FLAG is set if the address is below the start.
51C1
If the CARRY FLAG is set (the address is below the start), JUMP to 51CCH to write it unchanged.
51C3
PUSH HL E5
Save Register Pair HL, the address to write, on the stack.
51C4
LD HL,0000H 21 00 00
Self-Modifying Code
Load Register Pair HL with the load address, the operand at 51C5H (0000H in the file, stored at 514CH).
51C7
OR A B7
OR Register A with itself to clear the CARRY FLAG before the SBC.
51C8
SBC HL,DE ED 52
Subtract Register Pair DE (the start address) from Register Pair HL (the load address): Register Pair HL = the load address minus the start.
51CA
POP DE D1
Restore Register Pair DE from the stack: the address to write.
51CB
ADD HL,DE 19
Add Register Pair DE (the address) to Register Pair HL (load minus start): Register Pair HL = the address translated to where it will be loaded.
51CC
LD A,L 7D
Load Register A with Register L, the low byte of the address to write (translated or not).
51CD
GOSUB to 51D3H to write the low byte in Register A to the file.
51D0
LD A,H 7C
Load Register A with Register H, the high byte of the address, which 51D3H below writes before returning to the caller.
51D1
POP DE D1
Restore Register Pair DE from the stack: the caller's memory pointer (or entry address), saved at 51B5H.
51D2
POP HL E1
Restore Register Pair HL from the stack: the caller's count of bytes left, saved at 51B4H.
51D3
EXX D9
Exchange Register Pairs BC, DE and HL with the alternate set: Register Pair DE = the DOS FCB at 4480H (kept there since 5148H).
51D4
GOSUB to ROM 001BH, the output routine, to send the byte in Register A to the control block at Register Pair DE; byte 0 of the FCB (80H, open) is not the output device type, so the ROM jumps through 4033H to SYS0 4ADBH, which writes the byte to the file and returns the Z FLAG on success.
51D7
EXX D9
Exchange Register Pairs BC, DE and HL with the alternate set again: the caller's Register Pairs BC, DE and HL again; the flags from the write are kept.
51D8
RET Z C8
If the Z FLAG is set (the byte in Register A was written), RETURN to the caller.
51D9
JUMP to 4D5EH, the error exit, with the error code from the write (or from the rewind at 5143H or 5195H) in Register A.

51DCH - Unused Bytes

The end of the file. Nothing in SYS7 reads or writes these bytes; the password and text buffer starts after them at 51E8H.

51DC-51E7
NOP x 12 00 x 12
Twelve zero bytes up to 51E7H, the last byte of the file's fifth load record; no instruction in SYS7 reaches or reads them.