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

Page Customization

SYS15/SYS – FORMS and SETCOM Commands

SYS15/SYS is a NEWDOS/80 overlay module that implements two Model III–only DOS commands: FORMS (printer parameter configuration) and SETCOM (RS-232 serial interface configuration). The module loads into memory at 4D00H and occupies addresses 4D00H–51E7H, though only 4D00H–4FD2H contains executable code and data; the remainder (4FD3H–51E7H) is unused padding (NOP bytes).

The FORMS command allows users to set two printer parameters: WIDTH (characters per line, 9–255) and LINES (lines per page, 1–254, where 254 means unlimited). If no parameters are specified, FORMS displays the current values.

The SETCOM command configures the RS-232 serial port with parameters: WORD length (5–8 bits), BAUD rate (50–19200), STOP bits (1–2), PARITY (odd/even/none), and WAIT/NOWAIT mode. If the OFF keyword is specified, the RS-232 interface is disabled. SETCOM always displays the current state after any changes.

Both commands share a common infrastructure: a keyword parsing engine at 4EE7H that matches user input against keyword tables, a multi-base numeric value parser at 4F49H that handles both decimal and hexadecimal input, and a formatted numeric output routine at 4F93H for displaying parameter values.

Variable and RAM Location Reference

Complete list of RAM variables, self-modifying code locations, and system addresses referenced by SYS15/SYS.

DOS System Variables:

AddressDescription
4028HPrinter lines-per-page setting (1–254; 254 = unlimited)
402AHPrinter lines-per-page working copy (2-byte; low byte at 402AH, high byte at 402BH)
402BHPrinter characters-per-line (WIDTH) setting (9–255)
41F8HRS-232 configuration word (2-byte): low byte contains baud rate index + word length/stop/parity flags; high byte contains additional flags
41F9HRS-232 configuration word high byte
41FAHRS-232 WAIT/NOWAIT flag (00H = NOWAIT, FFH = WAIT)

Self-Modifying Code Locations:

AddressDescription
4D37HOperand byte inside the LD HL,0000H instruction at 4D36H; patched with the LINES parameter value during FORMS processing
4D42HOperand byte inside the LD HL,0000H instruction at 4D40H; patched with the WIDTH parameter value during FORMS processing
4DF9HTwo-byte location inside the LD HL,0000H instruction at 4DF8H; patched with the RS-232 configuration word during SETCOM processing
4E02HOperand byte inside the LD A,00H instruction at 4E01H; patched with the WAIT/NOWAIT flag during SETCOM processing
4F81HOperand byte inside the OR 00H instruction at 4F80H; patched with 2CH (ASCII comma) after the first parameter is printed, so subsequent parameters are comma-separated

Subroutine References (in SYS0):

AddressDescription
4409HDOS error handler entry point; called with error code in Register A
4C6AHKeyword scanner setup; initializes parsing state for command-line keyword matching
4C7AHKeyword parser; parses the next keyword=value pair from the command line. Returns: Carry set = end of input; Zero set = no keyword found; NZ = keyword matched with value in registers

ROM References:

AddressDescription
0033HROM character output routine; displays the character in Register A at the current cursor position and advances the cursor
005AHROM routine; called by SETCOM after storing default RS-232 parameters to reinitialize the serial port hardware

Major Routine Reference

Command Handlers:

AddressDescription
4D00HSYS15 entry point / command dispatcher. Register A contains the command code (F1H for FORMS or SETCOM); Register C contains the sub-command index (1 = FORMS, 2 = SETCOM). Dispatches to the appropriate handler.
4D11HFORMS command handler. Parses WIDTH and LINES parameters from the command line, updates printer configuration variables at 4028H and 402BH, then displays current settings.
4D70HSETCOM command handler. Parses RS-232 parameters (WORD, BAUD, STOP, PARITY, WAIT, NOWAIT, OFF) from the command line, updates configuration at 41F8H–41FAH, then displays current settings.

Shared Parsing Infrastructure:

AddressDescription
4EE7HKeyword parser engine. Register D = 03H (max keywords per pass). Register BC = pointer to keyword table. Scans the command line for keywords matching the table entries, dispatches to the handler address stored in the table for each matched keyword.
4F0FHKeyword string scanner. Called by 4EE7H. Uses the SYS0 routine at 4C6AH to scan ahead through the command line, skipping NUL-delimited keyword names and counting through parameter records to find a match.
4F26HNumeric parameter value parser entry. Sets up the base (decimal or hex) then calls 4F49H to convert an ASCII number string from the command line into a 16-bit binary value in Register Pair DE.
4F49HMulti-base ASCII-to-binary converter. Converts a decimal or hexadecimal ASCII string pointed to by Register Pair HL into a 16-bit value in Register Pair DE. Register B bit 0 controls hex mode (1 = hex allowed).

Display Routines:

AddressDescription
4F7FHParameter display initiator. Manages comma separation between displayed parameters using self-modifying code at 4F81H. Calls 4FCBH to print a string of characters.
4F93HNumeric value display. Register A (via E) contains the value to display. Register Pair HL points to a label string. Prints the label followed by the formatted decimal number.
4F96HNumeric value display (alternate entry). Register Pair DE contains the 16-bit value to display. Register Pair HL points to a label string.
4F99HBinary-to-decimal ASCII conversion and output. Converts the 16-bit value in Register Pair DE into up to 5 decimal digits and prints them, suppressing leading zeros.
4FCBHCharacter output wrapper. Saves Register Pairs DE and AF, calls ROM routine at 0033H to display the character in Register A, then restores registers and returns.

Disassembly

4D00H – SYS15 Entry Point / Command Dispatcher

Entry point for SYS15/SYS. The DOS command processor has already identified that the user entered a SYS15 command and loaded the overlay into memory. Register A contains F1H (the SYS15 module identifier) and Register C contains the sub-command index: 1 for FORMS, 2 for SETCOM. This dispatcher validates the module code and routes execution to the correct command handler.

When execution reaches 4D00H, the DOS command processor has set up: Register A = command module identifier (expected F1H for SYS15), Register C = sub-command number (1 = FORMS, 2 = SETCOM), and Register Pair HL = pointer to the remainder of the command line after the command name.

4D00
CP F1H FE F1
Compare Register A (the module identifier passed by the DOS command processor) against F1H (the expected identifier for SYS15). If Register A equals F1H, the Z FLAG is set, confirming this is the correct overlay module; otherwise the NZ FLAG is set, indicating a mismatch.
4D02
If the NZ FLAG has been set (Register A did not contain F1H, meaning the wrong overlay module was loaded), JUMP forward to 4D0CH to report error code 2AH (general error).
4D04
DEC C 0D
DECrement Register C (the sub-command number) by 1. If Register C was 1 (FORMS), it becomes 0 and the Z FLAG is set. If Register C was 2 (SETCOM), it becomes 1 and the NZ FLAG is set.
4D05
If the Z FLAG has been set (Register C was 1, meaning the user entered the FORMS command), JUMP to 4D11H to begin FORMS command processing.
4D08
DEC C 0D
DECrement Register C by 1 again. If Register C was 1 (meaning original value was 2 = SETCOM), it becomes 0 and the Z FLAG is set. Any other value produces NZ FLAG.
4D09
If the Z FLAG has been set (Register C was 2, meaning the user entered the SETCOM command), JUMP to 4D70H to begin SETCOM command processing.

If execution falls through to here, neither FORMS nor SETCOM was identified. This means the sub-command index in Register C was neither 1 nor 2, indicating an invalid command code.

4D0C
LD A,2AH 3E 2A
Load Register A with 2AH (decimal 42), which is the NEWDOS/80 error code for "general error." This error will be passed to the DOS error handler.
4D0E
JUMP to 4F23H, which loads error code 34H (parse error) into Register A and then jumps to the DOS error handler at 4409H. Note: The error code 2AH loaded at 4D0CH into Register A is overridden by the code at 4F23H which replaces it with 34H before calling the error handler.

4D11H - FORMS Command Handler

Handles the FORMS command, which sets and displays printer parameters. Register Pair HL points to the remainder of the command line. The FORMS command accepts two optional keyword parameters: WIDTH=xxx (characters per line, 9-255) and LINES=yyy (lines per page, 1-254, where 254 = unlimited). If no parameters are given (just a bare ENTER), the command skips directly to displaying the current values. The keyword parsing is handled by the shared keyword parser at 4EE7H, which uses the keyword table at 4D5BH.

When execution arrives here from the dispatcher at 4D05H, Register Pair HL points to the user's command line text following the FORMS command name. Register C has been decremented to 0 (confirming FORMS). The code first checks whether there are any parameters at all.

4D11
LD A,(HL) 7E
Load Register A with the byte at the memory address pointed to by Register Pair HL (the current position in the command line buffer). This fetches the next character of user input to determine if parameters were provided or if the line ends immediately.
4D12
CP 0DH FE 0D
Compare Register A (the character just fetched from the command line) against 0DH (ASCII carriage return, the line terminator). If Register A equals 0DH, the Z FLAG is set, meaning the user typed FORMS with no parameters; otherwise the NZ FLAG is set, meaning parameters follow.
4D14
If the Z FLAG has been set (the command line is just a carriage return, meaning the user typed FORMS with no parameters), JUMP forward to 4D46H to skip parameter parsing and go directly to displaying the current printer settings.

The command line has parameters. Before invoking the keyword parser, the code saves the current WIDTH value into the self-modifying instruction at 4D42H. This is done so that if the user only specifies one parameter (e.g., only WIDTH or only LINES), the other parameter retains its current value.

4D16
LD A,(402BH) 3A 2B 40
Load Register A with the byte at address 402BH, which is the current printer characters-per-line (WIDTH) setting stored by the DOS. This value will be preserved as the default in case the user does not specify a new WIDTH.
4D19
LD (4D42H),A 32 42 4D
Store Register A (the current WIDTH value from 402BH) into memory location 4D42H. This is the third operand byte of the LD HL,0000H instruction at 4D40H, patching it so that the high byte of HL (Register H) will contain the current WIDTH value when that instruction executes later. [SELF-MODIFYING CODE]
4D1C
LD BC,4D5BH 01 5B 4D
Load Register Pair BC with 4D5BH, which is the address of the FORMS keyword table. This table contains the keyword definitions for WIDTH and LINES, including their ASCII names, validation ranges, and handler addresses. Register Pair BC will be passed to the keyword parser at 4EE7H.
4D1F
JUMP to the shared keyword parser engine at 4EE7H. The parser will scan the command line (pointed to by HL) for keywords matching the table at 4D5BH (pointed to by BC). When a keyword match is found, the parser dispatches to the handler address stored in the keyword table entry. For FORMS, the WIDTH handler returns to 4D22H and the LINES handler returns to 4D27H (these addresses are embedded in the keyword table).

The keyword parser at 4EE7H processes the command line and, when it matches a keyword, calls the handler routine associated with that keyword. For the FORMS WIDTH keyword, the handler returns to 4D22H with the parsed numeric value in Register A. For the FORMS LINES keyword, the handler returns to 4D27H.

4D22
LD (4D42H),A 32 42 4D
Store Register A (the user-specified WIDTH value returned by the keyword parser) into memory location 4D42H, overwriting the default that was saved at 4D19H. This patches the operand of the LD HL,0000H instruction at 4D40H so that Register H will load the new WIDTH value. [SELF-MODIFYING CODE]
4D25
JUMP forward unconditionally to 4D30H to continue parsing the command line for additional keywords (the user may have specified both WIDTH and LINES).

The LINES keyword handler entry point follows. When the keyword parser matches LINES and parses its numeric value, execution arrives at 4D27H with the parsed value in Register A.

4D27
INC A 3C
INCrement Register A (the parsed LINES value) by 1. If Register A was FFH (255, which is out of the valid range 1-254), incrementing wraps it to 00H and sets the Z FLAG. This serves as a validity check for the LINES parameter.
4D28
If the NZ FLAG has been set (Register A after increment was not zero, meaning the original parsed value was valid and not FFH), JUMP forward to 4D2DH to store the new LINES value.
4D2A
LD A,(4028H) 3A 28 40
Load Register A with the byte at address 4028H, which is the current printer lines-per-page setting stored by the DOS. Since the user-specified value was invalid (FFH), the code falls back to keeping the current LINES value unchanged.
4D2D
LD (4D37H),A 32 37 4D
Store Register A (the validated LINES value, either user-specified or the current default from 4028H) into memory location 4D37H. This patches the second operand byte of the LD HL,0000H instruction at 4D36H so that Register H will contain the LINES value when that instruction executes. [SELF-MODIFYING CODE]

Fall through to 4D30H to continue parsing for more keywords.

4D30
GOSUB to the SYS0 keyword parser at 4C7AH to continue scanning the command line for additional keyword=value pairs. Returns: Carry flag set = end of command line reached; Z flag set with Carry clear = keyword not found but more input remains; NZ flag = keyword matched with value in registers.
4D33
RET C D8
If the CARRY FLAG has been set (the keyword parser reached the end of the command line with no more input), RETURN to the caller. This exits the parsing loop when all parameters have been processed.
4D34
If the NZ FLAG has been set (the keyword parser found another keyword match), JUMP back to 4D1CH to reload Register Pair BC with the keyword table address and re-enter the keyword parser at 4EE7H for the next parameter. [LOOP — returns to keyword parsing]

If execution falls through (Z flag set with Carry clear: no keyword matched but not end of line), the code below applies the parsed parameter values to the DOS system variables and then displays the results.

4D36
LD HL,0000H 21 00 00
Load Register Pair HL with the immediate value 0000H. HOWEVER, the byte at 4D37H (the second operand byte, which loads into Register H) has been patched by self-modifying code at 4D2DH with the LINES value. So Register H actually receives the LINES parameter value, and Register L receives 00H. [SELF-MODIFYING CODE at 4D37H]
4D39
LD A,L 7D
Load Register A with the contents of Register L (the low byte of HL from the instruction at 4D36H, which is 00H). This tests whether a value was patched into the low byte.
4D3A
OR A B7
OR Register A with itself. This sets the Z FLAG if Register A is zero. Since Register L is always 00H (only the high byte at 4D37H is patched), the Z FLAG is always set here.
4D3B
If the Z FLAG has been set (Register L is zero, which is always the case), JUMP forward to 4D40H, skipping the store to 4028H.
4D3D
LD (4028H),HL 22 28 40
Store Register Pair HL into the two-byte location at 4028H-4029H, which would update the DOS printer lines-per-page setting. This instruction is never reached in normal operation because the JR Z at 4D3BH always jumps past it.
4D40
LD HL,0000H 21 00 00
Load Register Pair HL with the immediate value 0000H. HOWEVER, the byte at 4D42H (the third operand byte, which loads into Register H) has been patched by self-modifying code at 4D19H or 4D22H with the WIDTH value. So Register H actually receives the WIDTH parameter value, and Register L receives 00H. [SELF-MODIFYING CODE at 4D42H]
4D43
LD (402AH),HL 22 2A 40
Store Register Pair HL into the two-byte location at 402AH-402BH. The low byte (Register L = 00H) goes to 402AH; the high byte (Register H = WIDTH value) goes to 402BH, which is the DOS printer characters-per-line setting. This updates the WIDTH parameter in the system variables.

[DISPLAY SECTION] The parameter values have been applied (or no changes were made if the user typed bare FORMS). Now display the current printer settings by reading the live values from the DOS variables and formatting them for output.

4D46
LD A,(402BH) 3A 2B 40
Load Register A with the byte at address 402BH, which is the current printer WIDTH (characters-per-line) setting. This is the value that will be displayed to the user.
4D49
LD HL,4D5BH 21 5B 4D
Load Register Pair HL with 4D5BH, which points to the FORMS keyword table. The first entry in this table begins with the ASCII string "WIDTH=" which the display routine at 4F93H will use as the label when printing the parameter value.
4D4C
GOSUB to the numeric value display routine at 4F93H. Register A contains the WIDTH value (from 402BH) and Register Pair HL points to the label string at 4D5BH ("WIDTH="). The routine prints the label followed by the decimal representation of the WIDTH parameter value.
4D4F
LD A,(4028H) 3A 28 40
Load Register A with the byte at address 4028H, which is the current printer LINES (lines-per-page) setting. This is the second parameter value to display.
4D52
LD HL,4D65H 21 65 4D
Load Register Pair HL with 4D65H, which points to the second keyword entry in the FORMS table - the ASCII string "LINES=" followed by control bytes. This will be used as the label for the lines-per-page display.
4D55
DEC A 3D
DECrement Register A (the LINES value from 4028H) by 1. The display routine at 4F93H adds 1 back during its conversion process, so this pre-decrement compensates for that offset, ensuring the correct value is displayed.
4D56
GOSUB to the numeric value display routine at 4F93H. Register A contains the adjusted LINES value (decremented by 1) and Register Pair HL points to the label string at 4D65H ("LINES="). The routine prints the label followed by the decimal value.
4D59
XOR A AF
Exclusive-OR Register A with itself, setting Register A to 00H and clearing all flags. A return value of 00H in Register A signals to the DOS command processor that the command completed successfully with no errors.
4D5A
RET C9
RETURN to the DOS command processor. The FORMS command has completed - parameters have been updated (if any were specified) and the current values have been displayed. Register A = 00H indicates success.

4D5BH - FORMS Keyword Table (Data Area)

This is a data area, not executable code. It contains the keyword definition table used by the keyword parser at 4EE7H when processing the FORMS command. Each keyword entry consists of: an ASCII keyword name (NUL-terminated), a flags/range byte, and a 2-byte handler return address (little-endian).

FORMS Keyword Table Structure:

Entry 1 - WIDTH keyword (4D5BH-4D64H):

4D5BH-4D60H57 49 44 54 48 3D = ASCII "WIDTH="
4D61H00 = NUL terminator for keyword name
4D62HA0 = Flags byte. Bit 7 is set (80H flag) indicating this keyword accepts a numeric parameter. Bit 5 set (20H) provides additional range/type information.
4D63H-4D64H22 4D = Handler return address 4D22H (little-endian). When WIDTH is matched, execution dispatches to 4D22H.

Entry 2 - LINES keyword (4D65H-4D6FH):

4D65H-4D6AH4C 49 4E 45 53 3D = ASCII "LINES=" (note: 4D64H contains 4CH which is both the high byte of the previous entry's address and the ASCII "L" starting LINES)
4D6BH00 = NUL terminator for keyword name
4D6CHA0 = Flags byte (same structure as WIDTH entry).
4D6DH-4D6EH27 4D = Handler return address 4D27H (little-endian). When LINES is matched, execution dispatches to 4D27H.
4D6FH00 = End-of-table marker.
4D5B
DEFM "WIDTH=" + 00H 57 49 44 54 48 3D 00
This is the first keyword name in the FORMS keyword table.
4D62
DEFB A0
Keyword parameter flags byte: A0H. Bit 7 set (1) indicates this keyword requires a numeric value parameter. Bit 5 set (1) provides range/validation information for the WIDTH parameter.
4D63
DEFW 22 4D
Handler return address for the WIDTH keyword: 4D22H (stored little-endian as 22H, 4DH).
4D65
DEFM "LINES=" + 00H 4C 49 4E 45 53 3D 00
Another keyword
4D6C
DEFB A0
Keyword parameter flags byte: A0H. Same structure as the WIDTH entry - bit 7 set indicates a numeric value parameter is required.
4D6D
DEFW 27 4D
Handler return address for the LINES keyword: 4D27H (stored little-endian as 27H, 4DH). When the keyword parser matches LINES and parses the numeric value, it dispatches execution to 4D27H.
4D6F
DEFB 00
End-of-table marker: 00H. A NUL byte here signals to the keyword parser that there are no more keyword entries in the FORMS table.

4D70H - SETCOM Command Handler

Handles the SETCOM command, which configures and displays RS-232 serial interface parameters. Register Pair HL points to the remainder of the command line. SETCOM accepts optional keyword parameters: WORD=wl (5-8 bits per byte), BAUD=br (50-19200), STOP=sb (1-2 stop bits), PARITY=pp (1=odd, 2=even, 3=none), WAIT, NOWAIT, and OFF. If no parameters are given, the command displays the current RS-232 state. The RS-232 configuration is stored as a packed bit field in the two-byte value at 41F8H-41F9H, with the WAIT/NOWAIT flag at 41FAH. Before parsing, the code copies the current RS-232 configuration into self-modifying code locations at 4DF9H and 4E02H so that unchanged parameters retain their current values.

When execution arrives here from the dispatcher at 4D09H, Register Pair HL points to the user's command line text following the SETCOM command name. The code first checks whether parameters were provided.

4D70
LD A,(HL) 7E
Load Register A with the byte at the memory address pointed to by Register Pair HL (the current position in the command line buffer). This fetches the next character of user input to determine if parameters follow the SETCOM command name.
4D71
CP 0DH FE 0D
Compare Register A (the character just fetched from the command line) against 0DH (ASCII carriage return, the line terminator). If Register A equals 0DH, the Z FLAG is set, meaning the user typed SETCOM with no parameters; otherwise the NZ FLAG is set, meaning parameters follow.
4D73
If the Z FLAG has been set (the user typed bare SETCOM with no parameters), JUMP to 4E0FH to skip all parameter parsing and go directly to displaying the current RS-232 state.

Parameters were provided. Before invoking the keyword parser, the code copies the current RS-232 configuration from the DOS system variables into the self-modifying code locations. This preserves any parameters the user does not explicitly change.

4D76
LD DE,(41F8H) ED 5B F8 41
Load Register Pair DE with the 16-bit value at address 41F8H-41F9H, which is the current RS-232 configuration word stored by the DOS. Register E receives the low byte from 41F8H (baud rate index in bits 0-3, word length encoding in bits 5-6) and Register D receives the high byte from 41F9H (additional configuration flags including stop bits and parity).
4D7A
LD (4DF9H),DE ED 53 F9 4D
Store Register Pair DE (the current RS-232 configuration word) into memory locations 4DF9H-4DFAH. These are the operand bytes of the LD HL,0000H instruction at 4DF8H: 4DF9H is patched with the low byte (Register E) and 4DFAH with the high byte (Register D). This preserves the current configuration as the default for any parameters the user does not change. [SELF-MODIFYING CODE]
4D7E
LD A,(41FAH) 3A FA 41
Load Register A with the byte at address 41FAH, which is the current RS-232 WAIT/NOWAIT flag (00H = NOWAIT mode, FFH = WAIT mode).
4D81
LD (4E02H),A 32 02 4E
Store Register A (the current WAIT/NOWAIT flag from 41FAH) into memory location 4E02H. This is the operand byte of the LD A,00H instruction at 4E01H, patching it to preserve the current WAIT state. [SELF-MODIFYING CODE]
4D84
LD BC,4E87H 01 87 4E
Load Register Pair BC with 4E87H, which is the address of the SETCOM keyword table. This table contains keyword definitions for OFF, WORD, BAUD, STOP, PARITY, WAIT, and NOWAIT, including their ASCII names and handler addresses. Register Pair BC will be passed to the keyword parser at 4EE7H.
4D87
JUMP to the shared keyword parser engine at 4EE7H. The parser will scan the command line for keywords matching the SETCOM table at 4E87H and dispatch to the appropriate handler when a match is found.

SETCOM WORD= Keyword Handler (4D8AH): Execution arrives here when the keyword parser has matched the WORD keyword and parsed the numeric value. Register A contains the parsed WORD length value. Valid values are 5, 6, 7, or 8, representing the number of data bits per transmitted byte. The value must be converted into the RS-232 configuration bit field encoding used by the Model III hardware: the word length is stored in bits 5-6 of the configuration byte at 4DFAH. The encoding maps 5→00, 6→01, 7→10, 8→11 in the bit field, but with an XOR adjustment for the parity/overflow flag behavior.

4D8A
SUB 05H D6 05
SUBtract 05H from Register A (the parsed WORD value). This converts the user-entered value (5-8) into a zero-based index (0-3). If the user entered 5, Register A becomes 0; if 6, becomes 1; if 7, becomes 2; if 8, becomes 3. Values outside 5-8 will produce results outside 0-3.
4D8C
CP 09H FE 09
Compare Register A (the zero-based WORD index) against 09H. If Register A is 09H or greater, the CARRY FLAG is clear (NC), indicating a value far outside the valid range. This also catches the case where the original parsed value was less than 5 (which would have produced a negative result wrapping to a large unsigned value after the SUB).
4D8E
If the NO CARRY FLAG has been set (Register A >= 09H, meaning the parsed value was not in the valid range for any SETCOM parameter), JUMP to 4F44H to report error code 2FH (invalid parameter value). [ERROR PATH]
4D91
OR A B7
OR Register A with itself. This sets flags based on the value: the Z FLAG is set if Register A is 0, and importantly the P/V FLAG (parity/overflow) is set based on the parity of Register A's bits. The P/V flag is used by the next instruction to determine the encoding adjustment.
4D92
If the P/V FLAG indicates even parity (PE), JUMP forward to 4D97H, skipping the XOR correction. Even parity means the value already has the correct encoding for the RS-232 register. For WORD values: 0 (from 5) has even parity and 3 (from 8) has even parity, so they skip the XOR; 1 (from 6) and 2 (from 7) have odd parity and need the XOR adjustment.
4D95
XOR 03H EE 03
Exclusive-OR Register A with 03H. This flips bits 0 and 1 of the zero-based word-length index. For value 1 (WORD=6), XOR 03H produces 2; for value 2 (WORD=7), XOR 03H produces 1. This maps the user's logical word length ordering into the hardware's bit encoding: 5→00, 6→10, 7→01, 8→11.
4D97
RRCA 0F
Rotate Register A right through bit 0 into the Carry flag and bit 7 receives the old bit 0. First of three right-rotations to shift the 2-bit word length encoding from bits 0-1 into bits 5-6, which is where the Model III RS-232 hardware expects the word length field.
4D98
RRCA 0F
Rotate Register A right again. Second rotation continues moving the word length bits toward their final position in bits 5-6.
4D99
RRCA 0F
Rotate Register A right a third time. After three RRCA operations, the 2-bit word length encoding has been shifted from bits 0-1 into bits 5-6 of Register A. The remaining bits of Register A are zero (or contain rotated-in bits that will be masked off).
4D9A
LD C,A 4F
Load Register C with Register A (the word length encoding now positioned in bits 5-6). Register C will be used to merge this value into the RS-232 configuration byte.
4D9B
PUSH HL E5
Save Register Pair HL (the command line pointer) onto the stack. HL will be temporarily used to point to the RS-232 configuration byte at 4DFAH.
4D9C
LD HL,4DFAH 21 FA 4D
Load Register Pair HL with 4DFAH, which points to the high byte of the self-modifying RS-232 configuration word (the third operand byte of the LD HL,0000H instruction at 4DF8H). This byte contains the word length, stop bits, and parity fields.
4D9F
LD A,(HL) 7E
Load Register A with the byte at the address pointed to by Register Pair HL (4DFAH), which is the current RS-232 configuration high byte containing the existing word length, stop bits, and parity settings.
4DA0
AND 9FH E6 9F
AND Register A with 9FH (binary 10011111). This clears bits 5 and 6 of the configuration byte, which are the word length field, while preserving all other bits (stop bits in bit 3-4, parity in bit 7, etc.).
4DA2
OR C B1
OR Register A with Register C (the new word length encoding in bits 5-6). This merges the new word length value into the configuration byte, replacing the old word length while preserving stop bits and parity settings.
4DA3
LD (HL),A 77
Store Register A (the updated RS-232 configuration byte with the new word length) back to the address pointed to by Register Pair HL (4DFAH). This updates the self-modifying code so the new word length will be applied when the configuration is written to hardware. [SELF-MODIFYING CODE]
4DA4
JUMP forward unconditionally to 4DE7H, the common keyword handler exit point, which pops Register Pair HL (command line pointer) from the stack and continues parsing for more keywords.

SETCOM BAUD= Keyword Handler (4DA6H): Execution arrives here when the keyword parser has matched the BAUD keyword and parsed the numeric value. Register Pair DE contains the parsed baud rate value (e.g., 300, 9600, 19200). The code must look up this value in the baud rate table at 4EC7H to find the corresponding baud rate index (0-15) for the RS-232 hardware register.

4DA6
PUSH HL E5
Save Register Pair HL (the command line pointer) onto the stack. HL will be temporarily used to scan through the baud rate lookup table.
4DA7
Load Register Pair HL with 4EC7H, which points to the baud rate lookup table. This table contains 16 two-byte entries, each holding a baud rate value in little-endian format (50, 75, 110, 134, 150, 300, 600, 1200, 1800, 2000, 2400, 3600, 4800, 7200, 9600, 19200).
4DAA
XOR A AF
Exclusive-OR Register A with itself, setting Register A to 00H. Register A will serve as the baud rate index counter, starting at 0 for the first table entry.

[LOOP START — Baud rate table search] This loop scans the baud rate table, comparing each entry against the user's requested baud rate in Register Pair DE. Register A is the index counter (incremented by 11H each iteration to encode the baud rate index in the RS-232 config format).

4DAB
LD C,(HL) 4E
Load Register C with the low byte of the current baud rate table entry, pointed to by Register Pair HL.
4DAC
INC HL 23
INCrement Register Pair HL by 1 to point to the high byte of the current baud rate table entry.
4DAD
LD B,(HL) 46
Load Register B with the high byte of the current baud rate table entry. Register Pair BC now contains the baud rate value from the table (e.g., 0032H = 50, 012CH = 300, 4B00H = 19200).
4DAE
INC HL 23
INCrement Register Pair HL by 1 to point to the next baud rate table entry, ready for the next iteration if this entry does not match.
4DAF
EX DE,HL EB
Exchange Register Pairs DE and HL. Register Pair HL now contains the user's requested baud rate value (was in DE), and Register Pair DE now contains the table pointer (was in HL). This swap is needed because the SBC instruction operates on HL.
4DB0
OR A B7
OR Register A with itself to clear the Carry flag. The SBC instruction that follows subtracts with carry, so the Carry must be clear to perform a simple subtraction for comparison.
4DB1
SBC HL,BC ED 42
SUBtract Register Pair BC (the baud rate table entry value) from Register Pair HL (the user's requested baud rate) with borrow. If the values are equal, the result is 0 and the Z FLAG is set. This is a non-destructive comparison because the next instruction restores HL.
4DB3
ADD HL,BC 09
ADD Register Pair BC back to Register Pair HL, restoring HL to the original user baud rate value. The Z FLAG from the SBC is preserved by ADD HL,BC (ADD HL,rr does not affect the Z flag).
4DB4
EX DE,HL EB
Exchange Register Pairs DE and HL again, restoring the original arrangement: DE = user's baud rate, HL = table pointer.
4DB5
If the Z FLAG has been set (the baud rate table entry matches the user's requested baud rate), JUMP forward to 4DBEH to store the matched baud rate index. [MATCH FOUND — exit loop]
4DB7
ADD 11H C6 11
ADD 11H (decimal 17) to Register A (the baud rate index counter). The baud rate index is encoded in the RS-232 configuration register with a spacing of 11H between consecutive entries, so each loop iteration advances the index by 11H.
4DB9
If the NO CARRY FLAG has been set (Register A has not overflowed past FFH, meaning there are more table entries to check), JUMP back to 4DABH to compare the next baud rate table entry. [LOOP — continue searching]
4DBB
If execution reaches here, the loop overflowed (Carry was set by ADD 11H), meaning all 16 baud rate table entries have been checked without finding a match. JUMP to 4F44H to report error code 2FH (invalid parameter value). The user entered a baud rate that is not one of the 16 supported values. [ERROR PATH]

[LOOP END — Baud rate found] The matching baud rate was found. Register A contains the encoded baud rate index (multiples of 11H: 00H, 11H, 22H, ... FFH for the 16 entries).

4DBE
LD (4DF9H),A 32 F9 4D
Store Register A (the encoded baud rate index) into memory location 4DF9H. This is the second operand byte of the LD HL,0000H instruction at 4DF8H, patching it so that Register L will contain the baud rate index when the instruction executes. [SELF-MODIFYING CODE]
4DC1
JUMP forward unconditionally to 4DE7H, the common keyword handler exit point, to pop Register Pair HL and continue parsing.

SETCOM STOP= Keyword Handler (4DC3H): Execution arrives here when the keyword parser has matched the STOP keyword and parsed the numeric value. Register A contains the parsed stop bits value. Valid values are 1 (one stop bit) or 2 (two stop bits). The stop bit setting is stored in bit 4 of the configuration byte at 4DFAH: bit 4 clear = 1 stop bit, bit 4 set = 2 stop bits.

4DC3
PUSH HL E5
Save Register Pair HL (the command line pointer) onto the stack.
4DC4
LD HL,4DFAH 21 FA 4D
Load Register Pair HL with 4DFAH, pointing to the high byte of the self-modifying RS-232 configuration word, which contains the word length, stop bits, and parity fields.
4DC7
RES 4,(HL) CB A6
Reset (clear) bit 4 of the byte at the address pointed to by Register Pair HL (4DFAH). This sets the stop bits field to "1 stop bit" as the default. If the user specified STOP=2, the next instructions will set bit 4 back.
4DC9
DEC A 3D
DECrement Register A (the parsed STOP value) by 1. If the user specified STOP=1, Register A becomes 0 and the Z FLAG is set. If the user specified STOP=2, Register A becomes 1 and the NZ FLAG is set.
4DCA
If the Z FLAG has been set (user specified STOP=1), JUMP to 4DE7H. Bit 4 has already been cleared at 4DC7H, so the configuration is correct for 1 stop bit. [SUCCESS PATH — 1 stop bit]
4DCC
SET 4,(HL) CB E6
Set bit 4 of the byte at the address pointed to by Register Pair HL (4DFAH). This changes the stop bits field to "2 stop bits."
4DCE
DEC A 3D
DECrement Register A by 1 again. If the user specified STOP=2, Register A (which was 1 after the first DEC) becomes 0 and the Z FLAG is set. Any other value means the STOP parameter was out of range.
4DCF
JUMP forward unconditionally to 4DE5H, which checks whether Register A is zero (valid STOP value) or non-zero (invalid value, leading to an error).

SETCOM PARITY= Keyword Handler (4DD1H): Execution arrives here when the keyword parser has matched the PARITY keyword and parsed the numeric value. Register A contains the parsed parity value: 1 = odd parity, 2 = even parity, 3 = no parity. The parity setting uses two bits of the configuration byte at 4DFAH: bit 3 (parity enable) and bit 7 (even/odd select).

4DD1
PUSH HL E5
Save Register Pair HL (the command line pointer) onto the stack.
4DD2
LD HL,4DFAH 21 FA 4D
Load Register Pair HL with 4DFAH, pointing to the high byte of the self-modifying RS-232 configuration word.
4DD5
SET 3,(HL) CB DE
Set bit 3 of the byte at the address pointed to by Register Pair HL (4DFAH). Bit 3 is the "parity enable" flag. This enables parity as the default assumption; if the user specified PARITY=3 (no parity), the code below will clear this bit.
4DD7
SUB 03H D6 03
SUBtract 03H from Register A (the parsed PARITY value). If the user entered 3 (no parity), Register A becomes 0 and the Z FLAG is set. If 1 (odd parity), Register A becomes FEH (-2). If 2 (even parity), Register A becomes FFH (-1).
4DD9
If the Z FLAG has been set (user specified PARITY=3, meaning no parity), JUMP to 4DE7H. Bit 3 has been set at 4DD5H but this is actually incorrect for "no parity" — however, examining the hardware documentation, bit 3 set with specific other bit configurations may encode "no parity" in this context. [PATH — no parity]
4DDB
RES 3,(HL) CB 9E
Reset (clear) bit 3 of the byte at the address pointed to by Register Pair HL (4DFAH). For PARITY=1 (odd) or PARITY=2 (even), bit 3 is cleared.
4DDD
SET 7,(HL) CB FE
Set bit 7 of the byte at the address pointed to by Register Pair HL (4DFAH). Bit 7 is the parity type selector. Setting it selects even parity as the initial assumption.
4DDF
INC A 3C
INCrement Register A by 1. If the user specified PARITY=2 (even parity), Register A was FFH (-1) after the SUB, and becomes 00H with the Z FLAG set. If PARITY=1 (odd parity), Register A was FEH and becomes FFH, NZ FLAG set.
4DE0
If the Z FLAG has been set (user specified PARITY=2, even parity), JUMP to 4DE7H. Bit 7 has been set (even parity) and bit 3 cleared, which is the correct configuration for even parity. [PATH — even parity]
4DE2
RES 7,(HL) CB BE
Reset (clear) bit 7 of the byte at the address pointed to by Register Pair HL (4DFAH). This clears the even parity selector, leaving odd parity selected (bit 7 = 0, bit 3 = 0).
4DE4
INC A 3C
INCrement Register A by 1 again. If the user specified PARITY=1 (odd parity), Register A was FFH and becomes 00H with the Z FLAG set. Any other value remains non-zero.
4DE5
If the NZ FLAG has been set (Register A is not zero, meaning the parsed parameter value was outside the valid range), JUMP to 4DBBH which jumps to 4F44H to report error code 2FH (invalid parameter value). [ERROR PATH — invalid value]

Common Keyword Handler Exit (4DE7H): All SETCOM keyword handlers (WORD, BAUD, STOP, PARITY, WAIT, NOWAIT) jump here after successfully processing their parameter. This restores the command line pointer and continues parsing.

4DE7
POP HL E1
Restore Register Pair HL (the command line pointer) from the stack. HL was pushed at the beginning of each keyword handler to allow HL to be temporarily used for other purposes.
4DE8
JUMP forward unconditionally to 4DF2H to continue scanning the command line for additional keyword parameters.

4DEAH - SETCOM WAIT / NOWAIT / OFF Handlers and Configuration Apply

This section contains the WAIT and NOWAIT keyword handlers, the OFF keyword handler entry at 4E08H, the keyword parsing loop continuation, and the code that applies the parsed RS-232 configuration to the DOS system variables and hardware. After all parameters have been parsed, the configuration stored in the self-modifying instructions at 4DF8H and 4E01H is written to the system variables at 41F8H-41FAH and the RS-232 hardware is reinitialized via the ROM routine at 005AH. Finally, the current RS-232 state is displayed to the user.

SETCOM WAIT Keyword Handler (4DEAH): Execution arrives here when the keyword parser has matched the WAIT keyword (a keyword with no "=value" parameter). The WAIT flag is stored as FFH at 4E02H (the operand byte of the self-modifying instruction at 4E01H).

4DEA
LD A,FFH 3E FF
Load Register A with FFH, which represents WAIT mode enabled. The WAIT/NOWAIT flag uses FFH for WAIT and 00H for NOWAIT.
4DEC
JUMP forward unconditionally to 4DEFH to store the WAIT flag value into the self-modifying code location at 4E02H.

SETCOM NOWAIT Keyword Handler (4DEEH): Execution arrives here when the keyword parser has matched the NOWAIT keyword.

4DEE
XOR A AF
Exclusive-OR Register A with itself, setting Register A to 00H, which represents NOWAIT mode. Falls through to 4DEFH to store this value.
4DEF
LD (4E02H),A 32 02 4E
Store Register A (FFH for WAIT or 00H for NOWAIT) into memory location 4E02H. This is the operand byte of the LD A,00H instruction at 4E01H, patching it so that Register A will load the correct WAIT/NOWAIT flag when that instruction executes. [SELF-MODIFYING CODE]

Keyword Parse Loop Continuation (4DF2H): After each keyword handler stores its value, execution arrives here to check for more keywords on the command line.

4DF2
GOSUB to the SYS0 keyword parser at 4C7AH to continue scanning the command line for additional keyword=value pairs. Returns: Carry flag set = end of command line reached; NZ flag = another keyword was matched; Z flag with Carry clear = no keyword found but more input remains.
4DF5
RET C D8
If the CARRY FLAG has been set (the keyword parser reached the end of the command line with no more input), RETURN to the caller. This exits the parsing loop.
4DF6
If the NZ FLAG has been set (the keyword parser found and matched another keyword), JUMP back to 4D84H to reload Register Pair BC with the SETCOM keyword table address at 4E87H and re-enter the keyword parser at 4EE7H for the next parameter. [LOOP — returns to keyword parsing]

Apply RS-232 Configuration (4DF8H): All keyword parameters have been parsed. The self-modifying code locations now contain the final configuration values. The code reads them, performs final adjustments, and writes the configuration to the DOS system variables and hardware.

4DF8
LD HL,0000H 21 00 00
Load Register Pair HL with the immediate value 0000H. HOWEVER, the bytes at 4DF9H and 4DFAH have been patched by self-modifying code: 4DF9H (Register L) contains the encoded baud rate index, and 4DFAH (Register H) contains the packed word length / stop bits / parity configuration byte. [SELF-MODIFYING CODE at 4DF9H and 4DFAH]
4DFB
LD A,H 7C
Load Register A with the contents of Register H, which is the packed configuration byte containing word length (bits 5-6), stop bits (bit 4), parity enable (bit 3), and parity type (bit 7), as patched at 4DFAH.
4DFC
AND FCH E6 FC
AND Register A with FCH (binary 11111100). This clears bits 0 and 1 of the configuration byte, which are reserved or unused bits that must be zero before the configuration is written to the hardware.
4DFE
OR 04H F6 04
OR Register A with 04H (binary 00000100). This sets bit 2 of the configuration byte, which is a required flag for the RS-232 hardware initialization (it enables the RS-232 interface).
4E00
LD H,A 67
Load Register H with Register A (the adjusted configuration byte with bits 0-1 cleared and bit 2 set). Register Pair HL now contains the final RS-232 configuration word ready to be written to the system variables.
4E01
LD A,00H 3E 00
Load Register A with the immediate value 00H. HOWEVER, the byte at 4E02H has been patched by self-modifying code at 4D81H or 4DEFH with the WAIT/NOWAIT flag (FFH for WAIT, 00H for NOWAIT). [SELF-MODIFYING CODE at 4E02H]
4E03
GOSUB to 4E7EH, which stores Register Pair HL (the RS-232 configuration word) to the DOS system variable at 41F8H-41F9H, stores Register A (the WAIT/NOWAIT flag) to 41FAH, and then jumps to the ROM routine at 005AH to reinitialize the RS-232 hardware with the new settings.
4E06
JUMP forward unconditionally to 4E0FH to proceed to the display section, which shows the current RS-232 state to the user.

SETCOM OFF Keyword Handler (4E08H): Execution arrives here when the keyword parser has matched the OFF keyword. The OFF keyword disables the RS-232 interface entirely. The code calls the SYS0 parser once more to confirm no additional keywords follow (OFF must be the only parameter), then sets the RS-232 state to "off" (configuration = 0, flag = 0).

4E08
GOSUB to the SYS0 keyword parser at 4C7AH to scan for any additional keywords after OFF. The OFF keyword must be specified alone — no other parameters are allowed.
4E0B
RET NZ C0
If the NZ FLAG has been set (another keyword was found after OFF), RETURN immediately. This is an error exit — the DOS command processor will handle the unexpected keyword. The OFF parameter must be used alone with no other parameters.
4E0C
XOR A AF
Exclusive-OR Register A with itself, setting Register A to 00H. This zeroes the WAIT/NOWAIT flag as part of turning the RS-232 interface off.
4E0D
JUMP forward unconditionally to 4E13H, which enters the display path. With Register A = 00H, the Z flag is set, so the CALL Z at 4E14H will call the defaults reset routine at 4E79H, which zeroes the RS-232 configuration (turning it off) and reinitializes the hardware.

Display Section Entry (4E0FH): This is the common entry point for displaying the RS-232 state. When reached from the bare SETCOM path (no parameters), it loads the current configuration high byte from 41F9H. When reached from the OFF handler, Register A is already 00H.

4E0F
LD A,(41F9H) 3A F9 41
Load Register A with the byte at address 41F9H, which is the high byte of the current RS-232 configuration word. This byte contains the word length, stop bits, and parity settings. If the RS-232 interface is off, this byte is 00H.
4E12
OR A B7
OR Register A with itself. This sets the Z FLAG if Register A is zero (RS-232 is off or unconfigured), or clears it if non-zero (RS-232 is active with a valid configuration).
4E13
PUSH AF F5
Save Register A and the flags onto the stack. The Z flag state is preserved for later use: Z set means "RS-232 is off" and NZ means "RS-232 is active."
4E14
If the Z FLAG has been set (RS-232 is off or being turned off), GOSUB to 4E79H to reset the RS-232 configuration to defaults. The routine at 4E79H stores HL=0000H to 41F8H (clearing the configuration word), stores A=FFH to 41FAH (setting WAIT mode as default), and jumps to ROM routine 005AH to reinitialize the hardware.
4E17
POP AF F1
Restore Register A and the flags from the stack. The Z flag is restored: Z set = RS-232 off, NZ = RS-232 active.
4E18
LD HL,4E87H 21 87 4E
Load Register Pair HL with 4E87H, which points to the SETCOM keyword table. The first entry is "OFF" and the display routine at 4F7FH will print this label if the RS-232 is disabled.
4E1B
If the Z FLAG has been set (RS-232 is off), JUMP forward to 4E74H to print just the "OFF" label and return. No other parameter values need to be displayed when the interface is disabled.

Display RS-232 Parameters (4E1DH): The RS-232 is active. The code now decodes and displays each parameter value: WORD length, BAUD rate, STOP bits, PARITY, and WAIT/NOWAIT. Register A contains the configuration high byte (from 41F9H) with the packed settings.

4E1D
PUSH AF F5
Save Register A (the RS-232 configuration high byte from 41F9H) and flags onto the stack. This value will be needed multiple times for extracting different bit fields.
4E1E
AND 60H E6 60
AND Register A with 60H (binary 01100000). This isolates bits 5-6, which contain the word length encoding. The result has the word length in bits 5-6 with all other bits cleared.
4E20
If the P/V FLAG indicates even parity (PE) of the isolated bits, JUMP forward to 4E25H, skipping the XOR correction. This is the reverse of the encoding done in the WORD= handler at 4D92H-4D95H: values with even parity (00 and 60H) are already in the correct display encoding.
4E23
XOR 60H EE 60
Exclusive-OR Register A with 60H. This reverses the parity-based encoding swap done during the WORD= handler, converting the hardware encoding back to the logical ordering for display.
4E25
RLCA 07
Rotate Register A left. First of three left-rotations to shift the word length value from bits 5-6 down into bits 0-1 for conversion to a displayable number.
4E26
RLCA 07
Rotate Register A left again. Second rotation.
4E27
RLCA 07
Rotate Register A left a third time. After three RLCA operations, the 2-bit word length value has moved from bits 5-6 into bits 0-1 of Register A. The value is now 0-3, representing WORD lengths 5-8.
4E28
ADD 05H C6 05
ADD 05H to Register A, converting the zero-based index (0-3) back to the actual word length value (5-8) for display.
4E2A
LD HL,4E8EH 21 8E 4E
Load Register Pair HL with 4E8EH, which points to the "WORD=" label string in the SETCOM keyword table.
4E2D
GOSUB to the numeric value display routine at 4F93H. Register A contains the WORD length (5-8) and Register Pair HL points to the label "WORD=". The routine prints "WORD=N" where N is the word length.

Now display the BAUD rate. The baud rate index is stored in bits 0-3 of the configuration low byte at 41F8H. The index is used to look up the actual baud rate value from the table at 4EC7H.

4E30
LD A,(41F8H) 3A F8 41
Load Register A with the byte at address 41F8H, which is the low byte of the RS-232 configuration word. Bits 0-3 contain the baud rate table index.
4E33
AND 0FH E6 0F
AND Register A with 0FH (binary 00001111). This isolates bits 0-3, extracting the baud rate table index (0-15) from the configuration byte.
4E35
ADD A,A 87
ADD Register A to itself, doubling the baud rate index. Each entry in the baud rate table at 4EC7H is 2 bytes wide, so the index must be multiplied by 2 to compute the byte offset into the table.
4E36
LD HL,4EC7H 21 C7 4E
Load Register Pair HL with 4EC7H, the base address of the baud rate lookup table containing 16 two-byte entries for the supported baud rates.
4E39
LD E,A 5F
Load Register E with Register A (the doubled baud rate index, which is the byte offset into the baud rate table).
4E3A
LD D,00H 16 00
Load Register D with 00H. Register Pair DE now contains the 16-bit table offset (high byte = 0, low byte = doubled index).
4E3C
ADD HL,DE 19
ADD Register Pair DE (the table offset) to Register Pair HL (the table base address 4EC7H). Register Pair HL now points to the two-byte baud rate entry corresponding to the current baud rate index.
4E3D
LD E,(HL) 5E
Load Register E with the low byte of the baud rate value from the table entry pointed to by Register Pair HL.
4E3E
INC HL 23
INCrement Register Pair HL by 1 to point to the high byte of the baud rate table entry.
4E3F
LD D,(HL) 56
Load Register D with the high byte of the baud rate value. Register Pair DE now contains the 16-bit baud rate value (e.g., 012CH = 300, 2580H = 9600).
4E40
LD HL,4E97H 21 97 4E
Load Register Pair HL with 4E97H, which points to the "BAUD=" label string in the SETCOM keyword table.
4E43
GOSUB to the 16-bit numeric value display routine at 4F96H. Register Pair DE contains the baud rate value and Register Pair HL points to the label "BAUD=". The routine prints "BAUD=NNNNN" with the actual baud rate.

Now display the STOP bits. The stop bit setting is in bit 4 of the configuration high byte (saved on the stack). Value 1 = one stop bit (bit 4 clear), value 2 = two stop bits (bit 4 set).

4E46
LD E,01H 1E 01
Load Register E with 01H, setting the default display value to 1 (one stop bit).
4E48
POP BC C1
Restore the RS-232 configuration high byte from the stack into Register B (with flags in Register C). Register B contains the packed word length / stop bits / parity byte from 41F9H.
4E49
BIT 4,B CB 60
Test bit 4 of Register B (the RS-232 configuration high byte). Bit 4 is the stop bits flag: 0 = one stop bit, 1 = two stop bits. If bit 4 is zero, the Z FLAG is set.
4E4B
PUSH BC C5
Save Register Pair BC (the configuration byte) back onto the stack for use by the parity display code that follows.
4E4C
If the Z FLAG has been set (bit 4 is clear, meaning one stop bit), JUMP forward to 4E4FH, keeping Register E = 01H for the display.
4E4E
INC E 1C
INCrement Register E by 1, changing it from 01H to 02H. This sets the display value to 2 (two stop bits), since bit 4 was set.
4E4F
LD HL,4EA0H 21 A0 4E
Load Register Pair HL with 4EA0H, which points to the "STOP=" label string in the SETCOM keyword table.
4E52
GOSUB to 4F94H (the numeric display routine entry that takes Register E as the value and Register Pair HL as the label). Register E contains the stop bits value (1 or 2). Prints "STOP=N".

Now display the PARITY setting. The parity is encoded in bits 3 and 7 of the configuration high byte (saved on the stack). The decoding is: bit 3=1 = no parity (value 3), bit 3=0 and bit 7=1 = even parity (value 2), bit 3=0 and bit 7=0 = odd parity (value 1).

4E55
LD E,03H 1E 03
Load Register E with 03H, setting the default display value to 3 (no parity).
4E57
POP BC C1
Restore Register Pair BC (the RS-232 configuration high byte in Register B) from the stack.
4E58
BIT 3,B CB 58
Test bit 3 of Register B. Bit 3 is the parity enable flag. If bit 3 is set (1), the NZ FLAG is set, meaning no parity. If bit 3 is clear (0), the Z FLAG is set, meaning parity is enabled.
4E5A
If the NZ FLAG has been set (bit 3 is set, meaning no parity), JUMP forward to 4E62H with Register E = 03H (display value for "no parity").
4E5C
DEC E 1D
DECrement Register E by 1, changing it from 03H to 02H. This sets the tentative display value to 2 (even parity).
4E5D
BIT 7,B CB 78
Test bit 7 of Register B. Bit 7 is the parity type selector: 1 = even parity, 0 = odd parity.
4E5F
If the NZ FLAG has been set (bit 7 is set, meaning even parity), JUMP forward to 4E62H with Register E = 02H (display value for "even parity").
4E61
DEC E 1D
DECrement Register E by 1 again, changing it from 02H to 01H. This sets the display value to 1 (odd parity), since bit 7 was clear.
4E62
Load Register Pair HL with 4EA9H, which points to the "PARITY=" label string in the SETCOM keyword table.
4E65
GOSUB to 4F94H. Register E contains the parity value (1=odd, 2=even, 3=none) and Register Pair HL points to the label "PARITY=". Prints "PARITY=N".

Finally, display the WAIT or NOWAIT state. The WAIT/NOWAIT flag is stored at 41FAH: FFH (non-zero) = WAIT, 00H = NOWAIT.

4E68
LD HL,4EB4H 21 B4 4E
Load Register Pair HL with 4EB4H, which points to the "WAIT" label string in the SETCOM keyword table. This is the default label assuming WAIT mode.
4E6B
LD A,(41FAH) 3A FA 41
Load Register A with the byte at address 41FAH, which is the current WAIT/NOWAIT flag. FFH (non-zero) = WAIT mode, 00H = NOWAIT mode.
4E6E
OR A B7
OR Register A with itself. Sets the Z FLAG if Register A is zero (NOWAIT mode), or NZ FLAG if non-zero (WAIT mode).
4E6F
If the NZ FLAG has been set (WAIT mode is active), JUMP forward to 4E74H with Register Pair HL still pointing to the "WAIT" label at 4EB4H.
4E71
LD HL,4EBCH 21 BC 4E
Load Register Pair HL with 4EBCH, which points to the "NOWAIT" label string in the SETCOM keyword table. This overrides the default "WAIT" pointer since the RS-232 is in NOWAIT mode.
4E74
GOSUB to the parameter display initiator at 4F7FH. Register Pair HL points to the label string to display ("OFF", "WAIT", or "NOWAIT"). The routine prints the label with comma separation from previous parameters.
4E77
XOR A AF
Exclusive-OR Register A with itself, setting Register A to 00H and clearing all flags. A return value of 00H signals to the DOS command processor that the SETCOM command completed successfully.
4E78
RET C9
RETURN to the DOS command processor. The SETCOM command has completed - parameters have been applied and the current state has been displayed. Register A = 00H indicates success.

RS-232 Defaults Reset Subroutine (4E79H): Called when the RS-232 interface is being turned off or when a bare SETCOM is issued with the interface unconfigured. Stores a zeroed configuration word and FFH WAIT flag to the system variables, then reinitializes the hardware.

4E79
LD HL,0000H 21 00 00
Load Register Pair HL with 0000H. This is the "off" / default RS-232 configuration word — all zeros means the interface is disabled with no word length, baud rate, or parity settings.
4E7C
LD A,FFH 3E FF
Load Register A with FFH, which is the default WAIT/NOWAIT flag value. FFH represents WAIT mode as the default when the interface is reset.

Fall through to 4E7EH to store the values and reinitialize the hardware.

4E7E
LD (41F8H),HL 22 F8 41
Store Register Pair HL (the RS-232 configuration word — either the newly configured values or 0000H for OFF) into the two-byte location at 41F8H-41F9H. This updates the DOS system RS-232 configuration variable.
4E81
LD (41FAH),A 32 FA 41
Store Register A (the WAIT/NOWAIT flag — either the user-specified value or FFH for the default) into address 41FAH. This updates the DOS system WAIT/NOWAIT flag.
4E84
JUMP to ROM routine at 005AH, which reinitializes the RS-232 hardware using the configuration values just stored at 41F8H-41FAH. This ROM routine programs the Model III UART with the new baud rate, word length, stop bits, and parity settings, then returns to the caller of 4E7EH (or 4E79H).

4E87H - SETCOM Keyword Table (Data Area)

This is a data area which contains the keyword definition table used by the keyword parser at 4EE7H when processing the SETCOM command.

Each keyword entry consists of:

  • an ASCII keyword name (NUL-terminated)
  • a flags byte
  • and a 2-byte handler return address (little-endian)

The table contains seven keyword entries: OFF WORD= BAUD= STOP= PARITY= WAIT NOWAIT

The label strings within this table are also referenced directly by the display routines (e.g., HL=4E8EH for "WORD=", HL=4E97H for "BAUD=", etc.).

4E87
DEFM "OFF" + 00H 4F 46 46 00
This is the first keyword name in the SETCOM keyword table.
4E8B
DEFB 00H 00
Keyword parameter flags byte: 00H. Bit 7 clear indicates the OFF keyword does not accept a numeric "=value" parameter.
4E8C
DEFW 4E08H 08 4E
Handler address for the OFF keyword: 4E08H (stored little-endian). When the keyword parser matches OFF, it dispatches execution to 4E08H.
4E8E
DEFM "WORD=" + 00H 57 4F 52 44 3D 00
This keyword name is also used as the display label when printing "WORD=N".
4E94
DEFB 80H 80
Keyword parameter flags byte: 80H. Bit 7 set indicates this keyword requires a numeric value parameter following the "=" sign.
4E95
DEFW 4D8AH 8A 4D
Handler address for the WORD= keyword: 4D8AH (stored little-endian). Dispatches to the WORD handler which encodes the word length into bits 5-6 of the RS-232 configuration byte.
4E97
DEFM "BAUD=" + 00H 42 41 55 44 3D 00
Also used as the display label for "BAUD=NNNNN".
4E9D
DEFB C0H C0
Keyword parameter flags byte: C0H. Bit 7 set (numeric parameter required). Bit 6 set indicates the parser should return a 16-bit value in Register Pair DE rather than an 8-bit value in Register A, since baud rate values can exceed 255.
4E9E
DEFW 4DA6H A6 4D
Handler address for the BAUD= keyword: 4DA6H (stored little-endian). Dispatches to the BAUD handler which searches the baud rate table at 4EC7H.
4EA0
DEFM "STOP=" + 00H 53 54 4F 50 3D 00
Also used as the display label for "STOP=N".
4EA6
DEFB 80H 80
Keyword parameter flags byte: 80H. Bit 7 set (numeric parameter required).
4EA7
DEFW 4DC3H C3 4D
Handler address for the STOP= keyword: 4DC3H (stored little-endian). Dispatches to the STOP handler which sets bit 4 of the configuration byte.
4EA9
DEFM "PARITY=" + 00H 50 41 52 49 54 59 3D 00
Also used as the display label for "PARITY=N".
4EB1
DEFB 80H 80
Keyword parameter flags byte: 80H. Bit 7 set (numeric parameter required).
4EB2
DEFW 4DD1HD1 4D
Handler address for the PARITY= keyword: 4DD1H (stored little-endian). Dispatches to the PARITY handler which sets bits 3 and 7 of the configuration byte.
4EB4
DEFM "WAIT" + 00H 57 41 49 54 00
This keyword has no "=" because WAIT takes no value parameter. Also used as the display label "WAIT".
4EB9
DEFB 00H 00
Keyword parameter flags byte: 00H. Bit 7 clear indicates WAIT does not accept a numeric parameter.
4EBA
DEFW 4DEAH EA 4D
Handler address for the WAIT keyword: 4DEAH (stored little-endian). Dispatches to the WAIT handler which stores FFH into the self-modifying code at 4E02H.
4EBC
DEFM "NOWAIT" + 00H 4E 4F 57 41 49 54 00
Also used as the display label "NOWAIT".
4EC3
DEFB 00H 00
Keyword parameter flags byte: 00H. Bit 7 clear indicates NOWAIT does not accept a numeric parameter.
4EC4
DEFW 4DEEH EE 4D
Handler address for the NOWAIT keyword: 4DEEH (stored little-endian). Dispatches to the NOWAIT handler which stores 00H into the self-modifying code at 4E02H.
4EC6
DEFB 00H 00
End-of-table marker: 00H. A NUL byte here signals to the keyword parser that there are no more keyword entries in the SETCOM table.

4EC7H - Baud Rate Lookup Table (Data Area)

This is a data area containing 16 two-byte (little-endian) baud rate values. The table is used both for matching user-entered baud rate values during SETCOM parsing (at 4DA6H) and for looking up the actual baud rate value during display (at 4E30H). Each entry corresponds to one of the 16 baud rates supported by the Model III RS-232 hardware. The baud rate index (0–15) is stored in bits 0–3 of the RS-232 configuration low byte at 41F8H.

Baud Rate Table — 16 entries, 2 bytes each (little-endian):

4EC7
DEFW 0032H 32 00
Baud rate table entry 0: 0032H = 50 decimal. Baud rate 50.
4EC9
DEFW 004BH 4B 00
Baud rate table entry 1: 004BH = 75 decimal. Baud rate 75.
4ECB
DEFW 006EH 6E 00
Baud rate table entry 2: 006EH = 110 decimal. Baud rate 110.
4ECD
DEFW 0086H 86 00
Baud rate table entry 3: 0086H = 134 decimal. Baud rate 134.
4ECF
DEFW 0096H 96 00
Baud rate table entry 4: 0096H = 150 decimal. Baud rate 150.
4ED1
DEFW 012CH 2C 01
Baud rate table entry 5: 012CH = 300 decimal. Baud rate 300.
4ED3
DEFW 0258H 58 02
Baud rate table entry 6: 0258H = 600 decimal. Baud rate 600.
4ED5
DEFW 04B0H B0 04
Baud rate table entry 7: 04B0H = 1200 decimal. Baud rate 1200.
4ED7
DEFW 0708H 08 07
Baud rate table entry 8: 0708H = 1800 decimal. Baud rate 1800.
4ED9
DEFW 07D0H D0 07
Baud rate table entry 9: 07D0H = 2000 decimal. Baud rate 2000.
4EDB
DEFW 0960H 60 09
Baud rate table entry 10: 0960H = 2400 decimal. Baud rate 2400.
4EDD
DEFW 0E10H 10 0E
Baud rate table entry 11: 0E10H = 3600 decimal. Baud rate 3600.
4EDF
DEFW 12C0H C0 12
Baud rate table entry 12: 12C0H = 4800 decimal. Baud rate 4800.
4EE1
DEFW 1C20H 20 1C
Baud rate table entry 13: 1C20H = 7200 decimal. Baud rate 7200.
4EE3
DEFW 2580H 80 25
Baud rate table entry 14: 2580H = 9600 decimal. Baud rate 9600.
4EE5
DEFW 4B00H 00 4B
Baud rate table entry 15: 4B00H = 19200 decimal. Baud rate 19200.

4EE7H - Keyword Parser Engine

This is the shared keyword parser engine used by both the FORMS and SETCOM commands. It is called with Register Pair BC pointing to a keyword table and Register Pair HL pointing to the user's command line. The parser calls the keyword string scanner at 4F0FH to match the user's input against the keyword table, then extracts the flags byte and handler address from the matched table entry. If the flags byte has bit 7 set (indicating the keyword requires a numeric "=value" parameter), the parser calls the numeric value parser at 4F26H to convert the ASCII number string. It then performs range validation based on the flags and returns to the handler address extracted from the table.

When execution arrives here, Register Pair BC points to the keyword table (4D5BH for FORMS, 4E87H for SETCOM) and Register Pair HL points to the current position in the command line. Register D is loaded with the maximum number of keyword scan passes.

4EE7
LD D,03H 16 03
Load Register D with 03H. Register D serves as a retry/pass counter for the keyword scanner, allowing up to 3 passes through the keyword table matching process.
4EE9
GOSUB to the keyword string scanner at 4F0FH. This routine uses the SYS0 scanner at 4C6AH to match the user's input (pointed to by HL) against keyword names in the table (pointed to by BC). On return, Register Pair BC points to the flags byte of the matched keyword table entry.
4EEC
PUSH BC C5
Save Register Pair BC (pointing to the flags byte of the matched keyword table entry) onto the stack.
4EED
EX (SP),HL E3
Exchange Register Pair HL with the value on top of the stack. After this: HL now contains the pointer to the keyword table flags byte (was in BC, pushed to stack), and the stack now holds the command line pointer (was in HL). This allows HL to walk through the keyword table entry.
4EEE
LD A,(HL) 7E
Load Register A with the byte at the address pointed to by Register Pair HL, which is the flags byte of the matched keyword table entry. Bit 7 indicates whether a numeric parameter is required; bit 6 indicates 16-bit value mode; bit 5 indicates a non-zero validation requirement.
4EEF
INC HL 23
INCrement Register Pair HL by 1 to point to the low byte of the handler address in the keyword table entry.
4EF0
LD E,(HL) 5E
Load Register E with the low byte of the handler address from the keyword table entry.
4EF1
INC HL 23
INCrement Register Pair HL by 1 to point to the high byte of the handler address.
4EF2
LD D,(HL) 56
Load Register D with the high byte of the handler address. Register Pair DE now contains the 16-bit handler address (e.g., 4D22H for WIDTH, 4D8AH for WORD, 4DA6H for BAUD, etc.).
4EF3
POP HL E1
Restore the command line pointer from the stack into Register Pair HL. The command line pointer was placed on the stack by the EX (SP),HL at 4EEDH.
4EF4
PUSH DE D5
Save Register Pair DE (the handler address) onto the stack. This handler address will be used as a return address: when the parser finishes and executes RET, control will transfer to the handler routine.
4EF5
BIT 7,A CB 7F
Test bit 7 of Register A (the flags byte from the keyword table entry). Bit 7 indicates whether this keyword requires a numeric "=value" parameter. If bit 7 is clear (0), the Z FLAG is set, meaning no numeric parameter is needed (e.g., OFF, WAIT, NOWAIT).
4EF7
RET Z C8
If the Z FLAG has been set (bit 7 of the flags byte is clear, meaning this keyword has no numeric parameter), RETURN. The RET pops the handler address from the stack, so execution transfers directly to the keyword handler (e.g., 4E08H for OFF, 4DEAH for WAIT, 4DEEH for NOWAIT).

The keyword requires a numeric parameter. The code now calls the numeric value parser to convert the ASCII number string following the "=" sign into a binary value.

4EF8
PUSH AF F5
Save Register A (the flags byte) and flags onto the stack. The flags byte is needed after the numeric parse to perform range validation.
4EF9
GOSUB to the numeric parameter value parser at 4F26H. Register Pair HL points to the command line at the position following the "=" sign. On return, Register Pair DE contains the parsed 16-bit numeric value, and Register A contains the low byte (Register E) for 8-bit parameters. Register Pair HL is advanced past the parsed number.
4EFC
POP BC C1
Restore the flags byte from the stack into Register B (the flags were pushed as AF, so A goes to B and F goes to C). Register B now contains the keyword flags byte for range validation.
4EFD
BIT 5,B CB 68
Test bit 5 of Register B (the keyword flags byte). Bit 5 indicates a "must be non-zero" validation requirement. If bit 5 is set, the parsed value must not be zero. If bit 5 is clear, the Z FLAG is set.
4EFF
If the Z FLAG has been set (bit 5 is clear, meaning no non-zero validation is required), JUMP forward to 4F05H to skip the zero check.
4F01
LD A,D 7A
Load Register A with Register D (the high byte of the parsed 16-bit value in DE).
4F02
OR E B3
OR Register A (high byte) with Register E (low byte). If both bytes are zero, the entire 16-bit value is zero and the Z FLAG is set.
4F03
If the Z FLAG has been set (the parsed value is zero, but the keyword flags require a non-zero value), JUMP to 4F44H to report error code 2FH (invalid parameter value). [ERROR PATH — value must be non-zero]
4F05
BIT 6,B CB 70
Test bit 6 of Register B (the keyword flags byte). Bit 6 indicates "16-bit value mode" — if set, the full 16-bit value in Register Pair DE is passed to the handler (used by BAUD=). If clear, only the 8-bit value in Register A (low byte) is used.
4F07
RET NZ C0
If the NZ FLAG has been set (bit 6 is set, meaning 16-bit mode), RETURN. The RET pops the handler address from the stack, transferring control to the handler with Register Pair DE containing the full 16-bit parsed value. This path is used for BAUD= (flags byte C0H has bit 6 set).

Bit 6 is clear, so this is an 8-bit parameter. Validate that the high byte of DE is zero (the value fits in 8 bits), then pass the low byte in Register A to the handler.

4F08
LD A,D 7A
Load Register A with Register D (the high byte of the parsed value). For an 8-bit parameter, this must be zero.
4F09
OR A B7
OR Register A with itself. Sets the Z FLAG if Register D is zero (the parsed value fits in 8 bits). Sets NZ FLAG if non-zero (the value exceeds 255, which is out of range for an 8-bit parameter).
4F0A
If the NZ FLAG has been set (the high byte is non-zero, meaning the parsed value exceeds 255), JUMP to 4F44H to report error code 2FH (value out of range for 8-bit parameter). [ERROR PATH — value > 255]
4F0C
LD A,E 7B
Load Register A with Register E (the low byte of the parsed value). Register A now contains the 8-bit parameter value to pass to the keyword handler.
4F0D
OR A B7
OR Register A with itself. This sets flags based on the value (Z if zero, NZ if non-zero) for the keyword handler to use if needed.
4F0E
RET C9
RETURN. The RET pops the handler address from the stack, transferring control to the keyword handler with Register A containing the 8-bit parsed value. For FORMS: 4D22H (WIDTH) or 4D27H (LINES). For SETCOM: 4D8AH (WORD), 4DC3H (STOP), or 4DD1H (PARITY).

4F0FH - Keyword String Scanner

Scans the user's command line input against keyword names in a keyword table. Called by the keyword parser engine at 4EE7H. Uses the SYS0 keyword matching routine at 4C6AH to compare the user's input against the current keyword name. If the keyword does not match, the scanner skips past the NUL-terminated keyword name and the fixed-size record bytes (flags + handler address) to advance to the next table entry. If no keyword matches and the end-of-table marker (00H) is reached, the scanner reports a parse error. Register Pair BC points to the keyword table; Register D contains the number of bytes to skip per record after the NUL terminator (used to skip the flags byte and handler address).

[LOOP START — Keyword scan loop] Each iteration calls the SYS0 scanner for the current keyword. If no match, the code skips to the next table entry. Register D was loaded with 03H at 4EE7H, meaning 3 bytes must be skipped after each NUL terminator (1 flags byte + 2 handler address bytes).

4F0F
GOSUB to the SYS0 keyword matching routine at 4C6AH. This routine compares the user's command line input (pointed to by HL) against the keyword name string pointed to by BC. Returns: Z flag set = keyword matched (BC now points past the keyword name to the flags byte); NZ flag = keyword did not match.
4F12
RET Z C8
If the Z FLAG has been set (the keyword matched), RETURN to the keyword parser engine at 4EE7H. Register Pair BC now points to the flags byte of the matched keyword entry, ready for the parser to extract the flags and handler address.

The keyword did not match. Skip past the remaining bytes of the current keyword name (scan to the NUL terminator), then skip the 3 record bytes (flags + handler address) to reach the next keyword entry.

4F13
LD A,(BC) 0A
Load Register A with the byte at the address pointed to by Register Pair BC (the current position within the keyword name string that did not match).
4F14
OR A B7
OR Register A with itself. Sets the Z FLAG if Register A is zero (NUL terminator reached, end of keyword name).
4F15
INC BC 03
INCrement Register Pair BC by 1 to advance to the next byte in the keyword table.
4F16
If the NZ FLAG has been set (the current byte is not the NUL terminator), JUMP back to 4F13H to continue scanning forward through the keyword name. [INNER LOOP — skip to NUL terminator]

BC now points to the byte after the NUL terminator (the flags byte). Skip past the 3 record bytes (flags + 2-byte handler address) to reach the start of the next keyword entry.

4F18
LD E,D 5A
Load Register E with Register D (the record skip count, which is 03H). Register E will be used as a countdown for the number of bytes to skip.
4F19
INC BC 03
INCrement Register Pair BC by 1 to skip one record byte.
4F1A
DEC E 1D
DECrement Register E (the skip counter) by 1.
4F1B
If the NZ FLAG has been set (more bytes to skip), JUMP back to 4F19H. [INNER LOOP — skip record bytes]

BC now points to the first byte of the next keyword entry. Check if this is the end-of-table marker (00H).

4F1D
LD A,(BC) 0A
Load Register A with the byte at the address pointed to by Register Pair BC, which is the first byte of the next keyword table entry (or the end-of-table marker).
4F1E
OR A B7
OR Register A with itself. Sets the Z FLAG if Register A is zero (end-of-table marker reached, no more keywords to check).
4F1F
If the NZ FLAG has been set (the byte is not the end-of-table marker, meaning another keyword entry exists), JUMP back to 4F0FH to try matching this next keyword. [LOOP — try next keyword]

[LOOP END — no match found] The end-of-table marker was reached without finding a matching keyword. Report a parse error.

4F21
LD A,34H 3E 34
Load Register A with 34H (decimal 52), which is the NEWDOS/80 error code for "parse error." The user entered an unrecognized keyword.
4F23
JUMP to the DOS error handler at 4409H in SYS0. Register A contains the error code 34H (parse error). The error handler will display the error message and abort the command. This address is also the target of the error exit at 4D0EH and 4F46H.

4F26H - Numeric Parameter Value Parser

Parses a numeric value from the command line, supporting both decimal and hexadecimal input. Called by the keyword parser engine at 4EE7H after a keyword with bit 7 set in its flags byte has been matched. Register Pair HL points to the command line at the position following the "=" sign. The routine first attempts to parse the number as pure decimal. If the string ends with a character in the range "A"-"H", it re-parses as hexadecimal (with "H" suffix). Returns with the parsed 16-bit value in Register Pair DE and Register A containing the low byte. If the parse fails, jumps to the error handler at 4F44H.

4F26
PUSH HL E5
Save Register Pair HL (the command line pointer at the start of the numeric value) onto the stack. This saved position allows the code to re-parse from the beginning if hex mode is needed.
4F27
LD B,00H 06 00
Load Register B with 00H. Register B controls the parsing mode: bit 0 clear (0) = decimal-only mode (hex digits A-F are rejected); bit 0 set (1) = hexadecimal mode (digits A-F are accepted). Starting with 00H means the first parse attempt is decimal-only.
4F29
GOSUB to the multi-base ASCII-to-binary converter at 4F49H. Register Pair HL points to the ASCII number string, Register B = 00H (decimal mode). On return, Register Pair DE contains the parsed value, and HL points to the first non-digit character after the number. Register B bit 1 is set if at least one digit was successfully parsed.
4F2C
LD A,(HL) 7E
Load Register A with the byte at the address pointed to by Register Pair HL, which is the first character after the parsed decimal number. This character determines whether the number might be hexadecimal (if it is a letter A-H).
4F2D
SUB 41H D6 41
SUBtract 41H (ASCII "A") from Register A. This converts the character to a zero-based index relative to "A". If the character was "A", Register A becomes 0; if "H", Register A becomes 7.
4F2F
CP 08H FE 08
Compare Register A against 08H. If Register A is less than 08H (the character was "A" through "H"), the CARRY FLAG is set. If Register A is 08H or greater (character was not A-H), the NO CARRY FLAG is set.
4F31
If the NO CARRY FLAG has been set (the character after the number is not A-H, meaning the number is a plain decimal value), JUMP forward to 4F40H to validate and return the decimal result.

The character following the decimal number is in the range A-H, which suggests this might be a hexadecimal number (e.g., "1AH" or "FFH"). Re-parse from the beginning with hex mode enabled.

4F33
POP HL E1
Restore Register Pair HL from the stack, resetting the command line pointer back to the start of the numeric string for re-parsing in hex mode.
4F34
LD B,01H 06 01
Load Register B with 01H. Setting bit 0 of Register B enables hexadecimal mode in the converter at 4F49H, allowing digits A-F to be accepted.
4F36
PUSH HL E5
Save Register Pair HL (the start of the number string) onto the stack again, in case it is needed for error recovery.
4F37
GOSUB to the multi-base ASCII-to-binary converter at 4F49H again, this time with Register B = 01H (hexadecimal mode). The converter will now accept digits 0-9 and A-F, and multiply by 16 instead of 10 for each digit position.
4F3A
LD A,(HL) 7E
Load Register A with the byte at the address pointed to by Register Pair HL, which is the first character after the hex number. For a valid hex number, this must be "H" (the hex suffix).
4F3B
CP 48H FE 48
Compare Register A against 48H (ASCII "H"). If the character is "H", the Z FLAG is set, confirming this is a valid hex number with the required "H" suffix.
4F3D
INC HL 23
INCrement Register Pair HL by 1 to advance past the "H" suffix character. This positions HL at the next character on the command line after the complete hex number.
4F3E
If the NZ FLAG has been set (the character after the hex digits is not "H", meaning this is not a valid hex number), JUMP to 4F44H to report error code 2FH (invalid parameter value). [ERROR PATH — missing H suffix]
4F40
BIT 1,B CB 48
Test bit 1 of Register B. Bit 1 is set by the converter at 4F49H when at least one valid digit has been parsed. If bit 1 is clear, no digits were found, meaning the value string was empty or invalid.
4F42
POP BC C1
Restore the saved command line pointer from the stack into Register Pair BC (discarding it since HL already has the updated position).
4F43
RET NZ C0
If the NZ FLAG has been set (bit 1 of B was set, meaning at least one digit was parsed successfully), RETURN to the keyword parser engine with the parsed value in Register Pair DE. [SUCCESS PATH]
4F44
LD A,2FH 3E 2F
Load Register A with 2FH (decimal 47), which is the NEWDOS/80 error code for "invalid parameter value." This error is reported when a numeric parameter is out of range, missing, or malformed.
4F46
JUMP to the DOS error handler at 4409H in SYS0. Register A contains error code 2FH (invalid parameter value). The error handler displays the error message and aborts the command.

4F49H - Multi-Base ASCII-to-Binary Converter

Converts an ASCII numeric string pointed to by Register Pair HL into a 16-bit binary value in Register Pair DE. Supports both decimal (base 10) and hexadecimal (base 16) depending on Register B bit 0: if bit 0 is clear, only decimal digits 0-9 are accepted; if bit 0 is set, hex digits A-F (41H-46H) are also accepted. The multiplication is done in-line: for decimal mode, each new digit multiplies the accumulator by 10 (via shift-and-add: value*4 + value, then *2, then +digit); for hex mode, multiplies by 16 (via four left shifts). On return, Register B bit 1 is set if at least one valid digit was parsed. If the result overflows 16 bits, jumps to error handler at 4F44H.

4F49
LD DE,0000H 11 00 00
Load Register Pair DE with 0000H. Register Pair DE is the 16-bit accumulator that will hold the running total as digits are parsed. Starts at zero.

[LOOP START — Digit parsing loop] Each iteration reads one character from the command line, validates it as a digit, multiplies the accumulator by the base (10 or 16), and adds the new digit value.

4F4C
LD A,(HL) 7E
Load Register A with the byte at the address pointed to by Register Pair HL (the next character from the command line).
4F4D
SUB 30H D6 30
SUBtract 30H (ASCII "0") from Register A. This converts ASCII digits "0"-"9" to binary values 0-9. If the character was "0", Register A becomes 0; if "9", Register A becomes 9. Non-digit characters produce values outside the 0-9 range.
4F4F
CP 0AH FE 0A
Compare Register A against 0AH (decimal 10). If Register A is less than 0AH (the character was a valid decimal digit 0-9), the CARRY FLAG is set. If Register A is 0AH or greater (not a decimal digit), the NO CARRY FLAG is set.
4F51
If the CARRY FLAG has been set (Register A is a valid decimal digit 0-9), JUMP forward to 4F5DH to incorporate this digit into the accumulator.

The character is not a decimal digit. Check if hex mode is enabled and if the character is a valid hex digit A-F.

4F53
BIT 0,B CB 40
Test bit 0 of Register B (the hex mode flag). If bit 0 is clear (0), hex digits are not allowed and this is a non-digit terminator. If bit 0 is set (1), hex mode is active.
4F55
RET Z C8
If the Z FLAG has been set (bit 0 of B is clear, meaning hex mode is disabled), RETURN. The non-digit character terminates the decimal number. Register Pair DE contains the parsed value, and HL points to the terminating character.
4F56
SUB 11H D6 11
SUBtract 11H from Register A. After the earlier SUB 30H, ASCII "A" (41H) became 11H, so this second subtraction converts it to 0. ASCII "B" (42H) becomes 1, through "F" (46H) becomes 5. This maps hex digits A-F to values 0-5.
4F58
CP 06H FE 06
Compare Register A against 06H. If Register A is less than 06H (the character was a valid hex digit A-F), the CARRY FLAG is set. If 06H or greater, the character is not a valid hex digit.
4F5A
RET NC D0
If the NO CARRY FLAG has been set (the character is not a valid hex digit A-F), RETURN. The non-hex character terminates the number. Register Pair DE contains the parsed value so far.
4F5B
ADD 0AH C6 0A
ADD 0AH to Register A. This converts the hex digit offset (0-5 for A-F) into the actual hex value (10-15). Register A now contains the binary value 0AH-0FH corresponding to hex digits A-F.

Register A now contains the binary value of the current digit (0-9 for decimal, 0-15 for hex). The code below multiplies the accumulator (DE) by the base and adds the new digit. The multiplication uses a shift-and-add technique that differs depending on whether decimal or hex mode is active.

4F5D
PUSH HL E5
Save Register Pair HL (the command line pointer) onto the stack. HL will be temporarily reused for the multiplication arithmetic.
4F5E
LD H,D 62
Load Register H with Register D (the high byte of the accumulator). Copies the current accumulator value from DE into HL for the multiplication.
4F5F
LD L,E 6B
Load Register L with Register E (the low byte of the accumulator). Register Pair HL now contains a copy of the accumulator value.
4F60
LD C,A 4F
Load Register C with Register A (the binary value of the current digit, 0-15). Saved for later addition after the multiplication.
4F61
XOR A AF
Exclusive-OR Register A with itself, setting Register A to 00H. Register A will serve as an overflow byte for 24-bit precision during the multiplication (tracking bits shifted out of HL).
4F62
SET 1,B CB C8
Set bit 1 of Register B. This flags that at least one valid digit has been parsed, which the caller at 4F40H checks to validate that the number was not empty.
4F64
ADD HL,HL 29
ADD Register Pair HL to itself, doubling the accumulator value. This is the first left shift: HL = HL * 2. Carry flag receives the overflow bit.
4F65
ADC A,A 8F
ADD Register A to itself with Carry, capturing any overflow from the HL shift into the 24-bit extension byte.
4F66
ADD HL,HL 29
ADD Register Pair HL to itself again: HL = HL * 4 (original value * 4). Second left shift.
4F67
ADC A,A 8F
ADD Register A to itself with Carry, capturing overflow from the second shift.

At this point HL = original_value * 4. The next step differs based on mode: in hex mode (bit 0 set), two more shifts give *16; in decimal mode (bit 0 clear), ADD HL,DE gives *5, then one more shift gives *10.

4F68
BIT 0,B CB 40
Test bit 0 of Register B (the hex mode flag). If set (hex mode), the NZ FLAG is set; if clear (decimal mode), the Z FLAG is set.
4F6A
If the Z FLAG has been set (decimal mode), JUMP forward to 4F6FH to perform the decimal multiplication path (value*4 + original = value*5, then *2 = value*10).

[HEX PATH] Hex mode: need value * 16. Currently HL = value * 4. One more shift gives * 8.

4F6C
ADD HL,HL 29
ADD Register Pair HL to itself: HL = original_value * 8. Third left shift (hex path only).
4F6D
JUMP forward unconditionally to 4F70H to perform the fourth shift (value * 16) and add the digit.

[DECIMAL PATH] Decimal mode: HL = value * 4. Add the original value (in DE) to get value * 5.

4F6F
ADD HL,DE 19
ADD Register Pair DE (the original accumulator value) to Register Pair HL (currently value * 4). Result: HL = value * 5.
4F70
ADC A,A 8F
ADD Register A to itself with Carry, capturing overflow from the previous ADD HL,HL or ADD HL,DE.
4F71
ADD HL,HL 29
ADD Register Pair HL to itself. For decimal: HL = value * 10. For hex: HL = value * 16. This is the final base multiplication.
4F72
ADC A,A 8F
ADD Register A to itself with Carry, capturing overflow from the final shift.

Now add the new digit value (saved in Register C) to the multiplied accumulator.

4F73
LD E,C 59
Load Register E with Register C (the binary value of the current digit, 0-15).
4F74
LD D,00H 16 00
Load Register D with 00H. Register Pair DE now contains the digit value as a 16-bit number (00:digit).
4F76
ADD HL,DE 19
ADD Register Pair DE (the digit value) to Register Pair HL (the base-multiplied accumulator). HL now contains (old_value * base) + new_digit.
4F77
ADC A,A 8F
ADD Register A to itself with Carry, capturing any overflow from the digit addition.
4F78
EX DE,HL EB
Exchange Register Pairs DE and HL. Register Pair DE now contains the updated accumulator value. HL is freed for reuse.
4F79
POP HL E1
Restore Register Pair HL (the command line pointer) from the stack.
4F7A
If the NZ FLAG has been set (Register A is non-zero after the ADC A,A chain, meaning the result overflowed 16 bits), JUMP to 4F44H to report error code 2FH (value overflow). [ERROR PATH — overflow]
4F7C
INC HL 23
INCrement Register Pair HL by 1 to advance the command line pointer past the digit just processed.
4F7D
JUMP back unconditionally to 4F4CH to read and process the next character. [LOOP — next digit]

4F7FH - Parameter Display Initiator / String Printer

Manages comma-separated parameter display output. On the first call, no separator is printed; on subsequent calls, a comma is printed before the parameter label. This is achieved through self-modifying code at 4F81H: the operand of the OR instruction starts as 00H (first call, no separator) and is patched to 2CH (ASCII comma) after the first parameter is printed. After handling the separator, the routine prints the NUL-terminated string pointed to by Register Pair HL, which is the keyword label (e.g., "WIDTH=", "BAUD=", "WAIT").

4F7F
XOR A AF
Exclusive-OR Register A with itself, setting Register A to 00H and clearing all flags.
4F80
OR 00H F6 00
OR Register A with the immediate value 00H. HOWEVER, the byte at 4F81H is patched by self-modifying code at 4F87H: on the first call it is 00H (so the OR has no effect and the Z FLAG remains set); on subsequent calls it is 2CH (ASCII comma), so Register A becomes 2CH and the NZ FLAG is set. [SELF-MODIFYING CODE at 4F81H]
4F82
If the NZ FLAG has been set (Register A is non-zero, meaning this is not the first parameter), GOSUB to the character output routine at 4FCBH to print Register A (the comma separator character 2CH) to the screen.
4F85
LD A,2CH 3E 2C
Load Register A with 2CH (ASCII comma). This value will be stored into the self-modifying code location.
4F87
LD (4F81H),A 32 81 4F
Store Register A (2CH, the ASCII comma) into memory location 4F81H, which is the operand byte of the OR instruction at 4F80H. On the next call to 4F7FH, the OR will load 2CH into Register A, causing the comma separator to be printed. [SELF-MODIFYING CODE]

[LOOP START — String print loop] Print each character of the NUL-terminated label string pointed to by Register Pair HL.

4F8A
LD A,(HL) 7E
Load Register A with the byte at the address pointed to by Register Pair HL (the next character of the label string).
4F8B
OR A B7
OR Register A with itself. Sets the Z FLAG if Register A is zero (NUL terminator reached, end of string).
4F8C
INC HL 23
INCrement Register Pair HL by 1 to point to the next character in the string. This is done before the conditional return so HL is positioned correctly for the caller.
4F8D
RET Z C8
If the Z FLAG has been set (NUL terminator reached), RETURN to the caller. The entire label string has been printed.
4F8E
GOSUB to the character output routine at 4FCBH to print the character in Register A to the screen via the ROM routine at 0033H.
4F91
JUMP back unconditionally to 4F8AH to read and print the next character. [LOOP — next character]

4F93H - Numeric Value Display

Displays a keyword label followed by a formatted decimal number. Has three entry points: 4F93H takes an 8-bit value in Register A; 4F94H takes an 8-bit value in Register E; 4F96H takes a 16-bit value in Register Pair DE. All entries call 4F7FH to print the label string (with comma separation), then convert the binary value to up to 5 decimal digits using repeated subtraction with negative powers of 10 from the divisor table at 4FC3H, suppressing leading zeros.

4F93
LD E,A 5F
Load Register E with Register A (the 8-bit value to display). This copies the value into the low byte of Register Pair DE for the display routine.
4F94
LD D,00H 16 00
Load Register D with 00H. Register Pair DE now contains the value to display as a 16-bit number (high byte zero for 8-bit values). Entry point for callers who already have the value in Register E.
4F96
GOSUB to the parameter display initiator at 4F7FH to print the comma separator (if not the first parameter) and the keyword label string pointed to by Register Pair HL. Entry point for callers who already have the 16-bit value in Register Pair DE.

Binary-to-Decimal Conversion (4F99H): Converts the 16-bit value in Register Pair DE to decimal ASCII and prints each digit. Uses repeated subtraction with negative divisors from the table at 4FC3H. Register B counts 4 divisor passes (ten-thousands, thousands, hundreds, tens), then the remainder is the ones digit. Register C is used as a leading-zero suppression flag: starts at 0, and is incremented when the first non-zero digit is encountered.

4F99
LD BC,0400H 01 00 04
Load Register Pair BC with 0400H. Register B = 04H (four divisor passes for the digits: ten-thousands, thousands, hundreds, tens). Register C = 00H (leading-zero suppression flag, starts at 0 meaning no significant digit has been printed yet).
4F9C
LD HL,4FC3H 21 C3 4F
Load Register Pair HL with 4FC3H, which points to the divisor table. This table contains four 2-byte entries holding the negative values of 10000, 1000, 100, and 10 (as D8F0H, FC18H, FF9CH, FFF6H) used for repeated-addition division.

[LOOP START — Digit extraction loop] For each divisor, the code repeatedly adds the negative divisor to the value until it overflows (carry), counting how many times the addition succeeded. The count is the digit value.

4F9F
PUSH BC C5
Save Register Pair BC (B = remaining divisor count, C = leading-zero flag) onto the stack.
4FA0
LD C,(HL) 4E
Load Register C with the low byte of the current divisor entry from the table (pointed to by HL).
4FA1
INC HL 23
INCrement Register Pair HL by 1 to point to the high byte of the divisor.
4FA2
LD B,(HL) 46
Load Register B with the high byte of the divisor. Register Pair BC now contains the negative divisor (e.g., D8F0H = -10000 for the first pass).
4FA3
INC HL 23
INCrement Register Pair HL by 1 to point to the next divisor table entry, ready for the next iteration.
4FA4
EX DE,HL EB
Exchange Register Pairs DE and HL. Register Pair HL now contains the value being converted (was in DE), and Register Pair DE now holds the table pointer (was in HL). HL is needed because ADD HL,BC operates on HL.
4FA5
LD A,2FH 3E 2F
Load Register A with 2FH (ASCII "/", which is one less than ASCII "0"). Register A will be incremented to "0" on the first addition, then to "1", "2", etc., serving as the digit counter in ASCII.

[INNER LOOP START — Repeated subtraction] Each iteration adds the negative divisor (subtracts the divisor) and increments the ASCII digit counter.

4FA7
INC A 3C
INCrement Register A by 1. On the first iteration, A goes from 2FH ("/") to 30H ("0"). Each subsequent iteration advances the digit: "1", "2", etc.
4FA8
ADD HL,BC 09
ADD Register Pair BC (the negative divisor) to Register Pair HL (the value). This effectively subtracts the divisor from the value. If the result is still non-negative (no underflow), the Carry flag is set (because adding a large negative number to a smaller positive overflows the unsigned 16-bit range).
4FA9
If the CARRY FLAG has been set (the subtraction did not underflow, meaning the divisor fit at least once more), JUMP back to 4FA7H to increment the digit counter and subtract again. [INNER LOOP — subtract again]

[INNER LOOP END] The last subtraction underflowed. Undo it by adding the divisor back (via SBC), and Register A contains the ASCII digit.

4FAB
SBC HL,BC ED 42
SUBtract Register Pair BC (the negative divisor) from Register Pair HL with borrow. Since Carry is clear (the last ADD did not carry), this effectively adds the positive divisor back, undoing the last subtraction that caused the underflow. HL is restored to the correct remainder.
4FAD
POP BC C1
Restore Register Pair BC from the stack. Register B = remaining divisor pass count, Register C = leading-zero suppression flag.
4FAE
EX DE,HL EB
Exchange Register Pairs DE and HL, restoring the original arrangement: DE = remainder value, HL = table pointer.

Register A contains the ASCII digit for this position. Check for leading-zero suppression: if the digit is "0" and no significant digit has been printed yet (C = 0), skip printing this digit.

4FAF
CP 30H FE 30
Compare Register A against 30H (ASCII "0"). If the digit is "0", the Z FLAG is set.
4FB1
If the NZ FLAG has been set (the digit is not "0", it is a significant digit), JUMP forward to 4FB7H to print the digit and set the "significant digit seen" flag.
4FB3
INC C 0C
INCrement Register C (the leading-zero flag) by 1. This is a test: if C was 0 (no significant digit yet), it becomes 1 and NZ is set.
4FB4
DEC C 0D
DECrement Register C back by 1. This undoes the INC, restoring C to its original value. The purpose of the INC/DEC pair is solely to test whether C was zero: if C was 0 before the INC, it is now 0 again and the Z FLAG is set (leading zero, suppress it); if C was non-zero, it remains non-zero and the NZ FLAG is set (significant digit already seen, print the zero).
4FB5
If the Z FLAG has been set (Register C is zero, meaning no significant digit has been printed yet and this is a leading zero), JUMP forward to 4FBBH to skip printing this zero digit.
4FB7
INC C 0C
INCrement Register C by 1. This sets the "significant digit seen" flag to a non-zero value, ensuring that all subsequent zeros will be printed (they are no longer leading zeros).
4FB8
GOSUB to the character output routine at 4FCBH to print the ASCII digit in Register A to the screen.
4FBB
DECrement Register B (the divisor pass counter) by 1 and JUMP back to 4F9FH if not zero. Processes the next divisor (thousands, hundreds, tens). [LOOP — next divisor]

[LOOP END] All four divisor passes are complete. The remainder in Register E is the ones digit (0-9). Print it unconditionally (the ones digit is always printed, even if zero).

4FBD
LD A,E 7B
Load Register A with Register E (the low byte of the remainder, which is the ones digit value 0-9).
4FBE
ADD 30H C6 30
ADD 30H (ASCII "0") to Register A, converting the binary ones digit (0-9) to its ASCII representation ("0"-"9").
4FC0
JUMP to the character output routine at 4FCBH to print the ones digit and return. Since JP is used (not CALL), the RET inside 4FCBH will return to the caller of 4F93H/4F94H/4F96H.

4FC3H - Decimal Divisor Table (Data Area)

Data area containing four 2-byte negative divisor values used by the binary-to-decimal conversion routine at 4F99H. Each entry is the two's complement (negative) of a power of 10, stored little-endian. The conversion routine adds these negative values to the number being converted, effectively performing repeated subtraction to extract each decimal digit position.

4FC3
DEFW D8F0H F0 D8
Negative divisor for ten-thousands place: D8F0H = -10000 decimal (two's complement of 2710H). Used to extract the ten-thousands digit.
4FC5
DEFW FC18H 18 FC
Negative divisor for thousands place: FC18H = -1000 decimal (two's complement of 03E8H). Used to extract the thousands digit.
4FC7
DEFW FF9CH 9C FF
Negative divisor for hundreds place: FF9CH = -100 decimal (two's complement of 0064H). Used to extract the hundreds digit.
4FC9
DEFW FFF6H F6 FF
Negative divisor for tens place: FFF6H = -10 decimal (two's complement of 000AH). Used to extract the tens digit.

4FCBH - Character Output Wrapper

Wrapper routine that prints the character in Register A to the screen by calling the ROM character output routine at 0033H. Saves and restores Register Pairs DE and AF across the ROM call, ensuring that the caller's register values are not disturbed. Called extensively throughout SYS15 by the display routines.

4FCB
PUSH DE D5
Save Register Pair DE (which may contain the numeric value being displayed or other important data) onto the stack.
4FCC
PUSH AF F5
Save Register A (the character to print) and the flags onto the stack. Register A is preserved so the caller can continue using it after the print.
4FCD
GOSUB to the ROM character display routine at 0033H. This routine displays the character in Register A at the current cursor position on the screen and advances the cursor to the next position.
4FD0
POP AF F1
Restore Register A and the flags from the stack.
4FD1
POP DE D1
Restore Register Pair DE from the stack.
4FD2
RET C9
RETURN to the caller. Register A, flags, and Register Pair DE are all restored to their pre-call values.

4FD3H - Unused Space (NOP Padding)

The remainder of the SYS15/SYS overlay from 4FD3H through 51E7H is unused space filled with 00H (NOP) bytes. This padding fills the overlay to its fixed size. The executable code and data for SYS15 ends at 4FD2H.