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 number (09H). SYSTEM, PDRIVE and PURGE are only started here: SYS7 reads the drive and checks the diskette password, and passes the rest of the command line to SYS17, SYS16 or SYS3.

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

Sub-Functions of Code E9H

CCommandWhat SYS7 does
1SYSTEMReads [password]:d, then RST 28H 33H (SYS17 function 1) with B = 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 B = 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 C = 06H (SYS3 function 7 sub-function 6) and B = 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.
other-Error 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). 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). A wrong keyword or separator gives error 34H, a bad value 2FH.
  • Passwords are encoded into 16-bit codes (501CH, the same algorithm as SYS2 5155H; a blank password is 4296H). A password is a letter followed by up to seven letters or digits.
  • ATTRIB needs the file to be open with full access: with option AA on, it must have been named with its update password; otherwise error 19H.
  • PROT, SYSTEM, PDRIVE and PURGE compare a password given before the drive number (password:d) with the diskette password in GAT bytes CEH-CFH, but only when option AA is on: a wrong one gives error 37H (4E89H). Without a password nothing is checked.

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 the 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 the load address and the data are written, without records.

The file's sector buffer is 4D61H-4E60H, inside SYS7 itself. DUMP first positions the file at 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 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 and Work Areas

AddressContents
4DCBHOperand of CP nn: the TIME or DATE separator (3AH or 2FH).
4F13HOperand of LD A,nn: the PROT file flags, bit 0 UNLOCK, bit 1 LOCK, bit 2 RUF.
4F66HOperand of CP nn: the number of FDE sectors (8 + HIT byte 1FH).
51B7H, 51BEH, 51C5HOperands at 51B6H, 51BDH and 51C4H: the DUMP end, start and load addresses.
4D61H-4E60HThe DUMP file's sector buffer (over SYS7's own code).
51E8H-51EFH
not in the file
The password being encoded (blank afterwards), and the text buffer for HIMEM, TIME and DATE.
4200H-42FFHThe directory sector: GAT for AUTO and PROT, the FPDE's sector for ATTRIB, the HIT and FDE sectors for LOCK/UNLOCK/RUF.

SYS0 locations SYS7 uses: 4041H-4046H (clock and date), 4049H (HIMEM), 4308H (current drive, IY-78H), 436CH bit 7 (option AA), 43A9H (top of memory), 4480H (the DOS FCB, for DUMP).

Disassembly

4D00H - Function Dispatcher

SYS7 is entered by the SYS0 RST 28H dispatcher (4BC2H) with Register A = the RST 28H code. Only function 7 (E9H) exists; Register C is the sub-function from SYS1's command table (4F58H), and Register Pair HL points to the rest of the command line. Sub-functions: 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 at 5137H), 9 PURGE, 0AH TIME, 0BH DATE. Anything else returns error 2AH.

4D00
LD IY,4380H FD 21 80 43
Load Index Register IY with 4380H, the base SYS0 and the overlays use for the variables around 4300H (IY-78H = 4308H, the current drive).
4D04
CP E9H FE E9
Compare Register A (the RST 28H code) against E9H: SYS7, function 7.
4D06
If the NZ FLAG is set (another code), JUMP to 4D32H to return error 2AH.
4D08
DEC C 0D
Decrement Register C, the sub-function: the Z FLAG is set if it was 1.
4D09
If the Z FLAG is set (Register C was 1, SYSTEM), JUMP to 4D61H.
4D0B
DEC C 0D
Decrement Register C, the sub-function, again: the Z FLAG is set if it was 2.
4D0C
If the Z FLAG is set (Register C was 2, HIMEM), JUMP to 4D76H.
4D0F
DEC C 0D
Decrement Register C, the sub-function, again: the Z FLAG is set if it was 3.
4D10
If the Z FLAG is set (Register C was 3, PDRIVE), JUMP to 4D65H.
4D12
DEC C 0D
Decrement Register C, the sub-function, again: the Z FLAG is set if it was 4.
4D13
If the Z FLAG is set (Register C was 4, AUTO), JUMP to 4DD4H.
4D16
DEC C 0D
Decrement Register C, the sub-function, again: the Z FLAG is set if it was 5.
4D17
If the Z FLAG is set (Register C was 5, ATTRIB), JUMP to 4DF3H.
4D1A
DEC C 0D
Decrement Register C, the sub-function, again: the Z FLAG is set if it was 6.
4D1B
If the Z FLAG is set (Register C was 6, PROT), JUMP to 4EC5H.
4D1E
DEC C 0D
Decrement Register C, the sub-function, again: the Z FLAG is set if it was 7.
4D1F
If the Z FLAG is set (Register C was 7, DUMP), JUMP to 50EDH.
4D22
DEC C 0D
Decrement Register C, the sub-function, again: the Z FLAG is set if it was 8.
4D23
If the Z FLAG is set (Register C was 8, DUMP after its first write), JUMP to 5142H.
4D26
DEC C 0D
Decrement Register C, the sub-function, again: the Z FLAG is set if it was 9.
4D27
If the Z FLAG is set (Register C was 9, PURGE), JUMP to 4D69H.
4D29
LD DE,4043H 11 43 40
Prepare TIME: load Register Pair DE with 4043H, the hours (the time is kept as seconds, minutes, hours at 4041H-4043H).
4D2C
LD B,3AH 06 3A
Load Register B with 3AH, the TIME separator (a colon).
4D2E
DEC C 0D
Decrement Register C, the sub-function, again: the Z FLAG is set if it was 0AH.
4D2F
If the Z FLAG is set (Register C was 0AH, TIME), JUMP to 4D3AH.
4D31
DEC C 0D
Decrement Register C, the sub-function, again: the Z FLAG is set if it was 0BH (DATE).

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

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

4D32
LD A,2AH 3E 2A
Load Register A with 2AH, error code ILLEGAL DOS FUNCTION. LD does not change the flags.
4D34
If the NZ FLAG is set (not sub-function 0BH, or not function 7), JUMP to 4D5EH to return error 2AH.
4D36
LD E,46H 1E 46
DATE: load Register E with 46H: Register Pair DE = 4046H, the month (the date is kept as year, day, month at 4044H-4046H).
4D38
LD B,2FH 06 2F
Load Register B with 2FH, the DATE separator (a slash).
4D3A
LD A,B 78
TIME and DATE: load Register A with Register B, the separator.
4D3B
LD (4DCBH),A 32 CB 4D
Self-Modifying Code
Store Register A (the separator) at 4DCBH, the operand of the CP at 4DCAH.
4D3E
LD A,(HL) 7E
Load Register A with the byte at Register Pair HL, the next character of the command line.
4D3F
CP 0DH FE 0D
Compare Register A against 0DH, the carriage return at the end of the line.
4D41
If the NZ FLAG is set (a parameter follows), JUMP to 4DA7H to set the clock or date.
4D43
LD HL,51E8H 21 E8 51
No parameter: load Register Pair HL with 51E8H, the text buffer after the end of the file.
4D46
PUSH HL E5
Save Register Pair HL (51E8H, the start of the text) on the stack.
4D47
GOSUB to SYS0 44ACH, which writes the three bytes from Register Pair DE downward at Register Pair HL as two decimal digits each, separated by Register B.
4D4A
JUMP to 4D86H to end the text and display it.

4D4CH - Unreferenced Error Exit

Nothing in SYS7 or in the other overlays reaches 4D4CH.

4D4C
LD A,2CH 3E 2C
Load Register A with 2CH, error code BAD DIRECTORY DATA; nothing reaches this row.
4D4E
JUMP to 4D5EH to return the error in Register A; unreferenced.

4D50H - Error Exits and the End of the Command

4D50H returns error 20H (from 4EA2H). 4D54H accepts the end of the line or a separator (comma or spaces; NZ, with HL past it) and otherwise gives error 34H; 4D58H accepts only the end of the line. 4D5EH is the common error exit through SYS0 4409H, which displays the error.

4D50
LD A,20H 3E 20
Load Register A with 20H, error code ILLEGAL OR MISSING DRIVE #.
4D52
JUMP to 4D5EH to return error 20H in Register A.
4D54
GOSUB to SYS0 4CD5H with Register Pair HL = the text: the Z FLAG at the end of the line, the NO CARRY FLAG after stepping over a comma or spaces, the CARRY FLAG if another character follows.
4D57
RET NC D0
If the NO CARRY FLAG is set (the end of the line or a separator), RETURN.
4D58
LD A,(HL) 7E
Load Register A with the byte at Register Pair HL, the next character.
4D59
CP 0DH FE 0D
Compare Register A against 0DH, the carriage return at the end of the line.
4D5B
RET Z C8
If the Z FLAG is set (the end), RETURN with the Z FLAG set.
4D5C
LD A,34H 3E 34
Load Register A with 34H, error code ILLEGAL KEYWORD OR SEPARATOR OR TERMINATOR.
4D5E
JUMP to SYS0 4409H, the error exit, with the error code in Register A.

4D61H - SYSTEM, PDRIVE and PURGE Commands

These three only read [password]:d or d and check the diskette password (4E89H), then pass the rest of the 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, C = 06H).

4D61
LD B,33H 06 33
SYSTEM: load Register B with 33H, the RST 28H code of SYS17 function 1.
4D63
JUMP to 4D6CH with the code in Register B.
4D65
LD B,32H 06 32
PDRIVE: load Register B with 32H, the RST 28H code of SYS16 function 1.
4D67
JUMP to 4D6CH with the code in Register B.
4D69
LD BC,E506H 01 06 E5
PURGE: load Register Pair BC with E506H: B = E5H (SYS3, function 7), C = 06H (sub-function 6).
4D6C
PUSH BC C5
Save Register Pair BC (Register B = the code, Register C = the sub-function) on the stack.
4D6D
GOSUB to 4E89H to read the drive number (and a diskette password) at Register Pair HL, select the drive and read its GAT.
4D70
POP BC C1
Restore Register Pair BC from the stack: Register B = the code, Register C = the sub-function.
4D71
LD A,B 78
Load Register A with Register B, the RST 28H code.
4D72
LD B,(IY-78H) FD 46 88
Load Register B with the byte at Index Register IY-78H (4308H), the drive selected by 4E89H.
4D75
RST 28H EF
RST 28H with Register A = the code: the other overlay replaces SYS7 and does the work with Register B = the drive and Register Pair HL = the rest of the line.

4D76H - HIMEM Command

Without a parameter HIMEM displays the address in 4049H (HIMEM) as four hexadecimal digits. With one it stores the value, which may be decimal or hexadecimal with a trailing H (4F9EH), must be 7000H or higher, and 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 character.
4D77
CP 0DH FE 0D
Compare Register A against 0DH, the carriage return at the end of the line.
4D79
If the NZ FLAG is set (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.
4D7F
LD HL,51E8H 21 E8 51
Load Register Pair HL with 51E8H, the text buffer after the end of the file.
4D82
PUSH HL E5
Save Register Pair HL (51E8H, the start of the text) on the stack.
4D83
GOSUB to SYS0 4063H to write Register Pair DE as four hexadecimal digits at Register Pair HL.
4D86
LD (HL),0DH 36 0D
Store 0DH (a carriage return) at Register Pair HL, ending the text (also the end of TIME and DATE, from 4D4AH).
4D88
POP HL E1
Restore Register Pair HL from the stack: 51E8H, the start of the text.
4D89
JUMP to SYS0 4467H to display the text at Register Pair HL and return from there.
4D8C
GOSUB to 4F9EH to read the number at Register Pair HL into Register Pair DE.
4D8F
GOSUB to 4D58H: the line must end here (else error 34H).
4D92
LD A,D 7A
Load Register A with Register D, the value's high byte.
4D93
CP 70H FE 70
Compare Register A against 70H: the CARRY FLAG is set if the value is below 7000H.
4D95
If the CARRY FLAG is set (below 7000H), JUMP to 4DD0H for error 2FH.
4D98
LD HL,(43A9H) 2A A9 43
Load Register Pair HL with the 16-bit value at 43A9H, the top of memory found at reset.
4D9B
OR A B7
OR Register A with itself to clear the CARRY FLAG for the subtraction.
4D9C
SBC HL,DE ED 52
Subtract Register Pair DE (the value) from Register Pair HL (the top of memory): the CARRY FLAG is set if the value is above it.
4D9E
ADD HL,DE 19
Add Register Pair DE back: Register Pair HL = the top of memory again. ADD HL does not change the CARRY FLAG's meaning here, since it carries exactly when the subtraction borrowed.
4D9F
If the CARRY FLAG is set (the value is above the top of memory), JUMP to 4DA2H to store the top of memory.
4DA1
EX DE,HL EB
Exchange Register Pairs DE and HL: HL = the value.
4DA2
LD (4049H),HL 22 49 40
Store Register Pair HL at 4049H, HIMEM.
4DA5
XOR A AF
Load Register A with 00H (XOR A with itself), which also sets the Z FLAG: no error.
4DA6
RET C9
RETURN with Register A = 00H and the Z FLAG 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 DE: hours, minutes, seconds at 4043H-4041H, or month, day, year at 4046H-4044H. The values are not range-checked. Interrupts are off while the fields are stored, so the clock does not change 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 (already stored).

4DA7
DI F3
Disable interrupts, so the clock does not tick while it is set.
4DA8
LD B,03H 06 03
Load Register B with 03H, the three fields.

Register Pair HL = the text, Register Pair DE = the field, Register B = the fields left.

4DAA
LD A,(HL) 7E
Load Register A with the byte at Register Pair HL, the field's first digit.
4DAB
SUB 30H D6 30
Subtract 30H from Register A: the digits 0-9 become 00H-09H.
4DAD
CP 0AH FE 0A
Compare Register A against 0AH: the CARRY FLAG is set for a digit.
4DAF
INC HL 23
Increment Register Pair HL to the next character. INC HL does not change the flags.
4DB0
If the NO CARRY FLAG is set (not a digit), JUMP to 4DCFH for error 2FH.
4DB2
LD C,A 4F
Load Register C with Register A, the first digit.
4DB3
RLCA 07
Rotate Register A left: the digit times 2.
4DB4
RLCA 07
Rotate Register A left again: times 4.
4DB5
ADD A,C 81
Add Register C (the digit) to Register A: times 5.
4DB6
ADD A,A 87
Add Register A to itself: times 10.
4DB7
LD C,A 4F
Load Register C with Register A, the tens.
4DB8
LD A,(HL) 7E
Load Register A with the byte at Register Pair HL, the second digit.
4DB9
SUB 30H D6 30
Subtract 30H from Register A: the digits 0-9 become 00H-09H.
4DBB
CP 0AH FE 0A
Compare Register A against 0AH: the CARRY FLAG is set for a digit.
4DBD
INC HL 23
Increment Register Pair HL to the next character. INC HL does not change the flags.
4DBE
If the NO CARRY FLAG is set (not a digit), JUMP to 4DCFH for error 2FH.
4DC0
ADD A,C 81
Add Register C (the tens) to Register A: the field's value.
4DC1
LD (DE),A 12
Store Register A (the field) at Register Pair DE.
4DC2
DEC DE 1B
Decrement Register Pair DE to the next field down.
4DC3
Decrement Register B (the fields left); if it is not 0, JUMP to 4DC9H to check the separator.
4DC5
EI FB
All three fields stored: enable interrupts.
4DC6
JUMP to SYS0 4CD5H with Register Pair HL after the third field: the Z FLAG (no error) at the end of the line, otherwise error 34H for the caller.
4DC9
LD A,(HL) 7E
Load Register A with the byte at Register Pair HL, the separator character.
4DCA
CP 00H FE 00
Self-Modifying Code
Compare Register A against the separator, the operand 4DCBH (00H in the file, stored at 4D3BH: 3AH for TIME, 2FH for DATE).
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 (the right separator), LOOP back to 4DAAH for the next field.
4DCF
EI FB
Enable interrupts before the error.
4DD0
LD A,2FH 3E 2F
Load Register A with 2FH, error code BAD PARAMETER(S); also the exit for other bad parameters.
4DD2
JUMP to 4D5EH to return error 2FH in Register A.

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 run at reset). At most 31 characters; longer text gives error 2FH and nothing is written. AUTO without text stores only the carriage return (no AUTO command).

4DD4
EX DE,HL EB
Exchange Register Pairs DE and HL: DE = the text.
4DD5
XOR A AF
Load Register A with 00H (XOR A with itself): drive 0.
4DD6
GOSUB to SYS0 4776H to select drive Register A (0).
4DD9
RET NZ C0
If the NZ FLAG is set (an error), RETURN with the error in Register A.
4DDA
XOR A AF
Load Register A with 00H (XOR A with itself): directory sector 0, the GAT.
4DDB
GOSUB to SYS0 490AH to read directory sector Register A into 4200H; Register Pair HL = 4200H.
4DDE
RET NZ C0
If the NZ FLAG is set (a read error), RETURN with the error in Register A.
4DDF
LD B,20H 06 20
Load Register B with 20H: at most 32 bytes, the carriage return included.
4DE1
LD L,E0H 2E E0
Load Register L with E0H: Register Pair HL = 42E0H, GAT byte E0H.

COPY THE TEXT: Register Pair DE = the text, Register Pair HL = the GAT byte, Register B = the room left.

4DE3
LD A,(DE) 1A
Compare Register A against 0DH, the carriage return at the end of the line.
4DE4
CP 0DH FE 0D
Load Register A with the byte at Register Pair DE, a character of the text.
4DE6
LD (HL),A 77
Store Register A (the character) at Register Pair HL, in the GAT. LD does not change the flags.
4DE7
INC DE 13
Increment Register Pair DE to the next character.
4DE8
INC HL 23
Increment Register Pair HL to the next GAT byte.
4DE9
If the Z FLAG is set (the carriage return is stored), JUMP to 4DF0H to write the GAT.
4DEB
Decrement Register B (the room left); if it is not 0, LOOP back to 4DE3H.
4DED
Too long: JUMP to 4DD0H for error 2FH; the GAT is not written.
4DF0
JUMP to SYS0 491FH to write the directory sector in 4200H back and return from there (also the end of ATTRIB, 4E61H).

4DF3H - ATTRIB Command

SYS1 has opened the file (FCB at DE) and left the command line pointer on the stack. The file must have been opened with full access (the 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).
4DF4
POP HL E1
Restore Register Pair HL from the stack: the command line pointer left by SYS1.
4DF5
GOSUB to 4F6BH: a separator must follow the filespec at Register Pair HL.
4DF8
PUSH DE D5
Save Register Pair DE (the FCB) on the stack.
4DF9
POP IX DD E1
Restore Index Register IX from the stack: IX = the FCB.
4DFB
INC DE 13
Increment Register Pair DE to FCB+1, the access level the file was opened with.
4DFC
LD A,(DE) 1A
Load Register A with the byte at Register Pair DE, FCB+1.
4DFD
AND 07H E6 07
Mask Register A against 07H (0000 0111) to keep the access level: 0 is FULL.
4DFF
LD A,19H 3E 19
Load Register A with 19H, error code FILE ACCESS DENIED. LD does not change the flags.
4E01
RET NZ C0
If the NZ FLAG is set (not full access), RETURN with error 19H in Register A.
4E02
PUSH HL E5
Save Register Pair HL (the command line pointer) on the stack.
4E03
GOSUB to SYS0 494BH to read the file's FPDE: Register Pair HL = the entry in 4200H.
4E06
If the NZ FLAG is set (an error), JUMP to 4D5EH to return it 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): HL = the command line, and the FPDE's address is kept there.
4E0A
LD BC,504DH 01 4D 50
Load Register Pair BC with 504DH, the ATTRIB keyword table (4E5EH comes back here for further keywords).
4E0D
JUMP to 4F71H to find the keyword at Register Pair HL and go to its handler.

4E10H - ATTRIB LRL=

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

4E10
GOSUB to 4F9EH to read the number at Register Pair HL into Register Pair DE.
4E13
DEC DE 1B
Decrement Register Pair DE: 1-256 becomes 0000H-00FFH.
4E14
LD A,D 7A
Load Register A with Register D, the high byte.
4E15
OR A B7
OR Register A with itself: the Z FLAG is set if Register D is 00H.
4E16
If the NZ FLAG is set (n is not 1-256), JUMP to 4DD0H for error 2FH.
4E18
EX (SP),HL E3
Exchange Register Pair HL with the word at the top of the stack (at the Stack Pointer SP): HL = the FPDE, and the command line pointer is kept there.
4E19
PUSH HL E5
Save Register Pair HL (the FPDE's address) on the stack.
4E1A
INC HL 23
Increment Register Pair HL to byte 1 of the FPDE.
4E1B
INC HL 23
Increment Register Pair HL to byte 2.
4E1C
INC HL 23
Increment Register Pair HL to byte 3.
4E1D
INC HL 23
Increment Register Pair HL to byte 4, the record length.
4E1E
INC E 1C
Increment Register E: the 1 is added back, and 256 becomes 00H.
4E1F
LD (HL),E 73
Store Register E (the record length) at Register Pair HL, byte 4.
4E20
POP HL E1
Restore Register Pair HL from the stack: the FPDE's address.
4E21
JUMP to 4E4AH to put the FPDE back on the stack and go on.

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, no extension) and ASC (bit 6, no space release at CLOSE) are cleared by Y and set by N. Anything but Y or N gives error 2FH.

4E23
LD C,20H 0E 20
UDF: load Register C with 20H, bit 5.
4E25
LD DE,FF00H 11 00 FF
Load Register Pair DE with FF00H: D = FFH (set the bit) for Y, E = 00H (clear it) for N.
4E28
JUMP to 4E33H to read Y or N.
4E2A
LD C,80H 0E 80
ASE: load Register C with 80H, bit 7.
4E2C
JUMP to 4E30H.
4E2E
LD C,40H 0E 40
ASC: load Register C with 40H, bit 6.
4E30
LD DE,00FFH 11 FF 00
Load Register Pair DE with 00FFH: D = 00H (clear the bit) for Y, E = FFH (set it) for N.
4E33
LD A,(HL) 7E
Load Register A with the byte at Register Pair HL, the character after the =.
4E34
CP 59H FE 59
Compare Register A against 59H, the letter Y.
4E36
INC HL 23
Increment Register Pair HL past the character. INC HL does not change the flags.
4E37
If the Z FLAG is set (Y), JUMP to 4E3EH with the Y value in Register D.
4E39
LD D,E 53
Load Register D with Register E, the N value.
4E3A
CP 4EH FE 4E
Compare Register A against 4EH, the letter N.
4E3C
If the NZ FLAG is set (neither Y nor N), JUMP to 4DD0H for error 2FH.
4E3E
EX (SP),HL E3
Exchange Register Pair HL with the word at the top of the stack (at the Stack Pointer SP): HL = the FPDE, and the command line pointer is kept there.
4E3F
INC HL 23
Increment Register Pair HL to byte 1 of the FPDE.
4E40
LD A,C 79
Load Register A with Register C, the bit.
4E41
AND D A2
AND Register A with Register D, the value: the bit if it is to be set, else 00H.
4E42
LD B,A 47
Load Register B with Register A, the new bit.
4E43
LD A,FFH 3E FF
Load Register A with FFH.
4E45
XOR C A9
XOR Register A with Register C: a mask for the other bits.
4E46
AND (HL) A6
AND Register A with the byte at Register Pair HL: byte 1 with the bit cleared.
4E47
OR B B0
OR Register A with Register B, the new bit.
4E48
LD (HL),A 77
Store Register A at Register Pair HL, byte 1.
4E49
DEC HL 2B
Decrement Register Pair HL back to byte 0 of the FPDE.
4E4A
EX (SP),HL E3
Exchange Register Pair HL with the word at the top of the stack (at the Stack Pointer SP): HL = the command line, and the FPDE's address is kept there.
4E4B
JUMP to 4E5BH for the next keyword.

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, bit 3 set.
4E4F
JUMP to 4E53H with the new bit in Register C.
4E51
LD C,00H 0E 00
VIS: load Register C with 00H, bit 3 clear.
4E53
LD B,F7H 06 F7
Load Register B with F7H (1111 0111), the mask that keeps the other bits.
4E55
POP DE D1
Restore Register Pair DE from the stack: the FPDE's address (4E6FH also enters here for PROT= with the mask F8H).
4E56
LD A,(DE) 1A
Load Register A with the byte at Register Pair DE, byte 0 of the FPDE.
4E57
AND B A0
AND Register A with Register B, the mask: the other bits are kept.
4E58
OR C B1
OR Register A with Register C, the new bits.
4E59
LD (DE),A 12
Store Register A 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.
4E5B
GOSUB to 4D54H with Register Pair HL = the text: the Z FLAG at the end of the line, the NZ FLAG after a separator; anything else gives error 34H.
4E5E
If the NZ FLAG is set (a separator), LOOP back to 4E0AH for the next keyword.
4E60
POP AF F1
The end of the line: restore Register Pair AF from the stack, discarding the FPDE's address.
4E61
JUMP to 4DF0H to write the directory sector back.
4E63
LD BC,508CH 01 8C 50
PROT=: load Register Pair BC with 508CH, the access level table.
4E66
LD D,01H 16 01
Load Register D with 01H: one byte follows each name in that table.
4E68
GOSUB to 4F7DH to find the level name at Register Pair HL (error 34H if none matches); Register Pair BC comes back at its level byte.
4E6B
LD A,(BC) 0A
Load Register A with the byte at Register Pair BC, the level.
4E6C
LD C,A 4F
Load Register C with Register A, the level for bits 0-2.
4E6D
LD B,F8H 06 F8
Load Register B with F8H (1111 1000), the mask that keeps bits 3-7.
4E6F
JUMP to 4E55H to store it in byte 0 of the FPDE.

4E71H - ATTRIB ACC= and UPD=

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

4E71
LD A,12H 3E 12
ACC: load Register A with 12H, the offset of the access password code.
4E73
JUMP to 4E77H with the offset in Register A.
4E75
LD A,10H 3E 10
UPD: load Register A with 10H, the offset of the update password code.
4E77
PUSH AF F5
Save Register Pair AF (Register A = the offset) on the stack.
4E78
GOSUB to 4FFEH to read the password at Register Pair HL and return its code in Register Pair DE.
4E7B
PUSH HL E5
Save Register Pair HL (the command line pointer) on the stack.
4E7C
POP BC C1
Restore Register Pair BC from the stack: BC = the command line pointer.
4E7D
POP AF F1
Restore Register Pair AF from the stack: Register A = the offset.
4E7E
POP HL E1
Restore Register Pair HL from the stack: the FPDE's address.
4E7F
PUSH HL E5
Save Register Pair HL (the FPDE's address) on the stack again.
4E80
ADD A,L 85
Add Register L (the FPDE's low byte) to Register A, the offset.
4E81
LD L,A 6F
Load Register L with Register A: Register Pair HL = the password code field.
4E82
LD (HL),E 73
Store Register E (the code's low byte) at Register Pair HL.
4E83
INC HL 23
Increment Register Pair HL to the code's high byte.
4E84
LD (HL),D 72
Store Register D (the code's high byte) at Register Pair HL.
4E85
LD H,B 60
Load Register H with Register B, the command line pointer's high byte.
4E86
LD L,C 69
Load Register L with Register C. Register Pair HL = the command line pointer.
4E87
JUMP to 4E5BH for the next keyword.

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 (47ECH, error 08H if there is no diskette) and its GAT read into 4200H. If a password was given and it is not the diskette's password (GAT CEH-CFH), the result is error 37H, but only when option AA (436CH bit 7) is on. Returns with 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 (4296H if the text does not start with a letter).
4E8C
LD A,(HL) 7E
Load Register A with the byte at Register Pair HL, the character after the name.
4E8D
CP 3AH FE 3A
Compare Register A against 3AH, a colon.
4E8F
INC HL 23
Increment Register Pair HL past it. INC HL does not change the flags.
4E90
If the Z FLAG is set (a colon), JUMP to 4E9CH.
4E92
PUSH HL E5
No colon: save Register Pair HL (the text pointer) on the stack.
4E93
LD HL,4296H 21 96 42
Load Register Pair HL with 4296H, the code of a blank password.
4E96
RST 18H DF
RST 18H: compare Register Pair HL (4296H) with Register Pair DE (the code read); the Z FLAG is set if no name was given.
4E97
POP HL E1
Restore Register Pair HL from the stack: the text pointer. POP does not change the flags.
4E98
DEC HL 2B
Decrement Register Pair HL back to the character. DEC HL does not change the flags.
4E99
If the NZ FLAG is set (a name without a colon), JUMP to 4DD0H for error 2FH.
4E9C
PUSH DE D5
Save Register Pair DE (the password code) on the stack.
4E9D
GOSUB to 4F9EH to read the drive number at Register Pair HL into Register Pair DE.
4EA0
LD A,D 7A
Load Register A with Register D, the number's high byte.
4EA1
OR A B7
OR Register A with itself: the NZ FLAG is set for 256 or more.
4EA2
If the NZ FLAG is set, JUMP to 4D50H for error 20H.
4EA5
LD A,E 7B
Load Register A with Register E, the drive number.
4EA6
POP DE D1
Restore Register Pair DE from the stack: the password code.
4EA7
GOSUB to SYS0 47ECH to select drive Register A and check that a diskette is in it.
4EAA
If the NZ FLAG is set (an error), JUMP to 4EC2H to return it in Register A.
4EAC
PUSH HL E5
Save Register Pair HL (the text pointer) on the stack.
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 into 4200H.
4EB1
If the NZ FLAG is set (a read error), JUMP to 4EC2H to return it in Register A.
4EB3
LD HL,(42CEH) 2A CE 42
Load Register Pair HL with the 16-bit value at 42CEH, the diskette password code (GAT bytes CEH-CFH).
4EB6
OR A B7
OR Register A with itself to clear the CARRY FLAG for the subtraction.
4EB7
SBC HL,DE ED 52
Subtract Register Pair DE (the code given) from Register Pair HL: the Z FLAG is set if they match.
4EB9
POP HL E1
Restore Register Pair HL from the stack: the text pointer. POP does not change the flags.
4EBA
RET Z C8
If the Z FLAG is set (the same password), RETURN.
4EBB
LD A,(436CH) 3A 6C 43
Load Register A with the byte at 436CH, the option flags.
4EBE
RLCA 07
Rotate Register A left: bit 7 (option AA, passwords checked) goes into the CARRY FLAG.
4EBF
RET NC D0
If the NO CARRY FLAG is set (option AA off), RETURN: the password is not checked.
4EC0
LD A,37H 3E 37
Load Register A with 37H, error code DISKETTE ACCESS DENIED.
4EC2
JUMP to 4D5EH to return the error in Register A.

4EC5H - PROT Command

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

4EC5
GOSUB to 4E89H to read the drive at Register Pair HL, check the diskette password and read the GAT into 4200H.
4EC8
GOSUB to 4F6BH: a separator must follow the drive number.
4ECB
LD BC,50C0H 01 C0 50
Load Register Pair BC with 50C0H, the PROT keyword table (4F0CH comes back here for further keywords).
4ECE
JUMP to 4F71H to find the keyword at Register Pair HL and go to its handler.

4ED1H - PROT DATE= and NAME=

Copies up to 8 characters, up to a comma, space or the end of the line, to GAT bytes D8H-DFH (DATE=) or D0H-D7H (NAME=), padded with spaces.

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

COPY THE FIELD: Register Pair HL = the text, Register Pair DE = the GAT byte, Register B = the characters left.

4EDB
GOSUB to SYS0 4CD5H with Register Pair HL = the text: the NO CARRY FLAG at the end of the line (Z) or after stepping over a separator.
4EDE
If the NO CARRY FLAG is set (the field has ended), JUMP to 4EE4H.
4EE0
LD A,(HL) 7E
An ordinary character: load Register A with the byte at Register Pair HL.
4EE1
INC HL 23
Increment Register Pair HL past the character.
4EE2
JUMP to 4EE9H to store the character in Register A.
4EE4
If the Z FLAG is set (the end of the line), JUMP to 4EE7H.
4EE6
DEC HL 2B
A separator: decrement Register Pair HL back to it, so that it is found again after the field.
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, in the GAT.
4EEA
INC DE 13
Increment Register Pair DE to the next GAT byte.
4EEB
Decrement Register B (the characters left); if it is not 0, LOOP back to 4EDBH.
4EED
JUMP to 4F09H for the next keyword.

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.

4EEF
LD A,04H 3E 04
RUF: load Register A with 04H, bit 2.
4EF1
JUMP to 4EF9H with the bit in Register A.
4EF3
LD A,01H 3E 01
UNLOCK: load Register A with 01H, bit 0.
4EF5
JUMP to 4EF9H with the bit in Register A.
4EF7
LD A,02H 3E 02
LOCK: load Register A with 02H, bit 1.
4EF9
PUSH HL E5
Save Register Pair HL (the text pointer) 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.
4EFD
OR (HL) B6
OR Register A (the bit) with the byte at Register Pair HL, the flags so far.
4EFE
LD (HL),A 77
Self-Modifying Code
Store Register A (the flags) at Register Pair HL, 4F13H.
4EFF
POP HL E1
Restore Register Pair HL from the stack: the text pointer.
4F00
JUMP to 4F09H for the next keyword.

4F02H - PROT PW=

PW=password stores the new password's code in GAT bytes CEH-CFH. A later LOCK uses the new code.

4F02
GOSUB to 4FFEH to read the password at Register Pair HL and return its code in Register Pair DE.
4F05
LD (42CEH),DE ED 53 CE 42
Store Register Pair DE (the code) at 42CEH, the diskette password in GAT bytes CEH-CFH.

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 text: the Z FLAG at the end of the line, the NZ FLAG after a separator; anything else gives error 34H.
4F0C
If the NZ FLAG is set (a separator), LOOP back to 4ECBH for the next keyword.
4F0E
GOSUB to SYS0 491FH to write the GAT in 4200H back.
4F11
RET NZ C0
If the NZ FLAG is set (a write error), RETURN with the error in Register A.
4F12
LD A,00H 3E 00
Self-Modifying Code
Load Register A with the file flags. The operand (4F13H) is 00H in the file and is ORed by 4EF9H.
4F14
OR A B7
OR Register A with itself: the Z FLAG is set if none was given.
4F15
LD B,A 47
Load Register B with Register A, the file flags. LD does not change the flags.
4F16
RET Z C8
If the Z FLAG is set (no LOCK, UNLOCK or RUF), RETURN with the Z FLAG: no error.
4F17
LD DE,(42CEH) ED 5B CE 42
Load Register Pair DE with the 16-bit value at 42CEH, the diskette password code (GAT CEH-CFH): the LOCK code.
4F1B
RRCA 0F
Rotate Register A right: bit 0 (UNLOCK) goes into the CARRY FLAG.
4F1C
If the NO CARRY FLAG is set (no UNLOCK), JUMP to 4F21H.
4F1E
LD DE,4296H 11 96 42
UNLOCK: load Register Pair DE with 4296H, the blank password code.
4F21
LD A,01H 3E 01
Load Register A with 01H: directory sector 1, the HIT.
4F23
GOSUB to SYS0 490AH to read directory sector Register A into 4200H.
4F26
RET NZ C0
If the NZ FLAG is set (a read error), RETURN with the error 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.
4F2A
ADD A,08H C6 08
Add 08H to Register A: the number of FDE sectors.
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.
4F2F
XOR A AF
Load Register A with 00H (XOR A with itself): FDE sector 0 first.

SECTOR LOOP: Register C = the FDE sector, 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 (bits 0-4 of a DEC; entry 0).
4F31
GOSUB to SYS0 4936H to read FDE sector Register C and point Register Pair HL to its first entry.
4F34
RET NZ C0
If the NZ FLAG is set (a read error), RETURN with the error in Register A.

ENTRY LOOP: Register Pair HL = byte 0 of the entry.

4F35
LD A,(HL) 7E
Load Register A with the byte at Register Pair HL, byte 0 of the entry.
4F36
AND 90H E6 90
Mask Register A against 90H (1001 0000) to keep bit 7 (an FXDE) and bit 4 (in use).
4F38
CP 10H FE 10
Compare Register A against 10H: the Z FLAG is set for an FPDE in use.
4F3A
If the NZ FLAG is set (free, or an FXDE), JUMP to 4F57H for the next entry.
4F3C
BIT 2,B CB 50
Test bit 2 of Register B, the RUF flag.
4F3E
If the Z FLAG is set (no RUF), JUMP to 4F44H.
4F40
INC HL 23
Increment Register Pair HL to byte 1 of the entry.
4F41
RES 5,(HL) CB AE
Clear bit 5 of the byte at Register Pair HL (byte 1): the file is no longer marked as updated.
4F43
DEC HL 2B
Decrement Register Pair HL back to byte 0.
4F44
LD A,B 78
Load Register A with Register B, the file flags.
4F45
AND 03H E6 03
Mask Register A against 03H (0000 0011) to keep UNLOCK (bit 0) and LOCK (bit 1).
4F47
If the Z FLAG is set (neither), JUMP to 4F57H.
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 against 48H (0100 1000) to keep bit 6 (a system file) and bit 3 (invisible).
4F4C
If the NZ FLAG is set (either), JUMP to 4F57H: the file is left alone.
4F4E
SET 4,L CB E5
Set bit 4 of Register L: Register Pair HL = byte 16 of the entry (entry + 10H).
4F50
LD (HL),E 73
Store Register E (the code's low byte) at Register Pair HL, the update password (byte 16).
4F51
INC HL 23
Increment Register Pair HL to byte 17.
4F52
LD (HL),D 72
Store Register D (the code's high byte) at Register Pair HL (byte 17).
4F53
INC HL 23
Increment Register Pair HL to byte 18, the access password.
4F54
LD (HL),E 73
Store Register E (the code's low byte) at Register Pair HL (byte 18).
4F55
INC HL 23
Increment Register Pair HL to byte 19.
4F56
LD (HL),D 72
Store Register D (the code's high byte) at Register Pair HL (byte 19).
4F57
LD A,L 7D
Load Register A with Register L, the position inside the entry.
4F58
AND E0H E6 E0
Mask Register A against E0H (1110 0000): back to the start of the entry.
4F5A
ADD A,20H C6 20
Add 20H to Register A: the next entry. The CARRY FLAG is set after the eighth.
4F5C
LD L,A 6F
Load Register L with Register A: Register Pair HL = the next entry.
4F5D
If the NO CARRY FLAG is set (more entries in the sector), LOOP back to 4F35H.
4F5F
GOSUB to SYS0 491FH to write the sector in 4200H back.
4F62
RET NZ C0
If the NZ FLAG is set (a write error), RETURN with the error in Register A.
4F63
INC C 0C
Increment Register C, the next FDE sector.
4F64
LD A,C 79
Load Register A with Register C, the next FDE sector.
4F65
CP 00H FE 00
Self-Modifying Code
Compare it with the number of FDE sectors (the operand at 4F66H, stored at 4F2CH).
4F67
If the CARRY FLAG is set, 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 with Register A = 00H and the Z FLAG set.

4F6BH - A Separator Must Follow

Steps 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 text: the NO CARRY FLAG after stepping over a comma or spaces.
4F6E
RET NC D0
If the NO CARRY FLAG is set (a separator), RETURN with Register Pair HL past it.
4F6F
JUMP to 4F90H for error 34H.

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 HL, with HL past the keyword. 4F7DH does the search for any table with D bytes after each name and returns BC pointing to them. No match gives error 34H. The text only has to start with the keyword.

4F71
LD D,02H 16 02
Load Register D with 02H: two bytes (the handler address) follow each name.
4F73
GOSUB to 4F7DH to find the keyword: Register Pair BC comes back at its handler address.
4F76
LD A,(BC) 0A
Load Register A with the byte at Register Pair BC, the handler's low byte.
4F77
LD E,A 5F
Load Register E with Register A, the handler's low byte.
4F78
INC BC 03
Increment Register Pair BC to the handler's high byte.
4F79
LD A,(BC) 0A
Load Register A with the byte at Register Pair BC, the handler's high byte.
4F7A
LD D,A 57
Load Register D with Register A. Register Pair DE = the handler's address.
4F7B
PUSH DE D5
Push Register Pair DE (the handler's address) on the stack.
4F7C
RET C9
RETURN, which jumps to the handler with Register Pair HL past the keyword.

TABLE LOOP. Register Pair BC = the entry, Register Pair HL = the text, Register D = the bytes after each name.

4F7D
GOSUB to SYS0 4CC5H to compare the name at Register Pair BC with the text at Register Pair HL: the Z FLAG, with Register Pair HL and Register Pair BC past the name, if it matches.
4F80
RET Z C8
If the Z FLAG is set (a match), RETURN with Register Pair BC at the bytes after the name.
4F81
LD A,(BC) 0A
Load Register A with the byte at Register Pair BC, a byte of the name.
4F82
CP 00H FE 00
Compare Register A against 00H, the byte that ends the name.
4F84
INC BC 03
Increment Register Pair BC to the next byte. INC BC does not change the flags.
4F85
If the NZ FLAG is set (not the end of the name), LOOP back to 4F81H.
4F87
LD E,D 5A
Load Register E with Register D, the number of bytes after the name.
4F88
INC BC 03
Increment Register Pair BC past one of them.
4F89
DEC E 1D
Decrement Register E, the bytes left to skip.
4F8A
If the NZ FLAG is set (more), 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.
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 (another entry), LOOP back to 4F7DH.
4F90
No keyword matched (or a separator is missing): JUMP to 4D5CH for error 34H.

4F93H - Read an Optional Number

4F93H: at the end of the line RETURN with DE unchanged; 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-F and H after decimal digits restart the reading as hexadecimal). Returns 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 text: the Z FLAG at the end of the line.
4F96
If the NZ FLAG is set (not the end), JUMP to 4F9CH.
4F98
RET C9
The end of the line: RETURN with Register Pair DE unchanged (the default).
4F99
GOSUB to SYS0 4CD9H with Register Pair HL = the text: the NO CARRY FLAG after stepping over a comma or spaces.
4F9C
If the CARRY FLAG is set (no separator), JUMP to 4F90H for error 34H.
4F9E
PUSH HL E5
Save Register Pair HL (the start of the number) on the stack.
4F9F
LD B,00H 06 00
Load Register B with 00H: decimal, no digit yet.
4FA1
GOSUB to 4FBFH to read the digits at Register Pair HL into Register Pair DE.
4FA4
LD A,(HL) 7E
Load Register A with the byte at Register Pair HL, the character that ended the digits.
4FA5
SUB 41H D6 41
Subtract 41H from Register A: the letters A-H become 00H-07H.
4FA7
CP 08H FE 08
Compare Register A against 08H: the CARRY FLAG is set for A-H.
4FA9
If the NO CARRY FLAG is set (not A-H: a decimal number), JUMP to 4FB8H.
4FAB
POP HL E1
Restore Register Pair HL from the stack: the start of the number.
4FAC
LD B,01H 06 01
Load Register B with 01H: hexadecimal.
4FAE
PUSH HL E5
Save Register Pair HL (the start of the number) on the stack again.
4FAF
GOSUB to 4FBFH to read the hexadecimal digits at Register Pair HL into Register Pair DE.
4FB2
LD A,(HL) 7E
Load Register A with the byte at Register Pair HL, the character that ended them.
4FB3
CP 48H FE 48
Compare Register A against 48H, the letter H.
4FB5
INC HL 23
Increment Register Pair HL past it. INC HL does not change the flags.
4FB6
If the NZ FLAG is set (no H), JUMP to 4FBCH for error 2FH.
4FB8
BIT 1,B CB 48
Test bit 1 of Register B: set if at least one digit was read.
4FBA
POP BC C1
Restore Register Pair BC from the stack, discarding the saved start of the number.
4FBB
RET NZ C0
If the NZ FLAG is set (a digit was read), RETURN with the value in Register Pair DE.
4FBC
JUMP to 4DD0H for error 2FH.
4FBF
LD DE,0000H 11 00 00
Load Register Pair DE with 0000H, the value.

DIGIT LOOP. Register Pair HL = the text, Register Pair DE = the value, Register B = the flags.

4FC2
LD A,(HL) 7E
Load Register A with the byte at Register Pair HL, the next character.
4FC3
SUB 30H D6 30
Subtract 30H from Register A: the digits 0-9 become 00H-09H.
4FC5
CP 0AH FE 0A
Compare Register A against 0AH: the CARRY FLAG is set for a digit 0-9.
4FC7
If the CARRY FLAG is set (0-9), JUMP to 4FD3H to add the digit.
4FC9
BIT 0,B CB 40
Test bit 0 of Register B: set for hexadecimal.
4FCB
RET Z C8
If the Z FLAG is set (decimal), RETURN: the number ends here.
4FCC
SUB 11H D6 11
Subtract 11H from Register A: the letters A-F become 00H-05H.
4FCE
CP 06H FE 06
Compare Register A against 06H: the CARRY FLAG is set for A-F.
4FD0
RET NC D0
If the NO CARRY FLAG is set (not A-F), RETURN: the number ends here.
4FD1
ADD A,0AH C6 0A
Add 0AH to Register A: A-F become the values 10-15.
4FD3
PUSH HL E5
Save Register Pair HL (the text pointer) on the stack.
4FD4
LD H,D 62
Load Register H with Register D, the value's high byte.
4FD5
LD L,E 6B
Load Register L with Register E. Register Pair HL = the value so far.
4FD6
LD C,A 4F
Load Register C with Register A, the digit.
4FD7
XOR A AF
Load Register A with 00H (XOR A with itself): Register A collects any overflow.
4FD8
SET 1,B CB C8
Set bit 1 of Register B: a digit has been read.
4FDA
ADD HL,HL 29
Add Register Pair HL to itself: the value times 2.
4FDB
ADC A,A 8F
Add Register A to itself with the CARRY FLAG: the overflow is kept.
4FDC
ADD HL,HL 29
Add Register Pair HL to itself: the value times 4.
4FDD
ADC A,A 8F
Add Register A to itself with the CARRY FLAG: the overflow is kept.
4FDE
BIT 0,B CB 40
Test bit 0 of Register B: set for hexadecimal.
4FE0
If the Z FLAG is set (decimal), JUMP to 4FE5H.
4FE2
ADD HL,HL 29
Hexadecimal: add Register Pair HL to itself, the value times 8.
4FE3
JUMP to 4FE6H.
4FE5
ADD HL,DE 19
Decimal: add Register Pair DE (the old value) to Register Pair HL, the value times 5.
4FE6
ADC A,A 8F
Add Register A to itself with the CARRY FLAG: the overflow is kept.
4FE7
ADD HL,HL 29
Add Register Pair HL to itself: the value times 16 (hexadecimal) or 10 (decimal).
4FE8
ADC A,A 8F
Add Register A to itself with the CARRY FLAG: the overflow is kept.
4FE9
LD E,C 59
Load Register E with Register C, the digit.
4FEA
LD D,00H 16 00
Load Register D with 00H. Register Pair DE = the digit.
4FEC
ADD HL,DE 19
Add Register Pair DE (the digit) to Register Pair HL.
4FED
ADC A,A 8F
Add Register A to itself with the CARRY FLAG: the NZ FLAG is set if anything overflowed.
4FEE
EX DE,HL EB
Exchange Register Pairs DE and HL: DE = the new value.
4FEF
POP HL E1
Restore Register Pair HL from the stack: the text pointer. POP does not change the flags.
4FF0
If the NZ FLAG is set (over FFFFH), JUMP to 4FBCH for error 2FH.
4FF2
INC HL 23
Increment Register Pair HL to the next character.
4FF3
LOOP back to 4FC2H for the next digit.

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 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 DE with the same algorithm as SYS2 5155H (a blank name gives 4296H). The buffer is left blank.

COPY THE NAME. Register Pair HL = the text, Register Pair DE = the buffer position, Register B = the characters left.

4FF5
LD A,(HL) 7E
Load Register A with the byte at Register Pair HL, the next character.
4FF6
CP 30H FE 30
Compare Register A against 30H, the character 0: the CARRY FLAG is set below it.
4FF8
If the CARRY FLAG is set (below 0), JUMP to 500FH: the name ends.
4FFA
CP 3AH FE 3A
Compare Register A against 3AH: the CARRY FLAG is set for a digit.
4FFC
JUMP to 5004H with that result.
4FFE
LD DE,51E7H 11 E7 51
Entry: load Register Pair DE with 51E7H, one before the buffer at 51E8H-51EFH.
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: the first character must be a letter.
5004
If the CARRY FLAG is set (a digit, 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.
5007
CP 41H FE 41
Compare Register A against 41H, the letter A: the CARRY FLAG is set below it.
5009
If the CARRY FLAG is set (not a letter), JUMP to 500FH: the name ends.
500B
CP 5BH FE 5B
Compare Register A against 5BH, one above Z: the CARRY FLAG is set for A-Z.
500D
If the CARRY FLAG is set (a letter), JUMP to 5017H to store it.
500F
INC DE 13
Increment Register Pair DE to the next buffer position.

PAD WITH SPACES. Register Pair DE = the buffer position, Register B = the positions left.

5010
LD A,20H 3E 20
Load Register A with 20H, a space.
5012
LD (DE),A 12
Store Register A (a space) at Register Pair DE.
5013
Decrement Register B (the positions left); if it is not 0, LOOP back to 500FH.
5015
JUMP to 501CH to encode the name.
5017
INC DE 13
Increment Register Pair DE to the next buffer position.
5018
LD (DE),A 12
Store Register A (the character) at Register Pair DE.
5019
INC HL 23
Increment Register Pair HL to the next character.
501A
Decrement Register B (the characters left); if it is not 0, LOOP back to 4FF5H.
501C
PUSH HL E5
Save Register Pair HL (the text pointer after the name) on the stack.
501D
EX DE,HL EB
Exchange Register Pairs DE and HL: HL = 51EFH, the last buffer byte.
501E
LD DE,FFFFH 11 FF FF
Load Register Pair DE with FFFFH, the code's starting value.
5021
LD B,08H 06 08
Load Register B with 08H: eight characters, from the last to the first.

ENCODE LOOP. Register Pair DE = the code, Register Pair HL = the character, Register B = the characters left (saved 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.
5024
LD A,E 7B
Load Register A with Register E, the code's low byte.
5025
AND 07H E6 07
Mask Register A against 07H (0000 0111) to keep its bits 0-2.
5027
LD C,A 4F
Load Register C with Register A, those bits.
5028
LD A,E 7B
Load Register A with Register E, the code's low byte.
5029
RLCA 07
Rotate Register A left.
502A
RLCA 07
Rotate Register A left again.
502B
RLCA 07
Rotate Register A left a third time: the low byte rotated left by 3.
502C
XOR C A9
XOR Register A with Register C, the low byte's bits 0-2.
502D
RLCA 07
Rotate Register A left once more.
502E
LD C,A 4F
Load Register C with Register A, the mixed value.
502F
AND F0H E6 F0
Mask Register A against F0H (1111 0000) to keep its high four bits.
5031
LD B,A 47
Load Register B with Register A, those bits.
5032
LD A,C 79
Load Register A with Register C, the mixed value.
5033
RLCA 07
Rotate Register A left.
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.
5037
XOR D AA
XOR Register A with Register D, the code's high byte.
5038
LD E,A 5F
Load Register E with Register A: the code's new low byte.
5039
LD A,C 79
Load Register A with Register C, the mixed value.
503A
AND 0FH E6 0F
Mask Register A against 0FH (0000 1111) to keep its low four bits.
503C
LD B,A 47
Load Register B with Register A, those bits.
503D
LD A,C 79
Load Register A with Register C, the mixed value.
503E
RLCA 07
Rotate Register A left.
503F
RLCA 07
Rotate Register A left again.
5040
RLCA 07
Rotate Register A left a third time.
5041
RLCA 07
Rotate Register A left a fourth time: the halves are swapped.
5042
XOR B A8
XOR Register A with Register B, the 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.
5045
LD D,A 57
Load Register D with Register A: the code's new high byte.
5046
LD (HL),20H 36 20
Store 20H (a space) at Register Pair HL: the buffer is blanked as it is used.
5048
DEC HL 2B
Decrement Register Pair HL to the character before.
5049
Decrement Register B (the characters left); if it is not 0, LOOP back to 5023H.
504B
POP HL E1
Restore Register Pair HL from the stack: the text pointer after the name.
504C
RET C9
RETURN with the password code in Register Pair DE.

504DH - ATTRIB Keyword Table

Searched by 4F71H: the keyword, 00H, and the handler address.

504D
DEFM "INV", 00H / DEFW 4E4DH 49 4E 56 00 4D 4E
INV: set the invisible bit (4E4DH).
5053
DEFM "VIS", 00H / DEFW 4E51H 56 49 53 00 51 4E
VIS: clear the invisible bit (4E51H).
5059
DEFM "PROT=", 00H / DEFW 4E63H 50 52 4F 54 3D 00 63 4E
PROT=level: the access level (4E63H).
5061
DEFM "ACC=", 00H / DEFW 4E71H 41 43 43 3D 00 71 4E
ACC=password: the access password (4E71H).
5068
DEFM "UPD=", 00H / DEFW 4E75H 55 50 44 3D 00 75 4E
UPD=password: the update password (4E75H).
506F
DEFM "ASE=", 00H / DEFW 4E2AH 41 53 45 3D 00 2A 4E
ASE=Y/N: automatic space extension (4E2AH).
5076
DEFM "ASC=", 00H / DEFW 4E2EH 41 53 43 3D 00 2E 4E
ASC=Y/N: automatic space compression (4E2EH).
507D
DEFM "UDF=", 00H / DEFW 4E23H 55 44 46 3D 00 23 4E
UDF=Y/N: the updated flag (4E23H).
5084
DEFM "LRL=", 00H / DEFW 4E10H 4C 52 4C 3D 00 10 4E
LRL=n: the record length (4E10H).
508B
DEFB 00H 00
00H, the end of the ATTRIB keyword table (4F8DH tests it).

508CH - Access Level Table

Searched by 4E68H for PROT=: the name, 00H, and the level for FPDE byte 0 bits 0-2.

508C
DEFM "LOCK", 00H, 07H 4C 4F 43 4B 00 07
LOCK: level 7.
5092
DEFM "EXEC", 00H, 06H 45 58 45 43 00 06
EXEC: level 6.
5098
DEFM "READ", 00H, 05H 52 45 41 44 00 05
READ: level 5.
509E
DEFM "WRITE", 00H, 04H 57 52 49 54 45 00 04
WRITE: level 4.
50A5
DEFM "RENAME", 00H, 02H 52 45 4E 41 4D 45 00 02
RENAME: level 2.
50AD
DEFM "NAME", 00H, 02H 4E 41 4D 45 00 02
NAME: level 2 too.
50B3
DEFM "KILL", 00H, 01H 4B 49 4C 4C 00 01
KILL: level 1.
50B9
DEFM "FULL", 00H, 00H 46 55 4C 4C 00 00
FULL: level 0.
50BF
DEFB 00H 00
00H, the end of the access level table (4F8DH tests it).

50C0H - PROT Keyword Table

Searched by 4F71H: the keyword, 00H, and the handler address.

50C0
DEFM "PW=", 00H / DEFW 4F02H 50 57 3D 00 02 4F
PW=password: the diskette password (4F02H).
50C6
DEFM "UNLOCK", 00H / DEFW 4EF3H 55 4E 4C 4F 43 4B 00 F3 4E
UNLOCK: blank the passwords of the files (4EF3H).
50CF
DEFM "LOCK", 00H / DEFW 4EF7H 4C 4F 43 4B 00 F7 4E
LOCK: give the files the diskette password (4EF7H).
50D6
DEFM "NAME=", 00H / DEFW 4ED6H 4E 41 4D 45 3D 00 D6 4E
NAME=name: the diskette name (4ED6H).
50DE
DEFM "DATE=", 00H / DEFW 4ED1H 44 41 54 45 3D 00 D1 4E
DATE=date: the diskette date (4ED1H).
50E6
DEFM "RUF", 00H / DEFW 4EEFH 52 55 46 00 EF 4E
RUF: reset the updated flags (4EEFH).
50EC
DEFB 00H 00
00H, the end of the PROT keyword table (4F8DH tests it).

50EDH - DUMP Command

DUMP filespec,start,end[,entry[,load]] writes memory start-end to the file (opened by SYS1 in the 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, defaults to start. With entry = FFFFH the file is written without records instead (only the load address as two 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 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 file's sector buffer (4D61H-4E60H, over SYS7's own code).
50F0
LD (4483H),HL 22 83 44
Store Register Pair HL (4D61H) at 4483H, the FCB's buffer address (FCB+3/4).
50F3
POP AF F1
Restore Register Pair AF from the stack, discarding the dispatcher's return address (4C20H).
50F4
POP HL E1
Restore Register Pair HL from the stack: the command line pointer left by SYS1.
50F5
GOSUB to 4F99H: a separator, then the start address into Register Pair DE.
50F8
PUSH DE D5
Save Register Pair DE (the start) on the stack.
50F9
GOSUB to 4F99H: a separator, then the end address into Register Pair DE.
50FC
EX DE,HL EB
Exchange Register Pairs DE and HL: HL = the end, DE = the text 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 is kept there, and HL = the start.
50FE
EX DE,HL EB
Exchange Register Pairs DE and HL: DE = the start, HL = the text pointer.
50FF
PUSH DE D5
Save Register Pair DE (the start) on the stack.
5100
LD DE,402DH 11 2D 40
Load Register Pair DE with 402DH, the default entry address (DOS READY).
5103
GOSUB to 4F93H to read the entry address into Register Pair DE, if one follows.
5106
LD A,D 7A
Load Register A with Register D, the entry's high byte.
5107
AND E A3
AND Register A with Register E: FFH only if the entry is FFFFH.
5108
INC A 3C
Increment Register A: the Z FLAG is set if the entry is FFFFH (no records).
5109
EX DE,HL EB
Exchange Register Pairs DE and HL: HL = the entry, DE = the text pointer.
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 is kept there, and HL = the start.
510B
EX DE,HL EB
Exchange Register Pairs DE and HL: DE = the start, HL = the text pointer.
510C
PUSH DE D5
Save Register Pair DE (the start, the default load address) on the stack.
510D
If the NZ FLAG is set (the entry is not FFFFH), GOSUB to 4F93H to read the load address into Register Pair DE (default: the start).
5110
GOSUB to 4D58H: the line must end here (else error 34H).
5113
POP BC C1
Restore Register Pair BC from the stack: the start.
5114
POP AF F1
Restore Register Pair AF from the stack: the entry address (A = high byte, F = low byte).
5115
POP HL E1
Restore Register Pair HL from the stack: the end.
5116
PUSH AF F5
Save Register Pair AF (the entry) on the stack.
5117
PUSH BC C5
Save Register Pair BC (the start) on the stack.
5118
PUSH HL E5
Save Register Pair HL (the end) on the stack.
5119
PUSH DE D5
Save Register Pair DE (the load address) on the stack.
511A
OR A B7
OR Register A with itself to clear the CARRY FLAG for the subtraction.
511B
SBC HL,BC ED 42
Subtract Register Pair BC (the start) from Register Pair HL (the end): 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. PUSH does not change the flags.
511E
If the CARRY FLAG is set (the end is below the start), JUMP to 4DD0H for error 2FH.
5121
LD BC,0005H 01 05 00
Load Register Pair BC with 0005H, to make the count plus 4.
5124
ADD HL,BC 09
Add Register Pair BC to Register Pair HL: HL = the byte count plus 4; the CARRY FLAG is set if it passes FFFFH.
5125
If the NO CARRY FLAG is set, JUMP to 512CH to divide.
5127
LD HL,0104H 21 04 01
A count near 64K: load Register Pair HL with 0104H, the sector to write.
512A
JUMP to 5131H with the sector in Register Pair HL.
512C
LD A,FCH 3E FC
Load Register A with FCH, 252: the data bytes per sector, allowing for the record headers.
512E
GOSUB to SYS0 4CB4H to divide Register Pair HL by Register A: HL = the number of sectors the file will need.
5131
LD (448AH),HL 22 8A 44
Store Register Pair HL at 448AH, the FCB's NEXT middle and high bytes (FCB+10/11): the file is positioned at that sector.
5134
LD DE,4480H 11 80 44
Load Register Pair DE with 4480H, the FCB.
5137
LD BC,E908H 01 08 E9
Load Register Pair BC with E908H: code E9H (SYS7, function 7) and sub-function 8.
513A
LD HL,49D3H 21 D3 49
Load Register Pair HL with 49D3H, the SYS0 return point that turns a pushed word into an RST 28H.
513D
PUSH BC C5
Push Register Pair BC (E908H) on the stack.
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 at the FCB at Register Pair DE, which allocates the file's space (SYS2 may be loaded for that); it returns to 49D3H, which displays an error or calls SYS7 sub-function 8.

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

Entered through 49D3H with DE = the FCB and the values pushed at 5116H-511DH on the stack. The file is rewound and the bytes are sent one at a time through the ROM output routine at 001BH with 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).
5143
GOSUB to SYS0 443FH to rewind the file at Register Pair DE (NEXT = 0).
5146
If the NZ FLAG is set (an error), JUMP to 5198H, which goes on to the error exit.
5148
EXX D9
Exchange Register Pairs BC, DE and HL with the alternate set: the FCB in Register Pair DE is kept aside for the output routine at 51D3H.
5149
POP DE D1
Restore Register Pair DE from the stack: the byte count minus 1.
514A
POP HL E1
Restore Register Pair HL from the stack: the load address.
514B
INC DE 13
Increment Register Pair DE: the byte count (0000H for 65536).
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.
514F
POP HL E1
Restore Register Pair HL from the stack: the end address.
5150
LD (51B7H),HL 22 B7 51
Self-Modifying Code
Store Register Pair HL (the end) 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.
5154
LD (51BEH),HL 22 BE 51
Self-Modifying Code
Store Register Pair HL (the start) 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.
5158
EX DE,HL EB
Exchange Register Pairs DE and HL: HL = the byte count, DE = the start, the first byte to write.
5159
LD A,B 78
Load Register A with Register B, the entry's high byte.
515A
AND C A1
AND Register A with Register C: FFH only if the entry is FFFFH.
515B
INC A 3C
Increment Register A: the Z FLAG is set if the entry is FFFFH.
515C
If the Z FLAG is set (no records), JUMP to 519DH.
515E
PUSH BC C5
Save Register Pair BC (the entry address) on the stack.
515F
LD A,H 7C
Load Register A with Register H, the count's high byte.
5160
OR L B5
OR Register A with Register L: the Z FLAG is set for a count of 0000H (65536 bytes).
5161
If the NZ FLAG is set (a smaller count), JUMP to 516BH.
5163
LD BC,00FEH 01 FE 00
65536 bytes: load Register Pair BC with 00FEH, 254.
5166
OR A B7
OR Register A with itself to clear the CARRY FLAG for the subtraction.
5167
SBC HL,BC ED 42
Subtract Register Pair BC (254) from Register Pair HL (the count).
5169
JUMP to 5173H to write a full record.

RECORD LOOP: Register Pair HL = the bytes left, Register Pair DE = the next 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 for the subtraction.
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 are left.
5171
If the CARRY FLAG is set, JUMP to 5186H for the last, short record.
5173
INC C 0C
Increment Register C: the length byte is the data length plus 2...
5174
INC C 0C
Increment Register C again (FEH + 2 = 00H, meaning 256, for a full record).
5175
LD B,01H 06 01
Load Register B with 01H, record type 01H (load data).
5177
GOSUB to 51ACH to write the type (Register B), the length (Register C) and the load address of Register Pair DE.
517A
DEC C 0D
Decrement Register C...
517B
DEC C 0D
Decrement Register C again: Register C = the number of data bytes.

DATA LOOP: Register Pair DE = the next 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 memory.
517D
INC DE 13
Increment Register Pair DE to the next byte.
517E
GOSUB to 51D3H to write the byte in Register A to the file.
5181
DEC C 0D
Decrement Register C, the bytes left in the record.
5182
If the NZ FLAG is set (more), LOOP back to 517CH.
5184
LOOP back to 516BH for the next record.
5186
OR A B7
OR Register A with itself to clear the CARRY FLAG.
5187
ADC HL,BC ED 4A
Add Register Pair BC (254) back to Register Pair HL: HL = the bytes left (0-253), the Z FLAG set if none.
5189
LD C,L 4D
Load Register C with Register L, the bytes left.
518A
LD L,H 6C
Load Register L with Register H (00H): Register Pair HL = 0000H, nothing after this record.
518B
If the NZ FLAG is set (bytes left), JUMP to 5173H for a short record (516BH then finds none left).
518D
POP DE D1
Restore Register Pair DE from the stack: the entry address.
518E
LD B,02H 06 02
Load Register B with 02H, record type 02H (transfer).
5190
LD C,B 48
Load Register C with Register B: the length byte 02H.
5191
GOSUB to 51ACH to write the transfer record: type, length and the entry address in Register Pair DE (translated if it lies in the dumped range).
5194
EXX D9
Exchange the alternate set back: Register Pair DE = the FCB.
5195
GOSUB to SYS0 443FH to rewind the file at Register Pair DE.
5198
If the NZ FLAG is set (an error), JUMP to 51D9H to return it in Register A.
519A
JUMP to SYS0 4428H to close the file at Register Pair DE, which returns to SYS1.
519D
Without records: GOSUB to 51B4H to write the address in Register Pair DE (the start, translated: the load address).

RAW DATA LOOP: Register Pair DE = the next 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 memory.
51A1
INC DE 13
Increment Register Pair DE to the next byte.
51A2
GOSUB to 51D3H to write the byte in Register A to the file.
51A5
DEC HL 2B
Decrement Register Pair HL, the bytes left.
51A6
LD A,H 7C
Load Register A with Register H, to test Register Pair HL for zero.
51A7
OR L B5
OR Register A with Register L: the Z FLAG is set when no bytes are left.
51A8
If the NZ FLAG is set (more), LOOP back to 51A0H.
51AA
JUMP to 5194H to rewind and close the file.

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

51ACH writes Register B (the type) and Register C (the length). 51B4H writes the address in DE as two bytes, translated when it lies between start and end: DE - start + load. 51D3H writes the byte in Register A through ROM 001BH with the FCB in 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.
51AD
GOSUB to 51D3H to write the type in Register A.
51B0
LD A,C 79
Load Register A with Register C, the length byte.
51B1
GOSUB to 51D3H to write the length in Register A.
51B4
PUSH HL E5
Save Register Pair HL (the caller's count) on the stack.
51B5
PUSH DE D5
Save Register Pair DE (the address to write) on the stack.
51B6
LD HL,0000H 21 00 00
Self-Modifying Code
Load Register Pair HL with the end address, the operand 51B7H (0000H in the file, stored at 5150H).
51B9
RST 18H DF
RST 18H: compare Register Pair HL (the end) with Register Pair DE (the address); the CARRY FLAG is set if the address is past the end.
51BA
EX DE,HL EB
Exchange Register Pairs DE and HL: HL = the address, DE = the end. EX does not change the flags.
51BB
If the CARRY FLAG is set (past the end), JUMP to 51CCH and write the address unchanged.
51BD
LD DE,0000H 11 00 00
Self-Modifying Code
Load Register Pair DE with the start address, the operand 51BEH (0000H in the file, stored at 5154H).
51C0
RST 18H DF
RST 18H: compare Register Pair HL (the address) with Register Pair DE (the start); the CARRY FLAG is set if the address is below the start.
51C1
If the CARRY FLAG is set (below the start), JUMP to 51CCH and write the address unchanged.
51C3
PUSH HL E5
Save Register Pair HL (the address) on the stack.
51C4
LD HL,0000H 21 00 00
Self-Modifying Code
Load Register Pair HL with the load address, the operand 51C5H (0000H in the file, stored at 514CH).
51C7
OR A B7
OR Register A with itself to clear the CARRY FLAG for the subtraction.
51C8
SBC HL,DE ED 52
Subtract Register Pair DE (the start) from Register Pair HL: HL = the load address minus the start.
51CA
POP DE D1
Restore Register Pair DE from the stack: the address.
51CB
ADD HL,DE 19
Add Register Pair DE to Register Pair HL: HL = the address translated to the load address.
51CC
LD A,L 7D
Load Register A with Register L, the address's low byte.
51CD
GOSUB to 51D3H to write the low byte in Register A.
51D0
LD A,H 7C
Load Register A with Register H, the address's high byte, written by 51D3H below.
51D1
POP DE D1
Restore Register Pair DE from the stack: the caller's address pointer.
51D2
POP HL E1
Restore Register Pair HL from the stack: the caller's count.
51D3
EXX D9
Exchange Register Pairs BC, DE and HL with the alternate set: Register Pair DE = the FCB.
51D4
GOSUB to ROM 001BH ($PUT) to write the byte in Register A to the device at Register Pair DE; the FCB's byte 0 is not a device type, so SYS0 4ADBH writes it to the file.
51D7
EXX D9
Exchange the alternate set back: the caller's registers again.
51D8
RET Z C8
If the Z FLAG is set (written), RETURN.
51D9
JUMP to 4D5EH to return the write error in Register A.

51DCH - Unused Bytes

51DC-51E7
NOP x 12 00 x 12
Twelve zero bytes to the end of the file (51E7H). Nothing in SYS7 reads or writes them; the password buffer starts after them at 51E8H.