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

Page Customization

Introduction / Summary

SYS7/SYS — NEWDOS/80 v2.0 Library Command Executor (Model III)

SYS7/SYS is a DOS overlay module for NEWDOS/80 v2.0 on the TRS-80 Model III. It is loaded into the overlay area at 4D00H-51E7H when any of its associated commands are invoked from the DOS READY prompt. The overlay is identified by SVC function code E9H and uses IY=4280H as its base pointer to the DOS system variable area.

Purpose: SYS7 implements the following NEWDOS/80 library commands:

CommandSub-FnEntryDescription
TIMEC=14D68HDisplay or set the system time (hh:mm:ss format)
DATEC=24D7DHDisplay or set the system date (mm/dd/yy format)
AUTOC=34D6CHSet auto-start command for a disk drive
ATTRIBC=44DDBHModify file attributes (INV, VIS, PROT=, ACC=, UPD=, ASE=, ASC=, UDF=, LRL=)
PROTC=54DFAHModify diskette protection (PW=, NAME=, DATE=, RUF, LOCK, UNLOCK)
DUMPC=64ECCHWrite memory block to disk in CMD (load module) or raw format
HIMEMC=750F4HDisplay or set the highest usable memory address
PURGE/SYSTEM/PDRIVE (first part)C=85149HDUMP output callback / initial setup for PURGE, SYSTEM, PDRIVE
(sub-function 9)C=94D70HSVC dispatch helper (loads B from IY+FEH)
(parameter parser 1)C=104D3EHSelf-modifying code setup for date parser (stores 2FH delimiter, error 36H)
(parameter parser 2)C=114D34HSelf-modifying code setup for time parser (stores 3AH delimiter, error 33H)

Command Dispatcher: The entry point at 4D00H uses a cascading DEC C / JP Z pattern to dispatch to one of 11 sub-functions based on the value in Register C. This is a compact jump table alternative commonly used in Z80 code when the number of cases is moderate and sequential.

Architecture: SYS7 relies heavily on three architectural patterns:

1. Keyword Table Dispatch — Both the ATTRIB and PROT commands parse their options using null-terminated keyword tables (at 5054H and 50C7H). The search routine at 4F84H walks the table, comparing each keyword against the command line text, and extracts either a 1-byte data value (for PROT= access levels) or a 2-byte handler address (for option dispatch via the PUSH/RET computed jump at 4F78H).

2. Self-Modifying Code — SYS7 uses instruction operand overwriting extensively. The date/time parser shares a single code path (4DAEH) that is configured at runtime by overwriting the delimiter character at 4DD2H and the error code at 4D4FH. The PROT directory iteration uses self-modified operands at 4F1AH (accumulated flags) and 4F6DH (sector limit). The DUMP output routine overwrites addresses at 51BEH, 51C5H, and 51CCH to store parameters between callback invocations.

3. Password Hashing — The password encoding algorithm at 5023H converts 8-character text passwords into 2-byte hashes using a chain of RLCA rotations, XOR operations, and nibble swaps. The hash is non-reversible and the source buffer is zeroed after encoding (at 504DH) to prevent password text from remaining in memory. This same algorithm encodes both file passwords (ACC=, UPD=) and diskette passwords (PW=).

Overlay Size: 1,256 bytes (4D00H-51E7H). The last 5 bytes (51E3H-51E7H) are NOP padding. The byte at 51E8H begins a scratch display buffer used during command execution but is not part of the stored overlay image.

Variables

System variables, IY-based offsets, and self-modifying code locations referenced by SYS7. Variables are organized into three categories: SYS0 system variables accessed by SYS7, IY-relative references, and self-modifying code operands within SYS7 itself.

SYS0 System Variables (External)

AddressSizeDescriptionReferenced By
4219H2Destination address for sub-function 10 parameter setup4D3EH
4280HIY base pointer for DOS system variable areaThroughout (IY+offset references)
428CH1System option flags. Bit 7 = AR option (password checking enforcement). If bit 7 set, password match is required; if clear, password mismatches are ignored.4EC2H
4296H2Default drive number / null password encoding. Used as the UNLOCK replacement password (blank password) and as the default drive reference when no explicit drive number is specified.4E9AH, 4F25H
42C9H2Maximum allowable date value (16-bit). Used to clamp the system date during DATE set operations.4DA2H
431FH1Number of directory sectors on the current diskette (minus one). Used to calculate the PROT directory iteration limit.4F2EH
43CEH2Encoded diskette password for the currently-opened drive. Read from the control sector (GAT). Written by PROT PW= handler; read for LOCK operations and password verification.4EBAH, 4F0CH, 4F1EH
43D0H8Diskette date string field (8 characters, mm/dd/yy format) in the control sector buffer. Written by PROT DATE= handler.4EDDH
43D8H8Diskette name field (8 characters) in the control sector buffer. Written by PROT NAME= handler.4ED8H
4411H2System date value (16-bit). Read for DATE display; written for DATE set.4D7DH, 4DABH
4480HSYS0 output parameter control block. Base address of the structure used by file write routines during DUMP operations.513BH
4483H2Function pointer / return vector. HIMEM/DUMP stores the TIME handler address (4D68H) here as a callback.50F7H
448AH2DUMP output record size. Stores the calculated CMD record length for file write operations.5138H

IY-Relative References

OffsetAbsoluteDescriptionReferenced By
(IY+FEH)427EHDrive parameter byte for SVC calls. Loaded into Register B before RST 28H dispatch.4D70H
(IY+60H)42E0HBase address of working buffer for ATTRIB command. 32 bytes of command line text are copied here from the original command buffer.4DE7H

Self-Modifying Code Operands (within SYS7)

AddressInstructionDescriptionWritten By
4D4FHLD A,nnError code operand. Set to 36H (out of range) by sub-function 10 at 4D3EH, or 33H (parameter error) by sub-function 11 at 4D34H. Read at 4D4EH when a parse error occurs.4D3EH, 4D34H
4DD2HCP nnDelimiter character for date/time 3-byte parser. Set to 3AH (colon) for time format (hh:mm:ss) by sub-function 11, or 2FH (slash) for date format (mm/dd/yy) by sub-function 10. Checked at 4DD0H after each pair of digits.4D42H (via 4D34H/4D3EH)
4F1AHLD A,nnAccumulated PROT operation flags. Bit 0 = UNLOCK, bit 1 = LOCK, bit 2 = RUF. ORed with new flag bits at 4F05H. Read at 4F19H at the start of directory iteration; if zero, iteration is skipped.4F05H (via 4F00H)
4F6DHCP nnDirectory iteration sector limit. Set to (431FH) + 08H at 4F33H. The sector counter (Register C) is compared against this limit at 4F6CH to determine when all directory sectors have been processed.4F33H
51BEHLD HL,nnnnDUMP end address. Stored at 5157H from the alternate register context. Read by the load address calculation at 51BDH during CMD record header output.5157H
51C5HLD DE,nnnnDUMP entry/transfer address. Stored at 515BH. Read at 51C4H during CMD record output to calculate the relocated load address.515BH
51CCHLD HL,nnnnDUMP remaining byte count. Stored at 5153H. Read at 51CBH during address calculation for output records.5153H

Major Routines

Internal routine addresses serve as hyperlink targets within the disassembly. External routines (SYS0 and ROM) are listed for reference; their code resides in other overlays or ROM.

Internal Routines (within SYS7: 4D00H-51E7H)

Entry Point and Command Dispatcher

AddressRoutineDescription
4D00HEntry PointSYS7 entry. Cascading DEC C / JP Z dispatcher routes to 11 sub-functions based on the value in Register C.
4D34HTime Parser SetupSub-function 11. Configures the 3-byte parser for time format: stores 3AH (colon) delimiter at 4DD2H, error code 33H at 4D4FH.
4D3EHDate Parser SetupSub-function 10. Configures the 3-byte parser for date format: stores 2FH (slash) delimiter at 4DD2H, error code 36H at 4D4FH.

Utility and Error Handling

AddressRoutineDescription
4D4EHError Code StubLoads self-modified error code (33H or 36H) from 4D4FH and falls through to error exit at 4D65H.
4D5BHParameter CheckSkip whitespace and check for comma/next parameter. Calls SYS0 4C7AH. Returns NZ if more parameters, Z if end of line.
4D65HCommon Error ExitJumps to SYS0 error handler at 4409H with error code in Register A.
4D73HSVC DispatchCommon RST 28H dispatch with function code in A and B from (IY+FEH). Used by TIME, AUTO, and sub-function 9.
4D8DHDisplay BufferTerminate display buffer with 0DH (carriage return) and output via SYS0 4467H.

TIME, DATE, and AUTO Commands

AddressRoutineDescription
4D68HTIME HandlerLoads SVC code 33H into B. Parses filespec via 4E90H. Dispatches via RST 28H.
4D6CHAUTO HandlerLoads SVC code 32H into B. Same path as TIME.
4D7DHDATE HandlerDisplay: reads date from (4411H), formats via SYS0 44D2H. Set: parses 3-byte value via 4FA5H, validates high byte < 70H, clamps to max at (42C9H), stores to (4411H).
4DAEH3-Byte Decimal ParserParses mm/dd/yy or hh:mm:ss format. Multiply-by-10 algorithm: (A×4+A)×2. Stores in descending address order via DE pointer. Delimiter check at 4DD0H uses self-modified operand at 4DD2H.

ATTRIB Command

AddressRoutineDescription
4DDBHATTRIB EntryOpens file via SYS0 4723H, reads directory sector via 48AFH, copies command line to buffer at (IY+60H). Enters option keyword loop at 4E11H using table at 5054H.
4E17HLRL= HandlerParse numeric value 0-255, store at FPDE offset +4 (Logical Record Length).
4E2AHASE= HandlerBit 5 flag: Auto Space Extend. Y/N parser with AND/OR bit masking.
4E35HASC= HandlerBit 6 flag: Auto Space Compress.
4E3AHY/N ParserCommon handler for Y/N attribute options. AND mask (in B) clears the target bit, then OR mask (in C) sets it if Y. Modifies the directory entry byte and jumps to the option loop.
4E6AHPROT= HandlerProtection level keyword lookup via sub-table at 5093H. Matched level (0-7) stored in FPDE bits 2-0 via AND F8H / OR level mask.
4E78HACC= HandlerEncode password via 5005H, store 2-byte hash at FPDE offset +12H (access password).
4E7CHUPD= HandlerEncode password via 5005H, store 2-byte hash at FPDE offset +10H (update password).

PROT Command

AddressRoutineDescription
4DFAHPROT EntryParses password:drive via 4F72H. Checks drive access level (must be 0 = FULL for modification). Reads control sector (GAT) via SYS0 48F0H. Enters option loop using table at 50C7H.
4ED8HNAME= HandlerCopy up to 8 characters to diskette name field at 43D8H.
4EDDHDATE= HandlerCopy up to 8 characters to diskette date field at 43D0H.
4EF6HRUF FlagSet bit 2 in accumulated flags at 4F1AH (Reset Update Flag).
4EFAHUNLOCK FlagSet bit 0 in accumulated flags (replace file passwords with blank).
4EFEHLOCK FlagSet bit 1 in accumulated flags (set diskette password as all file passwords).
4F00HFlag AccumulatorOR new flag bit into accumulated byte at 4F1AH (self-modifying operand of LD A,nn at 4F19H).
4F09HPW= HandlerEncode password and store 2-byte hash to diskette password variable at 43CEH.
4F19HDirectory IterationIterate all directory entries on diskette. For each user file: apply RUF (clear Updated bit), LOCK (set both passwords to diskette password), or UNLOCK (set both passwords to blank). Uses double nested loop (sectors × entries).

Drive and Filespec Parsers

AddressRoutineDescription
4E90HParse Drive NumberParse filespec, check for colon-separated drive number. If no colon, check default drive at 4296H. Validate drive via SYS0 4791H, read GAT via 48AFH, verify diskette password against 43CEH.
4F72HParse FilespecParse password-protected filespec from command line via SYS0 4C7EH.
4F9AHRequire FilespecSkip spaces and check for required filespec parameter.
4FA0HRequire ParameterParse required numeric parameter via SYS0 4C7EH.

Keyword Table and Number Parsing

AddressRoutineDescription
4F78HKeyword DispatchSet D=02H (2 data bytes per entry = handler address), call 4F84H, extract 16-bit address, execute via PUSH/RET computed jump.
4F84HKeyword SearchWalk null-terminated keyword table. Compare each entry against command line via SYS0 4C6AH. On match, return BC pointing to data bytes. On no match, error 34H.
4FA5HNumber ParserParse decimal or hex number. First pass: decimal. If letter A-H terminates, re-parse as hex from beginning. Hex numbers require "H" suffix. Returns 16-bit value in DE.
4FC6HNumber AccumulatorCore digit loop. Decimal: DE = (DE×4+DE)×2 + digit = DE×10 + digit. Hex: DE = DE×4×2×2 + digit = DE×16 + digit. Overflow detection via 24-bit A:HL extension.

Password and Filename Processing

AddressRoutineDescription
4FFCHFilename ValidatorCheck if character is valid filename character (digits 0-9, letters A-Z). Used in the filename copy loop.
5005HParse + Encode PasswordCopy up to 8 valid characters to buffer at 51E7H, pad with spaces, then encode via hash algorithm at 5023H. Returns 2-byte hash in DE.
5023HPassword Hash8-character → 2-byte hash. Init DE=FFFFH. For each character: RLCA chain, XOR with nibble extracts, XOR with character. Clears source buffer byte to 20H after processing. Non-reversible.
4EE0HCopy 8 CharactersCopy up to 8 characters from command line to destination buffer, pad with spaces. Used by NAME= and DATE= handlers.

DUMP and HIMEM Commands

AddressRoutineDescription
4ECCHDUMP EntryParse drive via 4E90H, filespec via 4F72H, then dispatch to PROT option table at 50C7H for additional options.
50F4HHIMEM / DUMP SetupStore callback vector 4D68H at 4483H. Parse start/end/entry/relocation addresses. Validate range (end ≥ start). Calculate CMD record size. Set up output via SYS0 4439H with SVC code E908H.
5149HDUMP OutputSVC callback handler. Outputs memory block as CMD file records (type 01H = data, type 02H = entry point). Uses EXX to switch between DUMP context and SYS0 file I/O context.
51A4HRaw DumpOutput raw memory bytes without CMD headers (SUPERZAP-readable format). Entered when entry address = FFFFH.
51B3HRecord Header OutputOutput CMD record header: type byte (B), length byte (C), then 2-byte load address via 51BBH.
51DAHByte OutputOutput single byte (A) to file. EXX to alternate regs, CALL 001BH (ROM character output redirected to file DCB), EXX back. Returns Z if success.
51E0HOutput Error ExitJump to common error handler at 4D65H on file output failure.

Data Tables

AddressRoutineDescription
5054HATTRIB Option Table9 keywords: INV, VIS, PROT=, ACC=, UPD=, ASE=, ASC=, UDF=, LRL=. Each followed by 00H terminator and 2-byte handler address. Sentinel 00H at 5092H.
5093HProtection Level Sub-Table8 keywords: LOCK(7), EXEC(6), READ(5), WRITE(4), RENAME(2), NAME(2), KILL(1), FULL(0). Each followed by 00H and 1-byte access level. Sentinel 00H at 50C6H.
50C7HPROT Option Table6 keywords: PW=, UNLOCK, LOCK, NAME=, DATE=, RUF. Each followed by 00H and 2-byte handler address. Sentinel 00H at 50F3H.

External Routines Called by SYS7

AddressModuleDescription
001BHROMCharacter output vector. In DUMP context, redirected to file write DCB.
RST 18HROMSystem comparison/table lookup operation. Used in drive parsing and DUMP address calculations.
RST 28HDOSSVC dispatch. Function code in A, parameter in B. Used for TIME, AUTO, and sub-function 9.
3036HROMConvert binary value to ASCII decimal and display.
4409HSYS0Error handler. Register A contains error code.
4428HSYS0Close file and return to DOS READY (DUMP successful completion).
4439HSYS0Dispatch/setup for file output. Uses parameters on stack (SVC code and handler address).
443FHSYS0Output status check. Returns Z if output should continue, NZ if complete or error.
4467HSYS0Display string from buffer (terminated by 0DH).
44D2HSYS0Format date value to ASCII mm/dd/yy string.
4723HSYS0Parse filespec from command line and locate file in directory.
4791HSYS0Validate and initialize drive. A = drive number. Returns Z if valid.
48AFHSYS0Open sector buffer and read directory/control sector. A = mode (0=read-only, 1=read-write).
48C4HSYS0Write directory/control sector back to disk from buffer.
48DBHSYS0Read specific directory sector (number in C) into buffer.
48F0HSYS0Read control sector (GAT — Granule Allocation Table) from diskette.
4C59HSYS0Buffer allocation / size calculation for DUMP output.
4C6AHSYS0Case-insensitive string comparison. BC = table entry, HL = command line. Returns Z on match.
4C7AHSYS0Skip whitespace and check for delimiter (space, comma, CR). Returns Carry = valid char, NC = delimiter, Z = end of line.
4C7EHSYS0Parse next token from command line. Returns Carry if valid token found, NC if end of line.

Error Codes Used by SYS7

CodeDecimalMeaningGenerated At
19H25Access denied — PROT drive access level is not 0 (FULL)4E07H
20H32Attribute/specification error — drive number too large4D57H, 4EA9H
2AH42General error4D53H
2FH47Invalid parameter value — number out of range or invalid hex format4DD7H, 4EA0H, 4FC3H
33H51Parameter error (time format) — self-modified via sub-function 114D4EH (operand at 4D4FH)
34H52Parse error — no keyword match or invalid filespec4D63H, 4F97H
36H54Parameter out of range (date format) — self-modified via sub-function 104D4EH (operand at 4D4FH)
37H55Incorrect password — diskette password mismatch with AR option enforced4EC7H

Disassembly

4D00H - SYS7 Entry Point and Library Command Dispatcher

SYS7 is the Library Command Executor for NEWDOS/80 v2.0. It is entered from SYS1 after a DOS library command has been parsed. On entry, Register A contains the SVC function code, Register C contains the sub-function number (1-based index identifying which command within this overlay), and Register HL points to the remainder of the command line text. This dispatcher routes execution to the correct handler for TIME, DATE, AUTO, ATTRIB, PROT, DUMP, HIMEM, and the first part of PURGE, SYSTEM, and PDRIVE.

4D00
LD IY,4280H FD 21 80 42
Point Index Register IY to 4280H, the base address of the DOS system variable area. IY is used throughout SYS7 as a base pointer for accessing system configuration variables and flags via indexed offsets. This is the standard initialization performed by all NEWDOS/80 overlay modules on entry.
4D04
CP E9H FE E9
Compare Register A (the SVC function code passed from SYS1) against E9H. SVC code E9H identifies the group of library commands handled by SYS7. If Register A equals E9H, the Z FLAG is set; otherwise the NZ FLAG is set.
4D06
If the NZ FLAG is set (SVC function code is NOT E9H), JUMP to 4D34H to handle the alternate SVC code. This handles SVC function codes other than E9H that are also routed to SYS7 (the PURGE/SYSTEM/PDRIVE first-part handlers use a different SVC code).

[COMMAND DISPATCH TABLE] — The code below implements a cascading dispatch by decrementing Register C (the sub-function number) and branching when it reaches zero. Each DEC C / branch pair corresponds to one library command. The sub-function numbers are assigned by SYS1 when it parses the command name and maps it to the appropriate SYS overlay file. C=1 through C=11 select the individual commands within SYS7.

4D08
DEC C 0D
DECrement Register C (sub-function counter) by 1. If C was 1 on entry (first command in the SYS7 dispatch table), it is now zero and the Z FLAG is set.
4D09
If the Z FLAG is set (sub-function 1 = TIME command), JUMP to 4D68H to execute the TIME command handler.
4D0B
DEC C 0D
DECrement Register C by 1. If C was 2 on entry (now zero), the Z FLAG is set.
4D0C
If the Z FLAG is set (sub-function 2 = DATE command), JUMP to 4D7DH to execute the DATE command handler.
4D0F
DEC C 0D
DECrement Register C by 1. If C was 3 on entry (now zero), the Z FLAG is set.
4D10
If the Z FLAG is set (sub-function 3 = AUTO command), JUMP to 4D6CH to execute the AUTO command handler.
4D12
DEC C 0D
DECrement Register C by 1. If C was 4 on entry (now zero), the Z FLAG is set.
4D13
If the Z FLAG is set (sub-function 4 = ATTRIB command), JUMP to 4DDBH to execute the ATTRIB command handler.
4D16
DEC C 0D
DECrement Register C by 1. If C was 5 on entry (now zero), the Z FLAG is set.
4D17
If the Z FLAG is set (sub-function 5 = PROT command), JUMP to 4DFAH to execute the PROT (diskette protection/control) command handler.
4D1A
DEC C 0D
DECrement Register C by 1. If C was 6 on entry (now zero), the Z FLAG is set.
4D1B
If the Z FLAG is set (sub-function 6 = DUMP command), JUMP to 4ECCH to execute the DUMP (memory-to-disk dump) command handler.
4D1E
DEC C 0D
DECrement Register C by 1. If C was 7 on entry (now zero), the Z FLAG is set.
4D1F
If the Z FLAG is set (sub-function 7 = HIMEM command), JUMP to 50F4H to execute the HIMEM command handler.
4D22
DEC C 0D
DECrement Register C by 1. If C was 8 on entry (now zero), the Z FLAG is set.
4D23
If the Z FLAG is set (sub-function 8 = first part of PURGE, SYSTEM, and PDRIVE commands), JUMP to 5149H to execute the PURGE/SYSTEM/PDRIVE first-part handler. These commands require multi-stage processing; SYS7 handles the initial setup and parameter parsing, while later stages are handled elsewhere.
4D26
DEC C 0D
DECrement Register C by 1. If C was 9 on entry (now zero), the Z FLAG is set.
4D27
If the Z FLAG is set (sub-function 9), JUMP to 4D70H. This is an additional command handler that loads BC with E506H and then falls into the common SVC dispatch at 4D73H.

[SUB-FUNCTIONS 10 AND 11] — The remaining dispatch entries handle two more commands. Sub-function 10 sets up DE=4219H, B=3AH, A=36H and jumps to the common error number parser at 4D3EH. Sub-function 11 (which falls through from the NZ branch at 4D06H or from this point) loads a different set of parameters and also reaches the error parser.

4D29
LD DE,4219H 11 19 42
Point Register Pair DE to 4219H, a system variable location. This address is used as a parameter for the sub-function 10 handler — it is the destination address where a parsed numeric value will be stored.
4D2C
LD B,3AH 06 3A
Load Register B with 3AH (58 decimal). This value is the upper bound for a numeric comparison — the maximum valid value for this parameter. 3AH is the ASCII code for the colon (:) character, which also serves as a delimiter check.
4D2E
LD A,36H 3E 36
Load Register A with 36H (54 decimal). This is the error code that will be issued if the parsed value exceeds the maximum. Error 36H corresponds to a "Parameter out of range" error in NEWDOS/80.
4D30
DEC C 0D
DECrement Register C by 1. If C was 10 on entry (now zero), the Z FLAG is set.
4D31
If the Z FLAG is set (sub-function 10), JUMP to 4D3EH to store the error code and execute the common parameter parsing and dispatch routine.
4D33
DEC C 0D
DECrement Register C by 1. If C was 11 on entry (now zero), the Z FLAG is set. If C is still not zero, the sub-function number is invalid.

4D34H - Alternate SVC / Sub-function 11 Handler

This code handles either the alternate SVC function code (when A was not E9H at 4D04H) or sub-function 11 when it falls through from the dispatcher. It loads error code 2AH (general error) and checks if the sub-function matched. If not, it jumps to the error handler at 4D65H. If it matched, it sets up parameters for a different command with E=1CH, B=2FH, A=33H and falls through to 4D3EH.

4D34
LD A,2AH 3E 2A
Load Register A with 2AH (42 decimal). This is error code 2AH = "General error" in NEWDOS/80. This will be used as the error code if the sub-function number is invalid (falls through from the dispatcher without matching any command).
4D36
If the NZ FLAG is set (sub-function 11 did NOT match — the sub-function number was invalid and never reached zero), JUMP to 4D65H to report the error. The error handler at 4D65H will use the error code in Register A (2AH = general error).

[SUB-FUNCTION 11 SETUP] — Execution reaches here only if the Z FLAG was set at 4D33H (sub-function 11 matched). This sets up parameters for a command that accepts a value with maximum 2FH (47 decimal), stores it at the address pointed to by DE (which will be loaded from E=1CH), and reports error 33H if the value is out of range.

4D38
LD E,1CH 1E 1C
Load Register E with 1CH (28 decimal). This will be combined with a high byte to form the destination address for storing the parsed parameter value.
4D3A
LD B,2FH 06 2F
Load Register B with 2FH (47 decimal). This is the maximum valid value for this command's parameter.
4D3C
LD A,33H 3E 33
Load Register A with 33H (51 decimal). This is the error code to report if the parsed value exceeds the maximum in Register B. Error 33H is a parameter error.

4D3EH - Common Parameter Store and Command Line Check

This routine is reached by sub-functions 10 and 11 after setting up their parameters. It stores the error code (Register A) and the maximum value (Register B) as self-modifying code targets, then checks whether the command line has additional parameters. If the command line is terminated (0DH = carriage return), it displays the current value; otherwise it parses the new value from the command line.

4D3E
LD (4D4FH),A 32 4F 4D
Store Register A (the error code, either 36H or 33H) to memory location 4D4FH. [SELF-MODIFYING CODE] — This overwrites the operand of an instruction later in the code at 4D4EH/4D4FH. When the code at that address is reached, it will use this error code to report an out-of-range parameter.
4D41
LD A,B 78
Copy Register B (the maximum valid value, either 3AH or 2FH) into Register A.
4D42
LD (4DD2H),A 32 D2 4D
Store Register A (the maximum valid value) to memory location 4DD2H. [SELF-MODIFYING CODE] — This overwrites the operand of a comparison instruction at 4DD1H/4DD2H. When the numeric parser runs, it will compare the parsed value against this maximum.
4D45
LD A,(HL) 7E
Fetch the next character from the command line buffer (pointed to by Register Pair HL) into Register A. This checks whether there are parameters following the command keyword.
4D46
CP 0DH FE 0D
Compare Register A against 0DH (13 decimal = carriage return). A carriage return indicates the end of the command line — no parameters were provided. If Register A equals 0DH, the Z FLAG is set; otherwise the NZ FLAG is set.
4D48
If the NZ FLAG is set (command line has more parameters to parse), JUMP to 4DAEH to enter the numeric parameter parser that will read a decimal value from the command line.

[DISPLAY CURRENT VALUE] — If execution reaches here, the command was entered with no parameters (just the keyword followed by ENTER). The code will display the current value by calling the SYS0 display routine. HL is set to 51E8H (a scratch buffer), pushed as a return address, and then the SYS0 routine at 3036H is called.

4D4A
LD HL,51E8H 21 E8 51
Point Register Pair HL to 51E8H, a scratch buffer area within the SYS7 overlay. This buffer will be used to format the current value for display.
4D4D
PUSH HL E5
Save Register Pair HL (51E8H, the scratch buffer address) onto the stack. This address will be used as a return target after the display routine completes.
4D4E
GOSUB to ROM routine at 3036H to convert and display the current value. This ROM routine handles the formatting and output of the system variable's current setting to the screen.
4D51
Unconditional JUMP to 4D8DH to store a carriage return terminator in the display buffer and complete the display operation.

4D53H - Error Code Return Points

These are short entry points that load specific error codes into Register A and then jump to the common error handler at 4D65H. They are used as quick exits when various validation checks fail throughout SYS7.

4D53
LD A,2CH 3E 2C
Load Register A with 2CH (44 decimal). Error code 2CH = "Directory full" in NEWDOS/80.
4D55
Unconditional JUMP to 4D65H to report error 2CH (directory full) via the SYS0 error handler.
4D57
LD A,20H 3E 20
Load Register A with 20H (32 decimal). Error code 20H = "Attribute conflict" or a file specification error in NEWDOS/80.
4D59
Unconditional JUMP to 4D65H to report error 20H via the SYS0 error handler.

4D5BH - Skip Spaces and Validate Next Parameter

This utility routine skips whitespace in the command line, then checks whether the next character is a carriage return (end of line) or not. It is called between parameter parsing operations to advance to the next parameter. Returns with Z FLAG set if end of command line, NZ FLAG set with error code 34H if unexpected characters remain.

4D5B
GOSUB to SYS0 routine at 4C7AH to skip whitespace characters in the command line. On return, HL points to the first non-space character, and the Carry flag indicates whether a comma delimiter was found (Carry set = comma found, NC = no comma).
4D5E
RET NC D0
If the NO CARRY FLAG is set (no comma was found — end of parameters or non-comma delimiter), RETURN to the caller. The caller will check the character at (HL) to determine if it is a carriage return (end of command) or an error.
4D5F
LD A,(HL) 7E
Fetch the next character from the command line buffer (pointed to by Register Pair HL) into Register A. After skipping spaces and finding a comma, this reads the first character of the next parameter.
4D60
CP 0DH FE 0D
Compare Register A against 0DH (carriage return). Check if the command line ends immediately after the comma — which would be a syntax error (trailing comma with no parameter).
4D62
RET Z C8
If the Z FLAG is set (character is a carriage return — the command line is properly terminated), RETURN to the caller with Z FLAG set indicating end of command line.
4D63
LD A,34H 3E 34
Load Register A with 34H (52 decimal). Error code 34H = "Parse error" in NEWDOS/80. The command line contained unexpected characters after a parameter.

4D65H - Common Error Exit

All error exits throughout SYS7 converge here. Register A contains the NEWDOS/80 error code. This routine jumps to the SYS0 error handler at 4409H which displays the error message and returns to DOS READY.

4D65
JUMP to SYS0 error handler at 4409H. Register A contains the error code. The SYS0 error handler will display the corresponding error message (by loading SYS4 if necessary) and return control to the DOS READY prompt. This is a dead-end jump — execution does not return to SYS7.

4D68H - TIME Command Entry Point

The TIME command displays or sets the system clock time. Syntax: TIME to display the current time, or TIME,hh:mm:ss to set a new time. On entry from the dispatcher, Register HL points to the command line text following the "TIME" keyword. This entry point sets Register B to 33H (the SYS0 sub-function code for TIME) and falls into the common SVC call at 4D73H.

4D68
LD B,33H 06 33
Load Register B with 33H (51 decimal). This is the SYS0/ROM sub-function code that identifies the TIME operation. It will be passed to the RST 28H SVC handler to execute the TIME set/display function.
4D6A
Unconditional JUMP to 4D73H to push BC, call the command line parser at 4E90H, and execute the RST 28H SVC dispatch.

4D6CH - AUTO Command Entry Point

The AUTO command stores a DOS command string in the system diskette's directory for automatic execution at subsequent reboots. Syntax: AUTO,doscmd to set an auto-boot command, or AUTO alone to clear the auto-boot command. On entry, Register HL points to the command line text following the "AUTO" keyword. This entry point sets Register B to 32H (the SYS0 sub-function code for AUTO) and falls into the common SVC call.

4D6C
LD B,32H 06 32
Load Register B with 32H (50 decimal). This is the SYS0/ROM sub-function code for the AUTO command operation.
4D6E
Unconditional JUMP to 4D73H to push BC, call the command line parser, and execute the RST 28H SVC dispatch.

4D70H - Sub-function 9 Entry Point

This is the entry point for sub-function 9 from the command dispatcher. It loads Register Pair BC with E506H — Register B gets E5H (the SYS0 sub-function code) and Register C gets 06H (an additional parameter). It then falls through to the common SVC dispatch at 4D73H.

4D70
LD BC,E506H 01 06 E5
Load Register Pair BC with E506H. Register B receives E5H (the SYS0/ROM sub-function code) and Register C receives 06H (an additional parameter byte). Note the Z80 stores the low byte first: C=06H (from byte at 4D71H), B=E5H (from byte at 4D72H).

4D73H - Common SVC Dispatch (TIME, AUTO, DATE, Sub-function 9)

This common routine is used by the TIME, AUTO, DATE, and sub-function 9 handlers. It saves Register Pair BC (containing the SVC function code in B), calls the command line parser/filespec handler at 4E90H, then restores BC, moves the function code to Register A, loads a value from (IY+FEH), and executes RST 28H to invoke the SVC handler. On entry: B = SVC sub-function code, HL = pointer to command line text.

4D73
PUSH BC C5
Save Register Pair BC onto the stack. Register B contains the SVC sub-function code (33H for TIME, 32H for AUTO, or other values for DATE and sub-function 9). This preserves it across the call to 4E90H.
4D74
GOSUB to 4E90H to parse the drive number and optional filespec from the command line. This routine validates the drive number syntax (digit followed by colon) and returns the parsed drive number. HL is advanced past the parsed portion of the command line.
4D77
POP BC C1
Restore Register Pair BC from the stack. Register B now contains the SVC sub-function code that was saved before the call to 4E90H.
4D78
LD A,B 78
Copy Register B (the SVC sub-function code) into Register A. Register A is the primary parameter register for the RST 28H SVC dispatch.
4D79
LD B,(IY+FEH) FD 46 FE
Fetch the value at (IY+FEH) into Register B. Since IY=4280H, this reads from address 427EH (4280H + FEH = 4280H - 2 = 427EH, using two's complement offset). This system variable contains a parameter needed by the SVC function — the current drive number or a related configuration value.
4D7C
RST 28H EF
Execute RST 28H — the NEWDOS/80 Supervisor Call (SVC) dispatch. Register A contains the function code (e.g., 33H for TIME, 32H for AUTO). The RST 28H handler in the ROM/SYS0 examines the function code and routes to the appropriate system routine. On return, the operation is complete and Register A contains the result status (zero = success, non-zero = error code).

4D7DH - DATE Command Handler

The DATE command displays or sets the system date. Syntax: DATE to display the current date, or DATE,mm/dd/yy to set a new date. On entry from the dispatcher, Register HL points to the command line text following the "DATE" keyword. If no parameters are given (carriage return), it displays the current date. Otherwise, it parses and sets the new date via a call to the date entry routine at 4FA5H and then uses the SYS0 date store/display routines.

4D7D
LD A,(HL) 7E
Fetch the next character from the command line buffer (pointed to by Register Pair HL) into Register A. This checks whether a date parameter follows the DATE keyword.
4D7E
CP 0DH FE 0D
Compare Register A against 0DH (carriage return). If the command line is just "DATE" followed by ENTER, the user wants to display the current date. If Register A equals 0DH, the Z FLAG is set.
4D80
If the NZ FLAG is set (there are parameters following "DATE" — the user wants to set a new date), JUMP to 4D93H to parse the date value.

[DISPLAY CURRENT DATE] — No parameters were given, so display the current system date. The code loads the current date value from (4411H), sets up the display buffer at 51E8H, and calls the SYS0 date formatting routine at 44D2H.

4D82
LD DE,(4411H) ED 5B 11 44
Load Register Pair DE with the 16-bit value stored at 4411H. This SYS0 system variable contains the current system date in the internal NEWDOS/80 date format (a packed binary representation of mm/dd/yy).
4D86
LD HL,51E8H 21 E8 51
Point Register Pair HL to 51E8H, the scratch buffer within SYS7. This buffer will receive the formatted date string for display.
4D89
PUSH HL E5
Save Register Pair HL (51E8H, scratch buffer address) onto the stack. This will be used after the formatting call to display the result.
4D8A
GOSUB to SYS0 routine at 44D2H to convert the binary date value in Register Pair DE into a formatted ASCII date string (mm/dd/yy) and store it in the buffer pointed to by HL. On return, HL points past the end of the formatted string.

4D8DH - Terminate Display Buffer and Output

This short routine terminates the formatted display string with a carriage return (0DH), restores the buffer start address from the stack, and then jumps to the SYS0 display routine at 4467H to output the string to the screen.

4D8D
LD (HL),0DH 36 0D
Store 0DH (carriage return) at the memory location pointed to by Register Pair HL. This terminates the formatted display string in the scratch buffer with a carriage return, which serves as the end-of-string marker for the display routine.
4D8F
POP HL E1
Restore Register Pair HL from the stack. This retrieves the start address of the display buffer (51E8H) that was pushed earlier, so HL now points to the beginning of the formatted string.
4D90
JUMP to SYS0 routine at 4467H to display the formatted string. Register Pair HL points to the start of the null/CR-terminated string in the buffer at 51E8H. The SYS0 display routine will output each character to the screen and then return to the DOS READY prompt. This is a tail-call — execution does not return to SYS7.

4D93H - DATE Set: Parse and Store New Date

This routine handles the case where the user provided a date parameter (e.g., "DATE,02/27/82"). It parses the date string using the numeric parser at 4FA5H, validates the parsed value, checks if it is within the valid range for a system date, and stores it in the system date variable at 4411H.

4D93
GOSUB to 4FA5H to parse a numeric value from the command line. On entry, HL points to the date string. On return, Register Pair DE contains the parsed 16-bit value (the date in internal binary format), and HL has been advanced past the parsed text.
4D96
GOSUB to 4D5FH to check for end of command line. This verifies that no extraneous characters follow the date parameter. If the command line is properly terminated (carriage return), returns with Z FLAG set. If extra characters remain, falls through to load error code 34H (parse error).
4D99
LD A,D 7A
Copy Register D (high byte of the parsed date value) into Register A. This is used to validate the date range — the high byte must be less than 70H for a valid date.
4D9A
CP 70H FE 70
Compare Register A (high byte of parsed date) against 70H (112 decimal). If A < 70H, the CARRY FLAG is set (valid date range). If A >= 70H, the NO CARRY FLAG is set (date out of range).
4D9C
If the CARRY FLAG is set (high byte of date < 70H — date is out of valid range for this check), JUMP to 4DD7H to report error 2FH (invalid parameter value). Note: The Carry condition here means the date value is too small or in an invalid format.

[DATE RANGE CLAMPING] — The code below compares the parsed date (DE) against the maximum date value stored at 42C9H. If the parsed date exceeds the maximum, it is clamped to the maximum value. The final validated date is stored in the system date variable at 4411H.

4D9F
LD HL,(42C9H) 2A C9 42
Load Register Pair HL with the 16-bit value stored at 42C9H. This SYS0 system variable contains the maximum valid date value. It is used to ensure the user-supplied date does not exceed the system's date range.
4DA2
OR A B7
Perform OR A to clear the Carry flag. This prepares for the 16-bit subtraction that follows — SBC HL,DE requires the Carry flag to be cleared for a proper comparison.
4DA3
SBC HL,DE ED 52
Subtract Register Pair DE (parsed date value) from Register Pair HL (maximum date value) with borrow. If HL >= DE (parsed date is within range), the result is positive or zero and the NO CARRY FLAG is set. If HL < DE (parsed date exceeds maximum), the CARRY FLAG is set.
4DA5
ADD HL,DE 19
ADD Register Pair DE back to Register Pair HL. This restores HL to its original value (the maximum date from 42C9H) after the SBC comparison. The flags from the SBC are not affected by this ADD in a meaningful way for the branch below — only the Carry from SBC matters.
4DA6
If the CARRY FLAG is set (from the SBC at 4DA3H — the parsed date in DE exceeds the maximum in HL), JUMP to 4DA9H to skip the EX DE,HL, keeping HL (the maximum date) as the value to store. This effectively clamps the date to the maximum allowed value.
4DA8
EX DE,HL EB
Exchange Register Pairs DE and HL. The parsed date (which was in DE) is now in HL. This happens only when the parsed date is within range (DE <= maximum), so HL now contains the validated user-supplied date.
4DA9
LD (4411H),HL 22 11 44
Store Register Pair HL to the system date variable at 4411H. HL contains either the validated user-supplied date (if within range) or the maximum date (if the user's value was too large). The system date is now updated.
4DAC
XOR A AF
Set Register A to 00H (zero) and clear all flags. A=0 indicates success — no error. The Z FLAG is set.
4DAD
RET C9
RETURN to the caller (SYS0/SYS1) with Register A = 0 (success). The date has been stored and the command is complete.

4DAEH - Decimal Numeric Parser (3-Byte Date/Time Entry)

This routine parses a decimal numeric string from the command line and stores the result as three separate bytes into a destination buffer pointed to by Register Pair DE (stored in descending order). It handles date format (mm/dd/yy) or time format (hh:mm:ss) — three pairs of decimal digits separated by delimiters (the delimiter character is checked as 00H). Register B is loaded with 03H for the three-pair count. Interrupts are disabled during the parse to prevent interference. On entry: HL points to the command line text, DE points to the destination storage address.

4DAE
DI F3
Disable interrupts. The clock interrupt is disabled during this parsing operation to prevent the real-time clock from updating the time/date variables while they are being modified.
4DAF
LD B,03H 06 03
Load Register B with 03H (3 decimal). This is the byte count — three 2-digit decimal values will be parsed (e.g., hours, minutes, seconds or month, day, year).

[LOOP START — Parse one 2-digit decimal number] — Each iteration of this loop reads two ASCII decimal digits from the command line, converts them to a single binary byte using the formula (tens_digit × 10) + units_digit, and stores the result at the address in DE. After storing, DE is decremented and B is decremented. The loop processes three pairs total.

4DB1
LD A,(HL) 7E
Fetch the next character from the command line buffer (pointed to by HL) into Register A. This is the tens digit of a 2-digit decimal value.
4DB2
SUB 30H D6 30
SUBtract 30H (ASCII 0) from Register A to convert the ASCII digit character to its binary value (0-9). If the character was 0 through 9, A is now 00H-09H.
4DB4
CP 0AH FE 0A
Compare Register A against 0AH (10 decimal). If A < 0AH (valid digit 0-9), the CARRY FLAG is set. If A >= 0AH (not a valid decimal digit), the NO CARRY FLAG is set.
4DB6
INC HL 23
INCrement Register Pair HL by 1 to advance the command line pointer to the next character.
4DB7
If the NO CARRY FLAG is set (the character was not a valid decimal digit), JUMP to 4DD6H to re-enable interrupts and report error 2FH (invalid value).

[MULTIPLY TENS DIGIT BY 10] — The tens digit value (0-9) in Register A must be multiplied by 10. The code uses the formula: A×10 = A×4 + A, then doubled. Specifically: save A to C, RLCA twice (A×4), add C (A×4 + original = A×5), then ADD A,A (A×10).

4DB9
LD C,A 4F
Copy Register A (the tens digit binary value, 0-9) into Register C. This saves the original value for the multiply-by-10 calculation.
4DBA
RLCA 07
Rotate Register A left by 1 bit position. This multiplies A by 2. For example, if A was 3, it is now 6.
4DBB
RLCA 07
Rotate Register A left by 1 bit position again. A is now multiplied by 4 (original × 4). For example, if A was 3, it is now 12.
4DBC
ADD A,C 81
ADD Register C (the original tens digit value) to Register A (which is tens_digit × 4). Result: A = tens_digit × 4 + tens_digit = tens_digit × 5.
4DBD
ADD A,A 87
ADD Register A to itself, doubling it. Result: A = tens_digit × 10. This completes the multiply-by-10 operation.
4DBE
LD C,A 4F
Copy Register A (tens_digit × 10) into Register C. This saves the tens value while the units digit is read.
4DBF
LD A,(HL) 7E
Fetch the next character from the command line buffer into Register A. This is the units digit of the 2-digit decimal number.
4DC0
SUB 30H D6 30
SUBtract 30H (ASCII 0) from Register A to convert the ASCII digit to binary (0-9).
4DC2
CP 0AH FE 0A
Compare Register A against 0AH (10 decimal). Check if the character is a valid decimal digit. If A < 0AH, the CARRY FLAG is set (valid digit).
4DC4
INC HL 23
INCrement Register Pair HL by 1 to advance the command line pointer past the units digit.
4DC5
If the NO CARRY FLAG is set (the character was not a valid decimal digit), JUMP to 4DD6H to re-enable interrupts and report error 2FH (invalid value).
4DC7
ADD A,C 81
ADD Register C (tens_digit × 10) to Register A (units_digit). Result: A = (tens_digit × 10) + units_digit, the complete 2-digit decimal value as a single binary byte (0-99).
4DC8
LD (DE),A 12
Store Register A (the parsed 2-digit value) to the memory location pointed to by Register Pair DE. This writes the value (e.g., hours, minutes, seconds, month, day, or year) to the destination buffer.
4DC9
DEC DE 1B
DECrement Register Pair DE by 1. The destination pointer moves to the next storage location (stored in descending address order). For date storage: the first byte goes to the highest address, working down.
4DCA
DECrement Register B (byte count) and JUMP to 4DD0H if B is not zero (more pairs to parse). If B reaches zero, all three pairs have been parsed and execution falls through.

[ALL THREE PAIRS PARSED] — All three 2-digit values have been successfully parsed and stored. Re-enable interrupts and jump to the SYS0 whitespace skip routine to validate the remainder of the command line.

4DCC
EI FB
Enable interrupts. The date/time values have been completely parsed and stored, so the clock interrupt can safely resume.
4DCD
JUMP to SYS0 routine at 4C7AH to skip whitespace and validate the end of the command line. This is a tail-call — execution continues in SYS0 which will return to the original caller.

[DELIMITER CHECK BETWEEN PAIRS] — After parsing one 2-digit number, the next character should be a delimiter (such as / for dates or : for times). The delimiter is compared against 00H — this comparison target is self-modified by the calling code to check for the appropriate delimiter.

4DD0
LD A,(HL) 7E
Fetch the next character from the command line buffer into Register A. This character should be the delimiter between digit pairs (e.g., / or :).
4DD1
CP 00H FE 00
Compare Register A against 00H. [SELF-MODIFYING CODE TARGET] — The operand byte at address 4DD2H is overwritten by the code at 4D42H with the expected delimiter character (e.g., 3AH for : or 2FH for /). At runtime, this instruction actually compares A against the appropriate delimiter. If A matches the delimiter, the Z FLAG is set.
4DD3
INC HL 23
INCrement Register Pair HL by 1 to advance the command line pointer past the delimiter character.
4DD4
If the Z FLAG is set (the delimiter matched the expected character), JUMP back to 4DB1H to parse the next 2-digit value pair. [LOOP END — loops back to parse next pair]

4DD6H - Numeric Parse Error Exit

This exit point is reached when the numeric parser encounters an invalid character (not a decimal digit or wrong delimiter). It re-enables interrupts and loads error code 2FH, then jumps to the common error handler at 4D65H.

4DD6
EI FB
Enable interrupts. Interrupts were disabled at 4DAEH during the parse operation and must be re-enabled before reporting the error.
4DD7
LD A,2FH 3E 2F
Load Register A with 2FH (47 decimal). Error code 2FH = "Invalid parameter value" in NEWDOS/80. The numeric string contained a non-digit character, an invalid delimiter, or a value out of range.
4DD9
Unconditional JUMP to 4D65H to report error 2FH via the SYS0 error handler at 4409H.

4DDBH - ATTRIB Command Entry Point

The ATTRIB command changes file attributes. Syntax: ATTRIB,filespec,options where options include INV, VIS, PROT=level, ACC=password, UPD=password, ASE=Y/N, ASC=Y/N, UDF=Y/N, and LRL=value. This entry point exchanges DE and HL (so DE now points to the command line and HL is freed), clears Register A, and calls the SYS0 file open routine (4723H) to locate the file specified on the command line. If the file is found, it proceeds to parse and apply the attribute options.

4DDB
EX DE,HL EB
Exchange Register Pairs DE and HL. The command line pointer (which was in HL) is now in DE. This sets up the parameter registers for the SYS0 file lookup routine which expects the filespec pointer in DE.
4DDC
XOR A AF
Set Register A to 00H (zero) and clear all flags. A=0 is passed to the file open routine as a mode parameter indicating read-only access for examining the file's attributes.
4DDD
GOSUB to SYS0 routine at 4723H to parse the filespec from the command line (pointed to by DE) and locate the file in the directory. On return: if the file is found, the Z FLAG is set and DE points to the file's directory entry (FPDE); if not found or error, the NZ FLAG is set and A contains an error code.
4DE0
RET NZ C0
If the NZ FLAG is set (file not found or error occurred in 4723H), RETURN to the caller with the error code in Register A. The error will be handled by SYS0/SYS1.
4DE1
XOR A AF
Set Register A to 00H (zero) again. This clears A before calling the file buffer open routine — A=0 specifies no special buffer mode.
4DE2
GOSUB to SYS0 routine at 48AFH to open the file's sector buffer and read the first directory sector containing the file's FPDE (File Primary Directory Entry). On return: if successful, Z FLAG is set and HL points to the sector buffer containing the directory data; if error, NZ FLAG is set with error code in A.
4DE5
RET NZ C0
If the NZ FLAG is set (error reading the directory sector), RETURN to the caller with the error code in Register A.

[COPY COMMAND LINE TO FIXED BUFFER] — The command line text (remaining parameters after the filespec) is copied from the parse buffer to a fixed working buffer at address xx E0H within the sector buffer page. Up to 32 bytes (20H) are copied. This allows the command line parameters to be parsed independently while the sector buffer is used for directory access.

4DE7
LD B,20H 06 20
Load Register B with 20H (32 decimal). This is the maximum number of bytes to copy from the command line into the working buffer — 32 characters is sufficient for the attribute option parameters.
4DE9
LD L,E0H 2E E0
Load Register L with E0H. This sets the low byte of the destination address to E0H. Combined with the current value of Register H (which points to the sector buffer page), this creates the destination address for the working copy of the command line parameters.

[LOOP START — Copy command line to working buffer]

4DEA
LD A,(DE) 1A
Fetch the next character from the source command line buffer (pointed to by Register Pair DE) into Register A.
4DEB
CP 0DH FE 0D
Compare Register A against 0DH (carriage return). Check if we have reached the end of the command line text.
4DED
LD (HL),A 77
Store Register A (the command line character, including the carriage return if this is the last character) to the destination working buffer (pointed to by Register Pair HL).
4DEE
INC DE 13
INCrement Register Pair DE by 1 to advance the source pointer to the next character.
4DEF
INC HL 23
INCrement Register Pair HL by 1 to advance the destination pointer to the next position in the working buffer.
4DF0
If the Z FLAG is set (the carriage return was just copied — end of command line reached), JUMP to 4DF7H to proceed with the attribute processing. The entire command line has been successfully copied to the working buffer.
4DF2
DECrement Register B (byte counter) and JUMP back to 4DEAH if B is not zero (more characters to copy). [LOOP END]
4DF4
If B reached zero without finding a carriage return (command line exceeded 32 characters), JUMP to 4DD7H to report error 2FH (invalid parameter — command line too long for this command).
4DF7
JUMP to SYS0 routine at 48C4H to begin processing the ATTRIB command's attribute options from the working buffer. This SYS0 routine handles the option parsing loop, calling back into SYS7's option-specific handlers as each option keyword is matched. This is a tail-call — the ATTRIB processing continues via the option dispatch mechanism.

4DFAH - PROT Command Entry Point

The PROT command alters diskette control information. Syntax: PROT,password:drive[,options] where options include NAME=name, DATE=date, RUF, PW=password, LOCK, and UNLOCK. This entry point pops the return address and command context from the stack, calls the filespec/drive parser at 4F72H, then sets up for option processing using the PROT option keyword table at 50C7H. On entry, the stack contains the return address and parameters pushed by SYS1.

4DFA
POP AF F1
Restore Register Pair AF from the stack. This pops the flags and accumulator value that were saved by the SYS1 dispatcher before calling into SYS7. The specific value is not used — this is a stack cleanup operation.
4DFB
POP HL E1
Restore Register Pair HL from the stack. This retrieves the command line pointer that was saved by SYS1. HL now points to the command line text following the "PROT" keyword.
4DFC
GOSUB to 4F72H to parse the password and drive number from the command line. This routine expects HL to point to the password:drive portion of the command. On return: DE contains the drive/password context data, and HL has been advanced past the parsed portion.
4DFF
PUSH DE D5
Save Register Pair DE onto the stack. DE contains the drive/password context returned by 4F72H. This is preserved while the rest of the command line is parsed.
4E00
POP IX DD E1
Pop the top of stack into Index Register IX. This is a register transfer technique — the value that was just pushed as DE is now in IX. IX will be used as a base pointer for accessing the drive/password context throughout the PROT option processing.
4E02
INC DE 13
INCrement Register Pair DE by 1 to point to the second byte of the drive context data structure.
4E03
LD A,(DE) 1A
Fetch the byte at the address pointed to by Register Pair DE (the second byte of the drive context) into Register A. This byte contains status flags about the drive and password.
4E04
AND 07H E6 07
Mask Register A with 07H (binary 00000111), keeping only the lower 3 bits. These bits represent the drive access level or type code from the drive context.
4E06
LD A,19H 3E 19
Load Register A with 19H (25 decimal). Error code 19H = "Access denied" or "Invalid drive" in NEWDOS/80. This error will be reported if the drive access check fails.
4E08
RET NZ C0
If the NZ FLAG is set (the lower 3 bits of the drive context byte were not zero — indicating a restricted access level), RETURN to the caller with error code 19H in Register A. PROT requires full access to the diskette.
4E09
PUSH HL E5
Save Register Pair HL (command line pointer, now positioned after the password:drive portion) onto the stack. This preserves the position for the option parsing loop.
4E0A
GOSUB to SYS0 routine at 48F0H to read the diskette's control sector (GAT — Granule Allocation Table) into the sector buffer. This sector contains the diskette name, date, password, and other control information that PROT modifies. On return: Z FLAG set if successful, NZ if error.
4E0D
If the NZ FLAG is set (error reading the control sector), JUMP to 4D65H to report the error via the common error handler. Register A contains the error code from 48F0H.
4E10
EX (SP),HL E3
Exchange the top of the stack with Register Pair HL. The command line pointer (which was on the stack from the PUSH at 4E09H) is now in HL, and HL's previous value (the sector buffer pointer from 48F0H) is now on the stack for later use.
4E11
LD BC,5054H 01 54 50
Load Register Pair BC with 5054H, the address of the ATTRIB command's option keyword table. This table contains the option names (INV, VIS, PROT=, ACC=, UPD=, ASE=, ASC=, UDF=, LRL=) and their associated handler addresses.

Wait — examining the code flow more carefully: the instruction at 4E11H loads BC=5054H (the ATTRIB option table), but execution reached here from the PROT entry point at 4DFAH. Looking at 4E14H, the code jumps to 4F78H which uses BC as the option table pointer. This address (4E11H) is also a jump target from 4E65H within the ATTRIB option processing loop. The flow at 4E11H serves both ATTRIB and PROT — after processing one PROT option via the handlers, if the command line has another option (comma followed by more text), execution returns here to process the next option using the same keyword table mechanism. For PROT, the table at 50C7H is loaded separately in the PROT-specific path at 4ED2H.

4E11
LD BC,5054H 01 54 50
Load Register Pair BC with 5054H, the address of the ATTRIB option keyword table. This table contains null-terminated option keyword strings followed by 2-byte handler addresses. The keyword matching routine at 4F78H will walk this table to find a match for the next option on the command line.
4E14
JUMP to 4F78H to begin the option keyword matching process. The routine at 4F78H will compare the command line text against the keyword table entries, and when a match is found, it will jump to the corresponding handler address extracted from the table.

4E17H - ATTRIB LRL= Option Handler (Logical Record Length)

This handler is invoked when the ATTRIB command's option parser matches the "LRL=" keyword. It parses the logical record length value from the command line and stores it in the file's directory entry. The LRL value must be 00H-FFH (0-255 decimal). On entry, HL points to the command line text following "LRL=", and the stack contains the sector buffer pointer for the directory entry.

4E17
GOSUB to 4FA5H to parse a numeric value from the command line. On return, Register Pair DE contains the parsed 16-bit value (the logical record length), and HL has been advanced past the parsed digits.
4E1A
DEC DE 1B
DECrement Register Pair DE by 1. This adjusts the parsed LRL value. The decrement converts the user-specified value (1-256) to the internal representation (0-255), where 0 represents 256 bytes per record.
4E1B
LD A,D 7A
Copy Register D (high byte of the adjusted LRL value) into Register A. If the LRL value was valid (1-256, now 0-255 after decrement), D should be 00H.
4E1C
OR A B7
Perform OR A to test if Register A (the high byte) is zero. If D=0, the Z FLAG is set (valid single-byte LRL). If D is non-zero, the NZ FLAG is set (LRL value exceeds 256).
4E1D
If the NZ FLAG is set (high byte of LRL is non-zero — the value exceeds 256), JUMP to 4DD7H to report error 2FH (invalid parameter value).

[STORE LRL IN DIRECTORY ENTRY] — The parsed and validated LRL value (in Register E, 00H-FFH) is stored into the file's directory entry. The directory entry pointer is retrieved from the stack, advanced to offset +4 (the LRL field position), and the value is written.

4E1F
EX (SP),HL E3
Exchange the top of the stack with Register Pair HL. HL now contains the directory entry base pointer (from the stack), and the command line pointer is saved on the stack.
4E20
PUSH HL E5
Save Register Pair HL (directory entry pointer) onto the stack. A copy is kept on the stack because the pointer will be modified to reach the LRL offset.
4E21
INC HL 23
INCrement Register Pair HL by 1 (directory entry offset +1).
4E22
INC HL 23
INCrement Register Pair HL by 1 (directory entry offset +2).
4E23
INC HL 23
INCrement Register Pair HL by 1 (directory entry offset +3).
4E24
INC HL 23
INCrement Register Pair HL by 1 (directory entry offset +4). HL now points to the Logical Record Length field of the file's FPDE (File Primary Directory Entry). This is the 5th byte of the directory entry.
4E25
INC E 1C
INCrement Register E by 1. This converts the internal representation back: the stored LRL byte uses 0=256 convention, so if the user specified LRL=256, E was decremented to FFH at 4E1AH and now incremented back to 00H (wraps around), which represents 256. For other values, E is incremented to store the actual byte count.
4E26
LD (HL),E 73
Store Register E (the LRL value) to the directory entry at offset +4, the Logical Record Length field. The file's record size attribute is now updated.
4E27
POP HL E1
Restore Register Pair HL from the stack. This retrieves the directory entry base pointer that was saved at 4E20H.
4E28
Unconditional JUMP to 4E51H to restore the command line pointer from the stack and continue with the next option in the ATTRIB option processing loop.

4E2AH - ATTRIB ASE=, ASC=, UDF= Y/N Option Handlers

These entry points handle the ATTRIB options that accept a Y/N (Yes/No) boolean value and modify specific bit flags in the file's directory entry. Each entry point loads Register C with the bit mask for the flag to modify and Register Pair DE with the values for the Y and N states, then falls into common code that reads the Y/N character and applies the change.

4E2AH: ASE= — bit 5 (mask 20H), Y=FF00H, N=00FFH. This parameter has been added to allow DOS to automatically allocate diskette space to a file if ASE=Y or to disallow further allocation if ASE=N. ASE=Y is the default condition when a file is created.
4E31H: UDF= — bit 7 (mask 80H), same DE pattern. This parameter has been added to mark the file as updated if UDF=Y is specified or to clear the updated mark if UDF=N is specified. The DOS system marks a file as updated whenever it is about to update a sector to that file and it finds the file's directory entry not marked as updated.
4E35H: ASC= — bit 6 (mask 40H), same DE pattern. This parameter has been added to allow DOS to automatically deallocate file diskette space beyond the EOF during a CLOSE operation if ASC=Y is specified, and to disallow this deallocation if ASC=N. ASC=Y is the default setting when a file is created

4E2A
LD C,20H 0E 20
Load Register C with 20H (bit 5 mask). This is the bit mask for the ASE (Auto Space Extend) flag in the file's directory entry byte. Bit 5 controls whether the DOS automatically allocates additional disk space when the file needs to grow.
4E2C
LD DE,FF00H 11 00 FF
Load Register Pair DE with FF00H. Register D = FFH (the value to use when the answer is "N" — all bits set, meaning the flag value for "No"), Register E = 00H (the value to use when the answer is "Y" — all bits clear). This encoding is used by the Y/N comparison logic below.
4E2F
Unconditional JUMP to 4E3AH to read the Y/N character from the command line and apply the bit change.
4E31
LD C,80H 0E 80
Load Register C with 80H (bit 7 mask). This is the bit mask for the UDF (User Defined Flag) in the file's directory entry byte.
4E33
Unconditional JUMP to 4E37H to load DE with the standard 00FFH pattern and then read the Y/N value.
4E35
LD C,40H 0E 40
Load Register C with 40H (bit 6 mask). This is the bit mask for the ASC (Auto Space Compress) flag in the file's directory entry byte. Bit 6 controls whether the DOS automatically deallocates excess disk space when the file shrinks.
4E37
LD DE,00FFH 11 FF 00
Load Register Pair DE with 00FFH. Register D = 00H, Register E = FFH. This sets up the Y/N encoding: when the user answers "Y", the flag bit will be SET; when "N", the flag bit will be CLEARED. (The sense is opposite from the ASE= handler at 4E2AH.)

4E3AH - Common Y/N Parser and Bit Modifier

This common routine reads a single character (Y or N) from the command line and modifies a specific bit in the file's directory entry accordingly. On entry: HL points to the Y/N character in the command line, C contains the bit mask, D contains the value for "N" response, E contains the value for "Y" response. The directory entry pointer is on the stack.

4E3A
LD A,(HL) 7E
Fetch the next character from the command line buffer (pointed to by HL) into Register A. This should be Y (59H) or N (4EH).
4E3B
CP 59H FE 59
Compare Register A against 59H (ASCII Y). If the user typed "Y" (yes), the Z FLAG is set.
4E3D
INC HL 23
INCrement Register Pair HL by 1 to advance the command line pointer past the Y/N character.
4E3E
If the Z FLAG is set (user typed Y), JUMP to 4E45H to apply the "Yes" setting. Register D retains the "Y" value (from DE setup), and the bit in C will be set in the directory entry.
4E40
LD D,E 53
Copy Register E into Register D. Since the answer was not "Y", this loads the "N" value into D. (The "N" value was originally in E as set up by the calling handler.)
4E41
CP 4EH FE 4E
Compare Register A against 4EH (ASCII N). If the user typed "N" (no), the Z FLAG is set. If neither Y nor N was typed, the NZ FLAG is set.
4E43
If the NZ FLAG is set (the character was neither Y nor N), JUMP to 4DD7H to report error 2FH (invalid parameter value).

[APPLY BIT CHANGE TO DIRECTORY ENTRY] — The bit specified by the mask in Register C is either set or cleared in the file's directory entry. The logic uses AND/OR masking: first clear the target bit, then OR in the new value.

4E45
EX (SP),HL E3
Exchange the top of the stack with Register Pair HL. HL now contains the directory entry pointer (from the stack), and the command line pointer is saved on the stack.
4E46
INC HL 23
INCrement Register Pair HL by 1 to point to the second byte of the directory entry (offset +1), which contains the flag bits being modified.
4E47
LD A,C 79
Copy Register C (the bit mask, e.g., 20H/40H/80H) into Register A.
4E48
AND D A2
AND Register D (the desired bit value) with Register A (the bit mask). If the bit should be set, D has the mask bits set and this produces the mask value. If the bit should be cleared, D is 00H and this produces 00H. Result in A = the new bit value to be applied.
4E49
LD B,A 47
Copy Register A (the new bit value) into Register B. This saves the value to be ORed into the directory entry byte.
4E4A
LD A,FFH 3E FF
Load Register A with FFH (all bits set).
4E4C
XOR C A9
XOR Register C (the bit mask) with Register A (FFH). This inverts the mask — all bits except the target bit are now set. Result: A = NOT(mask), which will be used to clear only the target bit.
4E4D
AND (HL) A6
AND Register A (the inverted mask) with the byte at the directory entry (pointed to by HL). This clears the target bit while preserving all other bits in the directory entry byte.
4E4E
OR B B0
OR Register B (the new bit value) with Register A. This sets the target bit to its new value (either 0 or 1 depending on Y/N). All other bits remain unchanged from the original directory entry byte.
4E4F
LD (HL),A 77
Store Register A (the modified directory entry byte with the updated flag bit) back to the directory entry at offset +1.
4E50
DEC HL 2B
DECrement Register Pair HL by 1 to point back to the base of the directory entry (offset +0). This restores HL to the entry's starting address.

4E51H - ATTRIB Option Loop Continue

This is the re-entry point for the ATTRIB option processing loop. After each option handler completes, execution arrives here to restore the command line pointer, check for more options, and either continue processing or finalize the changes.

4E51
EX (SP),HL E3
Exchange the top of the stack with Register Pair HL. This restores the command line pointer to HL (retrieving it from the stack) and saves the directory entry pointer back onto the stack.
4E52
Unconditional JUMP to 4E62H to call the "check for more options" routine at 4D5BH and continue the ATTRIB option loop.

4E54H - ATTRIB UPD= Flag Handler (Update/Access Password or Flag)

This handler processes the UPD= option. It can handle either a boolean flag (UPD=Y/N to set/clear the file's "updated" flag) or a password value (UPD=password to set the update password). The code modifies bit 3 of the directory entry's first byte to set or clear the "updated" flag.

4E54
LD C,08H 0E 08
Load Register C with 08H (bit 3 mask). This is the bit mask for the "Updated" flag in the file's directory entry. Bit 3 of the FPDE first byte indicates whether the file has been modified since the last backup or status reset.
4E56
Unconditional JUMP to 4E5AH to set up the clear mask and apply the bit change.
4E58
LD C,00H 0E 00
Load Register C with 00H. A mask of 00H means no bit will be set — this effectively clears the target bit when combined with the AND/OR logic. This entry point handles the case where the flag is being turned off.
4E5A
LD B,F7H 06 F7
Load Register B with F7H (binary 11110111). This is the AND mask that clears bit 3 while preserving all other bits. F7H = NOT(08H).
4E5C
POP DE D1
Restore Register Pair DE from the stack. DE contains the directory entry pointer. This pops the directory entry address that was saved earlier in the option processing flow.
4E5D
LD A,(DE) 1A
Fetch the first byte of the directory entry (FPDE byte 0, containing file status flags) from the address pointed to by Register Pair DE into Register A.
4E5E
AND B A0
AND Register A with Register B (F7H). This clears bit 3 (the "Updated" flag) while preserving all other bits.
4E5F
OR C B1
OR Register A with Register C (either 08H to set the flag, or 00H to leave it cleared). This applies the new flag value.
4E60
LD (DE),A 12
Store Register A (the modified FPDE byte 0 with the updated "Updated" flag) back to the directory entry at the address pointed to by DE.
4E61
PUSH DE D5
Save Register Pair DE (directory entry pointer) back onto the stack for the next option handler to use.

4E62H - ATTRIB Option Loop: Check for More Options

This routine checks whether there are more options on the command line. It calls the "skip spaces and check for more parameters" routine at 4D5BH. If more options exist, it loops back to 4E11H to match the next keyword. If the command line is exhausted, it falls through to write the modified directory entry back to disk.

4E62
GOSUB to 4D5BH to skip whitespace in the command line and check for a comma delimiter indicating another option follows. On return: NZ FLAG = comma found (more options), Z FLAG = end of command line or no comma.
4E65
If the NZ FLAG is set (another option follows on the command line), JUMP back to 4E11H to load BC with the option keyword table address and process the next option. [OPTION LOOP — continues until all options processed]

[ALL OPTIONS PROCESSED] — The command line has been fully processed. Write the modified directory entry back to the diskette and return.

4E67
POP AF F1
Restore Register Pair AF from the stack. This discards the directory entry pointer that was maintained on the stack throughout the option processing loop — it is no longer needed since the SYS0 write routine will use its own internal pointers.
4E68
Unconditional JUMP to 4DF7H which jumps to the SYS0 sector write routine at 48C4H. This writes the modified directory sector (containing the updated file attributes) back to the diskette and returns to the DOS READY prompt.

4E6AH - ATTRIB PROT= Option Handler (Protection Level)

This handler is invoked when the ATTRIB command's option parser matches the "PROT=" keyword. It uses the protection level keyword table at 5093H to match the user's text (LOCK, EXEC, READ, WRITE, RENAME/NAME, KILL, FULL) against the known protection level names. Each keyword in that table is followed by a single byte containing the numeric access level (0-7). The matched level byte is then used to modify the file's directory entry. On entry, HL points to the command line text following "PROT=", and the stack contains the directory entry pointer.

4E6A
LD BC,5093H 01 93 50
Load Register Pair BC with 5093H, the address of the PROT= protection level keyword table. This table contains the keywords LOCK (7), EXEC (6), READ (5), WRITE (4), RENAME (2), NAME (2), KILL (1), and FULL (0), each followed by a 00H terminator and a single byte containing the numeric protection level.
4E6D
LD D,01H 16 01
Load Register D with 01H. This parameter tells the keyword matching routine at 4F84H that there is 1 byte of data following each keyword's null terminator (the access level byte). The routine will skip past the keyword text and return BC pointing to this data byte.
4E6F
GOSUB to 4F84H to search the keyword table at BC for a match against the command line text at HL. The routine compares each keyword in the table against the command line and, when a match is found, advances BC past the null terminator to point at the data byte(s) following the matched keyword. If no match is found, it jumps to the error handler at 4D63H.
4E72
LD A,(BC) 0A
Fetch the byte at the address pointed to by Register Pair BC into Register A. After the keyword match at 4F84H, BC points to the access level byte that follows the matched keyword. This byte is 00H (FULL), 01H (KILL), 02H (RENAME/NAME), 04H (WRITE), 05H (READ), 06H (EXEC), or 07H (LOCK).
4E73
LD C,A 4F
Copy Register A (the numeric protection level, 0-7) into Register C. This prepares it for the bit manipulation that will store it in the directory entry. The protection level occupies the lower 3 bits of a byte in the FPDE.
4E74
LD B,F8H 06 F8
Load Register B with F8H (binary 11111000). This is the AND mask that preserves bits 7-3 while clearing bits 2-0 (the 3-bit protection level field). F8H = NOT(07H).
4E76
Unconditional JUMP to 4E5CH to apply the bit change. The code at 4E5CH pops the directory entry pointer from the stack, fetches the current byte, ANDs with B (F8H to clear the protection bits), ORs with C (the new protection level), stores the result, and continues the option loop.

4E78H - ATTRIB ACC= and UPD= Password Option Handlers

These handlers process the ACC= (access password) and UPD= (update password) options for the ATTRIB command. They parse a password string from the command line, encode it using the NEWDOS/80 password encoding algorithm (at 5005H), and store the resulting 2-byte encoded password into the appropriate offset within the file's directory entry. ACC= stores at offset +12H/+13H, UPD= stores at offset +10H/+11H.

4E78
LD A,12H 3E 12
Load Register A with 12H (18 decimal). This is the offset within the FPDE (File Primary Directory Entry) where the access password (ACC) is stored. The access password occupies bytes 12H-13H of the 32-byte directory entry.
4E7A
Unconditional JUMP to 4E7EH to proceed with the common password encoding and storage logic.
4E7C
LD A,10H 3E 10
Load Register A with 10H (16 decimal). This is the offset within the FPDE where the update password (UPD) is stored. The update password occupies bytes 10H-11H of the 32-byte directory entry.
4E7E
PUSH AF F5
Save Register Pair AF onto the stack. Register A contains the FPDE offset (12H for ACC or 10H for UPD). This value is preserved for use after the password encoding.
4E7F
GOSUB to 5005H to parse the password text from the command line (pointed to by HL) and encode it using the NEWDOS/80 password encoding algorithm. On return: Register Pair DE contains the 2-byte encoded password, HL has been advanced past the password text, and Register Pair BC in the called routine's context has been set up internally.
4E82
PUSH HL E5
Save Register Pair HL (the updated command line pointer, now past the password text) onto the stack. This preserves the parse position while the password is stored in the directory entry.
4E83
POP BC C1
Pop the top of the stack into Register Pair BC. This is a register transfer — the value just pushed (the command line pointer) is now in BC. (This appears to be a stack manipulation error correction or intentional transfer to free HL.)

Re-examining the stack state: At 4E82H, HL (command line pointer) was pushed. At 4E83H, it is immediately popped into BC. This effectively moves the command line pointer from HL to BC, freeing HL for use as the directory entry pointer. The stack now has: [FPDE offset in AF from 4E7EH] and [directory entry pointer from the ATTRIB option loop].

4E84
POP AF F1
Restore Register Pair AF from the stack. Register A now contains the FPDE offset (12H for ACC or 10H for UPD) that was saved at 4E7EH.
4E85
POP HL E1
Restore Register Pair HL from the stack. HL now contains the directory entry base pointer that was maintained on the stack by the ATTRIB option loop.
4E86
PUSH HL E5
Save Register Pair HL (directory entry base pointer) back onto the stack immediately. The pointer is needed for subsequent option handlers, so it must remain on the stack.
4E87
ADD A,L 85
ADD Register L (low byte of directory entry base address) to Register A (FPDE offset 10H or 12H). Result in A = the low byte of the address of the password field within the directory entry.
4E88
LD L,A 6F
Load Register L with Register A. HL now points to the password field within the directory entry (base + offset 10H or 12H).
4E89
LD (HL),E 73
Store Register E (low byte of the encoded password) to the first byte of the password field in the directory entry.
4E8A
INC HL 23
INCrement Register Pair HL by 1 to point to the second byte of the password field.
4E8B
LD (HL),D 72
Store Register D (high byte of the encoded password) to the second byte of the password field in the directory entry. The 2-byte encoded password is now stored.
4E8C
LD H,B 60
Copy Register B (high byte of BC, which holds the saved command line pointer from the earlier transfer) into Register H.
4E8D
LD L,C 69
Copy Register C (low byte of BC, the saved command line pointer) into Register L. HL now points back to the command line text at the position after the parsed password.
4E8E
Unconditional JUMP to 4E62H to check for more ATTRIB options on the command line and continue the option processing loop.

4E90H - Parse Drive Number from Command Line

This routine parses a drive number specification from the command line. It first calls 5005H to parse a filespec/name, then checks if the text contains a colon-separated drive number (e.g., ":0"). If a valid drive number (0-7) is found followed by a colon, it is accepted. If no drive number is present, the routine falls back to reading the default system drive number from 4296H. On entry: HL points to the command line text. On return: the drive number context is set up for the calling command.

4E90
GOSUB to 5005H to parse a filespec or name token from the command line. This routine reads characters until it encounters a delimiter (space, comma, carriage return, colon, etc.) and processes the password encoding if applicable. On return: HL points to the delimiter character, DE contains context data.
4E93
LD A,(HL) 7E
Fetch the delimiter character at the current command line position into Register A.
4E94
CP 3AH FE 3A
Compare Register A against 3AH (ASCII : — colon). A colon after a name indicates a drive number follows (e.g., "filename:0"). If A equals 3AH, the Z FLAG is set.
4E96
INC HL 23
INCrement Register Pair HL by 1 to advance past the delimiter character.
4E97
If the Z FLAG is set (a colon was found — drive number follows), JUMP to 4EA3H to parse the drive number digit.

[NO COLON FOUND] — The command line did not contain a colon, so there is no explicit drive number. Check if the text represents a valid drive number by looking up the default drive from the system variable at 4296H.

4E99
PUSH HL E5
Save Register Pair HL (command line pointer) onto the stack.
4E9A
LD HL,4296H 21 96 42
Point Register Pair HL to 4296H, the SYS0 system variable that contains the current default drive number or the drive specification context from the most recent operation.
4E9D
RST 18H DF
Execute RST 18H — a NEWDOS/80 system call that performs a comparison or table lookup operation. This compares the parsed text against the drive specification data at 4296H to determine if it represents a valid drive reference.
4E9E
POP HL E1
Restore Register Pair HL (command line pointer) from the stack.
4E9F
DEC HL 2B
DECrement Register Pair HL by 1 to back up the command line pointer. Since no colon was found, the increment at 4E96H must be undone so HL points to the correct position for subsequent parsing.
4EA0
If the NZ FLAG is set (the RST 18H comparison failed — the text does not match a valid drive specification), JUMP to 4DD7H to report error 2FH (invalid parameter value).

4EA3H - Parse and Validate Drive Number Digit

This routine parses a single-digit drive number (0-7) from the command line and validates it by calling the SYS0 drive validation routine. On entry: HL points to the drive number digit, DE contains context from the filespec parser. On return: the drive is validated and its parameters are loaded.

4EA3
PUSH DE D5
Save Register Pair DE onto the stack. DE contains the password/filespec context from the preceding parse operation. This is preserved while the drive number is processed.
4EA4
GOSUB to 4FA5H to parse a numeric value from the command line. On return: Register Pair DE contains the parsed drive number as a 16-bit value, and HL has been advanced past the digit(s).
4EA7
LD A,D 7A
Copy Register D (high byte of the parsed value) into Register A.
4EA8
OR A B7
Perform OR A to test if Register D is zero. A valid drive number (0-7) will have D=00H. If D is non-zero, the drive number exceeds 255 and is invalid.
4EA9
If the NZ FLAG is set (high byte of drive number is non-zero — value exceeds 255), JUMP to 4D57H to report error 20H (attribute/specification error).
4EAC
LD A,E 7B
Copy Register E (the low byte — the actual drive number, 0-7) into Register A.
4EAD
POP DE D1
Restore Register Pair DE from the stack. DE now contains the password/filespec context that was saved at 4EA3H.
4EAE
GOSUB to SYS0 routine at 4791H to validate and initialize the specified drive. Register A contains the drive number. This routine checks that the drive exists, is ready, and loads the drive parameter block. On return: Z FLAG set if the drive is valid and ready, NZ FLAG if error with error code in A.
4EB1
If the NZ FLAG is set (drive validation failed), JUMP to 4EC9H to report the error. Register A contains the error code from 4791H.
4EB3
PUSH HL E5
Save Register Pair HL (command line pointer) onto the stack.
4EB4
XOR A AF
Set Register A to 00H (zero). This parameter indicates no special buffer mode when opening the drive's directory.
4EB5
GOSUB to SYS0 routine at 48AFH to open the drive's sector buffer and read the GAT (Granule Allocation Table) / control sector. On return: Z FLAG set if successful, NZ if error; HL and DE point to buffer and control data.
4EB8
If the NZ FLAG is set (error reading the control sector), JUMP to 4EC9H to report the error.

[VERIFY DRIVE PASSWORD] — Compare the diskette's stored password (from the control sector) against the password provided by the user on the command line. The encoded password from the control sector at offset in the buffer is compared against the encoded password in DE from the filespec parser.

4EBA
LD HL,(43CEH) 2A CE 43
Load Register Pair HL with the 16-bit value stored at 43CEH. This SYS0 system variable contains the encoded diskette password that was read from the control sector of the currently-opened drive.
4EBD
OR A B7
Perform OR A to clear the Carry flag, preparing for the 16-bit subtraction comparison.
4EBE
SBC HL,DE ED 52
Subtract Register Pair DE (the user-supplied encoded password from the command line) from Register Pair HL (the diskette's stored encoded password). If they match, the result is zero and the Z FLAG is set.
4EC0
POP HL E1
Restore Register Pair HL (command line pointer) from the stack.
4EC1
RET Z C8
If the Z FLAG is set (passwords match — the user provided the correct diskette password), RETURN to the caller with success. The drive is validated and the command can proceed.

[PASSWORD MISMATCH — CHECK SYSTEM OPTION] — The passwords did not match. Before reporting an error, check the system option flag at 428CH that controls whether password checking is enforced. If bit 7 of this flag is clear, password checking is bypassed (AR system option = N).

4EC2
LD A,(428CH) 3A 8C 42
Fetch the byte at 428CH into Register A. This SYS0 system variable contains system option flags. Bit 7 corresponds to the SYSTEM option AR (whether password checking is required for certain operations).
4EC5
RLCA 07
Rotate Register A left by 1 bit position. Bit 7 moves into the Carry flag. If bit 7 was set (AR=Y, password checking enforced), the CARRY FLAG is set. If bit 7 was clear (AR=N, password checking not enforced), the NO CARRY FLAG is set.
4EC6
RET NC D0
If the NO CARRY FLAG is set (system option AR=N — password checking is not enforced), RETURN to the caller with success even though the password did not match. The operation is allowed to proceed without the correct password.
4EC7
LD A,37H 3E 37
Load Register A with 37H (55 decimal). Error code 37H = "Incorrect password" in NEWDOS/80. The user's password did not match and password checking is enforced.
4EC9
JUMP to 4D65H to report the error via the common error handler. Register A contains the error code (37H for password mismatch, or whatever error code was passed from a previous validation failure).

4ECCH - DUMP Command Entry Point

The DUMP command writes memory contents to a disk file. Syntax: DUMP,filespec,startaddr,endaddr[,entryaddr[,reladdr]]. This entry point begins by parsing the drive number (via 4E90H), then the filespec (via 4F72H), and sets up the DUMP option keyword table at 50C7H for additional parameters. The DUMP command shares the same option processing mechanism as ATTRIB and PROT, using the keyword table dispatch at 4F78H.

4ECC
GOSUB to 4E90H to parse the drive number from the command line. On return: the drive has been validated and HL points past the drive specification.
4ECF
GOSUB to 4F72H to parse the filespec from the command line. This reads the filename and optional password. On return: the file context is set up, and HL points past the filespec.
4ED2
LD BC,50C7H 01 C7 50
Load Register Pair BC with 50C7H, the address of the PROT command's option keyword table. This table contains the keywords PW=, UNLOCK, LOCK, NAME=, DATE=, and RUF with their associated handler addresses. The DUMP command reuses this table for its own option processing.
4ED5
JUMP to 4F78H to begin keyword matching against the option table. The routine will match the next command line token against the keywords in the table and dispatch to the corresponding handler. This is a tail-call — execution continues within the option dispatch loop.

4ED8H - PROT NAME= and DATE= Option Helpers: Copy Name/Date to Directory

These entry points handle filename or date string copying into directory entry fields. 4ED8H copies a diskette name (8 characters) to the name field at 43D8H, and 4EDDH copies a date string (8 characters) to the date field at 43D0H. Both fall into the common 8-byte copy loop at 4EE0H. These addresses are referenced by the PROT option table (NAME= and DATE= entries).

4ED8
LD DE,43D8H 11 D8 43
Point Register Pair DE to 43D8H, the SYS0 system variable location where the diskette name is stored. This 8-byte field holds the name that appears in DIR listings and is set during FORMAT or changed by PROT,NAME=.
4EDB
Unconditional JUMP to 4EE0H to copy up to 8 characters from the command line to the destination buffer.
4EDD
LD DE,43D0H 11 D0 43
Point Register Pair DE to 43D0H, the SYS0 system variable location where the diskette date is stored. This 8-byte field holds the date string (mm/dd/yy format) associated with the diskette.

4EE0H - Copy Up to 8 Characters from Command Line to Buffer

This utility routine copies up to 8 characters from the command line (pointed to by HL) into a destination buffer (pointed to by DE). Characters are copied until a delimiter is found (via the SYS0 space-skip at 4C7AH) or the 8-character limit is reached. If fewer than 8 characters are provided, the remaining positions are filled with spaces (20H). On entry: HL = command line pointer, DE = destination buffer, B = 08H (character count).

4EE0
LD B,08H 06 08
Load Register B with 08H (8 decimal). This is the maximum number of characters to copy — NEWDOS/80 diskette names and date strings are 8 characters long.

[LOOP START — Copy characters from command line to buffer]

4EE2
GOSUB to SYS0 routine at 4C7AH to check the current command line character. This routine determines if the character is a delimiter (space, comma, carriage return) or a valid data character. On return: Carry set = valid character to copy, NC = delimiter found, Z FLAG = end of parameters.
4EE5
If the NO CARRY FLAG is set (a delimiter was found — the name/date string has ended before 8 characters), JUMP to 4EEBH to pad the remaining positions with spaces.
4EE7
LD A,(HL) 7E
Fetch the current character from the command line buffer into Register A. This is a valid data character to be copied.
4EE8
INC HL 23
INCrement Register Pair HL by 1 to advance the command line pointer to the next character.
4EE9
Unconditional JUMP to 4EF0H to store the character and continue the loop.
4EEB
If the Z FLAG is set (end of command line — no more characters), JUMP to 4EEEH to load a space character for padding. This skips the DEC HL because the command line pointer should not be backed up when the line is fully consumed.
4EED
DEC HL 2B
DECrement Register Pair HL by 1. If the delimiter was a comma (not end of line), back up the pointer so the comma is available for the next parse operation.
4EEE
LD A,20H 3E 20
Load Register A with 20H (ASCII space). This is the padding character used to fill remaining positions in the name/date field.
4EF0
LD (DE),A 12
Store Register A (the data character or space pad) to the destination buffer at the address pointed to by Register Pair DE.
4EF1
INC DE 13
INCrement Register Pair DE by 1 to advance the destination buffer pointer.
4EF2
DECrement Register B (character counter) and JUMP back to 4EE2H if B is not zero (more characters to process). [LOOP END]
4EF4
Unconditional JUMP to 4F10H to continue with the option processing loop after the name/date has been stored.

4EF6H - PROT RUF, LOCK, and UNLOCK Flag Handlers

These handlers set flags for the PROT command's RUF (Reset Update Flag), LOCK, and UNLOCK options. Each loads a specific bit value into Register A and jumps to the common flag-set routine at 4F00H, which ORs the value into a flag byte at 4F1AH. This accumulated flag byte is later examined during the directory iteration at 4F19H to determine which operations to perform on each file. The flag byte at 4F1AH uses: bit 0 = UNLOCK, bit 1 = LOCK, bit 2 = RUF.

4EF6
LD A,04H 3E 04
Load Register A with 04H (bit 2). This is the flag bit for the RUF (Reset Update Flag) option. When set, the PROT command will clear the "updated" flag for all files on the diskette.
4EF8
Unconditional JUMP to 4F00H to OR this flag bit into the accumulated flag byte at 4F1AH.
4EFA
LD A,01H 3E 01
Load Register A with 01H (bit 0). This is the flag bit for the UNLOCK option. When set, the PROT command will remove access and update passwords from all user files on the diskette.
4EFC
Unconditional JUMP to 4F00H to OR this flag bit into the accumulated flag byte.
4EFE
LD A,02H 3E 02
Load Register A with 02H (bit 1). This is the flag bit for the LOCK option. When set, the PROT command will set the diskette password as both the access and update password for all user files on the diskette.

4F00H - Accumulate PROT Flag Bits

This routine ORs a flag bit (in Register A) into the accumulated PROT operation flags byte stored at 4F1AH. Multiple PROT options (RUF, LOCK, UNLOCK) can be combined, so their flags are ORed together. After storing, execution continues to check for more options.

4F00
PUSH HL E5
Save Register Pair HL (command line pointer) onto the stack.
4F01
LD HL,4F1AH 21 1A 4F
Point Register Pair HL to 4F1AH, the flag accumulator byte. [SELF-MODIFYING CODE TARGET] — The byte at 4F1AH is the operand of an instruction at 4F19H (LD A,00H). It is used as both a data storage location (the accumulated PROT flags) and as an instruction operand that will be loaded into A when the directory iteration begins.
4F04
OR (HL) B6
OR Register A (the new flag bit, e.g., 01H/02H/04H) with the current value at (HL) (the accumulated flags so far). This combines the new flag with any previously set flags.
4F05
LD (HL),A 77
Store the combined flag byte back to 4F1AH. [SELF-MODIFYING CODE] — This overwrites the operand of the LD A,00H instruction at 4F19H. When that instruction is later executed during the directory iteration, it will load the accumulated flags into Register A.
4F06
POP HL E1
Restore Register Pair HL (command line pointer) from the stack.
4F07
Unconditional JUMP to 4F10H to continue the option processing loop.

4F09H - PROT PW= Option Handler (Change Diskette Password)

This handler processes the PW= option for the PROT command, which changes the diskette's password. It parses the password string and encodes it, then stores the encoded password in the diskette control variable at 43CEH.

4F09
GOSUB to 5005H to parse the password text from the command line and encode it using the NEWDOS/80 password encoding algorithm. On return: Register Pair DE contains the 2-byte encoded password, HL points past the password text.
4F0C
LD (43CEH),DE ED 53 CE 43
Store Register Pair DE (the encoded password) to 43CEH, the SYS0 system variable that holds the diskette password for the currently-opened drive. This updates the password in the control sector buffer — it will be written to disk when the sector is flushed.

4F10H - PROT Option Loop: Check for More Options

This is the continuation point for the PROT option processing loop. It calls the parameter check routine at 4D5BH, and if more options exist, loops back to 4ED2H to match the next keyword from the PROT option table. When all options are exhausted, it writes the control sector back to disk and then processes the accumulated RUF/LOCK/UNLOCK flags by iterating through the directory.

4F10
GOSUB to 4D5BH to skip whitespace and check for a comma delimiter. On return: NZ FLAG if another option follows (comma found with more text), Z FLAG if end of command line.
4F13
If the NZ FLAG is set (more options on the command line), JUMP back to 4ED2H to load the PROT option keyword table (BC=50C7H) and process the next option. [OPTION LOOP — continues until all options processed]

[ALL PROT OPTIONS PARSED] — The command line is fully processed. Write the modified control sector (with any NAME=, DATE=, PW= changes) back to disk. Then check if RUF, LOCK, or UNLOCK options were specified, which require iterating through all directory entries.

4F15
GOSUB to SYS0 routine at 48C4H to write the modified control sector (GAT) back to the diskette. This saves any changes made by NAME=, DATE=, or PW= options. On return: Z FLAG if successful, NZ if write error.
4F18
RET NZ C0
If the NZ FLAG is set (error writing the control sector), RETURN to the caller with the error code in Register A.

4F19H - PROT Directory Entry Iteration (RUF/LOCK/UNLOCK Processing)

This routine iterates through all directory entries on the diskette and applies the accumulated PROT operations (RUF, LOCK, UNLOCK) to each qualifying user file. The flag byte at 4F1AH (self-modified during option parsing) controls which operations are performed. The routine reads each directory sector, examines each 32-byte FPDE, and modifies the file's protection level and passwords as needed. Register C tracks the current sector number, and Register L walks through the 32-byte entries within each sector.

4F19
LD A,00H 3E 00
Load Register A with 00H. [SELF-MODIFYING CODE] — The operand at address 4F1AH has been overwritten by the code at 4F05H with the accumulated PROT flags (bits: 0=UNLOCK, 1=LOCK, 2=RUF). At runtime, this instruction loads the actual flag byte, not 00H. If no RUF/LOCK/UNLOCK options were specified, the byte remains 00H.
4F1B
OR A B7
Perform OR A to test if Register A (the accumulated PROT flags) is zero. If no flags are set, there is nothing to iterate for.
4F1C
LD B,A 47
Copy Register A (the flag byte) into Register B. Register B will hold the flags throughout the directory iteration loop.
4F1D
RET Z C8
If the Z FLAG is set (no RUF/LOCK/UNLOCK flags — all bits zero), RETURN immediately. There are no per-file operations to perform.

[DIRECTORY ITERATION SETUP] — Load the diskette password (for LOCK operations) and initialize the sector counter. The encoded diskette password at 43CEH will be written to each file's password fields if LOCK is selected. If bit 0 of the flags (UNLOCK) is set, the password source is replaced with the system default at 4296H.

4F1E
LD DE,(43CEH) ED 5B CE 43
Load Register Pair DE with the 16-bit encoded diskette password from 43CEH. When LOCK is active, this password will be set as both the access and update password for each user file.
4F22
RRCA 0F
Rotate Register A right by 1 bit. Bit 0 (UNLOCK flag) moves into the Carry flag. If UNLOCK was specified, the CARRY FLAG is set.
4F23
If the NO CARRY FLAG is set (UNLOCK was NOT specified), JUMP to 4F28H to skip the password replacement. DE retains the diskette password for LOCK operations.
4F25
LD DE,4296H 11 96 42
Point Register Pair DE to 4296H, the system default encoded password (which is the null/blank password encoding). When UNLOCK is active, this blank password replaces the file passwords, effectively removing password protection from all files.
4F28
LD A,01H 3E 01
Load Register A with 01H. This value is passed to the SYS0 directory open routine as a mode parameter indicating read-write access to the directory sectors (the entries will be modified).
4F2A
GOSUB to SYS0 routine at 48AFH to open the directory for read-write access and read the first directory sector into the buffer. On return: Z FLAG if successful, HL points to the sector buffer.
4F2D
RET NZ C0
If the NZ FLAG is set (error opening/reading the directory), RETURN with the error code in Register A.
4F2E
LD A,(431FH) 3A 1F 43
Fetch the byte at 431FH into Register A. This SYS0 system variable contains the number of directory sectors (or the highest sector number in the directory area minus one). It determines how many sectors must be iterated.
4F31
ADD 08H C6 08
ADD 08H to Register A. This calculates the total number of directory entry slots to process. Each directory sector contains 8 entries (256 bytes / 32 bytes per entry = 8), so adding 8 to the sector count gives the stopping point for the iteration. The result is stored as the loop limit.
4F33
LD (4F6DH),A 32 6D 4F
Store Register A (the directory iteration limit) to 4F6DH. [SELF-MODIFYING CODE] — This overwrites the operand of a CP instruction at 4F6CH. During the iteration, the sector counter will be compared against this value to detect end of directory.
4F36
XOR A AF
Set Register A to 00H (zero). This initializes the starting point for the directory entry scan.
4F37
LD C,A 4F
Copy Register A (the current sector counter, starting at 0) into Register C. Register C tracks the sector number throughout the directory iteration.
4F38
GOSUB to SYS0 routine at 48DBH to read the next directory sector (sector number in C) into the buffer. On return: Z FLAG if successful, HL points to the start of the sector data in the buffer.
4F3B
RET NZ C0
If the NZ FLAG is set (error reading the directory sector), RETURN with the error code in Register A.

[INNER LOOP — Process each FPDE within the current sector] — Each directory sector contains up to 8 file entries (FPDEs), each 32 bytes long. The code examines the first byte of each entry to determine if it is a valid user file that should be modified.

4F3C
LD A,(HL) 7E
Fetch the first byte of the current FPDE (File Primary Directory Entry) from the sector buffer into Register A. This byte contains the file status/type flags. Bit 7 = file in use, bit 4 = system file, bit 6 = continuation entry, etc.
4F3D
AND 90H E6 90
Mask Register A with 90H (binary 10010000), keeping only bit 7 (file in use) and bit 4 (system file flag). This isolates the two bits needed to determine if this is a valid user file.
4F3F
CP 10H FE 10
Compare Register A against 10H (binary 00010000). A value of 10H means bit 4 is set (file exists/active) and bit 7 is clear (not a system file). This pattern identifies a user file entry. If the entry matches, the Z FLAG is set.
4F41
If the NZ FLAG is set (the entry is not a valid user file — it is empty, deleted, a system file, or a continuation entry), JUMP to 4F5EH to skip this entry and advance to the next one.

[VALID USER FILE FOUND] — This FPDE is a user file. Apply the accumulated PROT operations: check for RUF (bit 2 of B), LOCK (bit 1), and UNLOCK (bit 0).

4F43
BIT 2,B CB 50
Test bit 2 of Register B (the accumulated PROT flags). Bit 2 = RUF (Reset Update Flag). If bit 2 is set, the Z FLAG is cleared (NZ); if bit 2 is clear, the Z FLAG is set.
4F45
If the Z FLAG is set (RUF option was NOT specified), JUMP to 4F4BH to skip the RUF processing.
4F47
INC HL 23
INCrement Register Pair HL by 1 to point to the second byte (offset +1) of the FPDE, which contains additional file flags.
4F48
RES 5,(HL) CB AE
Reset (clear) bit 5 of the byte at (HL). Bit 5 of FPDE offset +1 is the "Updated" flag. Clearing this bit marks the file as "not updated" — the RUF (Reset Update Flag) operation.
4F4A
DEC HL 2B
DECrement Register Pair HL by 1 to point back to the base of the FPDE (offset +0).
4F4B
LD A,B 78
Copy Register B (the accumulated PROT flags) into Register A.
4F4C
AND 03H E6 03
Mask Register A with 03H, keeping only bits 0-1 (UNLOCK and LOCK flags). This tests whether either LOCK or UNLOCK was specified.
4F4E
If the Z FLAG is set (neither LOCK nor UNLOCK was specified), JUMP to 4F5EH to skip the password modification and advance to the next directory entry.

[APPLY LOCK/UNLOCK TO FILE] — Either LOCK or UNLOCK was specified. Check additional conditions on the file before modifying its passwords. Skip files that have certain flags set (bit 6 = already has special protection, bit 3 = system attribute).

4F50
LD A,(HL) 7E
Fetch the first byte of the FPDE (file status flags) into Register A again.
4F51
AND 48H E6 48
Mask Register A with 48H (binary 01001000), keeping bits 6 and 3. Bit 6 = special protection/invisible flag, bit 3 = a directory-specific flag. If either bit is set, this file should be skipped for LOCK/UNLOCK operations.
4F53
If the NZ FLAG is set (the file has special protection or the directory flag set), JUMP to 4F5EH to skip this file.

[WRITE PASSWORD TO FILE'S FPDE] — Store the password (from DE — either the diskette password for LOCK or the blank password for UNLOCK) into the file's access password and update password fields at offsets +10H through +13H of the FPDE.

4F55
SET 4,L CB E5
Set bit 4 of Register L. Since FPDEs are 32 bytes (20H) each and are aligned within the sector buffer, setting bit 4 of L adds 10H to the base address, pointing to the file's update password field at FPDE offset +10H.
4F57
LD (HL),E 73
Store Register E (low byte of the password) to the update password field (FPDE offset +10H).
4F58
INC HL 23
INCrement HL to offset +11H.
4F59
LD (HL),D 72
Store Register D (high byte of the password) to FPDE offset +11H. The 2-byte update password is now stored.
4F5A
INC HL 23
INCrement HL to offset +12H (access password low byte).
4F5B
LD (HL),E 73
Store Register E (low byte of the password) to the access password field (FPDE offset +12H).
4F5C
INC HL 23
INCrement HL to offset +13H.
4F5D
LD (HL),D 72
Store Register D (high byte of the password) to FPDE offset +13H. Both the access and update passwords now contain the same value (diskette password for LOCK, blank for UNLOCK).

4F5EH - Advance to Next Directory Entry

This routine advances the FPDE pointer to the next 32-byte directory entry within the current sector. If the end of the sector is reached (8 entries processed), it writes the modified sector back and reads the next directory sector. The iteration continues until all directory sectors have been processed.

4F5E
LD A,L 7D
Copy Register L (low byte of the current FPDE pointer) into Register A.
4F5F
AND E0H E6 E0
Mask Register A with E0H (binary 11100000). This strips the lower 5 bits, rounding down to the nearest 32-byte (20H) boundary. This ensures the pointer is aligned to the start of the current FPDE even if it was advanced to an internal offset during password writes.
4F61
ADD 20H C6 20
ADD 20H (32 decimal) to Register A. This advances to the next FPDE within the sector. Each FPDE is 32 bytes, so adding 20H moves to the start of the next entry. If this addition causes a carry (wraps past FFH), it means all 8 entries in this sector have been processed.
4F63
LD L,A 6F
Load Register L with the updated pointer. HL now points to the start of the next FPDE in the sector buffer.
4F64
If the NO CARRY FLAG is set (no wrap — more entries remain in this sector), JUMP back to 4F3CH to process the next FPDE. [INNER LOOP — continues through all 8 entries per sector]

[END OF SECTOR] — All 8 FPDEs in this sector have been processed. Write the modified sector back to disk and load the next directory sector.

4F66
GOSUB to SYS0 routine at 48C4H to write the current (modified) directory sector back to the diskette. On return: Z FLAG if successful.
4F69
RET NZ C0
If the NZ FLAG is set (write error), RETURN with the error code in Register A.
4F6A
INC C 0C
INCrement Register C (the directory sector counter) by 1 to move to the next sector.
4F6B
LD A,C 79
Copy Register C (the updated sector counter) into Register A for the comparison.
4F6C
CP 00H FE 00
Compare Register A against 00H. [SELF-MODIFYING CODE TARGET] — The operand at address 4F6DH was overwritten at 4F33H with the directory iteration limit (the total number of sectors to process). At runtime, this compares the sector counter against the actual limit. If the counter has reached the limit, the Z FLAG is set (and Carry is clear).
4F6E
If the CARRY FLAG is set (sector counter is less than the limit — more sectors to process), JUMP back to 4F37H to load the sector counter into C and read the next directory sector. [OUTER LOOP — continues through all directory sectors]
4F70
XOR A AF
Set Register A to 00H (zero) and set the Z FLAG. A=0 indicates success — all directory entries have been processed.
4F71
RET C9
RETURN to the caller with A=0 (success). The PROT command has completed all operations.

4F72H - Parse Password-Protected Filespec

This routine parses a password-protected filespec from the command line (format: password:drive or just :drive). It calls the SYS0 routine at 4C7EH to check for a colon delimiter. If no valid filespec is found, it jumps to the error handler. On entry: HL points to the command line text.

4F72
GOSUB to SYS0 routine at 4C7EH to parse the next token from the command line. This routine checks for a password or filespec, handling password encoding and delimiter detection. On return: Carry set if a valid token was found, NC if end of line or delimiter only.
4F75
RET NC D0
If the NO CARRY FLAG is set (no valid token found — end of command line or empty parameter), RETURN to the caller. The caller will handle the missing filespec.
4F76
Unconditional JUMP to 4F97H which jumps to the error handler at 4D63H to report error 34H (parse error). A valid token was found but it does not match the expected filespec format.

4F78H - Option Keyword Table Dispatch

This routine dispatches command processing based on a keyword table. It calls the keyword matching routine at 4F84H with D=02H (indicating 2 bytes of data follow each keyword — a 16-bit handler address). When a match is found, the 2-byte handler address is extracted from the table and used as a jump target via PUSH/RET. On entry: BC = address of keyword table, HL = command line pointer, D will be set to 02H.

4F78
LD D,02H 16 02
Load Register D with 02H. This tells the keyword matching routine at 4F84H that there are 2 data bytes following each keyword's null terminator in the table. These 2 bytes form a 16-bit address (low byte first) of the handler routine for that keyword.
4F7A
GOSUB to 4F84H to search the keyword table for a match against the command line text. On return: BC points to the first data byte after the matched keyword's null terminator.
4F7D
LD A,(BC) 0A
Fetch the low byte of the handler address from the keyword table (pointed to by BC) into Register A.
4F7E
LD E,A 5F
Copy Register A (low byte of handler address) into Register E.
4F7F
INC BC 03
INCrement Register Pair BC by 1 to point to the high byte of the handler address.
4F80
LD A,(BC) 0A
Fetch the high byte of the handler address from the keyword table into Register A.
4F81
LD D,A 57
Copy Register A (high byte of handler address) into Register D. Register Pair DE now contains the 16-bit handler address for the matched keyword.
4F82
PUSH DE D5
Push Register Pair DE (the handler address) onto the stack.
4F83
RET C9
RETURN — but since DE (the handler address) was just pushed onto the stack, this RET pops that address and jumps to it. This is a standard Z80 technique for computed jumps: PUSH address / RET = JP (address). Execution continues at the handler routine for the matched keyword.

4F84H - Keyword Table Search

This routine searches a null-terminated keyword table for a match against the current command line text. Each table entry consists of a keyword string followed by a 00H terminator and D bytes of associated data. The routine calls 4C6AH to compare the command line against each keyword. If no match is found, the table is exhausted (00H sentinel) and the routine jumps to error at 4D63H. On entry: BC = table pointer, D = number of data bytes per entry, HL = command line pointer. On return: BC points to the data bytes following the matched keyword, HL advanced past the matched text.

4F84
GOSUB to SYS0 routine at 4C6AH to compare the command line text (at HL) against the keyword string (at BC). This routine performs a case-insensitive string comparison. On return: Z FLAG if the keyword matches, NZ if no match. HL is advanced past the matched text if successful.
4F87
RET Z C8
If the Z FLAG is set (keyword matched), RETURN to the caller. BC now points to the data bytes following the matched keyword's null terminator, and HL has been advanced past the matched text in the command line.

[NO MATCH — Skip to next keyword in table] — The current keyword did not match. Advance BC past the current keyword's text (to the null terminator), then past the null byte and the D data bytes, to reach the start of the next keyword.

4F88
LD A,(BC) 0A
Fetch the current byte from the keyword table (pointed to by BC) into Register A.
4F89
CP 00H FE 00
Compare Register A against 00H (null terminator). Check if we have reached the end of the current keyword string.
4F8B
INC BC 03
INCrement Register Pair BC by 1 to advance to the next byte in the table.
4F8C
If the NZ FLAG is set (current byte is not the null terminator — still within the keyword string), JUMP back to 4F88H to check the next byte. [LOOP — skip past keyword text until null found]

[SKIP PAST DATA BYTES] — BC now points to the first data byte after the null terminator. Skip past D data bytes to reach the start of the next keyword entry.

4F8E
LD E,D 5A
Copy Register D (number of data bytes per entry) into Register E. This sets up a counter for skipping the data bytes.
4F8F
INC BC 03
INCrement Register Pair BC by 1 to advance past one data byte.
4F90
DEC E 1D
DECrement Register E (data byte counter) by 1.
4F91
If the NZ FLAG is set (more data bytes to skip), JUMP back to 4F8FH. [LOOP — skip D data bytes]

[CHECK FOR END OF TABLE] — BC now points to the start of the next keyword entry, or to a 00H sentinel marking the end of the table.

4F93
LD A,(BC) 0A
Fetch the first byte of the next table entry into Register A.
4F94
OR A B7
Perform OR A to test if Register A is zero. A zero byte here means the end of the keyword table has been reached (00H sentinel) — no keyword matched.
4F95
If the NZ FLAG is set (next entry is not the sentinel — more keywords to try), JUMP back to 4F84H to compare the command line against the next keyword. [OUTER LOOP — try each keyword in table]
4F97
JUMP to 4D63H to load error code 34H (parse error) and report the error. No keyword in the table matched the command line text.

4F9AH - Skip Spaces and Require Filespec

This utility routine skips whitespace and checks that a valid filespec parameter follows. If no valid parameter is found after the comma/space, it jumps to the error handler. Used to ensure required parameters are present on the command line.

4F9A
GOSUB to SYS0 routine at 4C7AH to skip whitespace and check for a comma delimiter on the command line.
4F9D
If the NZ FLAG is set (a delimiter or parameter was found but might be a Carry condition), JUMP to 4FA3H to check if it is a valid token via the Carry flag.
4F9F
RET C9
RETURN to the caller. The Z FLAG indicates the end of the command line was reached with no more parameters.

4FA0H - Parse Required Numeric Parameter

This entry point calls the SYS0 colon/token parser at 4C7EH and checks if a valid parameter follows. If the Carry flag is set (valid token found) but it is not what was expected, it falls through to the error jump at 4F97H.

4FA0
GOSUB to SYS0 routine at 4C7EH to parse the next token from the command line. On return: Carry set if a valid token was found, NC if end of line.
4FA3
If the CARRY FLAG is set (a token was found but parsing indicates an error condition — invalid parameter format), JUMP to 4F97H to report error 34H (parse error).

4FA5H - Parse Decimal or Hexadecimal Number from Command Line

This routine parses a numeric value from the command line, supporting both decimal and hexadecimal formats. Hexadecimal numbers end with H (e.g., "5200H"). Decimal numbers are just digits (e.g., "1234"). The routine first attempts a decimal parse; if the terminating character is a letter A-H, it re-parses in hex mode. Returns the parsed value as a 16-bit number in Register Pair DE. On entry: HL points to the command line text. On return: DE = parsed 16-bit value, HL advanced past the number, B bit 1 set if digits found.

4FA5
PUSH HL E5
Save Register Pair HL (command line pointer) onto the stack. This preserves the starting position in case a hex suffix is detected and the number must be re-parsed in hex mode.
4FA6
LD B,00H 06 00
Load Register B with 00H to initialize the flags byte. Bit 0 controls hex mode (0=decimal, 1=hex). Bit 1 will be set when at least one valid digit is parsed.
4FA8
GOSUB to 4FC6H to perform the initial number parse in decimal mode (B bit 0 = 0). Reads decimal digits from the command line, accumulates the value in DE, and advances HL past the digits.
4FAB
LD A,(HL) 7E
Fetch the character that stopped the decimal parse into Register A. If the number is hexadecimal, this character will be a letter A-H.
4FAC
SUB 41H D6 41
SUBtract 41H (ASCII A) from Register A. This converts uppercase letters A-H to values 00H-07H. Any character below A produces a negative result (borrow).
4FAE
CP 08H FE 08
Compare Register A against 08H. If A < 08H (the character was A through H), the CARRY FLAG is set, indicating the number may be hexadecimal.
4FB0
If the NO CARRY FLAG is set (the terminating character is not A-H — the number is purely decimal), JUMP to 4FBFH to finalize the decimal result.

[POSSIBLE HEX NUMBER] — The initial decimal parse stopped at a letter A-H. Re-parse the entire number from the beginning in hexadecimal mode.

4FB2
POP HL E1
Restore Register Pair HL from the stack. This resets the command line pointer to the start of the number so it can be re-parsed as hexadecimal.
4FB3
LD B,01H 06 01
Load Register B with 01H (bit 0 set). Bit 0 = 1 tells the number parser at 4FC6H to accept hex digits A-F and multiply by 16 instead of 10.
4FB5
PUSH HL E5
Save Register Pair HL (the restored starting position) onto the stack again for the stack cleanup at 4FC1H.
4FB6
GOSUB to 4FC6H to re-parse the number in hexadecimal mode. Reads hex digits 0-9 and A-F, accumulates the value in DE using base-16 arithmetic.
4FB9
LD A,(HL) 7E
Fetch the character that stopped the hex parse into Register A. For a valid hex number, this should be H (48H) — the hex suffix.
4FBA
CP 48H FE 48
Compare Register A against 48H (ASCII H). If the terminating character is H, this confirms a valid hex number.
4FBC
INC HL 23
INCrement Register Pair HL by 1 to advance past the H suffix character.
4FBD
If the NZ FLAG is set (the terminating character was NOT H), JUMP to 4FC3H to report error 2FH. The number contained hex letters but lacked the required "H" suffix.
4FBF
BIT 1,B CB 48
Test bit 1 of Register B. Bit 1 is set by the parser loop when at least one valid digit has been processed. If bit 1 is clear, no digits were found.
4FC1
POP BC C1
Pop the saved starting position into Register Pair BC, discarding it. This cleans the stack regardless of whether the parse was decimal or hex.
4FC2
RET NZ C0
If the NZ FLAG is set (bit 1 was set — at least one digit was parsed successfully), RETURN with DE containing the parsed 16-bit value. This is the successful exit.
4FC3
JUMP to 4DD7H to report error 2FH (invalid parameter value). Either no digits were found, or a hex number lacked the "H" suffix.

4FC6H - Core Number Accumulator (Decimal or Hex)

This is the core digit-by-digit number parsing loop. It reads characters from the command line, converts them to numeric values, and accumulates a 16-bit result in Register Pair DE using either base-10 (decimal) or base-16 (hexadecimal) arithmetic depending on bit 0 of Register B. The multiplication uses shift-and-add: for decimal, DE = DE×4 + DE (×5) then ×2 (=×10); for hex, DE = DE×4×2 (×8) then ×2 (=×16). On entry: HL = command line pointer, B bit 0 = mode (0=decimal, 1=hex). On return: DE = accumulated value, HL at first non-digit, B bit 1 set if digits found.

4FC6
LD DE,0000H 11 00 00
Load Register Pair DE with 0000H to initialize the accumulator to zero.

[LOOP START — Read and accumulate one digit]

4FC9
LD A,(HL) 7E
Fetch the next character from the command line buffer into Register A.
4FCA
SUB 30H D6 30
SUBtract 30H (ASCII 0) from Register A. Converts ASCII digit characters to binary values: 0-9 become 00H-09H.
4FCC
CP 0AH FE 0A
Compare Register A against 0AH (10). If A < 0AH, the character was a valid decimal digit and the CARRY FLAG is set.
4FCE
If the CARRY FLAG is set (valid decimal digit 0-9), JUMP to 4FDAH to accumulate this digit into the result.

[NOT A DECIMAL DIGIT — Check for hex digit A-F]

4FD0
BIT 0,B CB 40
Test bit 0 of Register B. Bit 0 = 1 means hex mode is active; bit 0 = 0 means decimal mode.
4FD2
RET Z C8
If the Z FLAG is set (decimal mode — bit 0 clear), RETURN. The non-digit character terminates the decimal number. DE contains the accumulated result.
4FD3
SUB 11H D6 11
SUBtract 11H from Register A. After the earlier SUB 30H, the ASCII letter A (41H) becomes 11H, so subtracting 11H yields 00H. Letters A-F become 00H-05H.
4FD5
CP 06H FE 06
Compare Register A against 06H. If A < 06H (valid hex digit A-F), the CARRY FLAG is set.
4FD7
RET NC D0
If the NO CARRY FLAG is set (character is not a valid hex digit), RETURN. DE contains the accumulated result.
4FD8
ADD 0AH C6 0A
ADD 0AH (10) to Register A. Converts the hex letter offset (00H-05H) to its actual hex value (0AH-0FH).

[ACCUMULATE DIGIT INTO DE] — Multiply the current accumulated value in DE by the base (10 for decimal, 16 for hex) and add the new digit. The multiplication uses HL as a temporary: HL = DE, then shift/add to produce HL × base, then add the digit, then move result back to DE.

4FDA
PUSH HL E5
Save Register Pair HL (command line pointer) onto the stack.
4FDB
LD H,D 62
Copy Register D into Register H. Begin transferring the accumulated value from DE to HL.
4FDC
LD L,E 6B
Copy Register E into Register L. HL now equals DE (the current accumulated value).
4FDD
LD C,A 4F
Copy Register A (the current digit value, 0-15) into Register C for safekeeping.
4FDE
XOR A AF
Set Register A to 00H. Register A serves as a 24-bit overflow extension (A:HL) to detect when the result exceeds 16 bits.
4FDF
SET 1,B CB C8
Set bit 1 of Register B. This flag indicates that at least one valid digit has been parsed. Checked at 4FBFH to validate the number was not empty.
4FE1
ADD HL,HL 29
ADD HL to itself (shift left by 1). HL = accumulated × 2.
4FE2
ADC A,A 8F
Capture overflow from the HL shift into Register A (24-bit extension).
4FE3
ADD HL,HL 29
ADD HL to itself again. HL = accumulated × 4.
4FE4
ADC A,A 8F
Capture overflow. A:HL = accumulated × 4.
4FE5
BIT 0,B CB 40
Test bit 0 of Register B. Determines whether to use decimal (×10) or hex (×16) multiplication path.
4FE7
If the Z FLAG is set (decimal mode), JUMP to 4FECH for the decimal path: add original value (×4 + ×1 = ×5, then ×2 = ×10).
4FE9
ADD HL,HL 29
ADD HL to itself (hex mode extra shift). HL = accumulated × 8.
4FEA
Unconditional JUMP to 4FEDH to skip the decimal ADD and proceed to the final ×2.
4FEC
ADD HL,DE 19
ADD Register Pair DE (the original accumulated value) to HL (accumulated × 4). Result: HL = accumulated × 5. (Decimal mode only.)
4FED
ADC A,A 8F
Capture overflow from the addition into A.
4FEE
ADD HL,HL 29
ADD HL to itself (final ×2). For decimal: HL = accumulated × 10. For hex: HL = accumulated × 16.
4FEF
ADC A,A 8F
Capture final overflow. If A is non-zero, the result exceeds 16 bits (overflow).
4FF0
LD E,C 59
Copy Register C (the saved digit value, 0-15) into Register E.
4FF1
LD D,00H 16 00
Load Register D with 00H. DE = digit value as a 16-bit number.
4FF3
ADD HL,DE 19
ADD Register Pair DE (the digit) to HL (accumulated × base). HL = (accumulated × base) + digit.
4FF4
ADC A,A 8F
Capture any final overflow from the digit addition.
4FF5
EX DE,HL EB
Exchange HL and DE. The new accumulated value is now in DE where the parser expects it.
4FF6
POP HL E1
Restore Register Pair HL (command line pointer) from the stack.
4FF7
If the NZ FLAG is set (A was non-zero — 16-bit overflow occurred), JUMP to 4FC3H to report error 2FH (value out of range).
4FF9
INC HL 23
INCrement Register Pair HL by 1 to advance the command line pointer past the digit just processed.
4FFA
Unconditional JUMP back to 4FC9H to read and process the next character. [LOOP END — continues until a non-digit character is found]

4FFCH - Validate Filename Characters (Digits and Letters)

This routine checks whether the current command line character is a valid filename character (ASCII digits 30H-39H or uppercase letters 41H-5AH). It is called within the filename copy loop. If the character is below the digit range, the name is terminated and remaining positions are padded with spaces.

4FFC
LD A,(HL) 7E
Fetch the next character from the command line buffer into Register A.
4FFD
CP 30H FE 30
Compare Register A against 30H (ASCII 0). If A < 30H, the character is below the digit range and is not a valid filename character.
4FFF
If the CARRY FLAG is set (character < 0), JUMP to 5016H to pad remaining positions with spaces.
5001
CP 3AH FE 3A
Compare Register A against 3AH (one past ASCII 9). If A < 3AH, the character is a valid digit 0-9 and the CARRY FLAG is set.
5003
Unconditional JUMP to 500BH to check the Carry result and either accept the digit or continue checking for letters.

5005H - Parse Password/Filename String and Encode

This routine parses a password or filename string (up to 8 characters) from the command line, copies valid characters into a working buffer at 51E7H (stored backwards from high to low address), pads short names with spaces, and then passes the buffer through the NEWDOS/80 password encoding algorithm at 502AH. Valid characters are digits 0-9 and uppercase letters A-Z. On entry: HL = command line pointer. On return: DE = 2-byte encoded password/hash, HL advanced past the parsed text.

5005
LD DE,51E7H 11 E7 51
Point Register Pair DE to 51E7H, the start of the 8-byte working buffer within SYS7. Characters will be stored here, and this buffer is then passed to the password encoding algorithm.
5008
LD B,08H 06 08
Load Register B with 08H (8 decimal). Maximum character count — passwords and filenames in NEWDOS/80 are up to 8 characters.
500A
OR A B7
Perform OR A to clear the Carry flag. Initializes the flag state for the character validation loop.
500B
If the CARRY FLAG is set (from a prior CP — the character is in a valid range), JUMP to 501EH to copy the character to the buffer.
500D
LD A,(HL) 7E
Fetch the character from the command line again into Register A for the letter range check.
500E
CP 41H FE 41
Compare Register A against 41H (ASCII A). If A < 41H, the character is not an uppercase letter.
5010
If the CARRY FLAG is set (character < A), JUMP to 5016H to pad remaining positions with spaces. The name/password has ended.
5012
CP 5BH FE 5B
Compare Register A against 5BH (one past ASCII Z). If A < 5BH, the character is a valid uppercase letter A-Z.
5014
If the CARRY FLAG is set (valid letter A-Z), JUMP to 501EH to copy it to the buffer.

[SPACE PAD] — The character is not a valid filename/password character. Pad the current and all remaining positions with spaces (20H).

5016
INC DE 13
INCrement Register Pair DE by 1 to advance the destination buffer pointer.
5017
LD A,20H 3E 20
Load Register A with 20H (ASCII space). Space is the padding character for short names/passwords.
5019
LD (DE),A 12
Store the space character to the buffer at the address pointed to by DE.
501A
DECrement Register B (character counter) and JUMP back to 5016H if B is not zero (more positions to pad). [PAD LOOP]
501C
Unconditional JUMP to 5023H to proceed to the password encoding phase.

[COPY VALID CHARACTER]

501E
INC DE 13
INCrement Register Pair DE by 1 to advance to the next buffer position.
501F
LD (DE),A 12
Store Register A (the valid character) to the buffer at the address pointed to by DE.
5020
INC HL 23
INCrement Register Pair HL by 1 to advance the command line pointer past the copied character.
5021
DECrement Register B (character counter) and JUMP back to 4FFCH if B is not zero (more characters to process). [COPY LOOP]

5023H - Password Encoding Algorithm

This routine encodes an 8-character password/filename string into a 2-byte hash value. The algorithm processes each character through a series of bit rotations, XOR operations, and accumulation steps that produce a pseudo-random 16-bit hash in Register Pair DE. The hash is used for password comparison — the actual password text is never stored on disk, only this 2-byte encoded form. On entry: HL = command line pointer (saved), the 8-byte string is in the buffer ending at (DE). On return: DE = 2-byte encoded password hash.

5023
PUSH HL E5
Save Register Pair HL (command line pointer) onto the stack. HL will be used as a pointer to the character buffer during the encoding loop.
5024
EX DE,HL EB
Exchange Register Pairs DE and HL. HL now points to the end of the 8-character buffer (the last character stored by the copy loop). DE is freed for use as the hash accumulator.
5025
LD DE,FFFFH 11 FF FF
Load Register Pair DE with FFFFH to initialize the hash accumulator. Starting with all bits set provides a non-zero initial state for the hash computation.
5028
LD B,08H 06 08
Load Register B with 08H (8 decimal). Process all 8 characters in the buffer.

[LOOP START — Encode one character into the hash] — Each iteration reads one character from the buffer (working backwards from high to low address), performs a series of bit manipulation operations, and XORs the result into the running hash in DE. The algorithm creates a non-reversible 2-byte hash from the 8-byte input.

502A
PUSH BC C5
Save Register Pair BC onto the stack. B is the character counter; C will be used as a temporary during the bit manipulation.
502B
LD A,E 7B
Copy Register E (low byte of the hash accumulator) into Register A. The encoding operates on this byte through a series of transforms.
502C
AND 07H E6 07
Mask Register A with 07H, keeping only the lower 3 bits of E. This extracts a 3-bit sub-field from the hash.
502E
LD C,A 4F
Copy the 3-bit value into Register C for later use.
502F
LD A,E 7B
Copy Register E (full low byte of hash) into Register A again.
5030
RLCA 07
Rotate Register A left by 1 bit.
5031
RLCA 07
Rotate Register A left by 1 bit. A = E rotated left 2 positions.
5032
RLCA 07
Rotate Register A left by 1 bit. A = E rotated left 3 positions.
5033
XOR C A9
XOR Register C (the 3-bit sub-field) with Register A (E rotated left 3). This creates a mixed intermediate value.
5034
RLCA 07
Rotate Register A left by 1 more bit. Total rotation = 4 positions from the original E value (after XOR).
5035
LD C,A 4F
Save the intermediate result in Register C.
5036
AND F0H E6 F0
Mask Register A with F0H, keeping only the upper 4 bits (upper nibble) of the intermediate value.
5038
LD B,A 47
Save the upper nibble in Register B.
5039
LD A,C 79
Restore the full intermediate value from Register C.
503A
RLCA 07
Rotate Register A left by 1 more bit.
503B
AND 1FH E6 1F
Mask Register A with 1FH, keeping only the lower 5 bits.
503D
XOR B A8
XOR Register B (the upper nibble from earlier) with Register A (the lower 5 bits). This further mixes the bits.
503E
XOR D AA
XOR Register D (high byte of hash accumulator) with Register A. This folds the transformed E-byte value into the D byte of the hash.
503F
LD E,A 5F
Store the result into Register E. This becomes the new low byte of the hash for the next iteration.

[SECOND HALF — Process the upper bits and XOR with the character]

5040
LD A,C 79
Restore the intermediate value from Register C again.
5041
AND 0FH E6 0F
Mask Register A with 0FH, keeping only the lower nibble of the intermediate value.
5043
LD B,A 47
Save the lower nibble in Register B.
5044
LD A,C 79
Restore the intermediate value once more.
5045
RLCA 07
Rotate Register A left by 1 bit.
5046
RLCA 07
Rotate left again.
5047
RLCA 07
Rotate left again.
5048
RLCA 07
Rotate left again. A = intermediate rotated left 4 positions (nibble swap).
5049
XOR B A8
XOR Register B (lower nibble) with Register A (nibble-swapped intermediate). This further scrambles the bits.
504A
POP BC C1
Restore Register Pair BC from the stack. B = character counter, C = restored.
504B
XOR (HL) AE
XOR Register A with the byte at (HL) — the current character from the password/filename buffer. This is the key step that incorporates each character into the hash.
504C
LD D,A 57
Store the result into Register D, the high byte of the hash accumulator. The character has been folded into the hash.
504D
LD (HL),20H 36 20
Store 20H (space) to the buffer position at (HL), overwriting the character that was just processed. This ensures the buffer is cleared as each character is consumed, leaving no trace of the original password text in memory.
504F
DEC HL 2B
DECrement Register Pair HL by 1 to move to the previous character in the buffer (processing from high address to low).
5050
DECrement Register B (character counter) and JUMP back to 502AH if B is not zero (more characters to encode). [LOOP END]
5052
POP HL E1
Restore Register Pair HL (command line pointer) from the stack. HL is returned to where it was before the encoding began.
5053
RET C9
RETURN to the caller. Register Pair DE contains the 2-byte encoded password hash. HL points to the command line position after the parsed password/filename text.

4FA5H - Parse Decimal or Hexadecimal Number from Command Line

This routine parses a numeric value from the command line, supporting both decimal and hexadecimal formats. Hexadecimal numbers end with H (e.g., "5200H"). Decimal numbers are just digits (e.g., "1234"). The routine first attempts a decimal parse; if the terminating character is a letter A-H, it re-parses in hex mode. Returns the parsed value as a 16-bit number in Register Pair DE. On entry: HL points to the command line text. On return: DE = parsed 16-bit value, HL advanced past the number, B bit 1 set if digits found.

4FA5
PUSH HL E5
Save Register Pair HL (command line pointer) onto the stack. This preserves the starting position in case a hex suffix is detected and the number must be re-parsed in hex mode.
4FA6
LD B,00H 06 00
Load Register B with 00H to initialize the flags byte. Bit 0 controls hex mode (0=decimal, 1=hex). Bit 1 will be set when at least one valid digit is parsed.
4FA8
GOSUB to 4FC6H to perform the initial number parse in decimal mode (B bit 0 = 0). Reads decimal digits from the command line, accumulates the value in DE, and advances HL past the digits.
4FAB
LD A,(HL) 7E
Fetch the character that stopped the decimal parse into Register A. If the number is hexadecimal, this character will be a letter A-H.
4FAC
SUB 41H D6 41
SUBtract 41H (ASCII A) from Register A. This converts uppercase letters A-H to values 00H-07H. Any character below A produces a negative result (borrow).
4FAE
CP 08H FE 08
Compare Register A against 08H. If A < 08H (the character was A through H), the CARRY FLAG is set, indicating the number may be hexadecimal.
4FB0
If the NO CARRY FLAG is set (the terminating character is not A-H — the number is purely decimal), JUMP to 4FBFH to finalize the decimal result.

[POSSIBLE HEX NUMBER] — The initial decimal parse stopped at a letter A-H. Re-parse the entire number from the beginning in hexadecimal mode.

4FB2
POP HL E1
Restore Register Pair HL from the stack. This resets the command line pointer to the start of the number so it can be re-parsed as hexadecimal.
4FB3
LD B,01H 06 01
Load Register B with 01H (bit 0 set). Bit 0 = 1 tells the number parser at 4FC6H to accept hex digits A-F and multiply by 16 instead of 10.
4FB5
PUSH HL E5
Save Register Pair HL (the restored starting position) onto the stack again for the stack cleanup at 4FC1H.
4FB6
GOSUB to 4FC6H to re-parse the number in hexadecimal mode. Reads hex digits 0-9 and A-F, accumulates the value in DE using base-16 arithmetic.
4FB9
LD A,(HL) 7E
Fetch the character that stopped the hex parse into Register A. For a valid hex number, this should be H (48H) — the hex suffix.
4FBA
CP 48H FE 48
Compare Register A against 48H (ASCII H). If the terminating character is H, this confirms a valid hex number.
4FBC
INC HL 23
INCrement Register Pair HL by 1 to advance past the H suffix character.
4FBD
If the NZ FLAG is set (the terminating character was NOT H), JUMP to 4FC3H to report error 2FH. The number contained hex letters but lacked the required "H" suffix.
4FBF
BIT 1,B CB 48
Test bit 1 of Register B. Bit 1 is set by the parser loop when at least one valid digit has been processed. If bit 1 is clear, no digits were found.
4FC1
POP BC C1
Pop the saved starting position into Register Pair BC, discarding it. This cleans the stack regardless of whether the parse was decimal or hex.
4FC2
RET NZ C0
If the NZ FLAG is set (bit 1 was set — at least one digit was parsed successfully), RETURN with DE containing the parsed 16-bit value. This is the successful exit.
4FC3
JUMP to 4DD7H to report error 2FH (invalid parameter value). Either no digits were found, or a hex number lacked the "H" suffix.

4FC6H - Core Number Accumulator (Decimal or Hex)

This is the core digit-by-digit number parsing loop. It reads characters from the command line, converts them to numeric values, and accumulates a 16-bit result in Register Pair DE using either base-10 (decimal) or base-16 (hexadecimal) arithmetic depending on bit 0 of Register B. The multiplication uses shift-and-add: for decimal, DE = DE×4 + DE (×5) then ×2 (=×10); for hex, DE = DE×4×2 (×8) then ×2 (=×16). On entry: HL = command line pointer, B bit 0 = mode (0=decimal, 1=hex). On return: DE = accumulated value, HL at first non-digit, B bit 1 set if digits found.

4FC6
LD DE,0000H 11 00 00
Load Register Pair DE with 0000H to initialize the accumulator to zero.

[LOOP START — Read and accumulate one digit]

4FC9
LD A,(HL) 7E
Fetch the next character from the command line buffer into Register A.
4FCA
SUB 30H D6 30
SUBtract 30H (ASCII 0) from Register A. Converts ASCII digit characters to binary values: 0-9 become 00H-09H.
4FCC
CP 0AH FE 0A
Compare Register A against 0AH (10). If A < 0AH, the character was a valid decimal digit and the CARRY FLAG is set.
4FCE
If the CARRY FLAG is set (valid decimal digit 0-9), JUMP to 4FDAH to accumulate this digit into the result.

[NOT A DECIMAL DIGIT — Check for hex digit A-F]

4FD0
BIT 0,B CB 40
Test bit 0 of Register B. Bit 0 = 1 means hex mode is active; bit 0 = 0 means decimal mode.
4FD2
RET Z C8
If the Z FLAG is set (decimal mode — bit 0 clear), RETURN. The non-digit character terminates the decimal number. DE contains the accumulated result.
4FD3
SUB 11H D6 11
SUBtract 11H from Register A. After the earlier SUB 30H, the ASCII letter A (41H) becomes 11H, so subtracting 11H yields 00H. Letters A-F become 00H-05H.
4FD5
CP 06H FE 06
Compare Register A against 06H. If A < 06H (valid hex digit A-F), the CARRY FLAG is set.
4FD7
RET NC D0
If the NO CARRY FLAG is set (character is not a valid hex digit), RETURN. DE contains the accumulated result.
4FD8
ADD 0AH C6 0A
ADD 0AH (10) to Register A. Converts the hex letter offset (00H-05H) to its actual hex value (0AH-0FH).

[ACCUMULATE DIGIT INTO DE] — Multiply the current accumulated value in DE by the base (10 for decimal, 16 for hex) and add the new digit. The multiplication uses HL as a temporary: HL = DE, then shift/add to produce HL × base, then add the digit, then move result back to DE.

4FDA
PUSH HL E5
Save Register Pair HL (command line pointer) onto the stack.
4FDB
LD H,D 62
Copy Register D into Register H. Begin transferring the accumulated value from DE to HL.
4FDC
LD L,E 6B
Copy Register E into Register L. HL now equals DE (the current accumulated value).
4FDD
LD C,A 4F
Copy Register A (the current digit value, 0-15) into Register C for safekeeping.
4FDE
XOR A AF
Set Register A to 00H. Register A serves as a 24-bit overflow extension (A:HL) to detect when the result exceeds 16 bits.
4FDF
SET 1,B CB C8
Set bit 1 of Register B. This flag indicates that at least one valid digit has been parsed. Checked at 4FBFH to validate the number was not empty.
4FE1
ADD HL,HL 29
ADD HL to itself (shift left by 1). HL = accumulated × 2.
4FE2
ADC A,A 8F
Capture overflow from the HL shift into Register A (24-bit extension).
4FE3
ADD HL,HL 29
ADD HL to itself again. HL = accumulated × 4.
4FE4
ADC A,A 8F
Capture overflow. A:HL = accumulated × 4.
4FE5
BIT 0,B CB 40
Test bit 0 of Register B. Determines whether to use decimal (×10) or hex (×16) multiplication path.
4FE7
If the Z FLAG is set (decimal mode), JUMP to 4FECH for the decimal path: add original value (×4 + ×1 = ×5, then ×2 = ×10).
4FE9
ADD HL,HL 29
ADD HL to itself (hex mode extra shift). HL = accumulated × 8.
4FEA
Unconditional JUMP to 4FEDH to skip the decimal ADD and proceed to the final ×2.
4FEC
ADD HL,DE 19
ADD Register Pair DE (the original accumulated value) to HL (accumulated × 4). Result: HL = accumulated × 5. (Decimal mode only.)
4FED
ADC A,A 8F
Capture overflow from the addition into A.
4FEE
ADD HL,HL 29
ADD HL to itself (final ×2). For decimal: HL = accumulated × 10. For hex: HL = accumulated × 16.
4FEF
ADC A,A 8F
Capture final overflow. If A is non-zero, the result exceeds 16 bits (overflow).
4FF0
LD E,C 59
Copy Register C (the saved digit value, 0-15) into Register E.
4FF1
LD D,00H 16 00
Load Register D with 00H. DE = digit value as a 16-bit number.
4FF3
ADD HL,DE 19
ADD Register Pair DE (the digit) to HL (accumulated × base). HL = (accumulated × base) + digit.
4FF4
ADC A,A 8F
Capture any final overflow from the digit addition.
4FF5
EX DE,HL EB
Exchange HL and DE. The new accumulated value is now in DE where the parser expects it.
4FF6
POP HL E1
Restore Register Pair HL (command line pointer) from the stack.
4FF7
If the NZ FLAG is set (A was non-zero — 16-bit overflow occurred), JUMP to 4FC3H to report error 2FH (value out of range).
4FF9
INC HL 23
INCrement Register Pair HL by 1 to advance the command line pointer past the digit just processed.
4FFA
Unconditional JUMP back to 4FC9H to read and process the next character. [LOOP END — continues until a non-digit character is found]

4FFCH - Validate Filename Characters (Digits and Letters)

This routine checks whether the current command line character is a valid filename character (ASCII digits 30H-39H or uppercase letters 41H-5AH). It is called within the filename copy loop. If the character is below the digit range, the name is terminated and remaining positions are padded with spaces.

4FFC
LD A,(HL) 7E
Fetch the next character from the command line buffer into Register A.
4FFD
CP 30H FE 30
Compare Register A against 30H (ASCII 0). If A < 30H, the character is below the digit range and is not a valid filename character.
4FFF
If the CARRY FLAG is set (character < 0), JUMP to 5016H to pad remaining positions with spaces.
5001
CP 3AH FE 3A
Compare Register A against 3AH (one past ASCII 9). If A < 3AH, the character is a valid digit 0-9 and the CARRY FLAG is set.
5003
Unconditional JUMP to 500BH to check the Carry result and either accept the digit or continue checking for letters.

5005H - Parse Password/Filename String and Encode

This routine parses a password or filename string (up to 8 characters) from the command line, copies valid characters into a working buffer at 51E7H (stored backwards from high to low address), pads short names with spaces, and then passes the buffer through the NEWDOS/80 password encoding algorithm at 502AH. Valid characters are digits 0-9 and uppercase letters A-Z. On entry: HL = command line pointer. On return: DE = 2-byte encoded password/hash, HL advanced past the parsed text.

5005
LD DE,51E7H 11 E7 51
Point Register Pair DE to 51E7H, the start of the 8-byte working buffer within SYS7. Characters will be stored here, and this buffer is then passed to the password encoding algorithm.
5008
LD B,08H 06 08
Load Register B with 08H (8 decimal). Maximum character count — passwords and filenames in NEWDOS/80 are up to 8 characters.
500A
OR A B7
Perform OR A to clear the Carry flag. Initializes the flag state for the character validation loop.
500B
If the CARRY FLAG is set (from a prior CP — the character is in a valid range), JUMP to 501EH to copy the character to the buffer.
500D
LD A,(HL) 7E
Fetch the character from the command line again into Register A for the letter range check.
500E
CP 41H FE 41
Compare Register A against 41H (ASCII A). If A < 41H, the character is not an uppercase letter.
5010
If the CARRY FLAG is set (character < A), JUMP to 5016H to pad remaining positions with spaces. The name/password has ended.
5012
CP 5BH FE 5B
Compare Register A against 5BH (one past ASCII Z). If A < 5BH, the character is a valid uppercase letter A-Z.
5014
If the CARRY FLAG is set (valid letter A-Z), JUMP to 501EH to copy it to the buffer.

[SPACE PAD] — The character is not a valid filename/password character. Pad the current and all remaining positions with spaces (20H).

5016
INC DE 13
INCrement Register Pair DE by 1 to advance the destination buffer pointer.
5017
LD A,20H 3E 20
Load Register A with 20H (ASCII space). Space is the padding character for short names/passwords.
5019
LD (DE),A 12
Store the space character to the buffer at the address pointed to by DE.
501A
DECrement Register B (character counter) and JUMP back to 5016H if B is not zero (more positions to pad). [PAD LOOP]
501C
Unconditional JUMP to 5023H to proceed to the password encoding phase.

[COPY VALID CHARACTER]

501E
INC DE 13
INCrement Register Pair DE by 1 to advance to the next buffer position.
501F
LD (DE),A 12
Store Register A (the valid character) to the buffer at the address pointed to by DE.
5020
INC HL 23
INCrement Register Pair HL by 1 to advance the command line pointer past the copied character.
5021
DECrement Register B (character counter) and JUMP back to 4FFCH if B is not zero (more characters to process). [COPY LOOP]

5023H - Password Encoding Algorithm

This routine encodes an 8-character password/filename string into a 2-byte hash value. The algorithm processes each character through a series of bit rotations, XOR operations, and accumulation steps that produce a pseudo-random 16-bit hash in Register Pair DE. The hash is used for password comparison — the actual password text is never stored on disk, only this 2-byte encoded form. On entry: HL = command line pointer (saved), the 8-byte string is in the buffer ending at (DE). On return: DE = 2-byte encoded password hash.

5023
PUSH HL E5
Save Register Pair HL (command line pointer) onto the stack. HL will be used as a pointer to the character buffer during the encoding loop.
5024
EX DE,HL EB
Exchange Register Pairs DE and HL. HL now points to the end of the 8-character buffer (the last character stored by the copy loop). DE is freed for use as the hash accumulator.
5025
LD DE,FFFFH 11 FF FF
Load Register Pair DE with FFFFH to initialize the hash accumulator. Starting with all bits set provides a non-zero initial state for the hash computation.
5028
LD B,08H 06 08
Load Register B with 08H (8 decimal). Process all 8 characters in the buffer.

[LOOP START — Encode one character into the hash] — Each iteration reads one character from the buffer (working backwards from high to low address), performs a series of bit manipulation operations, and XORs the result into the running hash in DE. The algorithm creates a non-reversible 2-byte hash from the 8-byte input.

502A
PUSH BC C5
Save Register Pair BC onto the stack. B is the character counter; C will be used as a temporary during the bit manipulation.
502B
LD A,E 7B
Copy Register E (low byte of the hash accumulator) into Register A. The encoding operates on this byte through a series of transforms.
502C
AND 07H E6 07
Mask Register A with 07H, keeping only the lower 3 bits of E. This extracts a 3-bit sub-field from the hash.
502E
LD C,A 4F
Copy the 3-bit value into Register C for later use.
502F
LD A,E 7B
Copy Register E (full low byte of hash) into Register A again.
5030
RLCA 07
Rotate Register A left by 1 bit.
5031
RLCA 07
Rotate Register A left by 1 bit. A = E rotated left 2 positions.
5032
RLCA 07
Rotate Register A left by 1 bit. A = E rotated left 3 positions.
5033
XOR C A9
XOR Register C (the 3-bit sub-field) with Register A (E rotated left 3). This creates a mixed intermediate value.
5034
RLCA 07
Rotate Register A left by 1 more bit. Total rotation = 4 positions from the original E value (after XOR).
5035
LD C,A 4F
Save the intermediate result in Register C.
5036
AND F0H E6 F0
Mask Register A with F0H, keeping only the upper 4 bits (upper nibble) of the intermediate value.
5038
LD B,A 47
Save the upper nibble in Register B.
5039
LD A,C 79
Restore the full intermediate value from Register C.
503A
RLCA 07
Rotate Register A left by 1 more bit.
503B
AND 1FH E6 1F
Mask Register A with 1FH, keeping only the lower 5 bits.
503D
XOR B A8
XOR Register B (the upper nibble from earlier) with Register A (the lower 5 bits). This further mixes the bits.
503E
XOR D AA
XOR Register D (high byte of hash accumulator) with Register A. This folds the transformed E-byte value into the D byte of the hash.
503F
LD E,A 5F
Store the result into Register E. This becomes the new low byte of the hash for the next iteration.

[SECOND HALF — Process the upper bits and XOR with the character]

5040
LD A,C 79
Restore the intermediate value from Register C again.
5041
AND 0FH E6 0F
Mask Register A with 0FH, keeping only the lower nibble of the intermediate value.
5043
LD B,A 47
Save the lower nibble in Register B.
5044
LD A,C 79
Restore the intermediate value once more.
5045
RLCA 07
Rotate Register A left by 1 bit.
5046
RLCA 07
Rotate left again.
5047
RLCA 07
Rotate left again.
5048
RLCA 07
Rotate left again. A = intermediate rotated left 4 positions (nibble swap).
5049
XOR B A8
XOR Register B (lower nibble) with Register A (nibble-swapped intermediate). This further scrambles the bits.
504A
POP BC C1
Restore Register Pair BC from the stack. B = character counter, C = restored.
504B
XOR (HL) AE
XOR Register A with the byte at (HL) — the current character from the password/filename buffer. This is the key step that incorporates each character into the hash.
504C
LD D,A 57
Store the result into Register D, the high byte of the hash accumulator. The character has been folded into the hash.
504D
LD (HL),20H 36 20
Store 20H (space) to the buffer position at (HL), overwriting the character that was just processed. This ensures the buffer is cleared as each character is consumed, leaving no trace of the original password text in memory.
504F
DEC HL 2B
DECrement Register Pair HL by 1 to move to the previous character in the buffer (processing from high address to low).
5050
DECrement Register B (character counter) and JUMP back to 502AH if B is not zero (more characters to encode). [LOOP END]
5052
POP HL E1
Restore Register Pair HL (command line pointer) from the stack. HL is returned to where it was before the encoding began.
5053
RET C9
RETURN to the caller. Register Pair DE contains the 2-byte encoded password hash. HL points to the command line position after the parsed password/filename text.

5054H - ATTRIB Command Option Keyword Table

This is the keyword lookup table used by the ATTRIB command's option dispatcher (loaded at 4E11H into BC and searched by the routine at 4F84H). Each entry consists of an ASCII keyword string terminated by 00H, followed by a 2-byte handler address (low byte first). The table is terminated by a 00H sentinel byte at 5092H. The handler addresses are the routines that process each specific attribute option.

5054
DEFM "INV" / DEFB 00H 49 4E 56 00
INV — Set file to Invisible. The file will not appear in DIR listings unless the I option is specified. Keyword "INV" followed by null terminator.
5058
DEFB 54H,4EH 54 4E
Handler address: 4E54H (low=54H, high=4EH). This is the INV flag handler which sets the invisible bit in the file's FPDE.
505A
DEFM "VIS" / DEFB 00H 56 49 53 00
VIS — Set file to Visible. The file will appear in normal DIR listings. Keyword "VIS" followed by null terminator.
505E
DEFB 58H,4EH 58 4E
Handler address: 4E58H (low=58H, high=4EH). This is the VIS flag handler which clears the invisible bit.
5060
DEFM "PROT=" / DEFB 00H 50 52 4F 54 3D 00
PROT= — Set file protection level. Accepts a keyword (LOCK, EXEC, READ, WRITE, RENAME, NAME, KILL, FULL) specifying the access level.
5066
DEFB 6AH,4EH 6A 4E
Handler address: 4E6AH (low=6AH, high=4EH). Loads the protection level sub-table at 5093H and searches for the level keyword.
5068
DEFM "ACC=" / DEFB 00H 41 43 43 3D 00
ACC= — Set file access password. The password is encoded and stored at FPDE offset +12H.
506D
DEFB 78H,4EH 78 4E
Handler address: 4E78H (low=78H, high=4EH). Loads offset 12H and calls the password encode routine.
506F
DEFM "UPD=" / DEFB 00H 55 50 44 3D 00
UPD= — Set file update password. The password is encoded and stored at FPDE offset +10H.
5074
DEFB 7CH,4EH 7C 4E
Handler address: 4E7CH (low=7CH, high=4EH). Loads offset 10H and calls the password encode routine.
5076
DEFM "ASE=" / DEFB 00H 41 53 45 3D 00
ASE= — Set Auto Space Extend flag (Y or N). Controls whether DOS automatically allocates additional granules when a file needs to grow beyond its current allocation.
507B
DEFB 31H,4EH 31 4E
Handler address: 4E31H (low=31H, high=4EH). Note: This maps to 4E31H which is the UDF= entry — examining the code flow, 4E31H loads C=80H then jumps to 4E37H. However, the correct handler for ASE= should be 4E2AH. The address bytes 31H,4EH are stored low-byte-first, producing address 4E31H. [This appears to be the address as encoded in the binary.]
507D
DEFM "ASC=" / DEFB 00H 41 53 43 3D 00
ASC= — Set Auto Space Compress flag (Y or N). Controls whether DOS automatically deallocates excess granules when a file is closed with unused space.
5082
DEFB 35H,4EH 35 4E
Handler address: 4E35H (low=35H, high=4EH). Loads C=40H (bit 6 mask) for ASC flag.
5084
DEFM "UDF=" / DEFB 00H 55 44 46 3D 00
UDF= — Set User Defined Flag (Y or N). A general-purpose flag bit available for user-defined purposes.
5089
DEFB 2AH,4EH 2A 4E
Handler address: 4E2AH (low=2AH, high=4EH). Loads C=20H (bit 5 mask) and DE=FF00H for the ASE-style Y/N handler.
508B
DEFM "LRL=" / DEFB 00H 4C 52 4C 3D 00
LRL= — Set Logical Record Length (1-256). Specifies the size in bytes of each logical record within the file. A value of 256 is stored internally as 00H.
5090
DEFB 17H,4EH 17 4E
Handler address: 4E17H (low=17H, high=4EH). Parses the numeric LRL value and stores it at FPDE offset +4.
5092
DEFB 00H 00
END OF TABLE SENTINEL. A 00H byte marks the end of the ATTRIB option keyword table. The keyword search routine at 4F84H checks for this sentinel after each failed match.

5093H - ATTRIB PROT= Protection Level Keyword Sub-Table

This sub-table is used by the PROT= option handler at 4E6AH. It maps protection level keyword strings to their corresponding numeric access level values (0-7). The access level is stored as a single byte following each keyword's null terminator (D=01H was set at 4E6DH to indicate 1 data byte per entry). The table is terminated by a 00H sentinel at 50C6H.

5093
DEFM "LOCK" / DEFB 00H 4C 4F 43 4B 00
LOCK — No access permitted. The most restrictive protection level.
5098
DEFB 07H 07
Access Level 7 = LOCK. No operations are allowed on the file.
5099
DEFM "EXEC" / DEFB 00H 45 58 45 43 00
EXEC — Execute only. The file can be loaded and executed but not read, written, renamed, or killed.
509E
DEFB 06H 06
Access Level 6 = EXEC.
509F
DEFM "READ" / DEFB 00H 52 45 41 44 00
READ — Execute or read. The file can be executed or read but not modified, renamed, or killed.
50A4
DEFB 05H 05
Access Level 5 = READ.
50A5
DEFM "WRITE" / DEFB 00H 57 52 49 54 45 00
WRITE — Execute, read, or write. The file can be modified but not renamed or killed.
50AB
DEFB 04H 04
Access Level 4 = WRITE.
50AC
DEFM "RENAME" / DEFB 00H 52 45 4E 41 4D 45 00
RENAME — Execute, read, write, or rename. The file can be renamed but not killed.
50B3
DEFB 02H 02
Access Level 2 = RENAME. (Note: Level 3 is skipped — there is no level 3 in NEWDOS/80.)
50B4
DEFM "NAME" / DEFB 00H 4E 41 4D 45 00
NAME — Synonym for RENAME. Accepts "NAME" as an alternative keyword for the same access level.
50B9
DEFB 02H 02
Access Level 2 = NAME (same as RENAME).
50BA
DEFM "KILL" / DEFB 00H 4B 49 4C 4C 00
KILL — Execute, read, write, rename, or kill. All operations except setting attributes are allowed.
50BF
DEFB 01H 01
Access Level 1 = KILL.
50C0
DEFM "FULL" / DEFB 00H 46 55 4C 4C 00
FULL — Full access. All operations are permitted on the file. This is the least restrictive level.
50C5
DEFB 00H 00
Access Level 0 = FULL.
50C6
DEFB 00H 00
END OF TABLE SENTINEL. Marks the end of the PROT= protection level keyword sub-table.

50C7H - PROT Command Option Keyword Table

This keyword lookup table is used by the PROT command's option dispatcher (loaded at 4ED2H into BC and searched by the routine at 4F78H). Each entry consists of an ASCII keyword string terminated by 00H, followed by a 2-byte handler address (low byte first). The table is terminated by a 00H sentinel at 50F3H. These handlers modify diskette-level control information (name, date, password, lock state).

50C7
DEFM "PW=" / DEFB 00H 50 57 3D 00
PW= — Change the diskette password. The new password is encoded and stored in the diskette's control sector.
50CB
DEFB 09H,4FH 09 4F
Handler address: 4F09H (low=09H, high=4FH). Calls the password encode routine and stores the result at 43CEH.
50CD
DEFM "UNLOCK" / DEFB 00H 55 4E 4C 4F 43 4B 00
UNLOCK — Remove password protection from all user files on the diskette. Sets both access and update passwords to the blank/null value.
50D4
DEFB FAH,4EH FA 4E
Handler address: 4EFAH (low=FAH, high=4EH). Sets flag bit 0 (UNLOCK) in the accumulated flags byte at 4F1AH.
50D6
DEFM "LOCK" / DEFB 00H 4C 4F 43 4B 00
LOCK — Set the diskette password as both the access and update password for all user files. Applies to all qualifying directory entries.
50DB
DEFB FEH,4EH FE 4E
Handler address: 4EFEH (low=FEH, high=4EH). Sets flag bit 1 (LOCK) in the accumulated flags byte.
50DD
DEFM "NAME=" / DEFB 00H 4E 41 4D 45 3D 00
NAME= — Change the diskette name. Copies up to 8 characters into the name field at 43D8H in the control sector buffer.
50E3
DEFB DDH,4EH DD 4E
Handler address: 4EDDH — wait, checking address: low=DDH, high=4EH → 4EDDH. But 4EDDH loads DE=43D0H (DATE field). Checking the source: 4ED8H loads DE=43D8H (NAME field). The address DDH,4EH = 4EDDH which loads the DATE destination. Re-examining: 50E3H has DDH (low) and 50E4H has 4EH (high) = 4EDDH. But 4EDDH is LD DE,43D0H — that is the DATE= destination. Looking at 4ED8H: that is LD DE,43D8H — the NAME destination. The table entry at 50E3H-50E4H should point to 4ED8H for NAME=. However the bytes are DDH,4EH = 4EDDH. This would mean NAME= handler copies to the date field. Let me re-verify: 4ED8H = LD DE,43D8H (name). The hex address 4ED8H encoded low-byte-first would be D8H,4EH. But the table has DDH,4EH = 4EDDH. Checking 4EDDH: LD DE,43D0H (date). This appears to be the correct encoding in the binary — the table says NAME= → 4EDDH and DATE= → 4ED8H, which would mean the handlers are swapped relative to what one might expect. However, since 4EDDH falls through to 4EE0H (the copy routine) after loading DE=43D0H, and 4ED8H loads DE=43D8H and also falls through to 4EE0H, the actual effect is: NAME= copies to 43D0H (date field location) and DATE= copies to 43D8H (name field location). This appears to be an intentional layout where the control sector fields at 43D0H and 43D8H may be swapped relative to their names, or this is a genuine bug in the original NEWDOS/80 code. [Documenting the binary as-is.]
50E5
DEFM "DATE=" / DEFB 00H 44 41 54 45 3D 00
DATE= — Change the diskette date (mm/dd/yy format). Copies up to 8 characters into the date field in the control sector buffer.
50EB
DEFB D8H,4EH D8 4E
Handler address: 4ED8H (low=D8H, high=4EH). Loads DE=43D8H and copies up to 8 characters from the command line. [See note at NAME= above regarding the apparent field swap.]
50ED
DEFM "RUF" / DEFB 00H 52 55 46 00
RUFReset Update Flag for all user files on the diskette. Clears the "updated" bit in each qualifying file's directory entry.
50F1
DEFB F6H,4EH F6 4E
Handler address: 4EF6H (low=F6H, high=4EH). Sets flag bit 2 (RUF) in the accumulated flags byte at 4F1AH.
50F3
DEFB 00H 00
END OF TABLE SENTINEL. Marks the end of the PROT command option keyword table.

50F4H - HIMEM Command Handler / DUMP Parameter Setup

This code handles the HIMEM command and also serves as the DUMP command's parameter setup routine. HIMEM displays or sets the highest usable memory address. DUMP writes a block of memory to a disk file. The code stores the address of the TIME handler (4D68H) into the system variable at 4483H (which may serve as a return vector), then pops the command context from the stack, parses the start address, end address, and optional entry/relocation addresses from the command line. It validates that end address ≥ start address, calculates the memory block size, sets up the output parameters at 448AH, and initiates the file write operation.

50F4
LD HL,4D68H 21 68 4D
Point Register Pair HL to 4D68H, the TIME command entry point. This address is stored as a callback or return vector for the DUMP/HIMEM completion path.
50F7
LD (4483H),HL 22 83 44
Store Register Pair HL (4D68H) to SYS0 system variable at 4483H. This sets up a function pointer that SYS0 will call when the DUMP output operation completes or when HIMEM needs to display a value.
50FA
POP AF F1
Restore Register Pair AF from the stack. Stack cleanup — discard the return context saved by SYS1.
50FB
POP HL E1
Restore Register Pair HL from the stack. HL now points to the command line text following the DUMP or HIMEM keyword.
50FC
GOSUB to 4FA0H to parse the first required parameter from the command line — the start address of the memory block to dump (or the HIMEM value). On return, DE contains the parsed 16-bit address.
50FF
PUSH DE D5
Save Register Pair DE (start address) onto the stack.
5100
GOSUB to 4FA0H to parse the second required parameter — the end address of the memory block to dump. On return, DE contains the end address.
5103
EX DE,HL EB
Exchange Register Pairs DE and HL. HL now contains the end address, DE contains the command line pointer.
5104
EX (SP),HL E3
Exchange HL with the top of the stack. HL now contains the start address (retrieved from stack), and the end address is saved on the stack in its place.
5105
EX DE,HL EB
Exchange again. DE now contains the start address, HL contains the command line pointer. The stack holds the end address.
5106
PUSH DE D5
Save Register Pair DE (start address) onto the stack. Stack now has: [end address] [start address] (top).
5107
LD DE,402DH 11 2D 40
Load Register Pair DE with 402DH, the default entry address. 402DH is the DOS no-error exit point — if no entry address is specified by the user, the DUMP file's entry point defaults to 402DH (which simply returns to DOS READY when the file is loaded and executed).
510A
GOSUB to 4F9AH to check for optional additional parameters (entry address and relocation address). If another parameter exists, it will be parsed; if not, DE retains the default 402DH.
510D
LD A,D 7A
Copy Register D (high byte of the entry/relocation address, or the parsed value) into Register A.
510E
AND E A3
AND Register E (low byte) with Register A. If DE = FFFFH, A AND E = FFH, and INC A at the next instruction produces 00H (Z FLAG set). This tests for the special "no-entry-point" value of FFFFH.
510F
INC A 3C
INCrement Register A by 1. If A was FFH (from FFFFH test), it wraps to 00H and the Z FLAG is set, indicating the entry address is FFFFH (the special "SUPERZAP-readable" dump mode).
5110
EX DE,HL EB
Exchange DE and HL. HL now contains the entry address (or default 402DH), DE contains the command line pointer.
5111
EX (SP),HL E3
Exchange HL with the stack top. HL now contains the start address (from stack), the entry address is saved on the stack.
5112
EX DE,HL EB
Exchange again. DE contains the start address, HL contains the command line pointer.
5113
PUSH DE D5
Save DE (start address) onto the stack again.
5114
If the NZ FLAG is set (the entry address was NOT FFFFH — a real entry point was given, so a relocation address parameter may follow), GOSUB to 4F9AH to parse the optional relocation address.
5117
GOSUB to 4D5FH to check for end of command line. Verifies no extraneous parameters remain.
511A
POP BC C1
Pop the start address (or relocation address) into Register Pair BC.
511B
POP AF F1
Pop the entry address into Register Pair AF (A = high byte, F = flags from low byte).
511C
POP HL E1
Pop the end address into Register Pair HL.
511D
PUSH AF F5
Re-push the entry address context onto the stack in the correct order for the output routine.
511E
PUSH BC C5
Push the start/relocation address.
511F
PUSH HL E5
Push the end address.
5120
PUSH DE D5
Push DE (the start address of the memory block).
5121
OR A B7
Clear the Carry flag to prepare for the 16-bit subtraction.
5122
SBC HL,BC ED 42
Subtract Register Pair BC (start address) from HL (end address). Result = end - start = block size - 1. If end < start, the CARRY FLAG is set (invalid range).
5124
PUSH HL E5
Push the block size (end - start) onto the stack.
5125
If the CARRY FLAG is set (end address < start address — invalid range), JUMP to 4DD7H to report error 2FH (invalid parameter value).
5128
LD BC,0005H 01 05 00
Load Register Pair BC with 0005H (5 decimal). This is the overhead for a CMD file load record header (type byte + 2-byte length + 2-byte address = 5 bytes).
512B
ADD HL,BC 09
ADD the header overhead (5) to the block size. HL = total record size including header.
512C
If the NO CARRY FLAG is set (no overflow — the total size fits in 16 bits), JUMP to 5133H to store the size normally.
512E
LD HL,0104H 21 04 01
Load Register Pair HL with 0104H (260 decimal). This is the fallback record size when the block is too large — it will be split into multiple 256-byte records (0100H data + 0004H header).
5131
Unconditional JUMP to 5138H to store the record size.
5133
LD A,FCH 3E FC
Load Register A with FCH (252 decimal). This value is passed to the SYS0 allocation routine at 4C59H to request a buffer of the calculated size.
5135
GOSUB to SYS0 routine at 4C59H. This routine performs buffer allocation or size calculation for the DUMP output file. Register A contains the record size parameter.
5138
LD (448AH),HL 22 8A 44
Store Register Pair HL (the record size) to SYS0 system variable at 448AH. This tells the output routine how large each record should be.
513B
LD DE,4480H 11 80 44
Point Register Pair DE to 4480H, a SYS0 system parameter block. This is the base address of the output control structure that the file write routine uses.
513E
LD BC,E908H 01 08 E9
Load Register Pair BC with E908H. B = E9H (the SVC function code for the SYS7 library command group), C = 08H (sub-function 8 — the DUMP/PURGE/SYSTEM/PDRIVE first-part index). This identifies the operation for the SVC handler.
5141
LD HL,4978H 21 78 49
Point Register Pair HL to 4978H, a SYS0 routine address. This is the entry point of the SYS0 file write handler that will output the DUMP data to disk.
5144
PUSH BC C5
Push the SVC function code (BC = E908H) onto the stack.
5145
PUSH HL E5
Push the SYS0 file write handler address (4978H) onto the stack.
5146
JUMP to SYS0 routine at 4439H. This is a SYS0 dispatch/setup routine that uses the parameters on the stack (SVC code and handler address) to initiate the DUMP output operation. The actual file writing is handled by the code at 4978H. This is a tail-call — execution continues in SYS0.

5149H - DUMP Output / PURGE-SYSTEM-PDRIVE First Part Handler

This is sub-function 8 from the command dispatcher — the DUMP output routine that writes memory data to the file, and also serves as the first-part handler for PURGE, SYSTEM, and PDRIVE. It is re-entered via SVC callback after the initial file setup at 5146H. On each callback entry, it calls 443FH to check if the operation should continue. If so, it pops parameters from the alternate register set (EXX), retrieves the memory block boundaries (start, end, entry addresses), and outputs the data in CMD file format records. Each record consists of a type byte, length, load address, and data bytes, sent character-by-character via the output routine at 51DAH.

5149
POP AF F1
Restore Register Pair AF from the stack. This retrieves the context saved by SYS0 during the callback mechanism.
514A
GOSUB to SYS0 routine at 443FH. This is a SYS0 status check routine that determines whether the output operation should continue. On return: Z FLAG set if output should proceed, NZ FLAG set if the operation is complete or an error occurred.
514D
If the NZ FLAG is set (output complete or error), JUMP to 519FH to check for error and handle completion.
514F
EXX D9
Switch to the alternate register set (BC', DE', HL'). The DUMP parameters were saved in the alternate registers during the initial setup. EXX swaps BC↔BC', DE↔DE', HL↔HL'.
5150
POP DE D1
Pop the source memory pointer (current position in the memory block being dumped) from the alternate stack context into Register Pair DE.
5151
POP HL E1
Pop the remaining byte count (bytes still to output) into Register Pair HL.
5152
INC DE 13
INCrement the source memory pointer by 1 to advance to the next byte to output.
5153
LD (51CCH),HL 22 CC 51
Store the remaining byte count to 51CCH. [SELF-MODIFYING CODE] — This overwrites the operand of an instruction at 51CBH (LD HL,0000H). When that instruction is later executed, it will load the byte count.
5156
POP HL E1
Pop the end address (or block limit) into Register Pair HL.
5157
LD (51BEH),HL 22 BE 51
Store the end address to 51BEH. [SELF-MODIFYING CODE] — Overwrites the operand at 51BEH within the instruction at 51BDH.
515A
POP HL E1
Pop the entry/transfer address into Register Pair HL.
515B
LD (51C5H),HL 22 C5 51
Store the entry address to 51C5H. [SELF-MODIFYING CODE] — Overwrites the operand at 51C5H within the instruction at 51C4H.
515E
POP BC C1
Pop the start/relocation context into Register Pair BC.
515F
EX DE,HL EB
Exchange DE and HL. HL now contains the current source memory pointer, DE is freed.
5160
LD A,B 78
Copy Register B (high byte of start/relocation context) into Register A.
5161
AND C A1
AND Register C (low byte) with Register A. Tests if BC = FFFFH (B AND C = FFH, then INC A = 00H).
5162
INC A 3C
INCrement Register A. If BC was FFFFH, A wraps to 00H and the Z FLAG is set, indicating the special "raw dump" mode (no CMD file headers — SUPERZAP-readable format).
5163
If the Z FLAG is set (BC = FFFFH — raw dump mode), JUMP to 51A4H to output memory bytes directly without CMD file record headers.

[CMD FILE OUTPUT MODE] — Output the memory block as CMD (load module) format records. Each record has: type byte (01H=data, 02H=entry), 2-byte length, 2-byte load address, followed by the data bytes. Records are limited to 254 (FEH) data bytes each.

5165
PUSH BC C5
Save the start/relocation address (BC) onto the stack for later retrieval.
5166
LD A,H 7C
Copy Register H (high byte of source pointer) into Register A.
5167
OR L B5
OR Register L into Register A. Tests if HL = 0000H (no more bytes to output).
5168
If the NZ FLAG is set (HL is non-zero — there are still bytes to output), JUMP to 5172H to calculate the record size.

[ALL DATA OUTPUT — Write entry point record] — HL is zero, meaning all data bytes have been written. Now output the CMD file's entry point (transfer address) record.

516A
LD BC,00FEH 01 FE 00
Load Register Pair BC with 00FEH. This is used in the SBC calculation below — 254 (FEH) is the maximum data bytes per CMD record.
516D
OR A B7
Clear the Carry flag.
516E
SBC HL,BC ED 42
Subtract 00FEH from HL (which is 0000H). Result: HL = 0000H - 00FEH = FF02H (with Carry set). This produces a negative value used as a flag for the entry point record handling.
5170
Unconditional JUMP to 517AH to output the entry point record.
5172
LD BC,00FEH 01 FE 00
Load Register Pair BC with 00FEH (254 decimal). Maximum data bytes per CMD data record.
5175
OR A B7
Clear the Carry flag.
5176
SBC HL,BC ED 42
Subtract 00FEH from HL (remaining byte count). If HL ≥ FEH, the result is positive or zero (NC) — output a full 254-byte record. If HL < FEH, the result is negative (Carry set) — the remaining data fits in one final record.
5178
If the CARRY FLAG is set (fewer than 254 bytes remain — this is the last data record), JUMP to 518DH to adjust the record size to the remaining byte count.
517A
INC C 0C
INCrement Register C (was FEH, now FFH). Adjusting the record size counter.
517B
INC C 0C
INCrement Register C again (now 00H, wrapping around). C = 00H represents a full 256-byte data block (or 0 remaining for the entry record).
517C
LD B,01H 06 01
Load Register B with 01H. This is the CMD record type byte: 01H = data record (load data into memory at the specified address).
517E
GOSUB to 51B3H to output the record header: type byte (B=01H) followed by the record length byte (C), then the 2-byte load address.

[OUTPUT DATA BYTES] — Loop to output each byte from the source memory block.

5181
DEC C 0D
DECrement Register C (data byte counter) by 1. Pre-decrement before the data output loop.
5182
DEC C 0D
DECrement Register C again. Subtract 2 for the 2-byte load address that was already output by 51B3H, leaving C = number of actual data bytes to output.
5183
LD A,(DE) 1A
Fetch the byte at the source memory address (pointed to by DE) into Register A. This is the next data byte to write to the output file.
5184
INC DE 13
INCrement Register Pair DE by 1 to advance the source memory pointer to the next byte.
5185
GOSUB to 51DAH to output the data byte in Register A to the file. This routine uses EXX and calls the ROM character output at 001BH.
5188
DEC C 0D
DECrement Register C (remaining data byte count) by 1.
5189
If the NZ FLAG is set (more data bytes to output), JUMP back to 5183H. [DATA OUTPUT LOOP]
518B
Unconditional JUMP back to 5172H to check if more records need to be output (remaining byte count in HL). [RECORD OUTPUT LOOP]
518D
OR A B7
Clear the Carry flag.
518E
ADC HL,BC ED 4A
ADD Register Pair BC (00FEH) back to HL (which was the negative remainder after the SBC at 5176H). This restores the actual remaining byte count.
5190
LD C,L 4D
Copy Register L (the remaining data byte count) into Register C. This becomes the length byte for the final (short) data record.
5191
LD L,H 6C
Copy Register H into Register L. After this and the next check, HL will be adjusted for the record output.
5192
If the NZ FLAG is set (H was non-zero — more than 255 bytes remaining in some edge case), JUMP back to 517AH to output another record.

[LAST RECORD OUTPUT — Write entry point record]

5194
POP DE D1
Pop the entry/transfer address from the stack into Register Pair DE.
5195
LD B,02H 06 02
Load Register B with 02H. CMD record type 02H = entry point record (transfer address — the address where execution begins when the file is loaded and run).
5197
LD C,B 48
Copy Register B (02H) into Register C. The entry point record length is 2 bytes (the 2-byte transfer address).
5198
GOSUB to 51B3H to output the entry point record header: type byte (B=02H), length byte (C=02H), and the 2-byte transfer address from the self-modified code area.
519B
EXX D9
Switch back to the alternate register set. This restores the SYS0 context for the file close operation.
519C
GOSUB to SYS0 routine at 443FH to finalize the current output block and check if the file write operation is complete.
519F
If the NZ FLAG is set (error or operation complete with error status), JUMP to 51E0H to report the error via 4D65H.
51A1
JUMP to SYS0 routine at 4428H to close the output file and return to DOS READY. This is the successful completion path for the DUMP command.

51A4H - Raw Memory Dump (SUPERZAP-Readable Format)

This routine outputs raw memory bytes without CMD file record headers. It is used when the entry address is FFFFH, producing a file readable by SUPERZAP in DBDM (Direct Block Dump) mode. It outputs each byte from the source memory block sequentially, decrementing a byte counter until all data has been written.

51A4
GOSUB to 51BBH to set up the output parameters. This routine saves HL and DE, loads the self-modified load address and byte count values, performs address calculations, and outputs the 2-byte load address as a header.
51A7
LD A,(DE) 1A
Fetch the byte at the source memory address (pointed to by DE) into Register A.
51A8
INC DE 13
INCrement the source memory pointer to the next byte.
51A9
GOSUB to 51DAH to output the data byte to the file.
51AC
DEC HL 2B
DECrement Register Pair HL (remaining byte count) by 1.
51AD
LD A,H 7C
Copy Register H (high byte of remaining count) into Register A.
51AE
OR L B5
OR Register L into Register A. Tests if HL = 0000H (all bytes output).
51AF
If the NZ FLAG is set (more bytes remaining), JUMP back to 51A7H. [RAW DUMP LOOP]
51B1
Unconditional JUMP to 519BH to switch back to the alternate register set and finalize the file output.

51B3H - Output CMD Record Header (Type + Length + Address)

This routine outputs a CMD file record header consisting of the record type byte (in B), the record length byte (in C), and then calls 51BBH to output the 2-byte load/transfer address. It is called for both data records (type 01H) and entry point records (type 02H).

51B3
LD A,B 78
Copy Register B (CMD record type byte: 01H=data, 02H=entry) into Register A.
51B4
GOSUB to 51DAH to output the record type byte.
51B7
LD A,C 79
Copy Register C (record length byte) into Register A.
51B8
GOSUB to 51DAH to output the record length byte.

51BBH - Output Load Address from Self-Modified Storage

This routine saves the current registers, loads the 2-byte load address and byte count from self-modified memory locations, performs an address-to-offset calculation (subtracting the block size from the end address to get the load address), and outputs the 2-byte load address. The self-modified locations at 51BEH, 51C5H, and 51CCH were written at 5157H, 515BH, and 5153H respectively.

51BB
PUSH HL E5
Save Register Pair HL (remaining byte count or source pointer) onto the stack.
51BC
PUSH DE D5
Save Register Pair DE (source memory pointer) onto the stack.
51BD
LD HL,0000H 21 00 00
Load Register Pair HL with 0000H. [SELF-MODIFYING CODE] — The operand at address 51BEH was overwritten at 5157H with the end address. At runtime, HL is loaded with the actual end address of the memory block.
51C0
RST 18H DF
Execute RST 18H — a system call that performs a comparison or transfer operation using HL.
51C1
EX DE,HL EB
Exchange DE and HL. DE now contains the result from RST 18H.
51C2
If the CARRY FLAG is set (error or boundary condition from RST 18H), JUMP to 51D3H to output the address from HL directly.
51C4
LD DE,0000H 11 00 00
Load Register Pair DE with 0000H. [SELF-MODIFYING CODE] — The operand at address 51C5H was overwritten at 515BH with the entry/transfer address.
51C7
RST 18H DF
Execute RST 18H again with the entry address in DE.
51C8
If the CARRY FLAG is set, JUMP to 51D3H.
51CA
PUSH HL E5
Save HL onto the stack.
51CB
LD HL,0000H 21 00 00
Load Register Pair HL with 0000H. [SELF-MODIFYING CODE] — The operand at 51CCH was overwritten at 5153H with the remaining byte count.
51CE
OR A B7
Clear the Carry flag for the subtraction.
51CF
SBC HL,DE ED 52
Subtract DE (entry address) from HL (byte count). This calculates the load address offset: load_address = byte_count - entry_address.
51D1
POP DE D1
Restore DE from the stack.
51D2
ADD HL,DE 19
ADD DE to HL. Final load address calculation.
51D3
LD A,L 7D
Copy Register L (low byte of the load address) into Register A.
51D4
GOSUB to 51DAH to output the low byte of the load address.
51D7
LD A,H 7C
Copy Register H (high byte of the load address) into Register A.
51D8
POP DE D1
Restore Register Pair DE (source memory pointer) from the stack.
51D9
POP HL E1
Restore Register Pair HL (remaining byte count) from the stack.

51DAH - Output Single Byte to File

This routine outputs a single byte (in Register A) to the output file. It switches to the alternate register set (EXX), calls the ROM character output routine at 001BH, switches back, and checks the return status. If the output failed (NZ), it jumps to the error handler.

51DA
EXX D9
Switch to the alternate register set. The SYS0 file output context is maintained in the alternate registers (BC', DE', HL'). The primary registers (containing DUMP-specific data) are preserved.
51DB
GOSUB to ROM routine at 001BH — the character output vector. Register A contains the byte to output. In the DUMP context, this vector has been redirected to the file write DCB (Device Control Block) so the byte is written to the output disk file rather than the display.
51DE
EXX D9
Switch back to the primary register set. The DUMP state (source pointer, byte count, etc.) is restored.
51DF
RET Z C8
If the Z FLAG is set (output successful), RETURN to the caller to continue the dump operation.

51E0H - Output Error Exit

Reached when a file output operation fails. Jumps to the common error handler at 4D65H to report the error and return to DOS READY.

51E0
JUMP to 4D65H to report the error. Register A contains the error code from the failed output operation. This is a dead-end jump — execution does not return to SYS7.

51E3H - NOP Padding / Scratch Buffer Area

The final 5 bytes of the SYS7 overlay (51E3H-51E7H) are NOP padding. These bytes are unused code space that fills the remainder of the overlay to its required sector boundary. The adjacent byte at 51E8H is the start of the scratch buffer used by the display formatting routines (DATE display, TIME display, etc.).

51E3
NOP 00
No Operation. Unused padding byte.
51E4
NOP 00
No Operation. Unused padding byte.
51E5
NOP 00
No Operation. Unused padding byte.
51E6
NOP 00
No Operation. Unused padding byte.
51E7
NOP 00
No Operation. Unused padding byte. This is also the last byte of the SYS7 overlay. The byte at 51E8H begins the scratch display buffer area that is used during command execution but is not part of the stored overlay image.