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

Page Customization

Introduction / Summary

SYS10/SYS is a NEWDOS/80 v2.0 overlay module loaded into the SYS overlay area at 4D00H–51E7H (1,256 bytes, with 26 bytes of NOP padding at 51CEH–51E7H). It is loaded on demand when BASIC encounters PUT or GET statements for disk files.

What It Does:
SYS10 implements the complete PUT and GET statement processing for both sequential and random access disk files. This is the core data I/O module that enables BASIC programs to write formatted data to disk files and read it back.

PUT Processing (4D03H–4EBDH): Handles writing data to an open file. The PUT handler processes the file number, evaluates each expression in the PUT argument list, converts values to the appropriate format, and writes them through the FCB buffer. For random access files, it manages field positioning and record boundaries. Subcommands handled through special tokens include: position restore (#), alternate position ($), file close/reset (%), EOF marker write (&), and USING format (CFH token). Numeric values are converted between BASIC's floating-point format and disk integer formats using the CVI/CVS/CVD and MKI$/MKS$/MKD$ conversion logic at 4DE4H–4E16H.

GET Processing (4F18H–51CDH): Handles reading data from an open file. The GET handler parses the BASIC text for variable references, reads data from the file through the FCB buffer, converts between disk format and BASIC variable types, and stores results in the target variables. Supports string fields (with LSET/RSET trimming), numeric fields (integer, single-precision, double-precision), and special record-at-a-time mode for files opened with the special status flag.

Common Exit (518EH–51CDH): Both PUT and GET share a common exit path that advances the file position, updates FCB state, and loops back for additional data items separated by commas or semicolons.

Key ROM Routines Called: 09D6H (string block copy), 0A7FH (numeric evaluation), 0AF6H (numeric conversion), 1E5AH (expression evaluator), 1EC5H (numeric expression evaluator), 1F33H (PRINT handler), 260DH (string expression evaluator), 29E3H (string space allocator).

Key BASIC/CMD Routines Called: 6031H (position compare), 603EH (absolute position calc), 60EBH (store alt position), 610DH/6110H (position store), 6117H (store alternate), 6122H (load primary position), 6129H/612FH (load alternate + check), 6136H (record count), 614CH (FCB status reader), 615EH (position + dirty), 6190H (string expression + descriptor), 619CH (string expr evaluator), 61A3H (primary + write), 61A6H (DOS position write), 61ACH (current position loader), 61B3H (alternate position loader), 61C8H (record position validator), 61DFH (single-byte write), 621EH (common SVC dispatch), 6232H/6237H (DOS write/read + result), 6245H/6246H (position advance), 6258H (record advance), 626CH (record type decoder), 62C7H/62CEH (buffer position check), 62D0H (buffer pos alt), 62D8H (write mode + variable), 62FFH (buffer state logic), 6331H (position compare), 6346H (position-to-record), 635AH (clear work area), 6362H (zero-fill loop), 6368H (comma checker), 661CH (string expr + SYS10 dispatch), 6623H (string expression), 662CH (validation).

Variable and RAM Location Reference

Variables Written by SYS10:

4F8CHRecord Count Storage. Stores the calculated record count / position limit value. Written by: 4F1BH, 4F77H. Read by: 4F8BH (as operand of LD DE instruction).
5094HMax Record Per Sector. Stores the maximum record count or FFH for unlimited. Written by: 500CH. Read by: 6136H (BASIC/CMD record count routine).
570BHSYS10 Communication Byte (IX+0BH). Stores the current HL position value for FCB tracking. Written by: 4D4BH. Read by: 4D88H.
5D38HPrint Column State. Stores the print column counter for PUT output formatting. Written by: 4F95H.
61CAHRecord Limit. Stores the negative record boundary limit for GET position validation. Written by: 4F8EH (via 4F8BH routine).
6226HSVC Post-Op Flag. Set to 01H at entry to enable post-operation processing. Written by: 4D05H.
40AFHROM BASIC Record Length. Written by: 5086H during GET record setup.
40DFHROM BASIC Variable Type Pointer. Written by: 50D1H during GET type determination.

Variables Read by SYS10:

5700HFCB Status Word (IX+00H). Read by: 4D09H, 4D41H, 4D68H, 4EBEH.
5702H–5704HPosition bytes. Read by: 4E74H, 4ED0H–4ED8H, 4F70H.
570BHSYS10 communication. Read by: 4D88H.
5710HPosition data. Read by: 4F0EH.
4121H/4123HROM BASIC single/double-precision accumulators. Read by: 4DE6H, 4DEAH.
40D6HROM BASIC string space pointer. Read by: 5036H, 50A6H.

Major Routine Reference

4D00HStack Cleanup Exit. Discards the top return address from the stack and returns to the grandparent caller.
4D03HPUT Main Entry. Sets the SVC post-op flag, loads FCB status, and begins PUT statement processing.
4D13HPUT Status Store. Stores the processed status flags into the FCB at IX+00H.
4D1FHPUT Position Setup. Loads current position and checks validity flags.
4D36HPUT FCB Update. Reads FCB status, stores alternate position, checks special mode.
4D5AHPUT Subcommand Dispatch. Dispatches on token: CFH=USING, 23H=alt pos, 24H=restore, 25H=close/reset, 26H=EOF write, 21H=numeric field.
4DBCHPUT '!' Numeric Field Handler. Handles the '!' token for numeric field output with type detection (integer, single, double).
4DE4HFloat-to-Integer Converter. Converts BASIC floating-point values to integer format for disk storage. Handles sign, exponent normalization, and overflow detection.
4E17HRandom Access Position Calculator. Calculates the byte position within a random access record using 25-bit multiplication.
4E48HSequential Advance Handler. Advances through sequential records when the buffer position is not at a record boundary.
4E5FHDefault Expression Handler. Evaluates a general expression for PUT output.
4E9AHStatus-9 Handler. Handles files with special status mode 09H (device I/O).
4EBEHPost-WRITE Completion. Handles completion after writing data — routes to sequential or random access path.
4F0EHPosition Check Helper. Loads position from 5710H and checks byte offset status.
4F18HGET Main Entry. Begins GET statement processing for random access files.
4F8BHRecord Limit Setup. Initializes the record limit and print column state for GET/PUT.
4FC1HLine Scanner. Scans BASIC text for the next data item, handling USING tokens and end-of-line detection.
4FDFHGET Format Handler. Determines the format (string expression, numeric, field reference) for the current GET item.
5017HPUT Data Output. Writes data items to the file — handles both string and numeric output.
506AHPUT '#' Handler. Handles '#' in PUT for file-to-file operations.
5076HPUT String Expression. Evaluates and writes a string expression to the file.
50F6HGET Special Mode. Handles GET for files with special status (record-at-a-time).
5144HGET '#' Expression. Handles '#' in GET for record count operations.
518EHCommon Loop/Exit. Shared exit point that advances position, updates state, and loops for next data item.
51C9HEnd-of-Statement Check. Checks for end of BASIC statement and returns or errors.

Disassembly

4D00H - STACK CLEANUP EXIT

Alternate exit point that discards the top return address from the stack, then returns to the grandparent caller. Used when a subroutine within SYS10 needs to abort and return directly past its caller's caller.

4D00
INC SP 33
INCrement the Stack Pointer by 1. This discards the low byte of the return address that was pushed when the calling routine executed a CALL instruction. Together with the next INC SP, this removes the entire 16-bit return address from the stack.
4D01
INC SP 33
INCrement the Stack Pointer by 1. This discards the high byte of the return address. The stack now points to the return address of the caller's caller.
4D02
RET C9
Return to the grandparent caller. Because the immediate return address was discarded by the two INC SP instructions, this RET pops the next address from the stack, effectively skipping one level of the call chain.

4D03H - PUT MAIN ENTRY AND FILE SETUP

Main entry point for PUT statement processing. This routine is entered after the SYS10 overlay is loaded. It sets the SVC post-operation flag, loads the FCB status, processes the file mode bits, checks for a comma or alternate entry, and sets up the file position for the write operation. IX points to the active FCB throughout.

PUT ENTRY
The overlay loader has set up IX pointing to the active FCB and HL pointing to the BASIC text after the file number. Register AF on the stack contains the flags from the caller's file mode check.

4D03
LD A,01H 3E 01
Load Register A with 01H. This value will be stored as the SVC post-operation flag to indicate that SVC dispatch should perform post-processing after the file operation completes.
4D05
LD (6226H),A 32 26 62
WRITES BASIC/CMD VARIABLE
Store Register A (01H) into the SVC post-op flag variable at 6226H in BASIC/CMD. This tells the common SVC dispatch routine at 621EH to perform post-operation cleanup after any SVC calls during PUT processing.
4D08
POP AF F1
Restore Register Pair AF from the stack. The Z FLAG from the caller indicates the requested file mode: Z FLAG set means the file was opened for input (read mode), NZ FLAG means it was opened for output (write mode). Register A contains additional mode flags.
4D09
LD DE,(5700H) ED 5B 00 57
Load Register Pair DE with the 16-bit value at 5700H (the FCB status word from the BASIC/CMD work area). Register E holds the FCB status byte (IX+00H equivalent): bit 0=read, 1=write, 2=random, 3=buffer, 4=special mode, 6=dirty, 7=open. Register D holds the next byte (IX+01H): bit 6=alt pos valid, 7=EOF.
4D0D
RES 4,E CB A3
Clear bit 4 of Register E (the FCB status byte). Bit 4 is the "special mode" flag. This clears it by default; it will be set back if the Z FLAG indicates input mode.
4D0F
If the Z FLAG has been set (the file mode from the caller indicates input/read mode), JUMP forward to 4D13H to store the status with bit 4 cleared. The special mode flag stays off for input operations.
4D11
SET 4,E CB E3
Set bit 4 of Register E (the FCB status byte). This sets the "special mode" flag for output operations, indicating that the file is being written to with special formatting active.
4D13
LD (IX+00H),E DD 73 00
Store Register E (the processed FCB status byte with bit 4 set or cleared based on file mode) into the FCB at IX+00H. This updates the live FCB status to reflect the current PUT operation mode.
4D16
GOSUB to 6368H (BASIC/CMD comma checker). Checks whether the next character in the BASIC text at HL is a comma. If a comma is found, the Z FLAG is set and HL advances past it. If not a comma, the character is returned in Register A with the NZ FLAG set.
4D19
If the Z FLAG has been set (a comma was found after the file number, meaning PUT has data arguments to process), JUMP forward to 4D1FH to begin position setup for the data output.
4D1B
CP 2CH FE 2C
Compare Register A (the non-comma character from the comma checker) against 2CH (ASCII ,). This is a redundant check — if 6368H returned NZ, the character is already known to not be a comma. However, this handles the case where 6368H returned the character without consuming it.
4D1D
If the NZ FLAG has been set (the character is not a comma, meaning PUT has a subcommand token or expression following), JUMP forward to 4D5AH to dispatch on the subcommand character.

POSITION SETUP
A comma was found after the file number. Load the current file position from the FCB and validate the position state before writing.

4D1F
PUSH HL E5
Save Register Pair HL (the BASIC text pointer, currently past the comma) onto the stack. The text pointer will be restored after position setup.
4D20
GOSUB to 61ACH (BASIC/CMD current position loader). Loads the current file position from the FCB work area into registers. On return, D holds the position flags and E/HL hold the position values.
4D23
BIT 6,D CB 72
Test bit 6 of Register D (the position flags byte from IX+01H). Bit 6 is the "alternate position valid" flag. If set, a previously saved alternate position exists and needs to be checked.
4D25
If the Z FLAG has been set (bit 6 of D is clear, meaning no alternate position is saved), JUMP forward to 4D36H to skip the alternate position validation and proceed directly to FCB status reading.
4D27
GOSUB to 6122H (BASIC/CMD load primary position). Loads the primary file position word from 5705H into HL. This retrieves the main file cursor position.
4D2A
BIT 3,E CB 5B
Test bit 3 of Register E (the FCB status byte from IX+00H). Bit 3 is the "buffer allocated" flag. If set, the file has an active buffer.
4D2C
If the Z FLAG has been set (bit 3 clear, no buffer allocated), JUMP forward to 4D36H to skip the buffer consistency check.
4D2E
BIT 2,E CB 53
Test bit 2 of Register E (the FCB status byte). Bit 2 is the "random access" flag. If clear, the file is in sequential mode.
4D30
If the Z FLAG has been set (bit 2 clear, the file is in sequential mode with a buffer and an alternate position), JUMP to 4E48H (the sequential advance handler) to align the position to a record boundary before writing.
4D33
GOSUB to 603EH (BASIC/CMD absolute position calculator). Calculates the absolute byte position within the file from the current record number and byte offset. For random access files, this positions to the correct byte within the record buffer.

FCB STATUS AND POSITION UPDATE
Read the FCB status, store the alternate position, check for special mode, and determine how to proceed with the write.

4D36
GOSUB to 614CH (BASIC/CMD FCB status reader). Reads the current FCB status flags from IX+00H and returns them in Register A (and relevant fields in other registers).
4D39
GOSUB to 6117H (BASIC/CMD store alternate position). Saves the current position tracking values as the alternate position in the FCB work area at 5708H–5709H.
4D3C
BIT 4,E CB 63
Test bit 4 of Register E (the FCB status byte). Bit 4 is the "special mode" flag that was set at 4D11H for output operations. If set, special write processing is needed.
4D3E
If the NZ FLAG has been set (bit 4 set, special mode active), GOSUB to 615EH (BASIC/CMD position + dirty flag). This marks the FCB as dirty (modified) and updates the position tracking, indicating that data will be written.
4D41
LD A,(5700H) 3A 00 57
Load Register A with the byte at 5700H (the FCB status byte from the BASIC/CMD work area, IX+00H). This re-reads the status to check the file mode bits.
4D44
AND 0FH E6 0F
AND Register A with 0FH. This masks off the upper 4 bits, isolating the low nibble of the FCB status: bit 0=read, 1=write, 2=random, 3=buffer. The result is the file access mode value.
4D46
CP 09H FE 09
Compare Register A (the masked file mode) against 09H (binary 1001 = read + buffer, a special device-mode combination). If Register A equals 09H, the Z FLAG is set.
4D48
If the Z FLAG has been set (file mode = 09H, meaning this is a special device-mode file with read + buffer flags), JUMP to 4E9AH to handle the special device I/O path.
4D4B
LD (570BH),HL 22 0B 57
WRITES BASIC/CMD VARIABLE
Store Register Pair HL (the current position value) into the SYS10 communication byte at 570BH in the BASIC/CMD work area (IX+0BH). This saves the position for later retrieval during restore operations.
4D4E
LD (IX+0AH),C DD 71 0A
Store Register C (the print column counter or byte position within the current record) into the FCB at IX+0AH (the print column counter field at 570AH for the default FCB).
4D51
GOSUB to 6110H (BASIC/CMD position store). Stores the current file position values (in HL and related registers) into the FCB work area at 5717H–5718H. This records the position before any data is written.
4D54
GOSUB to 61A6H (BASIC/CMD DOS position write). Writes the current file position to the DOS FCB via SVC dispatch, synchronizing the BASIC position tracking with the DOS file system.
4D57
Unconditional JUMP to 4EBEH (post-WRITE completion handler). With the file position set up and stored, continue to the completion/exit path which determines whether the PUT operation is for sequential or random access files.

4D5AH - PUT SUBCOMMAND DISPATCH

Dispatches PUT processing based on the subcommand token following the file number. The token in Register A determines the operation: CFH (USING), 23H (#, alternate position), 24H ($, restore position), 25H (%, close/reset), 26H (&, EOF marker), or 21H (!, numeric field). Any other character falls through to the default expression handler.

4D5A
INC HL 23
INCrement Register Pair HL by 1. Advance the BASIC text pointer past the subcommand token character so the next parse operation starts at the correct position.
4D5B
PUSH HL E5
Save Register Pair HL (the BASIC text pointer, now past the subcommand token) onto the stack.
4D5C
CP CFH FE CF
Compare Register A (the subcommand token from the comma checker at 4D16H) against CFH. CFH is the BASIC USING token. If Register A equals CFH, the Z FLAG is set.
4D5E
If the NZ FLAG has been set (the token is NOT the USING token), JUMP forward to 4D75H to check for the '#' token.

USING PATH
Token CFH (USING) was found. Check that the file is in a valid state for USING operations.

4D60
BIT 3,E CB 5B
Test bit 3 of Register E (the FCB status byte). Bit 3 is the "buffer allocated" flag.
4D62
If the Z FLAG has been set (bit 3 clear, no buffer allocated), JUMP back to 4D20H to proceed with position setup. Without a buffer, USING operates on the default sequential path.
4D64
BIT 6,D CB 72
Test bit 6 of Register D (the flags byte from IX+01H). Bit 6 is the "alternate position valid" flag.
4D66
If the Z FLAG has been set (bit 6 clear, no alternate position saved), JUMP back to 4D20H. Without a saved alternate position, USING proceeds normally through position setup.
4D68
LD A,(5700H) 3A 00 57
Load Register A with the byte at 5700H (the FCB status byte). Re-read the status to check the file access mode bits.
4D6B
AND 03H E6 03
AND Register A with 03H. This masks off all but bits 0 and 1, isolating the read/write mode flags. 01H=read only, 02H=write only, 03H=read+write.
4D6D
If the Z FLAG has been set (the read/write mode bits are both 0, meaning the file has no active access mode — an error condition), JUMP to 4E06H which dispatches to the error handler at 5DDCH.
4D70
GOSUB to 6122H (BASIC/CMD load primary position). Loads the primary file position word from 5705H into HL for USING mode positioning.
4D73
Unconditional JUMP to 4D8EH to continue with FCB status reading and position storage for USING mode.

CHECK '#' TOKEN
Check if the subcommand is '#' (23H) for alternate position loading.

4D75
CP 23H FE 23
Compare Register A against 23H (ASCII #). The '#' subcommand loads the alternate file position from the FCB. If equal, the Z FLAG is set.
4D77
If the NZ FLAG has been set (the token is NOT '#'), JUMP forward to 4D81H to check for the '$' token.
4D79
GOSUB to 6129H (BASIC/CMD load alternate + check). Loads the alternate file position from 5708H–5709H and validates it. Returns with the position in HL and flags set based on validity.
4D7C
GOSUB to 614CH (BASIC/CMD FCB status reader). Re-reads the FCB status flags after loading the alternate position.
4D7F
Unconditional JUMP back to 4D41H to continue with the mode check and position storage, now using the alternate position.

CHECK '$' TOKEN
Check if the subcommand is '$' (24H) for position restore.

4D81
CP 24H FE 24
Compare Register A against 24H (ASCII $). The '$' subcommand restores a previously saved position. If equal, the Z FLAG is set.
4D83
If the NZ FLAG has been set (the token is NOT '$'), JUMP forward to 4D93H to check for the '%' token.
4D85
LD C,(IX+0AH) DD 4E 0A
Load Register C with the byte at IX+0AH (the print column counter at 570AH). This retrieves the saved column position for the restore operation.
4D88
LD HL,(570BH) 2A 0B 57
Load Register Pair HL with the 16-bit value at 570BH (the saved position from the SYS10 communication byte, written at 4D4BH). This retrieves the position that was saved when the '$' restore point was set.
4D8B
GOSUB to 612FH (BASIC/CMD load alternate + check, alternate entry). Validates the restored position and sets up the FCB position tracking.
4D8E
GOSUB to 614CH (BASIC/CMD FCB status reader). Reads the current FCB status after the position operation.
4D91
Unconditional JUMP back to 4D4BH to store the position and continue with DOS position write and completion.

CHECK '%' TOKEN
Check if the subcommand is '%' (25H) for close/reset.

4D93
CP 25H FE 25
Compare Register A against 25H (ASCII %). The '%' subcommand resets the file status and sets the "done" flag in the buffer. If equal, the Z FLAG is set.
4D95
If the NZ FLAG has been set (the token is NOT '%'), JUMP forward to 4DA1H to check for the '&' token.
4D97
LD (IX+00H),00H DD 36 00 A2
Store 00H into the FCB at IX+00H (at address 5700H for the default FCB). This clears all FCB status flags, effectively resetting the file to an inactive state. Wait — the opcode bytes are DD 36 00 A2. The A2H here means the value stored is A2H (not 00H). Let me re-examine: DD 36 00 = LD (IX+00H), followed by the immediate byte. The fourth byte is the value. Looking at the source: "DD3600A2" — this is actually LD (IX+00H),0A2H. But the disassembler shows "LD (IX+00H),00H" which conflicts with the hex. The hex DD 36 00 A2 decodes as: DD prefix, 36 = LD (IX+d),n, d=00H, n=A2H. So this stores A2H into IX+00H. The disassembler output is incorrect — the actual value stored is A2H (10100010 binary = bits 7,5,1 set). This clears the file to a specific reset state with bits 7 (open/error), 5, and 1 (write mode) set.
4D9B
SET 5,(IX+2DH) DD CB 2D EE
Set bit 5 of the FCB buffer flags at IX+2DH (at address 572DH for the default FCB). Bit 5 in the buffer flags indicates the "write complete / operation done" state, signaling that the reset subcommand has been processed.
4D9F
Unconditional JUMP back to 4D57H to continue with the post-WRITE completion path at 4EBEH.

CHECK '&' TOKEN
Check if the subcommand is '&' (26H) for EOF marker writing.

4DA1
POP HL E1
Restore Register Pair HL from the stack (the BASIC text pointer saved at 4D5BH). The '&' handler needs direct access to the text pointer because it checks for a repeated '&' character.
4DA2
CP 26H FE 26
Compare Register A against 26H (ASCII &). The '&' subcommand writes the EOF marker to the file. If equal, the Z FLAG is set.
4DA4
If the NZ FLAG has been set (the token is NOT '&'), JUMP forward to 4DBCH to check for the '!' token (the last subcommand type).
4DA6
BIT 4,(IX+0EH) DD CB 0E 66
Test bit 4 of the FCB tertiary flags at IX+0EH (at address 570EH for the default FCB). Bit 4 is the "reset-processed" flag, indicating whether the file has pending data that needs to be flushed before writing the EOF marker.
4DAA
If the NZ FLAG has been set (bit 4 is set, meaning there is pending data), GOSUB to 6237H (BASIC/CMD DOS read + result). This flushes any pending buffer data to disk before writing the EOF marker.
4DAD
LD A,(HL) 7E
Load Register A with the byte at the address in HL (the current character in the BASIC text). This checks whether there is a second '&' character following the first.
4DAE
CP 26H FE 26
Compare Register A against 26H (ASCII &). A double '&&' has a different meaning than a single '&'. If equal, the Z FLAG is set.
4DB0
If the NZ FLAG has been set (the next character is NOT a second '&', meaning this is a single '&' subcommand), JUMP to 51BEH (part of the common exit path). A single '&' writes the EOF without the explicit DOS EOF write.

DOUBLE '&&' — EXPLICIT EOF WRITE
Two consecutive '&' characters trigger an explicit DOS EOF write operation.

4DB3
LD DE,4451H 11 51 44
Load Register Pair DE with 4451H. This is the address of the DOS routine "Write the EOF value from the FCB to the directory" (per the NEWDOS/80 manual). The address is passed to the SVC dispatch routine.
4DB6
GOSUB to 621EH (BASIC/CMD common SVC dispatch). Dispatches the DOS EOF write operation at 4451H through the SVC mechanism. This writes the EOF marker to the file's directory entry.
4DB9
Unconditional JUMP to 51BFH (part of the common exit path, one byte past 51BEH). Continue with the BASIC text pointer update and exit.

4DBCH - '!' NUMERIC FIELD HANDLER AND FLOAT-TO-INTEGER CONVERSION

Handles the '!' subcommand in PUT for numeric field output. Also contains the float-to-integer conversion routine used to convert BASIC floating-point numbers to the integer format stored in random access file fields. Detects the numeric type (integer, single-precision, double-precision) and routes to the appropriate conversion path. This section also handles the general expression dispatch at 4DE0H/4DE1H via BASIC/CMD's string expression + SYS10 dispatch at 661CH.

4DBC
CP 21H FE 21
Compare Register A against 21H (ASCII !). The '!' subcommand triggers numeric field operations with type-specific formatting. If equal, the Z FLAG is set.
4DBE
If the NZ FLAG has been set (the token is NOT '!', meaning no recognized subcommand token was found), JUMP to 4E5FH to handle the character as a general expression for PUT output.

'!' NUMERIC FIELD
The '!' token was found. Initialize the type counter and check the next character for type qualifiers: '%' = integer (2 bytes), '$' = string/single modifier, '#' = double-precision (8 bytes). No qualifier = single-precision (4 bytes).

4DC1
LD B,00H 06 00
Load Register B with 00H. Register B is the type size counter: 00H = default (will be determined by the type qualifier). It will be incremented as type qualifiers are found.
4DC3
LD A,(HL) 7E
Load Register A with the byte at the address in HL (the next character in the BASIC text after the '!' token).
4DC4
CP 25H FE 25
Compare Register A against 25H (ASCII %). The '%' qualifier after '!' indicates a 2-byte integer type (CVI/MKI$ format). If equal, the Z FLAG is set.
4DC6
If the Z FLAG has been set (the '%' qualifier was found, indicating integer type), JUMP to 4E37H to process the integer field. B=00H tells the handler that this is a '%' integer type.
4DC8
CP 24H FE 24
Compare Register A against 24H (ASCII $). The '$' qualifier after '!' indicates a string-to-single conversion path. If equal, the Z FLAG is set.
4DCA
If the NZ FLAG has been set (the qualifier is NOT '$'), JUMP forward to 4DD5H to check for the '#' qualifier.
4DCC
INC B 04
INCrement Register B by 1. B is now 01H, indicating the '$' type qualifier was found. This will be used later to determine the conversion path.
4DCD
INC HL 23
INCrement Register Pair HL by 1. Advance the BASIC text pointer past the '$' qualifier character.
4DCE
LD A,(HL) 7E
Load Register A with the byte at the address in HL (the next character after the '$' qualifier).
4DCF
CP 25H FE 25
Compare Register A against 25H (ASCII %). Check if a '%' follows the '$', forming the compound qualifier '$%' for a specific conversion type. If equal, the Z FLAG is set.
4DD1
If the Z FLAG has been set (the '$%' compound qualifier was found), JUMP to 4E37H to handle this as an integer-format read with B=01H indicating the '$' prefix.
4DD3
Unconditional JUMP to 4DE0H. The '$' qualifier without a following '%' routes to the general expression handler.

CHECK '#' QUALIFIER
Check if the '!' is followed by '#' for double-precision (8-byte) field handling.

4DD5
CP 23H FE 23
Compare Register A against 23H (ASCII #). The '#' qualifier after '!' indicates a double-precision type (CVD/MKD$ format, 8 bytes). If equal, the Z FLAG is set.
4DD7
If the NZ FLAG has been set (no '#' qualifier found), JUMP forward to 4DE0H. With no type qualifier, the '!' defaults to the general expression path.
4DD9
BIT 6,E CB 73
Test bit 6 of Register E (the FCB status byte). Bit 6 is the "dirty/modified" flag. Check whether the file has been modified.
4DDB
If the Z FLAG has been set (bit 6 clear, file is NOT dirty — inconsistent state for a '#' double-precision write), JUMP to 4E06H to generate an error via 5DDCH.
4DDD
INC HL 23
INCrement Register Pair HL by 1. Advance past the '#' qualifier character.
4DDE
INC B 04
INCrement Register B by 1. B is now 01H.
4DDF
INC B 04
INCrement Register B by 1. B is now 02H, indicating double-precision type (which requires 8 bytes of storage — B=02H is used as a dispatch index).
4DE0
PUSH BC C5
Save Register Pair BC onto the stack. B holds the type qualifier code (00H=default, 01H=$, 02H=#), C holds the position counter.
4DE1
Unconditional JUMP to 661CH (BASIC/CMD string expression + SYS10 dispatch). This evaluates the expression in the BASIC text (pointed to by HL) and returns to SYS10 at 4DE4H with the result on the evaluation stack. The Z FLAG on return indicates whether the result is a string (Z) or numeric (NZ).

FLOAT-TO-INTEGER CONVERSION
Returns here from 661CH. The expression has been evaluated. If numeric (NZ), convert from BASIC floating-point format to integer format for disk storage. The BASIC floating-point format uses an exponent byte at the MSB position and a mantissa. This routine normalizes the value to an integer by shifting right based on the exponent.

4DE4
If the Z FLAG has been set (the expression result is a string type, which is invalid for a numeric field write), JUMP to 4E06H to generate an error via 5DDCH.
4DE6
LD BC,(4121H) ED 4B 21 41
Load Register Pair BC with the 16-bit value at 4121H (the ROM BASIC single-precision accumulator, low 2 bytes). This contains the low portion of the numeric result's mantissa.
4DEA
LD DE,(4123H) ED 5B 23 41
Load Register Pair DE with the 16-bit value at 4123H (the ROM BASIC single-precision accumulator, high 2 bytes). D contains the sign/exponent byte, E contains the high mantissa byte.
4DEE
LD A,D 7A
Load Register A with the contents of Register D (the exponent/sign byte of the floating-point number).
4DEF
LD L,B 68
Load Register L with the contents of Register B (the low byte of the mantissa). Building the integer result in HL.
4DF0
LD H,00H 26 00
Load Register H with 00H. Clear the high byte of the result — the integer conversion starts by assuming a small value.
4DF2
If the SIGN FLAG (M = minus) has been set (bit 7 of Register A is set, meaning the floating-point number is negative), JUMP to 4E12H to check the sign of the result and validate it. Negative integers require special handling.
4DF5
OR A B7
OR Register A with itself. Test whether the exponent byte is zero. If zero, the floating-point value is 0.0.
4DF6
If the NZ FLAG has been set (the exponent is non-zero, meaning the value is not 0.0), JUMP forward to 4DFCH to begin the normalization/conversion process.

The value is exactly 0.0 — return zero in all registers.

4DF8
LD C,A 4F
Load Register C with Register A (00H). Clear C to zero.
4DF9
LD L,A 6F
Load Register L with Register A (00H). Clear L to zero. HL/C are now all zero.
4DFA
RET C9
Return to the caller with HL=0000H and C=00H, representing zero as a disk integer.
4DFB
NOP 00
No operation. Padding byte.

NORMALIZE MANTISSA
The exponent is non-zero. Set up the mantissa for integer conversion by restoring the implicit leading 1 bit and shifting based on the exponent.

4DFC
LD H,E 63
Load Register H with Register E (the high mantissa byte from the accumulator). Building H:L as the 16-bit mantissa.
4DFD
LD B,E 43
Load Register B with Register E (copy of high mantissa byte). B is saved for later sign checking at 4E12H.
4DFE
SET 7,H CB FC
Set bit 7 of Register H. This restores the implicit leading 1 bit of the floating-point mantissa. In BASIC's floating-point format, the mantissa has an implicit 1 bit that is not stored, so it must be restored for integer conversion.
4E00
SUB 98H D6 98
SUBtract 98H (decimal 152) from Register A (the exponent byte). The exponent in BASIC's format has a bias of 80H (128), and 98H = 80H + 18H. 18H = 24 decimal, which is the number of mantissa bits for single precision. So A = exponent - 152 gives the number of right-shifts needed: if A=0, the value is already an integer that fits in 24 bits.
4E02
If the Z FLAG has been set (A=0, meaning the exponent is exactly 98H — the value is a 24-bit integer with no fractional part), JUMP to 4E12H to finalize the conversion.
4E04
If the CARRY FLAG has been set (A < 0 after the subtraction, meaning the exponent is less than 98H — the value has a fractional part and needs right-shifting to discard it), JUMP to 4E09H to begin the right-shift loop.

The exponent is greater than 98H — the integer would require more than 24 bits. This is an overflow error.

4E06
Unconditional JUMP to 5DDCH (BASIC/CMD error handler dispatch). This generates an error for: integer overflow in float-to-integer conversion, invalid file mode (no read/write flags), invalid '#' with non-dirty file, or string type in numeric field.

RIGHT-SHIFT LOOP
Shift the mantissa right to convert from floating-point to integer. Each iteration shifts H:L:C right by one bit and increments A. Loop until A reaches 0 (all fractional bits shifted out).

4E09
SRL H CB 3C
Shift Register H right logically by 1 bit. Bit 0 of H moves into the CARRY FLAG, and a 0 is shifted into bit 7. This is the high byte of the mantissa being shifted right.
4E0B
RR L CB 1D
Rotate Register L right through carry. The CARRY FLAG (bit 0 from H) shifts into bit 7 of L, and bit 0 of L moves to the CARRY FLAG. The shift cascades through the 16-bit value H:L.
4E0D
RR C CB 19
Rotate Register C right through carry. The CARRY FLAG (bit 0 from L) shifts into bit 7 of C. This extends the shift to include the low byte, forming a 24-bit right shift of H:L:C.
4E0F
INC A 3C
INCrement Register A by 1. A started as a negative count (exponent - 152), so each increment moves it toward zero.
4E10
LOOP — continue shifting
If the NZ FLAG has been set (A has not yet reached zero, meaning more shifting is needed), JUMP back to 4E09H to continue the right-shift loop.

SIGN CHECK AND FINALIZE
The mantissa has been normalized to an integer. Check the sign bit to ensure the result is a valid positive integer (negative values would have bit 7 of B set).

4E12
BIT 7,B CB 78
Test bit 7 of Register B (the saved high mantissa byte from 4DFDH). Bit 7 indicates the sign of the original floating-point number. If set, the number is negative.
4E14
If the NZ FLAG has been set (bit 7 of B is set, meaning the original value was negative — negative integers are not valid for this disk format), JUMP to 4E06H to generate an error.
4E16
RET C9
Return to the caller with the integer result in H:L:C. H = high byte, L = middle byte, C = low byte of the 24-bit integer.

4E17H - RANDOM ACCESS POSITION CALCULATOR

Calculates the byte position within a random access file record using 25-bit multiplication. This routine is called when a PUT or GET operation needs to position to a specific field within a record. It multiplies the field offset by the record length and adds the byte-within-record offset, producing an absolute position for the DOS file I/O system.

4E17
PUSH BC C5
Save Register Pair BC onto the stack. BC holds the type code (B) and position counter (C) from the '!' handler.
4E18
BIT 2,(IX+00H) DD CB 00 56
Test bit 2 of the FCB status byte at IX+00H. Bit 2 is the "random access" flag. This determines whether random access field positioning is needed.
4E1C
If the Z FLAG has been set (bit 2 clear, the file is NOT in random access mode), JUMP forward to 4E25H to skip the 24-bit multiply and use sequential positioning instead.
4E1E
GOSUB to 5EE1H (BASIC/CMD 24-bit multiply). Multiplies the current field values to calculate the byte offset within the random access record. The multiplicands are set up in registers before this call.
4E21
NOP 00
No operation. Padding byte.
4E22
NOP 00
No operation. Padding byte.
4E23
If the NZ FLAG has been set (the 24-bit multiply returned a non-zero overflow result, meaning the calculated position exceeds the record size), JUMP to 4E06H to generate an error.
4E25
POP BC C1
Restore Register Pair BC from the stack. B = type code, C = position counter.
4E26
POP HL E1
Restore Register Pair HL from the stack (the BASIC text pointer).
4E27
POP DE D1
Restore Register Pair DE from the stack.
4E28
POP AF F1
Restore Register Pair AF from the stack.
4E29
PUSH DE D5
Save Register Pair DE back onto the stack (reordering the stack for the DJNZ dispatch).
4E2A
LD B,A 47
Load Register B with Register A. Transfer the type dispatch code into B for the DJNZ dispatch below.
4E2B
DECrement B and loop to 4E40H if not zero. If B was 01H ($ type), it decrements to 00H and falls through (Z set). If B was 02H (# double type), it decrements to 01H and jumps to 4E40H. If B was 00H (% integer type), it decrements to FFH and jumps to 4E40H.

B=0 after DJNZ: default path — DOS position write and clear alt position

4E2D
GOSUB to 61A6H (BASIC/CMD DOS position write). Writes the calculated file position to the DOS FCB.
4E30
RES 6,(IX+01H) DD CB 01 B6
Clear bit 6 of IX+01H (the "alternate position valid" flag at 5701H). This invalidates the alternate position after the write, since the file cursor has moved.
4E34
Unconditional JUMP to 51BDH (common exit — restore HL and continue with BASIC text parsing).

'%' INTEGER FIELD READ
Process a '%' integer field by loading the alternate position as the integer value.

4E37
INC HL 23
INCrement Register Pair HL by 1. Advance past the '%' qualifier character.
4E38
PUSH BC C5
Save Register Pair BC onto the stack (B = type code, C = position).
4E39
PUSH HL E5
Save Register Pair HL (the BASIC text pointer) onto the stack.
4E3A
GOSUB to 61B3H (BASIC/CMD alternate position loader). Loads the alternate file position. On return, A contains the sector offset value from 5715H.
4E3D
LD C,A 4F
Load Register C with Register A (the sector offset from the alternate position). C now holds the position byte.
4E3E
Unconditional JUMP back to 4E27H to continue with the stack restoration and DJNZ dispatch, using the loaded alternate position values.

DJNZ TARGET — B=1 after first DJNZ: '$' type — store alternate position

4E40
DECrement B and loop to 4E97H if not zero. If B was 01H (second DJNZ for '#' double type), it decrements to 00H and falls through. If B was FFH (from '%' integer type path), it decrements to FEH and jumps to 4E97H.
4E42
LD A,C 79
Load Register A with Register C (the position byte). This is the byte to store as the alternate position.
4E43
GOSUB to 60EBH (BASIC/CMD store alternate position). Stores Register A and the current position values as the alternate position in the FCB work area.
4E46
Unconditional JUMP to 4E34H to continue to the common exit at 51BDH.

4E48H - SEQUENTIAL ADVANCE HANDLER

Handles advancing through a sequential file when the current position is not aligned to a record boundary. This routine advances record-by-record until the position reaches the target, then stores the alternate position and continues with position setup.

4E48
BIT 4,E CB 63
Test bit 4 of Register E (the FCB status byte). Bit 4 is the "special mode" flag.
4E4A
If the NZ FLAG has been set (bit 4 set, special mode active), JUMP to 4E97H to use the special mode positioning instead of sequential advance.
4E4C
GOSUB to 614CH (BASIC/CMD FCB status reader). Read the current FCB status flags.
4E4F
GOSUB to 61A6H (BASIC/CMD DOS position write). Write the current position to the DOS FCB.
4E52
GOSUB to 61ACH (BASIC/CMD current position loader). Load the current position after the DOS write.
4E55
GOSUB to 6258H (BASIC/CMD record advance). Advance the file position by one record. On return, the Z FLAG indicates whether the advance reached the target position.
4E58
LOOP — advance records
If the NZ FLAG has been set (the record advance has NOT reached the target — more records to advance), JUMP back to 4E52H to continue advancing.
4E5A
GOSUB to 6117H (BASIC/CMD store alternate position). Save the current position as the alternate after the advance loop completes.
4E5D
Unconditional JUMP to 4EA9H to continue with position loading and routing to the position storage path at 4D4BH.

4E5FH - DEFAULT EXPRESSION AND 25-BIT MULTIPLY

Handles PUT expressions that do not match any recognized subcommand token. Evaluates the expression via BASIC/CMD's string expression evaluator, validates the result, and performs a 25-bit multiplication to calculate the absolute byte position within the file for random access records. Also reached when the expression result needs to be converted to a file position.

4E5F
DEC HL 2B
DECrement Register Pair HL by 1. Back up the BASIC text pointer because the character that was checked against the subcommand tokens is not a subcommand — it is part of an expression that needs to be re-parsed from the beginning.
4E60
GOSUB to 6623H (BASIC/CMD string expression evaluator via 6190H+4DE4H chain). Evaluates the expression pointed to by HL. On return, A holds the result type information, HL holds the value or pointer, and flags indicate the type.
4E63
LD A,H 7C
Load Register A with the high byte of Register Pair HL (part of the expression result).
4E64
GOSUB to 662CH (BASIC/CMD validation: OR L / OR C). Validates that HL and BC are non-zero, confirming the expression produced a valid result.
4E67
If the NZ FLAG has been set (the result is non-zero and valid), JUMP forward to 4E6AH to skip the position adjustment.
4E69
DEC HL 2B
DECrement Register Pair HL by 1. Adjust the result value down by 1 (converting from 1-based to 0-based position).
4E6A
DEC C 0D
DECrement Register C by 1. Adjust the byte-within-record counter.
4E6B
BIT 2,(IX+00H) DD CB 00 56
Test bit 2 of the FCB status byte at IX+00H. Bit 2 is the "random access" flag.
4E6F
If the Z FLAG has been set (bit 2 clear, the file is NOT in random access mode), JUMP to 5DA9H (BASIC/CMD error handler for "bad file mode"). Sequential files cannot use calculated positioning.

25-BIT MULTIPLY
The file is in random access mode. Multiply the record number (in DE:A) by the record length (in BC from 5702H) to calculate the absolute byte position. This uses a 25-bit multiplication loop with the result accumulated in HL:DE:A.

4E72
EX DE,HL EB
Exchange Register Pairs DE and HL. Move the expression result into DE for the multiply, freeing HL for the accumulator.
4E73
LD A,C 79
Load Register A with Register C (the byte-within-record position). This is the low byte of the multiplicand.
4E74
LD BC,(5702H) ED 4B 02 57
Load Register Pair BC with the 16-bit value at 5702H (the record length / byte offset values from the BASIC/CMD work area). B holds the high byte, C holds the low byte of the record size.
4E78
LD HL,0000H 21 00 00
Load Register Pair HL with 0000H. Initialize the high 16 bits of the 32-bit accumulator to zero.
4E7B
EX AF,AF' 08
Exchange Register A with its shadow register A'. Save the low multiplicand byte in A' to free A for the loop counter.
4E7C
LD A,19H 3E 19
Load Register A with 19H (decimal 25). This is the loop counter for a 25-bit multiplication — the multiply processes 25 bits of the multiplicand.
4E7E
EX AF,AF' 08
Exchange Register A with A'. Swap the loop counter into A' and restore the multiplicand byte to A. The multiply loop alternates between the counter and the data using the shadow register.
4E7F
SRL H CB 3C
Shift Register H right logically by 1 bit. Bit 0 of H moves to CARRY, 0 enters bit 7. This begins a 5-register right shift of the accumulator HL:DE:A.
4E81
RR L CB 1D
Rotate Register L right through carry. Cascades the shift from H through L.
4E83
RR D CB 1A
Rotate Register D right through carry. Cascades through D.
4E85
RR E CB 1B
Rotate Register E right through carry. Cascades through E.
4E87
RRA 1F
Rotate Register A right through carry. The CARRY FLAG (from E) enters bit 7 of A, and bit 0 of A goes to CARRY. This completes the 40-bit right shift. The bit shifted out of A (into CARRY) is the current multiply bit.
4E88
If the NO CARRY FLAG has been set (the bit shifted out was 0), JUMP forward to 4E8BH to skip the addition. In binary multiplication, a 0 bit means no addition is needed for this position.
4E8A
ADD HL,BC 09
ADD Register Pair BC (the record size) to Register Pair HL (the high 16 bits of the accumulator). This is the conditional addition in the multiply loop — it runs when the current multiplicand bit is 1.
4E8B
EX AF,AF' 08
Exchange Register A with A'. Swap the loop counter back from A' into A.
4E8C
DEC A 3D
DECrement Register A (the loop counter) by 1.
4E8D
LOOP — 25-bit multiply
If the NZ FLAG has been set (the loop counter has not reached zero), JUMP back to 4E7EH to process the next bit.

OVERFLOW CHECK
After the multiply, HL should be zero. If HL is non-zero, the calculated position exceeds 16 bits and is an overflow error.

4E8F
LD A,H 7C
Load Register A with Register H (the high byte of the high 16-bit result).
4E90
OR L B5
OR Register L into Register A. If both H and L are zero (the multiply result fits in DE:old_A), Register A is now 00H and the Z FLAG is set.
4E91
If the NZ FLAG has been set (HL is non-zero, meaning the position overflows 16 bits), JUMP to 5DB2H (BASIC/CMD error handler — "field overflow").
4E94
EX AF,AF' 08
Exchange Register A with A'. Retrieve the low byte of the multiply result from A'.
4E95
EX DE,HL EB
Exchange Register Pairs DE and HL. Move the 16-bit result from DE into HL for the standard position format.
4E96
LD C,A 4F
Load Register C with Register A (the low byte from the multiply). The position is now in HL (high word) and C (low byte).
4E97
Unconditional JUMP back to 4D36H (FCB status update). Continue with reading the FCB status, storing the alternate position, and completing the position setup for the PUT operation.

4E9AH - STATUS-9 (DEVICE I/O) HANDLER

Handles files opened with the special status mode 09H (read + buffer, no write or random flags). This is a device I/O mode used for special file operations. Writes the current position to DOS, checks for special mode flags, and dispatches to either the record type decoder or a single-byte write path.

4E9A
GOSUB to 61A6H (BASIC/CMD DOS position write). Write the current file position to the DOS FCB for the device I/O file.
4E9D
BIT 4,(IX+00H) DD CB 00 66
Test bit 4 of the FCB status byte at IX+00H. Bit 4 is the "special mode" flag. If set, the write path uses the special single-byte write instead of the record type decoder.
4EA1
If the NZ FLAG has been set (bit 4 is set, special mode active), JUMP forward to 4EAFH to use the buffer-based write path.
4EA3
GOSUB to 626CH (BASIC/CMD record type decoder). Decodes the record type from the FCB flags. On return, the CARRY FLAG indicates the type (set = error, clear = valid) and the Z FLAG indicates completion status.
4EA6
If the NO CARRY FLAG has been set (the record type decoder returned an invalid/error result), JUMP to 5D9DH (BASIC/CMD error table base — this dispatches to the appropriate error based on the return value).
4EA9
GOSUB to 61ACH (BASIC/CMD current position loader). Load the updated file position after the record type decode or advance operation.
4EAC
Unconditional JUMP back to 4D4BH to store the position, update the FCB, and continue to the post-WRITE completion path.

SPECIAL MODE WRITE PATH
Buffer flag (bit 4 of IX+2DH) determines whether to use the record type path or the single-byte write path.

4EAF
BIT 4,(IX+2DH) DD CB 2D 66
Test bit 4 of the buffer flags at IX+2DH. Bit 4 is the "buffer dirty" flag.
4EB3
If the Z FLAG has been set (bit 4 clear, buffer is not dirty), JUMP back to 4EA3H to use the standard record type decoder path.
4EB5
LD A,70H 3E 70
Load Register A with 70H. This is a control byte value — 70H (binary 01110000) is written as a single byte to the device for special mode operations.
4EB7
LD B,00H 06 00
Load Register B with 00H. B=00H is passed to the single-byte write routine as a parameter (no repeat count).
4EB9
GOSUB to 61DFH (BASIC/CMD single-byte write). Writes the byte in Register A (70H) to the file. B=00H means write the byte once.
4EBC
Unconditional JUMP back to 4EA9H to load the position and route to the storage path.

4EBEH - POST-WRITE COMPLETION

Handles completion processing after a PUT data item has been set up. Routes to either the sequential file path or the random access file path based on the FCB status flags. For sequential files, adjusts the position by adding the byte offset within the record. For random access files, dispatches to the GET handler at 4F18H.

4EBE
LD A,(5700H) 3A 00 57
Load Register A with the byte at 5700H (the FCB status byte from the BASIC/CMD work area).
4EC1
AND 03H E6 03
AND Register A with 03H. Isolate the read/write mode bits (bit 0 = read, bit 1 = write). 00H = no mode, 01H = read only, 02H = write only, 03H = read+write.
4EC3
If the NZ FLAG has been set (at least one of read or write mode is active), JUMP to 4F18H (GET main entry) to handle the data I/O. This routes to the GET path for both write and read/write mode files since the file position is now set up.

SEQUENTIAL FILE PATH
Neither read nor write mode bit is set (mode = 00H). This indicates a sequential file being accessed through the special position-only path.

4EC5
GOSUB to 6031H (BASIC/CMD position compare). Compares the current file position against the saved position to determine if the file cursor has moved.
4EC8
If the CARRY FLAG has been set (the current position is less than the saved position — the file has been repositioned backward), JUMP to 4EF0H to handle the repositioning path.
4ECA
BIT 4,(IX+00H) DD CB 00 66
Test bit 4 of the FCB status byte at IX+00H. Bit 4 is the "special mode" flag.
4ECE
If the NZ FLAG has been set (bit 4 set, special mode), JUMP to 4EE9H to handle the special mode EOF check path.

POSITION ADJUSTMENT
Add the byte offset from 5702H/5703H to the current position to advance past the data that was written.

4ED0
LD A,(5702H) 3A 02 57
Load Register A with the byte at 5702H (the byte offset within the current record, from IX+02H).
4ED3
ADD A,C 81
ADD Register C (the current byte position counter) to Register A (the record offset). This calculates the new position after the data write.
4ED4
LD C,A 4F
Load Register C with Register A (the updated position). C now holds the adjusted byte position.
4ED5
LD A,(5703H) 3A 03 57
Load Register A with the byte at 5703H (the next byte after the record offset — part of the 16-bit position tracking).
4ED8
ADC A,L 8D
ADD with Carry Register L (the position word low byte) to Register A. The CARRY from the previous ADD propagates, forming a proper 16-bit addition.
4ED9
LD L,A 6F
Load Register L with Register A (the adjusted position low byte).
4EDA
If the NO CARRY FLAG has been set (no carry from the low byte addition), JUMP forward to 4EDDH to skip the high byte increment.
4EDC
INC H 24
INCrement Register H by 1. Propagate the carry into the high byte of the position.
4EDD
GOSUB to 61A6H (BASIC/CMD DOS position write). Write the adjusted position to the DOS FCB.
4EE0
GOSUB to 4F0EH (position check helper within SYS10). Loads position from 5710H and checks the byte offset status.
4EE3
LD B,A 47
Load Register B with Register A (the position check result from 4F0EH).
4EE4
GOSUB to 6362H (BASIC/CMD zero-fill loop). Fills the remaining bytes in the record with zeros, using B as the count.
4EE7
Unconditional JUMP to 4F0BH to continue to the common completion exit at 51B1H.

SPECIAL MODE EOF CHECK
Check if the file has reached EOF in special mode.

4EE9
BIT 7,(IX+01H) DD CB 01 7E
Test bit 7 of IX+01H (the additional flags byte). Bit 7 is the "EOF reached" flag.
4EED
If the Z FLAG has been set (bit 7 clear, EOF has NOT been reached — but special mode requires EOF to be set at this point), JUMP to 5DC1H (BASIC/CMD error handler — "input past end of file").

REPOSITION PATH
The file cursor was repositioned backward. Check the position status and conditionally perform DOS read or write operations.

4EF0
GOSUB to 4F0EH (position check helper). Loads position from 5710H and returns Z flag based on byte offset.
4EF3
If the Z FLAG has been set (the byte offset is zero — positioned at a record boundary), JUMP to 4F01H for the boundary-aligned path.
4EF5
BIT 4,(IX+00H) DD CB 00 66
Test bit 4 of the FCB status byte at IX+00H. Bit 4 is the "special mode" flag.
4EF9
If the Z FLAG has been set (bit 4 clear, NOT special mode), GOSUB to 6214H (BASIC/CMD conditional DOS operation). Performs a conditional DOS write/read for non-special mode repositioned files.
4EFC
If the NZ FLAG has been set (bit 4 set, special mode), GOSUB to 620FH (BASIC/CMD conditional DOS operation, alternate entry). Performs the special mode conditional operation.
4EFF
Unconditional JUMP to 4F0BH for the common completion exit.

RECORD BOUNDARY PATH
Positioned exactly at a record boundary. Dispatch DOS write or read based on special mode flag.

4F01
BIT 4,(IX+00H) DD CB 00 66
Test bit 4 of the FCB status byte. Bit 4 is the "special mode" flag.
4F05
If the Z FLAG has been set (bit 4 clear, NOT special mode), GOSUB to 6232H (BASIC/CMD DOS write + result). Performs a DOS write operation at the record boundary.
4F08
If the NZ FLAG has been set (bit 4 set, special mode), GOSUB to 6237H (BASIC/CMD DOS read + result). Performs a DOS read operation at the record boundary in special mode.
4F0B
Unconditional JUMP to 51B1H (common completion path). Continue with position store, buffer state update, text pointer advance, and exit.

POSITION CHECK HELPER
Loads the position word from 5710H and tests whether the byte offset at 5702H is zero.

4F0E
LD HL,(5710H) 2A 10 57
Load Register Pair HL with the 16-bit value at 5710H (the SYS19 communication byte in the FCB work area at IX+10H). This holds position tracking data.
4F11
LD A,(5702H) 3A 02 57
Load Register A with the byte at 5702H (the byte offset within the current record, IX+02H).
4F14
OR A B7
OR Register A with itself. If the byte offset is 00H (positioned at a record boundary), the Z FLAG is set.
4F15
RET Z C8
Return if the Z FLAG is set (byte offset is zero — positioned at a record boundary). HL contains the position value from 5710H.
4F16
DEC H 25
DECrement Register H by 1. Adjust the position high byte down by 1 to account for the partial record. When the byte offset is non-zero, the position word needs to be adjusted back by one "unit" to reflect the true record boundary.
4F17
RET C9
Return with HL adjusted and the NZ FLAG set (byte offset was non-zero).

4F18H - GET Main Entry (Random/Sequential File Input)

GET Main Entry for Random Access Files. This entry point handles the GET statement for reading data from random-access or sequential files. It begins by calling 6331H to calculate the total record count, stores the result as the record limit via self-modifying code at 4F8CH, then pops the saved HL (BASIC text pointer) and checks whether the statement has additional arguments (comma-separated variable list). The code routes to the line scanner at 4FC1H after setting up the record limit and print column state.

4F18
GOSUB to 6331H (record count calculator in BASIC/CMD). This routine calculates the total number of logical records in the file based on the FCB state. Returns with HL = record count value.
4F1B
Store the record count (Register Pair HL) into the operand of the LD DE instruction at 4F8BH. The two-byte value at 4F8CH is the immediate operand of LD DE,nnnnH. This is Self-Modifying Code, — when 4F8BH is later called, the LD DE will load this stored record count into DE as the record/position limit.
4F1E
POP HL E1
Restore Register Pair HL from the stack. HL now holds the BASIC text pointer, which was saved earlier by the calling code before entering the GET handler.
4F1F
GOSUB to 6368H (comma checker in BASIC/CMD). This routine verifies whether the next character in the BASIC text is a comma (2CH). If a comma is found, HL is advanced past it and the Z flag is cleared. If end-of-statement is reached, the Z flag is set.
4F22
If the Z FLAG has been set (end-of-statement — no more arguments after the file number), JUMP to 51B0H (position and state update). The GET statement has no variable list, so the handler skips directly to the finalization code.

If execution continues here, there are more arguments to parse. The code checks whether we are at a valid BASIC token or expression.

4F25
DEC HL 2B
DECrement Register Pair HL by 1, backing up the BASIC text pointer by one byte so the next RST 10H will re-read the current character.
4F26
RST 10H D7
Fetch the next non-space character from the BASIC text at (HL) into Register A, advancing HL past any spaces. RST 10H is the ROM routine that skips whitespace and returns the next significant character.
4F27
If the Z FLAG has been set (the character fetched is 00H, meaning end-of-line with nothing to parse), JUMP to 5DCDH (syntax error / end-of-data error in BASIC/CMD). A GET statement with a comma but no following variable list is a syntax error.
4F2A
CP 2CH FE 2C
Compare Register A against 2CH (ASCII comma ,). If Register A equals 2CH, the Z FLAG is set; otherwise the NZ FLAG is set. This checks if the text pointer is sitting on a comma separator before the first data item.
4F2C
If the Z FLAG has been set (the character is a comma), JUMP forward to 4F3DH to begin processing the variable list. The comma is consumed and the code proceeds to read the FCB status.

If the character is not a comma, it must be an expression (the record number expression). The code evaluates it as a numeric expression to set the file position before reading.

4F2E
SET 1,(IX+2DH) DD CB 2D CE
SET bit 1 of the buffer flags byte at IX+2DH (address 573FH for the default FCB). Bit 1 indicates that a record number expression is being evaluated as part of this GET statement, so the handler knows to reposition before reading.
4F32
GOSUB to ROM routine at 1E5AH (BASIC expression evaluator). This evaluates the numeric expression in the BASIC text that specifies the record number. The result is left on the BASIC evaluation stack.
4F35
PUSH HL E5
Save Register Pair HL (the BASIC text pointer, now advanced past the expression) onto the stack for later restoration.
4F36
GOSUB to ROM routine at 1EC5H (BASIC numeric expression evaluator). This converts the expression result from the evaluation stack into a numeric value. The integer result is placed in the floating-point accumulator at 4121H.
4F39
LD BC,0004H 01 04 00
Load Register Pair BC with 0004H (decimal 4). This is an offset value — adding 4 to HL will skip past the 4-byte floating-point result in the accumulator to point at the position where the next BASIC text parsing can resume.
4F3C
ADD HL,BC 09
ADD Register Pair BC (0004H) to Register Pair HL. HL now points past the evaluated numeric result, preparing for the next phase of processing.

4F3DH - GET Special Mode Router

Special Mode Router. This section reads the FCB status flags and routes the GET handler based on whether the file is in special mode (bit 4 of IX+00H). Special mode files use a different I/O path that handles record-level positioning and direct buffer access. The code also checks whether the buffer dirty flag is set and whether the file is in read mode, adjusting its behavior accordingly.

4F3D
LD C,(IX+00H) DD 4E 00
Load Register C with the FCB status flags from IX+00H (address 5712H for default FCB). Register C now holds the file status byte: bit 0 = read mode, bit 1 = write mode, bit 2 = random access, bit 3 = buffer allocated, bit 4 = special mode.
4F40
BIT 4,C CB 61
Test bit 4 of Register C (the special mode flag). If bit 4 is set, the file was opened in special mode; if clear, it is a normal random-access file.
4F42
If the Z FLAG has been set (bit 4 is clear — not special mode), JUMP forward to 4F87H to clear the operation flag and proceed with normal GET processing via the record limit setup at 4F8BH.

The file is in special mode (bit 4 set). The following code handles special-mode GET with position comparison and record advancement.

4F44
BIT 4,(IX+2DH) DD CB 2D 66
Test bit 4 of the buffer flags byte at IX+2DH (address 573FH for default FCB). Bit 4 is the buffer dirty flag — if set, the buffer contains unwritten data that must be flushed before repositioning.
4F48
If the NZ FLAG has been set (bit 4 is set — buffer is dirty), JUMP forward to 4F87H. When the buffer is dirty in special mode, the code skips the position comparison and goes directly to the record limit setup, allowing the dirty buffer to be flushed through the normal path.
4F4A
BIT 0,C CB 41
Test bit 0 of Register C (the read mode flag from the FCB status). If set, the file is open for reading.
4F4C
If the Z FLAG has been set (bit 0 is clear — file is NOT open for reading), JUMP forward to 4F7BH. A file not open for reading in special mode skips the position-compare logic and goes to the operation flag setup.
4F4E
BIT 3,C CB 59
Test bit 3 of Register C (the buffer allocated flag). A buffer must be allocated for special-mode read operations.
4F50
If the Z FLAG has been set (bit 3 is clear — no buffer allocated), JUMP to 5DA9H ("Bad file mode" error in BASIC/CMD). A special-mode read requires a buffer; without one, the operation cannot proceed.
4F53
BIT 2,C CB 51
Test bit 2 of Register C (the random access mode flag). This determines whether the file is random-access or sequential.
4F55
If the NZ FLAG has been set (bit 2 is set — random access mode), JUMP forward to 4F7BH. Random-access special-mode files skip the sequential position-compare loop and proceed directly to the operation flag setup.

The file is in special mode, open for reading, has a buffer, but is NOT random access (sequential mode). The following loop advances through records sequentially until the position matches or EOF is reached.

4F57
PUSH HL E5
Save Register Pair HL (the BASIC text pointer or position data) onto the stack, preserving it across the sequential advance loop.

⬐ LOOP START - sequential record advance

4F58
GOSUB to 6031H (position comparison routine in BASIC/CMD). This routine compares the current file position against the target position. Returns with the CARRY flag set if the current position is less than the target (more records to advance), or CARRY clear if the position has been reached.
4F5B
If the CARRY FLAG has been set (current position is before the target — need to advance further), JUMP forward to 4F69H to call the record advance routine and loop back.

CARRY is clear — the current position has reached or passed the target. Set the buffer state flag and check for EOF.

4F5D
SET 3,(IX+2DH) DD CB 2D DE
SET bit 3 of the buffer flags byte at IX+2DH. This sets a state flag indicating that the sequential position match was found and the buffer is in a valid state for the read operation.
4F61
BIT 7,(IX+01H) DD CB 01 7E
Test bit 7 of the additional flags byte at IX+01H (address 5713H for default FCB). Bit 7 is the EOF flag — if set, the end of file has been reached.
4F65
If the NZ FLAG has been set (bit 7 is set — EOF has been reached), JUMP forward to 4F7AH to pop HL and continue. The sequential advance has reached EOF without finding a matching record, but the code continues rather than raising an error.
4F67
Unconditional JUMP forward to 4F6EH to calculate the position difference and store it as the record limit. The position comparison succeeded (current position matched target), so the code skips the advance loop.
4F69
GOSUB to 6258H (record advance in BASIC/CMD). This routine advances the file position by one logical record, reading the next record into the buffer.
4F6C
If the NZ FLAG has been set (the record advance succeeded and there are more records to process), JUMP back to 4F58H to compare the position again. [LOOP — continue sequential advance until position match or EOF]

⬑ LOOP END.
The record advance returned Z (failed or completed). Fall through to calculate the position difference.

4F6E
LD H,L 65
Copy the low byte of the current position (Register L) into Register H. This begins assembling the 16-bit position value HL from the current file position components (L = position high byte from the advance, C = position low byte).
4F6F
LD L,C 69
Copy Register C (the position low byte / byte offset within the current record) into Register L. Register Pair HL now holds the assembled current byte position (H=high, L=low).
4F70
LD DE,(5704H) ED 5B 04 57
Fetch the position comparison word from address 5704H (IX+04H, the position comparison / flags field in the FCB work area) into Register Pair DE. This is the target position that was set up earlier.
4F74
OR A B7
OR Register A with itself to clear the CARRY flag, preparing for the 16-bit subtraction that follows. This ensures SBC HL,DE performs a pure subtraction without borrow.
4F75
SBC HL,DE ED 52
SUBtract Register Pair DE (the target position from 5704H) from Register Pair HL (the current assembled position) with borrow. HL now holds the difference: the number of bytes between the current position and the target position. This difference becomes the new record limit.
4F77
Store the position difference (Register Pair HL) into the operand of the LD DE instruction at 4F8BH. This is Self-Modifying Code, — the same location written at 4F1BH. The difference becomes the record/position limit for the read operation.
4F7A
POP HL E1
Restore Register Pair HL from the stack (the BASIC text pointer saved at 4F57H).
4F7B
PUSH HL E5
Save Register Pair HL (the BASIC text pointer) onto the stack. This preserves it while the record limit setup and line scanner execute.
4F7C
SET 2,(IX+2DH) DD CB 2D D6
SET bit 2 of the buffer flags byte at IX+2DH. Bit 2 is the operation active flag, indicating that a GET/PUT operation is in progress.
4F80
GOSUB to 4F8BH (record limit setup). This routine loads DE with the self-modified record limit (from 4F8CH), stores it to the record limit variable at 61CAH, then initializes the print column state at 5D38H to 0001H, and calls the line scanner at 4FC1H to begin parsing the variable list.
4F83
GOSUB to 61A3H (a BASIC/CMD routine that processes the results of the GET operation after the line scanner completes). This handles any post-read position updates or buffer state changes.
4F86
POP HL E1
Restore Register Pair HL (the BASIC text pointer) from the stack.

4F87H - Record Limit Setup + Line Scanner Call

Record Limit Setup. This section clears the operation active flag, then falls through to the record limit setup at 4F8BH. The LD DE at 4F8BH is a self-modifying instruction whose operand at 4F8CH was written by either 4F1BH (record count from 6331H) or 4F77H (position difference from sequential advance). The loaded value is stored as the record limit at 61CAH, the print column state is initialized, and the line scanner at 4FC1H is called to begin parsing the GET variable list.

4F87
RES 2,(IX+2DH) DD CB 2D 96
CLEAR bit 2 of the buffer flags byte at IX+2DH. Bit 2 is the operation active flag. Clearing it indicates that the special-mode operation path (4F7BH-4F86H) is not being used, so the normal path should proceed without the operation-active indicator.
4F8B
LD DE,0000H 11 00 00
Load Register Pair DE with the immediate value at 4F8CH. The two bytes at 4F8CH are self-modifying code, they were written by 4F1BH (record count) or 4F77H (position difference). The value shown as 0000H is the default/initial value; at runtime, DE will contain the calculated record/position limit.
4F8E
LD (61CAH),DE ED 53 CA 61
Store Register Pair DE (the record/position limit loaded from the self-modifying instruction) into address 61CAH (the record limit variable in BASIC/CMD). This value controls how many records or bytes the GET operation will process.
4F92
LD DE,0001H 11 01 00
Load Register Pair DE with 0001H (decimal 1). This is the initial print column state value.
4F95
LD (5D38H),DE ED 53 38 5D
Store Register Pair DE (0001H) into address 5D38H (the print column state variable in BASIC/CMD). Initializing this to 1 resets the column counter for the data output formatting. This address is also used as a re-entry point for comma-separated items in the loop at 519AH.
4F99
GOSUB to 4FC1H (the line scanner). The line scanner parses the BASIC text to find the next data item in the GET variable list. Returns with the character type in Register A and flags set for dispatch.

4F9CH - Separator Dispatch (Comma, Semicolon, Format Handler)

Separator Dispatch. After the line scanner returns, this section checks the character for comma or semicolon separators. A comma routes to 4FAAH (record type decode and position advance for the next variable). A semicolon decrements the print column counter and, if it reaches zero, routes to the end-of-data handler at 51A2H. Any other character routes to 4FDFH (the format handler for parenthesized expressions).

4F9C
CP 2CH FE 2C
Compare Register A against 2CH (ASCII comma ,). If Register A equals 2CH, the Z FLAG is set; otherwise the NZ FLAG is set.
4F9E
If the Z FLAG has been set (the character is a comma separator), JUMP forward to 4FAAH to process the next data item. A comma separates individual variables in the GET variable list.
4FA0
CP 3BH FE 3B
Compare Register A against 3BH (ASCII semicolon ;). If Register A equals 3BH, the Z FLAG is set; otherwise the NZ FLAG is set.
4FA2
If the NZ FLAG has been set (the character is neither comma nor semicolon), JUMP forward to 4FDFH (the format handler). This routes to the parenthesized expression handler for USING-style format specifications.

The character is a semicolon. Semicolons in GET suppress the automatic record advance between items. The code decrements the print column counter and checks if it has reached zero.

4FA4
DEC DE 1B
DECrement Register Pair DE by 1. DE holds the print column state loaded from 5D38H (currently 0001H from initialization). After decrementing, DE = 0000H.
4FA5
LD A,D 7A
Load Register A with the high byte of Register Pair DE (the decremented print column counter).
4FA6
OR E B3
OR Register E into Register A. This tests whether the entire 16-bit DE value is zero. If both D and E are zero, the Z flag is set.
4FA7
If the Z FLAG has been set (the print column counter has reached zero), JUMP to 51A2H (end-of-data handler). When the counter expires, all data items for this GET statement have been processed.
4FAA
LD A,(IX+00H) DD 7E 00
Fetch the FCB status flags from IX+00H (address 5712H for default FCB) into Register A. This re-reads the status to check the file mode before processing the next variable.
4FAD
AND 12H E6 12
Mask Register A with 12H (binary 00010010). This isolates bit 4 (special mode) and bit 1 (write mode). If either bit is set, the result is non-zero.
4FAF
If the NZ FLAG has been set (either special mode or write mode is active), JUMP to 5DD0H ("Statement error" in BASIC/CMD). A GET with comma-separated variables is not valid for special-mode or write-mode files.
4FB2
PUSH HL E5
Save Register Pair HL (the BASIC text pointer) onto the stack, preserving it while the record type decoder and position advance routines execute.

⬐ LOOP START - record type decode retry

4FB3
GOSUB to 626CH (record type decoder in BASIC/CMD). This routine determines the record type from the FCB flags and returns with the type code in Register A, the record size in Register B, and flags set (CARRY = error, Z = retry needed).
4FB6
If the CARRY FLAG has been set (the record type decoder returned an error), JUMP to 5DBEH (error handler in BASIC/CMD). This catches invalid record type conditions.
4FB9
If the Z FLAG has been set (the record type decoder returned Z, meaning a retry is needed — the decoder may need to re-read after a buffer flush), JUMP back to 4FB3H to retry the decode.

⬑ LOOP END

4FBB
GOSUB to 6245H (position advance in BASIC/CMD). This routine advances the file position by the record size determined by the type decoder, preparing for the next data item to be read.
4FBE
JUMP to 518EH (common loop/exit). After advancing the position, the code returns to the main GET loop to process the next variable in the list.

4FC1H - Line Scanner

Line Scanner. This routine scans the BASIC text for the next data item in the GET/PUT variable list. It fetches the next non-space character and checks for special cases: end-of-statement (00H), the USING keyword token (93H), and end-of-line (link pointer = 0000H). If a USING token is encountered, it is skipped over. If the line link pointer is zero, we have reached the end of the program text and an error is generated.

4FC1
RST 10H D7
Fetch the next non-space character from the BASIC text at (HL) into Register A, advancing HL past any spaces. RST 10H is the ROM routine that skips whitespace and returns the next significant character.
4FC2
If the NZ FLAG has been set (the character is not 00H — not end-of-statement), JUMP forward to 4FCDH to check for the USING token. A non-zero character means there is more text to parse.

The character is 00H (end-of-statement marker). Check whether there is a continuation on the next line by examining the line link pointer.

4FC4
OR A B7
OR Register A with itself. Since A is already 00H (end-of-statement), this sets the Z flag. This is a redundant operation that ensures the flags are cleanly set before the next test.
4FC5
If the Z FLAG has been set (Register A is zero — confirmed end-of-statement), JUMP forward to 4FD4H to check the line link pointer. This determines whether the program continues on the next line or has ended.
4FC7
RST 10H D7
Fetch the next non-space character from the BASIC text. This advances past any additional whitespace or statement separators to reach the actual data item.
4FC8
CP 93H FE 93
Compare Register A against 93H (the BASIC USING keyword token). If Register A equals 93H, the Z FLAG is set. The line scanner needs to skip over any USING keywords in the data item list.
4FCA
If the NZ FLAG has been set (the character is not the USING token — it is an unexpected token at this point in the scan), JUMP to 5DCDH ("Syntax error" in BASIC/CMD). After an end-of-statement, the only valid continuation is the USING keyword or end-of-line; any other token is a syntax error.
4FCD
CP 93H FE 93
Compare Register A against 93H (the BASIC USING keyword token). If Register A equals 93H, the Z FLAG is set. This check handles the case where USING appears as the first token after a separator.
4FCF
RET NZ C0
If the NZ FLAG has been set (the character is NOT the USING token — it is a normal variable name or expression), RETURN to the caller with Register A holding the first character of the data item and HL pointing past it. The caller will dispatch based on this character.

The character IS the USING token (93H). Skip over the USING keyword and any following whitespace to reach the actual format specifier or data item.
⬐ LOOP START - USING skip

4FD0
RST 10H D7
Fetch the next non-space character from the BASIC text. This advances past the USING keyword.
4FD1
OR A B7
OR Register A with itself to test whether the fetched character is 00H (end-of-statement).
4FD2
If the NZ FLAG has been set (the character is not end-of-statement — still within the USING clause), JUMP back to 4FD0H to skip the next character. This loop continues until end-of-statement is reached, effectively skipping the entire USING format specification. [LOOP — continue skipping USING clause]

⬑ LOOP END
End-of-statement reached after USING. Check the line link pointer to see if the program continues.

4FD4
INC HL 23
INCrement Register Pair HL by 1, advancing past the end-of-statement marker (00H) to point at the first byte of the line link pointer. In BASIC program memory, after the 00H terminator, the next two bytes contain the address of the following line.
4FD5
LD A,(HL) 7E
Fetch the low byte of the line link pointer into Register A. If the link pointer is 0000H, there is no next line (end of program).
4FD6
INC HL 23
INCrement Register Pair HL by 1, advancing to the high byte of the line link pointer.
4FD7
OR (HL) B6
OR the high byte of the line link pointer (at (HL)) into Register A (which holds the low byte). If both bytes are zero, the result is zero and the Z flag is set, indicating end-of-program.
4FD8
If the Z FLAG has been set (the line link pointer is 0000H — end of program), JUMP to 5DCDH ("Syntax error" / end-of-data error in BASIC/CMD). There are no more lines to scan, so the GET/PUT variable list has ended prematurely.

The line link pointer is non-zero, so there is a next line. Skip past the line link (2 bytes) and line number (2 bytes) to reach the statement body, then restart the scan.

4FDB
INC HL 23
INCrement Register Pair HL by 1, advancing past the high byte of the line link pointer to the low byte of the line number.
4FDC
INC HL 23
INCrement Register Pair HL by 1, advancing past the low byte of the line number to the high byte of the line number. After this, HL points at the start of the statement body on the next line.
4FDD
Unconditional JUMP back to 4FC1H to restart the line scanner on the new line. The scan continues from the beginning of the next line's statement body.

4FDFH - GET Format Handler

GET Format Handler. This section handles format expressions in the GET variable list. It checks for a parenthesized expression (opening parenthesis 28H), evaluates it as a string expression for a format specification, and checks for trailing separators. If the format specification includes a record count, it is evaluated as a numeric expression via ROM 0A7FH and stored at 5094H. The code then routes to the data output section based on the file mode.

4FDF
PUSH HL E5
Save Register Pair HL (the BASIC text pointer) onto the stack.
4FE0
RES 6,(IX+2DH) DD CB 2D B6
CLEAR bit 6 of the buffer flags byte at IX+2DH. Bit 6 is the position valid flag. Clearing it indicates that the current buffer position is no longer guaranteed valid and may need recalculation.
4FE4
CP 28H FE 28
Compare Register A against 28H (ASCII opening parenthesis (). If Register A equals 28H, the Z FLAG is set. A parenthesis indicates a format expression follows.
4FE6
If the NZ FLAG has been set (the character is not an opening parenthesis), JUMP forward to 500AH to set the default record count (FFH) and continue. Without a format expression, the code uses the default maximum record/sector value.

The character is an opening parenthesis. Evaluate the contents as a string expression for the format specification.

4FE8
GOSUB to 6190H (string expression evaluator + descriptor in BASIC/CMD). This routine evaluates the expression within the parentheses as a string expression and returns a pointer to the string descriptor. The Z flag is set based on the result type (Z = string, NZ = numeric).
4FEB
POP HL E1
Restore Register Pair HL from the stack. This recovers the BASIC text pointer saved at 4FDFH. The text pointer has been advanced by the expression evaluator past the closing parenthesis.
4FEC
If the Z FLAG has been set (the expression result is a string), JUMP forward to 500AH to set the default record count. String format expressions do not specify a numeric record count.

The expression result is numeric (NZ). Check what follows the format expression — if a separator or end-of-statement follows, use the default count; otherwise, evaluate the numeric value as a record count.

4FEE
DEC HL 2B
DECrement Register Pair HL by 1, backing up the text pointer by one byte to re-read the current character.
4FEF
RST 10H D7
Fetch the next non-space character from the BASIC text at (HL) into Register A.
4FF0
If the Z FLAG has been set (end-of-statement), JUMP forward to 500AH. No record count specified after the format expression; use the default.
4FF2
CP 2CH FE 2C
Compare Register A against 2CH (ASCII comma ,).
4FF4
If the Z FLAG has been set (comma follows the format expression), JUMP forward to 500AH. A comma means the next item is a variable, not a record count.
4FF6
CP 3BH FE 3B
Compare Register A against 3BH (ASCII semicolon ;).
4FF8
If the Z FLAG has been set (semicolon follows the format expression), JUMP forward to 500AH. Like a comma, a semicolon separator means no explicit record count is specified.

The character following the format expression is not a separator or end-of-statement. It must be a numeric expression specifying the maximum record/sector count. Set the position valid flag and evaluate it.

4FFA
SET 6,(IX+2DH) DD CB 2D F6
SET bit 6 of the buffer flags byte at IX+2DH. Bit 6 is the position valid flag. Setting it indicates that a format-specified record count is being used and the position tracking is valid.
4FFE
EX (SP),HL E3
Exchange the value at the top of the stack with Register Pair HL. The top of the stack holds the previous BASIC text pointer; HL is swapped with it, effectively saving the current text pointer and restoring the previous one for the numeric evaluation.
4FFF
GOSUB to ROM routine at 0A7FH (numeric expression evaluation). This evaluates the record count expression. The result is returned in Register Pair HL as a 16-bit integer.
5002
LD A,H 7C
Load Register A with the high byte of Register Pair HL (the evaluated record count). If H is non-zero, the count exceeds 255.
5003
OR A B7
OR Register A with itself to test if the high byte is zero. If A (= H) is non-zero, the NZ flag is set.
5004
LD A,L 7D
Load Register A with the low byte of Register Pair HL (the record count). If the high byte was zero, A now holds the full count as a single byte.
5005
If the Z FLAG has been set (H was zero — the record count fits in a single byte), JUMP forward to 500CH to store the count. The count in Register A (from L) is valid as a byte value.
5007
JUMP to 5DD3H ("Record number overflow" error in BASIC/CMD). The record count exceeds 255 (the high byte H is non-zero), which is too large for a single-byte field.
500A
LD A,FFH 3E FF
Load Register A with FFH (decimal 255). This is the default maximum record/sector count, used when no explicit count is specified in the format expression.
500C
LD (5094H),A 32 94 50
Store Register A (the record count, either calculated or the FFH default) into address 5094H. This is the max record/sector variable that controls how many records are processed in the GET/PUT operation. This is Self-Modifying Code, — address 5094H is read by later code (6136H) to determine the maximum record count per sector.

500FH - GET/PUT Data Output Router

GET/PUT Data Output Router. This section checks the file mode (bit 4 of IX+00H for special mode) and routes to either the special-mode handler at 50F6H or the normal PUT data output at 5017H. For PUT (write mode), the code calls 62D8H to set up write mode and the target variable, then dispatches based on the data type: string output with LSET-style padding for close operations, numeric output with position advance for non-close operations, or hash-mark (#) handling for file-to-file operations.

500F
BIT 4,(IX+00H) DD CB 00 66
Test bit 4 of the FCB status flags at IX+00H (address 5712H for default FCB). Bit 4 is the special mode flag.
5013
If the NZ FLAG has been set (bit 4 is set — special mode), JUMP to 50F6H (special mode GET/PUT handler). Special-mode files use direct buffer I/O with byte-level positioning.
5016
POP HL E1
Restore Register Pair HL from the stack. HL now holds the BASIC text pointer for the current variable to be written.
5017
GOSUB to 62D8H (write mode + variable setup in BASIC/CMD). This routine configures the FCB for a write operation and prepares the target variable. Returns with: A = data type code (00H = no type / hash-mark, non-zero = type identifier), DE = record size or descriptor, Z flag set if the result is a hash-mark ('#') file reference.
501A
If the Z FLAG has been set (the result is a hash-mark '#' — file-to-file operation), JUMP forward to 506AH to handle the '#' case where data is transferred between files.
501C
PUSH DE D5
Save Register Pair DE (the record size or string descriptor from 62D8H) onto the stack.
501D
BIT 5,(IX+2DH) DD CB 2D 6E
Test bit 5 of the buffer flags byte at IX+2DH. Bit 5 is the close/reset flag (SET at 4D9BH by the '%' subcommand). If set, the file is being closed, which requires LSET-style string padding.
5021
If the Z FLAG has been set (bit 5 is clear — not a close operation), JUMP forward to 5056H to handle normal numeric output with position advance.

Bit 5 is set — this is a close/reset operation (the '%' subcommand was used). The code handles LSET-style string padding for the close operation.

5023
OR A B7
OR Register A with itself. A holds the data type code from 62D8H. This tests whether the type is 00H (no type).
5024
If the NZ FLAG has been set (data type is non-zero — a specific type was identified), JUMP forward to 5053H (JP 518EH, the common loop). When a type is specified during close, skip the LSET padding and proceed to the common loop.
5026
RST 20H E7
Evaluate the expression at (HL) using RST 20H (expression evaluator). Returns with flags indicating the expression type: Z = string, NZ = numeric, CARRY indicates single-precision, MINUS indicates integer.
5027
If the NZ FLAG has been set (the expression is numeric, not string), JUMP forward to 5053H (common loop). Numeric values during close operations do not need LSET-style padding.

The expression is a string. Perform LSET-style padding: get the string descriptor, compare lengths, and pad with spaces as needed.

5029
GOSUB to 5C9CH (string descriptor routine in BASIC/CMD). This routine returns the string descriptor: A = string length, HL = pointer to the descriptor, DE = pointer to the string data in string space.
502C
LD B,A 47
Copy the string length (Register A) into Register B. B now holds the source string length for the padding calculation.
502D
LD A,C 79
Load Register A with Register C (the field width / record size from the FCB setup). This is the target width for the LSET operation.
502E
SUB B 90
SUBtract Register B (source string length) from Register A (field width). If the string is shorter than the field, A holds the number of padding spaces needed. If the string is longer or equal, the CARRY flag is set.
502F
If the NO CARRY FLAG has been set (the field width is >= the string length — padding is needed), JUMP forward to 5034H to proceed with the copy and padding.

CARRY is set — the string is longer than the field. Truncate the string to the field width.

5031
XOR A AF
Set Register A to zero (no padding bytes needed since the string fills the entire field).
5032
LD (HL),C 71
Store the field width (Register C) into the string descriptor's length byte at (HL). This truncates the string to the field width by overwriting the descriptor length.
5033
LD B,C 41
Copy the field width (Register C) into Register B. B now holds the truncated string length for the copy operation.
5034
LD C,A 4F
Copy the padding count (Register A) into Register C. C holds the number of space characters to append after the string data.
5035
PUSH HL E5
Save Register Pair HL (pointer to the string descriptor) onto the stack.
5036
LD HL,(40D6H) 2A D6 40
Fetch the string space pointer from ROM BASIC address 40D6H into Register Pair HL. This is the base address of the current string storage area in BASIC's memory.
5039
RST 18H DF
Compare Register Pair HL (string space pointer from 40D6H) against Register Pair DE (string data address). RST 18H performs a 16-bit HL vs DE comparison, setting flags: CARRY if HL < DE, NO CARRY if HL >= DE.
503A
POP HL E1
Restore Register Pair HL (the string descriptor pointer) from the stack.
503B
If the NO CARRY FLAG has been set (the string space pointer >= the string data address — the string is within the managed string space), JUMP forward to 5041H to proceed with the block copy and padding.

CARRY is set — the string data is below the string space pointer (it may be in ROM or a temporary location). Check if padding is needed.

503D
LD A,C 79
Load Register A with Register C (the padding count).
503E
OR A B7
OR Register A with itself to test if the padding count is zero.
503F
If the Z FLAG has been set (no padding needed — the string exactly fills the field), JUMP to 5053H (common loop). No copy or padding is required.
5041
PUSH BC C5
Save Register Pair BC (B = copy length, C = padding count) onto the stack.
5042
PUSH DE D5
Save Register Pair DE (string data address) onto the stack.
5043
LD A,B 78
Load Register A with Register B (the copy length — how many bytes of string data to copy).
5044
ADD A,C 81
ADD Register C (the padding count) to Register A. A now holds the total field width (copy length + padding).
5045
GOSUB to 5CACH (zero-assign / buffer allocation in BASIC/CMD). This routine allocates A bytes of buffer space and zeroes it, preparing the destination for the LSET copy. Returns with HL pointing to the allocated buffer.
5048
EX DE,HL EB
Exchange Register Pairs DE and HL. DE now points to the newly allocated buffer (destination), and HL is free for use.
5049
POP DE D1
Restore the original DE (string data source address) from the stack. Now DE = source, and the buffer address is temporarily lost but was saved in HL via the exchange.
504A
POP BC C1
Restore Register Pair BC (B = copy length, C = padding count) from the stack.
504B
LD A,B 78
Load Register A with Register B (the copy length).
504C
OR A B7
OR Register A with itself to test if the copy length is zero.
504D
If the NZ FLAG has been set (copy length is non-zero), GOSUB to ROM routine at 09D6H (string block copy). This copies B bytes from the source (DE) to the destination in string space, performing the LSET data transfer.
5050
GOSUB to 5CBCH (space fill in BASIC/CMD). This routine fills C bytes with ASCII space (20H) starting at the current position after the copied string data. This completes the LSET-style right-padding.
5053
JUMP to 518EH (common loop/exit). After the LSET string operation is complete, return to the main GET/PUT processing loop.

5056H - Numeric Output / Expression PUT Handler

Numeric Output and Expression PUT Handler. This section handles non-close-mode PUT operations. It first checks the data type: if non-zero (a specific numeric type), it advances the file position and converts the position to a record number. If zero, it evaluates the expression at the BASIC text pointer and routes based on the result type (string vs. numeric) to the appropriate output handler.

5056
OR A B7
OR Register A with itself. A holds the data type code from 62D8H. If A is zero, the NZ flag is clear (Z is set); if non-zero, NZ is set.
5057
If the Z FLAG has been set (data type is 00H — no specific type, indicating an expression needs evaluation), JUMP forward to 5062H to evaluate the expression and determine its type.

Data type is non-zero (a specific numeric type). Advance the file position by the type size and convert to a record number.

5059
LD A,C 79
Load Register A with Register C (the field width / byte count for this data type from the FCB setup).
505A
GOSUB to 6246H (position advance in BASIC/CMD). This routine advances the file position by A bytes, updating the FCB's internal position tracking.
505D
GOSUB to 6346H (position-to-record converter in BASIC/CMD). This converts the current absolute byte position into a record number (DE) and byte offset within the record (A).
5060
Unconditional JUMP to 5053H (JP 518EH, common loop). After advancing and converting the position, return to the main loop.
5062
PUSH HL E5
Save Register Pair HL (the BASIC text pointer) onto the stack before evaluating the expression.
5063
RST 20H E7
Evaluate the expression at (HL) using RST 20H (expression evaluator). Returns with flags set for the type: Z = string, NZ = numeric, CARRY = single-precision, MINUS = integer. Register A reflects the type indicator.
5064
PUSH AF F5
Save Register Pair AF (the expression type flags) onto the stack for later type routing.
5065
If the NZ FLAG has been set (the expression is numeric), JUMP forward to 50BFH (numeric type determination). The numeric handler will determine the specific type (integer, single, or double precision) and process accordingly.

The expression is a string (Z flag set). Load the byte count and route to the string output handler.

5067
LD A,C 79
Load Register A with Register C (the field width / byte count).
5068
Unconditional JUMP forward to 5098H (LD B,A then string input processing). The byte count in A will be transferred to B for the string read operation.

506AH - '#' Handler (File-to-File Transfer) and String Expression PUT

'#' Handler for File-to-File Transfer. When a '#' appears in the PUT variable list, it indicates a file-to-file data transfer. This section loads the alternate buffer position via 62D0H and routes to the separator dispatch at 4FAAH. It also handles string expression PUT operations, where a string expression is evaluated via ROM 260DH and the result is written to the file with record type decoding and position advancing.

506A
LD A,(HL) 7E
Fetch the current character from the BASIC text at (HL) into Register A. This is the character following the '#' token identified by 62D8H.
506B
CP 23H FE 23
Compare Register A against 23H (ASCII hash mark #). If Register A equals 23H, the Z FLAG is set. A second '#' indicates file-to-file transfer mode.
506D
If the NZ FLAG has been set (the character is not '#' — it is a string expression after the file number), JUMP forward to 5076H to handle the string expression PUT.

The character IS '#' — this is a file-to-file transfer. Advance past it and load the alternate buffer position.

506F
INC HL 23
INCrement Register Pair HL by 1, advancing the BASIC text pointer past the '#' character.
5070
GOSUB to 62D0H (buffer position alternate loader in BASIC/CMD). This routine sets up the alternate buffer position for the file-to-file transfer, loading the source file's buffer cursor.
5073
JUMP to 4FAAH (the comma-dispatch entry point). After setting up the alternate buffer, the code re-enters the main dispatch loop to process the next separator and data item.

5076H: String expression PUT. The character was not '#', so it is a string expression to evaluate and write to the file.

5076
GOSUB to ROM routine at 260DH (BASIC string expression evaluator). This evaluates the string expression at the current BASIC text position. The result is a string descriptor on the evaluation stack.
5079
PUSH HL E5
Save Register Pair HL (the BASIC text pointer, advanced past the string expression) onto the stack.
507A
PUSH DE D5
Save Register Pair DE (string descriptor or related data from the evaluator) onto the stack.
507B
RST 20H E7
Evaluate the expression type using RST 20H (expression evaluator). This confirms the type flags for the string that was just evaluated.
507C
PUSH AF F5
Save Register Pair AF (the expression type flags) onto the stack.

⬐ LOOP START - record type decode for string PUT

507D
GOSUB to 626CH (record type decoder in BASIC/CMD). This determines the record type from the FCB flags for the write operation. Returns with CARRY = error, Z = retry needed, NZ = success with type info.
5080
If the CARRY FLAG has been set (error from record type decoder), JUMP to 5DBEH (error handler in BASIC/CMD).
5083
If the Z FLAG has been set (retry needed), JUMP back to 507DH to call the record type decoder again. [LOOP — retry record type decode]

⬑ LOOP END

5085
LD C,B 48
Copy the record size (Register B, from 626CH) into Register C. C now holds the number of bytes per record for this file type.
5086
LD (40AFH),A 32 AF 40
Store the record type code (Register A, from 626CH) into ROM BASIC address 40AFH. This is the record length variable used by BASIC's file I/O system. Writing here synchronizes BASIC/CMD's record type with the ROM's internal tracking.
5089
RST 20H E7
Evaluate the expression type again using RST 20H. This re-checks the type of the expression that was evaluated earlier, as the record type decoder may have modified state.
508A
If the NZ FLAG has been set (the expression is numeric), JUMP forward to 50BFH (numeric type determination). The numeric result will be converted and written to the file.

The expression is a string. Pop the saved flags, text pointer, push them again, and route to the numeric conversion at 0AF6H or the string handler.

508C
POP AF F1
Restore Register Pair AF (the expression type flags saved at 507CH) from the stack.
508D
POP HL E1
Restore Register Pair HL (the string descriptor or data pointer saved at 507AH) from the stack.
508E
PUSH HL E5
Re-save Register Pair HL onto the stack (it will be needed again after the conversion).
508F
PUSH AF F5
Re-save Register Pair AF onto the stack (preserving the type flags).
5090
If the NZ FLAG has been set (the original expression type from the saved flags indicates numeric), JUMP to ROM routine at 0AF6H (numeric conversion — string to number). This converts the numeric string representation into a binary value in the floating-point accumulator. Execution will return to the address on the stack.

The expression is confirmed as a string. Load the default comparison value and proceed to the string input handler.

5093
LD A,00H 3E 00
Load Register A with 00H. This is the default comparison value for the record/sector count check that follows. Note: address 5094H (the second byte of this instruction) is also written by 500CH — This is Self-Modifying Code, . At runtime, the value loaded here may be the count stored at 500CH rather than the assembled 00H.
5095
CP B B8
Compare Register A (the max record/sector count from 5094H) against Register B (the record size from the earlier type decode or string length). If A >= B, the NO CARRY flag is set; if A < B, the CARRY flag is set.
5096
If the NO CARRY FLAG has been set (the max count >= the record size — the count is sufficient), JUMP forward to 5099H to save BC and proceed with the string input.
5098
LD B,A 47
Copy the max record/sector count (Register A) into Register B. This limits the string read length to the maximum count when the count is less than the record size.

5099H - GET String Input with Field Handling

GET String Input with Field Handling. This section handles reading string data from a file into a BASIC string variable. It allocates string space via ROM 29E3H, manages the string descriptor, checks whether the string data is within the managed string space (via the 40D6H pointer comparison), and copies the field data with length adjustment. The result is a BASIC string variable updated with the file data.

5099
PUSH BC C5
Save Register Pair BC (B = record/string length, C = field width or type info) onto the stack.
509A
GOSUB to 5C9CH (string descriptor routine in BASIC/CMD). Returns: A = string length, HL = pointer to string descriptor, DE = pointer to string data in string space.
509D
LD B,D 42
Copy the high byte of the string data address (Register D) into Register B. This saves D temporarily.
509E
LD C,E 4B
Copy the low byte of the string data address (Register E) into Register C. Register Pair BC now holds a copy of the string data address (DE).
509F
LD D,H 54
Copy the high byte of the descriptor pointer (Register H) into Register D. This begins moving the descriptor pointer into DE.
50A0
LD E,L 5D
Copy the low byte of the descriptor pointer (Register L) into Register E. Register Pair DE now holds the descriptor pointer, and BC holds the string data address.
50A1
XOR A AF
Set Register A to zero and clear all flags. A=00H is passed to 29E3H as a length parameter, requesting zero-length string allocation (which sets up the allocation framework without reserving space).
50A2
GOSUB to ROM routine at 29E3H (string space allocator). This allocates string space for the incoming file data. Returns with HL pointing to the allocated space.
50A5
PUSH HL E5
Save Register Pair HL (pointer to allocated string space) onto the stack.
50A6
LD HL,(40D6H) 2A D6 40
Fetch the string space base pointer from ROM BASIC address 40D6H into Register Pair HL. This is the bottom of the current string storage area.
50A9
RST 18H DF
Compare Register Pair HL (string space base from 40D6H) against Register Pair DE (the descriptor pointer). RST 18H sets CARRY if HL < DE.
50AA
POP HL E1
Restore Register Pair HL (the allocated string space pointer) from the stack.
50AB
If the CARRY FLAG has been set (string space base is below the descriptor — the descriptor is in a higher memory area), JUMP forward to 50AFH, skipping the length zeroing.
50AD
LD (HL),00H 36 00
Store 00H at the allocated string space address (HL). This zeroes the first byte of the allocated space, initializing the string length to zero as a safety measure before the copy.
50AF
POP BC C1
Restore Register Pair BC (B = read length, C = field width or type info) from the stack (saved at 5099H).
50B0
LD A,(HL) 7E
Fetch the current string length byte from (HL) into Register A. This is the existing length of the string in the allocated space.
50B1
CP B B8
Compare Register A (existing string length) against Register B (the read length / record size). Sets CARRY if A < B (existing string is shorter than the read length).
50B2
PUSH BC C5
Save Register Pair BC onto the stack again (preserving the lengths for the copy operation).
50B3
LD (HL),B 70
Store the read length (Register B) as the new string length at (HL). This updates the string descriptor to reflect the number of bytes that will be read from the file.
50B4
LD A,B 78
Load Register A with the read length (Register B).
50B5
If the CARRY FLAG has been set (the existing string was shorter than the read length — the string needs to grow), GOSUB to 5CACH (zero-assign / buffer allocation). This expands the string buffer to accommodate the read length.
50B8
GOSUB to 5C9CH (string descriptor routine). Re-reads the string descriptor after any reallocation. Returns: HL = descriptor pointer, DE = string data address.
50BB
EX DE,HL EB
Exchange Register Pairs DE and HL. HL now points to the string data (destination for the file read), and DE holds the descriptor pointer.
50BC
POP BC C1
Restore Register Pair BC (B = read length, C = type info) from the stack.
50BD
Unconditional JUMP forward to 50DCH (buffer position check and data transfer). HL points to the destination buffer, B holds the byte count, and the code will transfer file data into the string variable.

50BFH - Numeric Type Determination

Numeric Type Determination. This section determines the specific numeric type of the expression (integer, single-precision, or double-precision) using the flags from RST 20H. It sets HL to point to the appropriate ROM BASIC accumulator: 4121H for single-precision (2+4 bytes) or 411DH for double-precision (8 bytes). The type size is loaded into B: 02H for integer, 04H for single, 08H for double. The variable type pointer at 40DFH is also updated.

50BF
LD HL,4121H 21 21 41
Point Register Pair HL to 4121H, the ROM BASIC single-precision floating-point accumulator. This is the default destination for numeric values (single-precision uses 4 bytes at 4121H-4124H, with 2 additional bytes at 411FH-4120H for the mantissa extension).
50C2
LD B,02H 06 02
Load Register B with 02H (decimal 2). This is the byte count for an integer type (2 bytes). If the type is integer, B is already correct.
50C4
If the MINUS FLAG (Sign flag) has been set (the expression type flags from RST 20H indicate integer type), JUMP forward to 50D0H to finalize with B=02H and HL=4121H.
50C7
LD B,04H 06 04
Load Register B with 04H (decimal 4). This is the byte count for a single-precision type (4 bytes).
50C9
If the CARRY FLAG has been set (the expression type flags indicate single-precision), JUMP forward to 50D0H to finalize with B=04H and HL=4121H.

Not integer and not single-precision — the type is double-precision. Set HL to the double-precision work area and B to the double-precision byte count.

50CB
LD HL,411DH 21 1D 41
Point Register Pair HL to 411DH, the ROM BASIC double-precision work area (8 bytes at 411DH-4124H). Double-precision values require 8 bytes of storage.
50CE
LD B,08H 06 08
Load Register B with 08H (decimal 8). This is the byte count for a double-precision type.
50D0
LD C,B 48
Copy the type size (Register B) into Register C. Both B and C now hold the byte count for this numeric type.
50D1
LD (40DFH),HL 22 DF 40
Store Register Pair HL (the accumulator/work area address: 4121H or 411DH) into ROM BASIC address 40DFH. This is the variable type pointer that tells BASIC's internal routines where to find the current numeric value.
50D4
POP AF F1
Restore Register Pair AF from the stack. The flags indicate the expression type (from the RST 20H evaluation saved earlier).
50D5
If the Z FLAG has been set (the expression was a string that needs numeric conversion), JUMP to ROM routine at 0AF6H (numeric conversion — string to number). This converts the string representation to a binary number in the accumulator. Execution returns to the address on the stack.
50D8
PUSH AF F5
Re-save Register Pair AF (the type flags) onto the stack. The flags will be needed by the data transfer code.

50D9H - Buffer Position Check and Data Transfer

Buffer Position Check and Data Transfer. This section validates the buffer position via 62C7H, then checks whether data needs to be transferred (B > 0). If the byte count is non-zero, the DOS read routine at 6214H is called to transfer data from the file buffer to the variable. After the transfer, the file position is advanced and converted to a record number. The section then routes to the common loop at 518EH or to the PRINT handler at 1F33H for formatted output.

50D9
GOSUB to 62C7H (buffer position check in BASIC/CMD). This routine validates the current buffer cursor position, ensuring it is within the record boundaries. The Z flag indicates whether the position is valid.
50DC
LD A,B 78
Load Register A with Register B (the byte count to transfer — the type size or string length).
50DD
OR A B7
OR Register A with itself to test if the byte count is zero.
50DE
If the NZ FLAG has been set (byte count is non-zero — there is data to transfer), GOSUB to 6214H (DOS read routine in BASIC/CMD). This transfers B bytes from the file buffer into the memory area pointed to by HL (the accumulator or string space).
50E1
LD A,C 79
Load Register A with Register C (the field width / type size). This is the total number of bytes that need to be accounted for in the position advance.
50E2
SUB B 90
SUBtract Register B (the number of bytes actually transferred) from Register A (the field width). A now holds the number of remaining bytes that were not transferred (padding or unused bytes in the field).
50E3
If the NZ FLAG has been set (there are remaining bytes to skip — the field is larger than the data transferred), GOSUB to 6246H (position advance in BASIC/CMD). This advances the file position by A bytes, skipping over the unused portion of the field.
50E6
GOSUB to 6346H (position-to-record converter in BASIC/CMD). This converts the current absolute byte position into a record number (DE) and byte offset (A), updating the internal position tracking.
50E9
POP AF F1
Restore Register Pair AF from the stack. The Z flag from this pop determines whether the data was a string (Z) or numeric (NZ) type, which affects the output routing.
50EA
POP HL E1
Restore Register Pair HL from the stack (the BASIC text pointer or related saved value).
50EB
If the Z FLAG has been set (the data is a string type), JUMP to 518EH (common loop/exit). String data has been fully processed — no PRINT formatting needed.

The data is numeric (NZ). Route it through the PRINT handler for formatted output to the file.

50EE
LD DE,518EH 11 8E 51
Load Register Pair DE with the address 518EH (common loop/exit). This is the return address that will be pushed onto the stack for the PRINT handler to return to.
50F1
PUSH DE D5
Save 518EH onto the stack (first return address for the PRINT handler).
50F2
PUSH DE D5
Save 518EH onto the stack again (second return address). The PRINT handler uses two levels of RET to return to the caller, so two copies of the return address are needed.
50F3
JUMP to ROM routine at 1F33H (BASIC PRINT handler). This routine formats and outputs the numeric value from the floating-point accumulator. The two return addresses on the stack ensure that after PRINT completes, execution returns to 518EH (the common loop).

50F6H - GET Special Mode Handler

GET Special Mode Handler. Entry from the bit 4 check at 5013H. This section handles GET operations for files opened in special mode (bit 4 of IX+00H). It first calls 62D8H to set up write mode and the variable, then routes based on the data type: '#' handling with record write loops, or string/numeric input with byte-by-byte writing via 61C8H and space-fill padding.

50F6
POP HL E1
Restore Register Pair HL (the BASIC text pointer) from the stack. This was saved before the special-mode check at 500FH.
50F7
GOSUB to 62D8H (write mode + variable setup in BASIC/CMD). Returns with: A = data type code (00H = hash-mark, non-zero = type), DE = record size, Z flag set for '#' reference.
50FA
If the Z FLAG has been set (the result is '#' — hash-mark reference), JUMP forward to 5144H (special mode '#' handler).
50FC
PUSH DE D5
Save Register Pair DE (the record size or descriptor) onto the stack.
50FD
OR A B7
OR Register A with itself to test if the data type code is zero.
50FE
If the Z FLAG has been set (type is 00H after the '#' check — this shouldn't normally occur but is a safety check), JUMP forward to 511EH for expression evaluation.
5100
CP 23H FE 23
Compare Register A against 23H (ASCII hash mark #). This re-checks for the '#' token in the type code.
5102
If the Z FLAG has been set (type code is '#'), JUMP forward to 5111H (record write loop for '#' in special mode).

The type code is non-zero and not '#'. Check the buffer flags to determine how to handle this data type.

5104
LD A,(IX+2DH) DD 7E 2D
Fetch the buffer flags byte from IX+2DH into Register A.
5107
BIT 2,A CB 57
Test bit 2 of Register A (the operation active flag). If set, a GET/PUT operation is already in progress.
5109
If the NZ FLAG has been set (operation active flag is set), JUMP to 518EH (common loop). The operation is already being handled, so skip to the next iteration.
510C
BIT 4,A CB 67
Test bit 4 of Register A (the buffer dirty flag). If set, the buffer has unwritten data.
510E
If the Z FLAG has been set (buffer is NOT dirty), JUMP to 5059H (numeric output handler). When the buffer is clean, the data can be written directly using the standard numeric output path.
5111
INC C 0C
INCrement Register C by 1. C holds the record/byte count for the write loop. Incrementing it compensates for the DEC C at the loop entry, ensuring the correct number of iterations. [LOOP SETUP — record write]
5112
Unconditional JUMP forward to 5119H (the DEC C / loop check entry point).

⬐ LOOP START - byte-by-byte write

5114
XOR A AF
Set Register A to zero and clear all flags. A=00H is the byte value to write (null byte for padding).
5115
LD B,A 47
Copy 00H (Register A) into Register B. B=00H is the secondary parameter for 61C8H (indicating no special processing).
5116
GOSUB to 61C8H (record position validator in BASIC/CMD). This writes the byte in A to the file at the current position and advances the position by one byte.
5119
DEC C 0D
DECrement Register C by 1 (the remaining byte count).
511A
If the NZ FLAG has been set (C is not zero — more bytes to write), JUMP back to 5114H to write the next null byte. [LOOP — continue byte-by-byte write]

⬑ LOOP END

511C
Unconditional JUMP to 518EH (common loop/exit). All bytes have been written.

511EH - Special Mode Expression Input

Special Mode Expression Input. This section handles expression evaluation in special mode. It evaluates the BASIC expression via RST 20H, checks the result type, and for string results, calls 619CH and then writes the data byte-by-byte using 61C8H with space-fill (20H) padding for any remaining field bytes.

511E
RST 20H E7
Evaluate the expression at (HL) using RST 20H (expression evaluator). Returns with flags set for the type: Z = string, NZ = numeric.
511F
If the NZ FLAG has been set (the expression is numeric), JUMP forward to 516CH (numeric type routing for special mode with type code and byte count setup).

The expression is a string. Process it through the string handler for special mode.

5121
LD A,C 79
Load Register A with Register C (the field width / byte count).
5122
GOSUB to 619CH (a BASIC/CMD routine that processes the string expression result). Returns with A = string length, B = byte count to write, HL = pointer to string data, C = remaining field bytes.
5125
LD C,B 48
Copy the byte count (Register B) into Register C. C now holds the number of string bytes to write.
5126
LD B,A 47
Copy the string length (Register A) into Register B. B holds the total string length for the padding calculation.
5127
LD A,C 79
Load Register A with Register C (the byte count to write).
5128
SUB B 90
SUBtract Register B (string length) from Register A (byte count). If the byte count exceeds the string length, A holds the number of padding spaces needed. If CARRY is set, the string is longer than the field.
5129
If the NO CARRY FLAG has been set (byte count >= string length — string fits in the field), JUMP forward to 517EH to check if the file is in write mode and proceed with the write.

CARRY is set — the string is longer than the field. Write the string data byte-by-byte and pad with spaces.

512B
PUSH AF F5
Save Register Pair AF (the padding count, which is negative since CARRY was set — the value represents the overflow) onto the stack.
512C
LD A,C 79
Load Register A with Register C (the byte count to write — the actual number of string bytes to output).
512D
OR A B7
OR Register A with itself to test if the byte count is zero.
512E
If the Z FLAG has been set (byte count is zero — no string data to write), JUMP forward to 5137H to skip the write loop and proceed directly to space-fill padding.
5130
LD A,(HL) 7E
Fetch the next byte of string data from (HL) into Register A.
5131
LD B,C 41
Copy Register C (remaining byte count) into Register B as a parameter for 61C8H.
5132
INC HL 23
INCrement Register Pair HL by 1, advancing the string data pointer to the next byte.
5133
DEC B 05
DECrement Register B by 1 (the remaining count). This adjusts the count parameter for 61C8H.
5134
GOSUB to 61C8H (record position validator). This writes the byte in A to the file and advances the position.
5137
POP HL E1
Restore from the stack. This pops the saved AF (pushed at 512BH) into HL. The value represents the padding count (overflow from the string-vs-field comparison). H holds the effective count.
5138
LD B,00H 06 00
Load Register B with 00H. B=00H is the secondary parameter for 61C8H during the space-fill loop (no special processing).

⬐ LOOP START - space-fill padding

513A
LD A,20H 3E 20
Load Register A with 20H (ASCII space). This is the fill character for padding the remaining field bytes.
513C
GOSUB to 61C8H (record position validator). Write the space character (20H) to the file at the current position.
513F
INC H 24
INCrement Register H by 1. H holds the padding counter (which was loaded as a negative value / overflow count). Incrementing moves it toward zero.
5140
If the NZ FLAG has been set (H is not zero — more padding bytes to write), JUMP back to 513AH to write another space.

⬑ LOOP END

5142
Unconditional JUMP to 518EH (common loop/exit). All string data and padding have been written.

5144H - Special Mode '#' Handler and Expression Evaluation

Special Mode '#' Handler. This section handles the '#' token in special-mode GET. It fetches the record count via 62CEH and 6136H, writes it byte-by-byte via 61C8H, then routes to the record write loop at 5111H. It also handles general expression evaluation for special mode, determining the type (string, integer, single, double) and writing the data byte-by-byte to the file.

5144
LD A,(HL) 7E
Fetch the current character from the BASIC text at (HL) into Register A.
5145
CP 23H FE 23
Compare Register A against 23H (ASCII hash mark #). This checks for the '#' file reference token.
5147
If the NZ FLAG has been set (not '#'), JUMP forward to 515AH (general expression evaluation for special mode).

The token is '#'. Fetch the record count and write it to the file.

5149
GOSUB to 62CEH (buffer position check in BASIC/CMD). This validates the buffer position and prepares for the record count fetch.
514C
PUSH DE D5
Save Register Pair DE onto the stack.
514D
LD B,FFH 06 FF
Load Register B with FFH (decimal 255). This is the maximum record count value to pass to 6136H.
514F
GOSUB to 6136H (record count calculator in BASIC/CMD). Returns with DE = record count based on the max value in B and the record/sector count at 5094H.
5152
LD C,B 48
Copy the resulting byte count (Register B) into Register C. C holds the number of bytes to write for the record count data.
5153
LD B,00H 06 00
Load Register B with 00H. B=00H is the value byte to write (null/zero padding).
5155
GOSUB to 61C8H (record position validator). Write the byte in B (00H) and advance the position.
5158
Unconditional JUMP back to 5111H (record write loop). The record count data has been set up, and the loop will write the remaining bytes.

515AH: General expression evaluation for special mode. Evaluate the expression and route by type.

515A
GOSUB to 6190H (string expression evaluator + descriptor in BASIC/CMD). This evaluates the BASIC expression and returns with Z set for string, NZ for numeric.
515D
If the NZ FLAG has been set (the expression is numeric), JUMP forward to 5164H to determine the specific numeric type.

The expression is a string. Get the record count and route to the byte-by-byte write.

515F
GOSUB to 6136H (record count calculator). Returns with the byte count in B.
5162
Unconditional JUMP forward to 518BH (CALL 61C8H, the byte-by-byte write routine, then to the common loop). The string data will be written one byte at a time.
5164
LD HL,4121H 21 21 41
Point Register Pair HL to 4121H, the ROM BASIC single-precision accumulator. This is the default source address for numeric data.
5167
If the CARRY FLAG has been set (from 6190H flags — single-precision type), JUMP forward to 516CH to set up the type code and byte count for single-precision.

Not single-precision. Check for double-precision.

5169
LD HL,411DH 21 1D 41
Point Register Pair HL to 411DH, the ROM BASIC double-precision work area (8 bytes).
516C
LD A,72H 3E 72
Load Register A with 72H. This is the default type code used for the record type identification (72H = default numeric format). The type code is adjusted below for single and double precision.
516E
LD B,02H 06 02
Load Register B with 02H (decimal 2). B = 2 is the byte count for integer type.
5170
If the MINUS FLAG has been set (integer type from the expression flags), JUMP forward to 517BH with A=72H, B=02H. The integer value at 4121H is 2 bytes long.
5173
INC A 3C
INCrement Register A by 1. A is now 73H, the type code for single-precision.
5174
LD B,04H 06 04
Load Register B with 04H (decimal 4). B = 4 is the byte count for single-precision type.
5176
If the CARRY FLAG has been set (single-precision type), JUMP forward to 517BH with A=73H, B=04H.

Not integer or single — must be double-precision.

5178
INC A 3C
INCrement Register A by 1. A is now 74H, the type code for double-precision.
5179
LD B,08H 06 08
Load Register B with 08H (decimal 8). B = 8 is the byte count for double-precision type.
517B
GOSUB to 62C7H (buffer position check in BASIC/CMD). Validates the buffer cursor position before writing the typed data.
517E
BIT 1,(IX+00H) DD CB 00 4E
Test bit 1 of the FCB status flags at IX+00H. Bit 1 is the write mode flag. If clear, the file is not open for writing.
5182
If the Z FLAG has been set (bit 1 is clear — file is NOT in write mode), JUMP forward to 518BH. In read-only mode, skip the byte-by-byte write and proceed directly to the 61C8H call for position tracking only.

The file IS in write mode. Write the data byte-by-byte from the accumulator/work area.

5184
LD A,B 78
Load Register A with Register B (the byte count to write).
5185
OR A B7
OR Register A with itself to test if the byte count is zero.
5186
If the Z FLAG has been set (byte count is zero — no data to write), JUMP to 518EH (common loop). Nothing to output.

⬐ LOOP START - byte-by-byte numeric write

5188
LD A,(HL) 7E
Fetch the next byte of numeric data from the accumulator/work area at (HL) into Register A.
5189
DEC B 05
DECrement Register B by 1 (remaining byte count).
518A
INC HL 23
INCrement Register Pair HL by 1, advancing the source pointer to the next byte in the accumulator.
518B
GOSUB to 61C8H (record position validator). Write the byte in A to the file and advance the position. When reached from 517EH with write mode off, this call handles position tracking without actual data output. [LOOP BODY / single iteration for read-only]

518EH - Common Loop / Exit

Common Loop and Exit. This is the main loop return point for GET/PUT operations. It pops the saved HL, backs up the text pointer, calls the line scanner at 4FC1H to find the next data item, and dispatches based on the separator: comma routes to 4F95H (re-initialize print column and call line scanner), semicolon routes to 51A2H (end-of-data handler). After processing all items, the code updates the position via 610DH and 62FFH, then exits through 641EH or 635AH depending on the buffer flags.

518E
POP HL E1
Restore Register Pair HL from the stack. HL holds the BASIC text pointer that was saved at the beginning of each data item processing iteration.
518F
DEC HL 2B
DECrement Register Pair HL by 1, backing up the BASIC text pointer by one byte so the line scanner will re-read the current separator character.
5190
GOSUB to 4FC1H (the line scanner). Scans the BASIC text for the next data item or separator. Returns with Register A holding the next character and flags set for dispatch.
5193
LD DE,(5D38H) ED 5B 38 5D
Fetch the print column state from address 5D38H into Register Pair DE. This value tracks the current column position for formatted output.
5197
INC DE 13
INCrement Register Pair DE by 1 (advance the column counter).
5198
CP 2CH FE 2C
Compare Register A (the character from the line scanner) against 2CH (ASCII comma ,).
519A
If the Z FLAG has been set (the separator is a comma), JUMP to 4F95H. This re-stores the print column state, re-calls the line scanner, and processes the next data item in the variable list. [LOOP — process next comma-separated item]
519D
CP 3BH FE 3B
Compare Register A against 3BH (ASCII semicolon ;).
519F
If the NZ FLAG has been set (the character is neither comma nor semicolon — it is the end of the variable list), JUMP to 51CBH (end-of-statement error check). This validates that the GET/PUT statement is properly terminated.

The separator is a semicolon. Call the end-of-data handler and check the buffer flags to determine the exit path.

51A2
GOSUB to 51C9H (end-of-statement check). This calls RST 10H to fetch the next character; if it is 00H (end-of-statement), the Z flag is set and the routine returns. If not end-of-statement, it jumps to 5DD0H (statement error).
51A5
LD A,(IX+2DH) DD 7E 2D
Fetch the buffer flags byte from IX+2DH into Register A.
51A8
BIT 2,A CB 57
Test bit 2 of Register A (the operation active flag). If set, a special-mode operation was in progress.
51AA
RET NZ C0
If the NZ FLAG has been set (operation active flag is set), RETURN to the caller. The special-mode handler at 4F80H-4F86H will continue processing.
51AB
BIT 1,A CB 4F
Test bit 1 of Register A (the record number expression flag, SET at 4F2EH). If set, a record number expression was specified in the GET statement.
51AD
If the Z FLAG has been set (bit 1 is clear — no record number expression was given), JUMP forward to 51B0H, skipping the extra POP. The text pointer is already on the stack from the correct call sequence.
51AF
POP HL E1
Restore Register Pair HL from the stack. When a record number expression was specified (bit 1 set), an extra value was pushed at 4F35H. This POP removes it to balance the stack.
51B0
PUSH HL E5
Save Register Pair HL (the BASIC text pointer) onto the stack. This preserves it while the position update and finalization routines execute.
51B1
BIT 5,(IX+2DH) DD CB 2D 6E
Test bit 5 of the buffer flags byte at IX+2DH. Bit 5 is the close/reset flag (SET by the '%' subcommand at 4D9BH). If set, the file is being closed.
51B5
If the NZ FLAG has been set (close/reset flag is set), JUMP forward to 51C3H to exit via the close handler at 635AH instead of the normal path.

Normal exit path (not a close operation). Update the file position and clear state, then exit through the BASIC continuation handler.

51B7
GOSUB to 610DH (position store in BASIC/CMD). This writes the current primary position data back to the FCB work area, updating 5705H and related fields.
51BA
GOSUB to 62FFH (state cleanup in BASIC/CMD). This performs final state cleanup after the GET/PUT operation, clearing temporary flags and resetting the buffer state.
51BD
POP HL E1
Restore Register Pair HL (the BASIC text pointer) from the stack.
51BE
DEC HL 2B
DECrement Register Pair HL by 1, backing up the text pointer so the BASIC interpreter can re-parse the current position.
51BF
RST 10H D7
Fetch the next non-space character from the BASIC text. This sets up the BASIC text pointer for the continuation handler.
51C0
JUMP to 641EH (BASIC continuation handler in BASIC/CMD). This returns control to the BASIC interpreter to continue executing the program after the GET/PUT statement.

51C3H - Close/Reset Exit Path

Close/Reset Exit Path. This alternate exit is taken when the '%' subcommand was used (bit 5 of IX+2DH is set). Instead of the normal position update and BASIC continuation, the code calls 635AH to perform the file close/reset operation, then returns to the caller.

51C3
GOSUB to 635AH (close/reset handler in BASIC/CMD). This routine performs the file close or reset operation, flushing any dirty buffers and updating the directory entry as needed.
51C6
POP HL E1
Restore Register Pair HL (the BASIC text pointer) from the stack.
51C7
RET C9
RETURN to the caller. After the close/reset operation, control returns to whichever routine initiated the PUT/GET statement.

51C8H - End-of-Statement Check

End-of-Statement Check. This short routine backs up the text pointer, fetches the next character, and validates that the statement has ended (character is 00H). If the statement has not ended, it generates a "Statement error".

51C8
DEC HL 2B
DECrement Register Pair HL by 1, backing up the BASIC text pointer by one byte.
51C9
RST 10H D7
Fetch the next non-space character from the BASIC text at (HL) into Register A.
51CA
RET Z C8
If the Z FLAG has been set (the character is 00H — end-of-statement), RETURN to the caller. The statement is properly terminated.
51CB
JUMP to 5DD0H ("Statement error" in BASIC/CMD). The statement text continues past where it should have ended, indicating a syntax error in the GET/PUT statement.

51CEH - NOP Padding

NOP Padding. 26 bytes of NOP (00H) padding from 51CEH through 51E7H. This unused space at the end of the SYS10 overlay fills the remainder of the allocated block. It is not executable code and serves as dead space within the overlay module.

51CE–51E7
NOP × 26 00 × 26
26 bytes of NOP padding (00H). This fills the remaining space in the SYS10/SYS overlay from 51CEH to 51E7H. These bytes are not executed during normal operation.