TRS-80 DOS - TRSDOS v1.3 - SYS13/SYS Disassembled

Program Overview

SYS13/SYS is the BASIC Functions overlay of TRSDOS v1.3 for the Model III. It is loaded by the DOS into the SYSLOW overlay area (4E00H–51D1H) when BASIC executes one of three BASIC CMD calls. The overlay's entry point at 4E00H masks off the lower nibble of Register A (the calling SVC code) and dispatches on the upper nibble to one of three handlers, returning a ?FC ERROR through the Model III ROM at 1E4AH for any other code.

The three handlers are:

VectorEntryHandlerBASIC syntax and behavior
VECT00 (80H)4E13HSORTSorts an array. BASIC syntax: CMD"O",exp,array(start). Implements a Shell sort over a list of VARPTRs read from BASIC2 (variable count) and BASIC1 (pointer to the VARPTR list).
VECT10 (90H)4EE3HRETJULConverts between calendar date and Julian day number. BASIC syntax: CMD"J",s$,d$. If the source string begins with a leading - the routine converts Julian to Gregorian (RETDAT at 4F92H); otherwise it converts MM/DD/YY to a Julian day count and stores a 3-byte ASCII result.
VECT20 (A0H)5102HCROSSCross-references a string or BASIC reserved-word token through the entire BASIC program. BASIC syntax: CMD"X",target. Polls the line printer port (F8H), echoes matching line numbers eight columns wide, and routes the output to both screen and printer when the printer is available.

Note the use of VECT00 / VECT10 / VECT20 as compares against the masked Register A. Those three labels are external equates from BASIC.GBL resolving to 80H, 90H, and A0H respectively.

Memory Map

RangeLabelContents
4E00H–4E12HSTARTEntry-point dispatch. Masks Register A and selects SORT, RETJUL, or CROSS.
4E13H–4ED4HSORTShell sort of a list of BASIC string VARPTRs.
4ED5H–4EE2HNUMB0…VARPTRSeven 2-byte SORT workspace cells: NUMB0, LAB13, LAB14, LAB15, LAB16, NUMB1, VARPTR.
4EE3H–4F91HRETJULCalendar → Julian conversion handler (chains through RETJU1…RETJU5 and RETEXT).
4F92H–5042HRETDATJulian → calendar conversion handler (chains through REDA00, REDA0X, RETDA1, RETDA8, RETDA9, RETDA0).
5043H–50A5HRETDA2…RETDA4Common date-output tail: format the result, allocate or reuse the destination string variable, and copy the 8-byte ASCII date.
50A6H–50B9HMOVITMove two ASCII digits from FACLO+19 to a temp area, supplying a leading 0 and a trailing /.
50BAH–50E5HGETNXT, GETACRTwo-digit and one-digit ASCII-to-binary fetchers used by the date parser.
50E6H–5101HEDITM, EDITX, EDITM1Hex–to–ASCII conversion via the Model III ROM floating-point output, with optional leading-zero substitution.
5102H–5134HCROSS, CROSS1, CROSS2Cross-reference entry: poll printer, parse the search argument (reserved-word byte or string).
5135H–516EHDOCROS, DOCRO1…DOCRO3Walk the BASIC program line by line, looking for a match.
516FH–51AFHDISPLY, DISPL1–DISPL4, DISP22Format the matching line number, advance to the next 8-column tab, emit a CR when the screen row is full.
51B2H–51C0HDISOUT, DISOU1Output a byte to the screen and (when the printer flag is set) the line printer. Contains the self-modifying byte PRTAVL at 51B4H.
51C1H–51D1HCOPARE, STRCM1, STRCM2Length-counted byte-by-byte string compare used by the cross-reference walker.

Variable List

The overlay uses two distinct kinds of storage. The first group lives inside the SORT routine's own code page (4ED5H–4EE2H) and is reset every time SYS13 is entered. The second group lives in the BASIC scratch area at 5587H–558AH, which sits above the SYSLOW overlay region and persists between BASIC's calls into SYS13. PRTAVL is a self-modifying operand byte inside the DISOUT routine.

Internal SORT workspace (4ED5H–4EE2H, fleeting)

AddressLabelBytesPurpose
4ED5HNUMB02Original number of variables to sort, copied from BASIC1 on entry.
4ED7HLAB132Inner-loop index i: counts from 0 up to NUMB0 − gap.
4ED9HLAB142Outer-loop index that drives the gap-shrinking Shell sort.
4EDBHLAB152NUMB0 − gap. Loop terminator for LAB13.
4EDDHLAB162LAB13 + gap. Index of the partner element being compared.
4EDFHNUMB12Current Shell-sort gap (initialized to NUMB0, halved each outer iteration).
4EE1HVARPTR2Pointer to the caller's VARPTR list (copied from BASIC2 on entry).

BASIC scratch storage (5587H–558AH, JSON-tracked)

AddressLabelBytesPurpose
5587HYR1User-supplied year (00–99) for the date conversion.
5588HMT1User-supplied month (01–12) for the date conversion.
5589HDY1User-supplied day for the date conversion.
558AHRTEMP8Temporary buffer that holds the formatted ASCII result before it is copied into the BASIC destination string. 3 bytes for a Julian result, 8 bytes for a Gregorian result.

Self-modifying operand (51B4H, HTML-only, NOT in JSON)

AddressLabelBytesPurpose
51B4HPRTAVL1The operand byte of the LD A,0 instruction at 51B3H. CROSS at 5108H stores Register A into 51B4H to record whether the line printer port returned a non-zero ready/select status, and DISOUT later loads that byte to decide whether to mirror the output to the printer. Because SYS13 is a transient overlay, this self-modifying location is not preserved across overlay swaps and is therefore not tracked in ram_addresses_data.json.

Major Routine List

EntryLabelDescriptionEntry / Exit
4E00HSTARTOverlay entry; mask Register A and dispatch on the upper nibble.ENTRY: A = SVC code (high nibble selects function). EXIT: jumps to SORT, RETJUL, CROSS, or FCERR.
4E13HSORTShell sort of an array of BASIC string VARPTRs.ENTRY: BASIC1 = number of variables, BASIC2 = pointer to the VARPTR list. EXIT: RET. Compares strings via SUB, swaps 3-byte VARPTR records in place.
4EE3HRETJULConvert MM/DD/YY in a BASIC string to a Julian day number.ENTRY: HL = (BASIC1) text pointer pointing past CMD"J",. EXIT through RETEXT after storing a 3-byte ASCII Julian day in the destination string variable.
4F34HRETJU1Inner loop of RETJUL that walks the month-length table at MAXTIM+3 (0269H in the Model III ROM) summing days for prior months.ENTRY: A = year masked & 03H, IX = leap-day adjustment. EXIT: falls through to RETJU3.
4F8EHRETEXTCommon exit for both date conversions.ENTRY: HL = updated text pointer. EXIT: stores HL to (BASIC1) and RETs.
4F92HRETDATConvert a Julian day in -YYDDD form back to MM/DD/YY.ENTRY: HL one past the leading - of the source string. EXIT through RETEXT.
4FD9HREDA0XInner loop that walks the month-length table subtracting until the residual day count goes negative, identifying the target month.ENTRY: DE = day-of-year, HL = MAXTIM+3. EXIT: falls through to RETDA8.
5043HRETDA2Format the resolved month/day/year as ASCII into RTEMP via repeated MOVIT calls.ENTRY: MT, DY, YR all set. EXIT: continues into the destination-string allocation/copy code.
5089HRETDA3Allocate 8 bytes of fresh BASIC string space for the formatted date.ENTRY: A = 8 (length to allocate). EXIT: continues into RETDA4.
5094HRETDA4Write the length byte and address into the destination VARPTR, then LDIR the 8 ASCII bytes from RTEMP.ENTRY: HL = string variable, DE = string-storage address. EXIT: JP RETEXT.
50A6HMOVITMove two ASCII digits from FACLO+19 (4134H) into a temp area, substituting 0 for a leading space and appending a / delimiter.ENTRY: HL = source after EDITM, DE = destination temp. EXIT: RET.
50BAHGETNXTVerify a / separator (via SYNCHK 2FH), then read the next two ASCII digits as a binary value.ENTRY: HL = text pointer. EXIT: A = combined value, HL advanced past the digits.
50BCHGETNX1GETNXT skipping the SYNCHK; reads two ASCII digits as a binary value.Same as GETNXT but without the leading separator check.
50D3HGETACRRead one ASCII digit, treating SPACE as 0; raise SNERR for non-numeric or out-of-range characters.ENTRY: HL = text pointer. EXIT: A = digit (0–9), HL advanced by 1, or JP SNERR.
50E6HEDITMHex–to–ASCII conversion with leading-zero substitution. Two-byte alias-trick entry: 50E6H falls into the EDITX entry at 50E7H but with carry cleared (suppress flag off, do edit).ENTRY: HL = 16-bit value to convert. EXIT: ASCII string at FACLO+16 (4131H).
50E7HEDITXEDITM with carry set on entry, suppressing the trailing leading-zero pass. Used by the cross-reference for line-number formatting.ENTRY: HL = 16-bit value to convert. EXIT: ASCII string at FACLO+16 with leading spaces preserved.
5102HCROSSCross-reference entry. Polls the printer status port (PORT = F8H), masks E0H, and stores the result into PRTAVL via 5108H to enable or disable the printer mirror.ENTRY: BASIC1 points at the comma after CMD"X". EXIT: falls through into CROSS1.
510BHCROSS1Read the search argument: a single reserved-word byte (bit 7 set) takes the DOCROS path immediately, otherwise FRMEVL evaluates the BASIC expression and FRESTR pins the resulting string.ENTRY: HL after SYNCHK 2CH (the comma). EXIT: JR DOCROS.
511FHCROSS2Branch of CROSS1 reached when the argument is a non-reserved-word string expression. Calls the Model III ROM FRMEVL/FRESTR and unpacks the string descriptor.ENTRY: HL = text after the comma. EXIT: BC = string length, HL = string address; falls into DOCROS.
5135HDOCROSSave the search argument's length and address; reload TXTTAB (40A4H, the start of the BASIC program) into the line walker's pointer.ENTRY: BC = length, HL = string address. EXIT: falls into DOCRO1.
5142HDOCRO1Top-of-program-line loop. If the line link is 0000H we are at the end of the BASIC program; otherwise advance past the link and the line number.EXIT: JP DISOUT with CR on end of program; otherwise falls into DOCR00.
5155HDOCRO2Per-byte scan of the current BASIC program line, looking for a match against the search argument.EXIT to DISPLY on match, back to DOCRO1 on end of line.
515FHDOCRO3Calls COPARE to compare the saved search argument against the current byte sequence in the program.EXIT: branches to DISPLY on match.
516FHDISPLYOn match, run the BASIC line pointer to the line-terminating 00H byte.EXIT: falls into DISPL1.
5176HDISPL1Format the matched line's number with EDITX and emit each digit through DISOUT.EXIT: falls into DISP22 once the digits are out.
5191HDISP22Read CURSOR (4020H) to see if the screen row has room for another tab stop. If column >= 58, emit a CR and continue with the next BASIC line; otherwise compute the next 8-column tab and emit the spaces.EXIT: JP DOCRO1.
51B2HDISOUTOutput a byte to the screen via DSP (0033H) and, if PRTAVL says the printer is ready, also to PRT (003BH).ENTRY: A = byte to display. EXIT: JP DSP (the JP performs the screen output and inherits the RET).
51C1HCOPARELength-counted byte-by-byte compare with full register save/restore around an LDI / JP PE,STRCM1 loop.ENTRY: HL = arg1, DE = arg2, BC = length. EXIT: Z set on equal, NZ on first difference. HL/DE/BC restored.

Dispatch Table

SYS13 does not use a true jump table. The dispatch is a chain of three CP/JR pairs at the start of START, comparing the masked Register A against three single-byte values supplied by BASIC.GBL:

AddressCompareMatch actionSVC code
4E02HCP VECT00JR Z,SORT → 4E13H80H — CMD"O"
4E06HCP VECT10JP Z,RETJUL → 4EE3H90H — CMD"J"
4E0BHCP VECT20JP Z,CROSS → 5102HA0H — CMD"X"
4E10H(no match)JP FCERR → 1E4AH?FC ERROR

Cross-References and Analysis Notes

External labels referenced from BASIC.GBL. SYS13 calls into ten Model III BASIC ROM routines and reads three BASIC scratch words. All ten ROM routines were already present in ram_addresses_data.json; no SYS0/ROM additions are required. The full reference list, used as targets of CALL, JP, or LD HL,(nnnn):

LabelAddressPurpose
SNERR1997H?SN ERROR (syntax error) re-entry to BASIC.
FCERR1E4AH?FC ERROR (function call error) re-entry to BASIC.
FRMEVL2337HEvaluate a BASIC expression pointed to by HL.
FRESTR29D7HPin a freshly-evaluated string and return its descriptor.
PTRGET260DHFind or create a BASIC variable, return its descriptor address in DE.
FRCSTR0AF4HForce the FAC to a string variable; raises ?TM ERROR otherwise.
STRINI2857HAllocate string space; A = length, address returned via DSCTMP+1.
MAKINT0A9AHMove HL into the FAC as an integer.
FOUINI1034HInitialize the FAC-to-ASCII output buffer.
FOUT20FD9HConvert the FAC integer to ASCII at FACLO+16 (4131H).
DSP0033HModel III ROM screen-character output.
PRT003BHModel III ROM line-printer output (waits for ready or BREAK).
BASIC14272HBASIC text pointer (LSB). Read at routine entry, written at exit through RETEXT.
BASIC24274HBASIC second argument pointer. Read on SORT entry to fetch the VARPTR list address.
TXTTAB40A4HPointer to the start of the BASIC program in RAM, read by DOCROS.
CURSOR4020HCurrent cursor position on the video display, read by DISP22 to decide on column tab vs. CR.
FACLO4121HBASIC floating-point accumulator low byte; the ASCII buffer used by EDITM begins at FACLO+16 (4131H).
DSCTMP40D3HLength/address descriptor for the most recent STRINI allocation. RETJU4 reads (DSCTMP+1) at 40D4H to obtain the new string address.
MAXTIM0266HModel III ROM month-length table. RETJU1 and REDA0X both walk this table starting at MAXTIM+3 (0269H).

Self-modifying code observation. Only one self-modifying pattern is present: the printer-ready flag PRTAVL at 51B4H, which is the operand byte of LD A,0 at 51B3H. CROSS at 5108H patches that byte during initialization. Because SYS13 is a transient SYSLOW overlay (any subsequent SYS1–SYS5 or SYS10 load overwrites the same memory), PRTAVL is documented in the variable list above but is intentionally absent from ram_addresses_data.json, per the project convention that only SYS0-resident self-modifying targets are JSON-tracked.

Disassembly:

 
ORG 4E00H
4E00START
AND 0F0H
MASK off the SYSTEM NUMBER from the byte passed to this OVERLAY by masking against F0H (1111 0000). This has the effect of turning off bits 3, 2, 1, 0, leaving only bits 7, 6, 5, 4 active.
Original Source Code Comment: MASK OFF SYSTEM NUMBER
4E02
CP 80HCP VECT00
Compare the remainder of Register A against 80H, which would be the SORT function call. If the masked value is 80H, then ...
Original Source Code Comment: SORT?
4E04
... JUMP to 4E13H.
4E06
CP 90HCP VECT10
Compare the remainder of Register A against 90H, which would be the JULIAN DATE CONVERSION function call. If the masked value is 90H, then ...
Original Source Code Comment: DO JULIAN?
4E08
... JUMP to 4EE3H.
4E0B
CP 0A0HCP VECT20
Compare the remainder of Register A against A0H, which would be the CROSS REFERENCE function call. If the masked value is A0H, then ...
Original Source Code Comment: CROSS REF?
4E0D
... JUMP to 5102H.
4E10
If none of those functions were called, then return to BASIC with a "?FC ERROR" via a JUMP to 1E4AH.
Original Source Code Comment: ILLEGAL FUNCTION

4E13H - SORT - "SORT" Routine Main Routine. On Entry BASIC1 = Number of variables to sort and BASIC2 = VARPTR for the variables to sort.

4E13SORT
LD HL,(4274H)LD HL,(BASIC2)
Fetch the VARPTR pointer from memory location 4274H and store it into Register Pair HL.
Original Source Code Comment: GET THE VARPTR POINTER
4E16
LD (4EE1H),HLLD (VARPTR),HL
Store the VARPTR pointer into memory location 4EE1H.
Original Source Code Comment: SAVE IT
4E19
LD HL,(4272H)LD HL,(BASIC1)
Fetch the NUMBER OF VARIABLES from memory location 4272H and store it into Register Pair HL.
Original Source Code Comment: GET THE NUMBER OF VARIABLES
4E1C
LD (4ED5H),HLLD (NUMB0),HL
Store the NUMBER OF VARIABLES into 4ED5H ...
Original Source Code Comment: SAVE IT
4E1F
LD (4EDFH),HLLD (NUMB1),HL
... and 4EDFH.
4E22LAB2
LD DE,(4EDFH)LD DE,(NUMB1)
Fetch the NUMBER OF VARIABLES from 4EDFH and store it into Register Pair DE.
Original Source Code Comment: GET NUMBER OF VARIABLES
4E26
SRL E
Shift the contents of Register E right one bit position with bit 0 moved to the carry flag and a zero is put into bit 7, so 76543210[x] becomes 07654321[0].
4E28
XOR A
Set Register A to ZERO and clear all Flags.
4E29
SRL D
Shift the contents of Register D right one bit position with bit 0 moved to the carry flag and a zero is put into bit 7, so 76543210[x] becomes 07654321[0].
4E2B
If Bit 0 of Register D wasn't a 0, the NC FLAG will be set, so JUMP to 4E2FH.
4E2D
SET 7,E
If Bit 0 of Register D was a 0, SET (i.e., set as 1) BIT 7 of Register E (the one bit which was set to 0 via the SRL).
4E2FLAB3
LD (4EDFH),DELD (NUMB1),DE
Store the modified/rotated NUMBER OF VARIABLES held in Register Pair DE into memory location 4EDFH.
4E33
LD A,D
Since the Z-80 cannot test Register Pair DE against zero, the common trick is to set Register A to equal to Register D, and then OR A against Register E. Only if both Register D and Register E were zero can the Z FLAG be set.
4E34
OR E
... Part 2
4E35
RET Z
If we were given 0 variables to sort, RETurn to the caller.
4E36
LD HL,(4ED5H)LD HL,(NUMB0)
Otherwise, fetch the original NUMBER OF VARIABLES from memory location 4ED5H and store it into Register Pair HL.
4E39
SBC HL,DE
Subtract the modified/shifted NUMBER OF VARIABLES (held in DE) from the original NUMBER OF VARIABLES (held in Register Pair HL).
4E3B
LD (4EDBH),HLLD (LAB15),HL
Store that difference into memory location 4EDBH.
4E3E
LD HL,0000H
Let Register Pair HL equal 0000H.
4E41
LD (4ED9H),HLLD (LAB14),HL
Store a 0000H into memory location 4ED9H.
4E44LAB4
LD HL,(4ED9H)LD HL,(LAB14)
Fetch the value held in memory location 4ED9H (which will be 0000H on a pass through) and store it into Register Pair HL.
4E47
LD (4ED7H),HLLD (LAB13),HL
Store the value held in Register Pair HL (which will be 0000H on a pass through) into memory location 4ED7H.
4E4ALAB5
LD HL,(4ED7H)LD HL,(LAB13)
Fetch the value held in memory location 4ED7H (which will be 0000H on a pass through) and store it into Register Pair HL.
4E4D
LD DE,(4EDFH)LD DE,(NUMB1)
Fetch the value held in memory location 4EDFH and store it into Register Pair DE.
4E51
ADD HL,DE
LET Register Pair HL = Register Pair HL + Register DE.
4E52
LD (4EDDH),HLLD (LAB16),HL
Store the value held in Register Pair HL into memory location 4EDDH.
4E55
EX DE,HL
Let DE = HL. We don't care what was in DE at the time of this EXchange because HL will be overwritten.

The next few instructions set HL = DE * 3

4E56
LD HL,0000H
Let Register Pair HL equal 0000H.
4E59
ADD HL,DE
LET Register Pair HL = Register Pair HL + Register DE.
4E5A
ADD HL,DE
LET Register Pair HL = Register Pair HL + Register DE.
4E5B
ADD HL,DE
LET Register Pair HL = Register Pair HL + Register DE.
4E5C
PUSH HL
Save the contents of Register Pair HL to the top of the stack.
4E5D
LD DE,(4ED7H)LD DE,(LAB13)
Fetch the value held in memory location 4ED7H and store it into Register Pair DE.

The next few instructions set HL = DE * 3

4E61
LD HL,0000H
Let Register Pair HL equal 0000H.
4E64
ADD HL,DE
LET Register Pair HL = Register Pair HL + Register DE.
4E65
ADD HL,DE
LET Register Pair HL = Register Pair HL + Register DE.
4E66
ADD HL,DE
LET Register Pair HL = Register Pair HL + Register DE.
4E67
LD BC,(4EE1H)LD BC,(VARPTR)
Fetch the value held in memory location 4EE1H and store it into Register Pair BC.
4E6B
ADD HL,BC
LET Register Pair HL = Register Pair HL + Register BC.
4E6C
EX DE,HL
EXchange the value stored in Register Pair HL with the value stored in Register Pair DE.
4E6D
POP HL
Put the value held at the top of the STACK into Register Pair HL, and then remove the entry from the stack.
4E6E
ADD HL,BC
LET Register Pair HL = Register Pair HL + Register BC.
4E6F
PUSH HL
Save the contents of Register Pair HL to the top of the stack.
4E70
PUSH DE
Save the contents of Register Pair DE to the top of the stack.
4E71
LD C,00H
Let Register C equal 00H.
4E73
LD A,(HL)
Fetch the value held in the memory location pointed to by Register Pair HL and store it into Register A.
4E74
LD B,A
Copy the contents of Register A into Register B.
4E75
LD A,(DE)
Fetch the value held in the memory location pointed to by Register Pair DE and store it into Register A.
4E76
CP B
Compare the value held in Register A against the value held in Register B. Results:
  • If Register A equals the value held in Register B, the Z FLAG is set.
  • If A < B, the CARRY FLAG will be set.
  • if A >= B, the NO CARRY FLAG will be set.
4E77
If the NC FLAG (No Carry) has been set, JUMP to 4E7CH.
4E79
LD C,01H
Let Register C equal 01H.
4E7B
LD B,A
Copy the contents of Register A into Register B.
4E7CLAB6
XOR A
Set Register A to ZERO and clear all Flags.
4E7D
OR B
OR Register B against Register A. The results are stored in Register A.
4E7E
If the Z FLAG (Zero) has been set, JUMP to 4E99H.
4E80
PUSH BC
Save the contents of Register Pair BC to the top of the stack.
4E81
INC DE
INCrement the value stored in Register Pair DE by 1.
4E82
INC HL
INCrement the value stored in Register Pair HL by 1.
4E83
LD C,(HL)
Fetch the value held in the memory location pointed to by Register Pair HL and store it into Register C.
4E84
INC HL
INCrement the value stored in Register Pair HL by 1.
4E85
LD B,(HL)
Fetch the value held in the memory location pointed to by Register Pair HL and store it into Register B.
4E86
PUSH BC
Save the contents of Register Pair BC to the top of the stack.
4E87
POP HL
Put the value held at the top of the STACK into Register Pair HL, and then remove the entry from the stack.
4E88
EX DE,HL
EXchange the value stored in Register Pair HL with the value stored in Register Pair DE.
4E89
LD C,(HL)
Fetch the value held in the memory location pointed to by Register Pair HL and store it into Register C.
4E8A
INC HL
INCrement the value stored in Register Pair HL by 1.
4E8B
LD B,(HL)
Fetch the value held in the memory location pointed to by Register Pair HL and store it into Register B.
4E8C
PUSH BC
Save the contents of Register Pair BC to the top of the stack.
4E8D
POP HL
Put the value held at the top of the STACK into Register Pair HL, and then remove the entry from the stack.
4E8E
POP BC
Put the value held at the top of the STACK into Register Pair BC, and then remove the entry from the stack.
4E8FLAB7
LD A,(DE)
Top of a DJNZ loop. Fetch the value held in the memory location pointed to by Register Pair DE and store it into Register A.
4E90
SUB (HL)
LET Register A = Register A - Register Pair HL.
4E91
If the C FLAG (Carry) has been set, JUMP to 4E9DH.
4E93
If the NZ FLAG (Not Zero) has been set, JUMP to 4EBCH.
4E95
INC DE
INCrement the value stored in Register Pair DE by 1.
4E96
INC HL
INCrement the value stored in Register Pair HL by 1.
4E97
LOOP back to 4E8FH, reducing Register B each time, and continue to LOOP until Register B has been reduced to ZERO, in which case, continue with the next instruction.
4E99LAB8
BIT 0,C
Test Bit Number 0 of Register C. Z FLAG will be set if that bit is 0, and NZ FLAG will be set if that bit is 1.
4E9B
If the NZ FLAG (Not Zero) has been set, JUMP to 4EBCH.
4E9DLAB9
POP DE
Put the value held at the top of the STACK into Register Pair DE, and then remove the entry from the stack.
4E9E
POP HL
Put the value held at the top of the STACK into Register Pair HL, and then remove the entry from the stack.
4E9F
LD B,03H
Let Register B equal 03H.
4EA1LAB10
LD C,(HL)
Top of a DJNZ loop. Fetch the value held in the memory location pointed to by Register Pair HL and store it into Register C.
4EA2
EX DE,HL
EXchange the value stored in Register Pair HL with the value stored in Register Pair DE.
4EA3
LD A,(HL)
Fetch the value held in the memory location pointed to by Register Pair HL and store it into Register A.
4EA4
LD (HL),C
Store the value held in Register C into the memory location pointed to by Register Pair HL.
4EA5
EX DE,HL
EXchange the value stored in Register Pair HL with the value stored in Register Pair DE.
4EA6
LD (HL),A
Store the value held in Register A into the memory location pointed to by Register Pair HL.
4EA7
INC HL
INCrement the value stored in Register Pair HL by 1.
4EA8
INC DE
INCrement the value stored in Register Pair DE by 1.
4EA9
LOOP back to 4EA1H, reducing Register B each time, and continue to LOOP until Register B has been reduced to ZERO, in which case, continue with the next instruction.
4EAB
LD DE,(4EDFH)LD DE,(NUMB1)
Fetch the value held in memory location 4EDFH and store it into Register Pair DE.
4EAF
LD HL,(4ED7H)LD HL,(LAB13)
Fetch the value held in memory location 4ED7H and store it into Register Pair HL.
4EB2
XOR A
Set Register A to ZERO and clear all Flags.
4EB3
SBC HL,DE
Subtracts the value stored in Register Pair DE and the carry flag from the value stored in Register Pair HL.
4EB5
LD (4ED7H),HLLD (LAB13),HL
Store the value held in Register Pair HL into memory location 4ED7H.
4EB8
If the NC FLAG (No Carry) has been set, JUMP to 4E4AH.
4EBA
JUMP to 4EBEH.

4EBCH - LAB11 - "SORT" Routine Main Routine.

4EBCLAB11
POP DE
Put the value held at the top of the STACK into Register Pair DE, and then remove the entry from the stack.
4EBD
POP HL
Put the value held at the top of the STACK into Register Pair HL, and then remove the entry from the stack.
4EBELAB12
LD HL,(4ED9H)LD HL,(LAB14)
Fetch the value held in memory location 4ED9H and store it into Register Pair HL.
4EC1
LD DE,0001H
Let Register Pair DE equal 0001H.
4EC4
XOR A
Set Register A to ZERO and clear all Flags.
4EC5
ADD HL,DE
LET Register Pair HL = Register Pair HL + Register DE.
4EC6
LD (4ED9H),HLLD (LAB14),HL
Store the value held in Register Pair HL into memory location 4ED9H.
4EC9
LD DE,(4EDBH)LD DE,(LAB15)
Fetch the value held in memory location 4EDBH and store it into Register Pair DE.
4ECD
SBC HL,DE
Subtracts the value stored in Register Pair DE and the carry flag from the value stored in Register Pair HL.
4ECF
If the C FLAG (Carry) has been set, JUMP to 4E44H.
4ED2
JUMP to 4E22H.

4ED5H - NUMB0 - "SORT" Routine Byte Storage Area.

4ED5NUMB0
DEFS 2
2 Bytes of Storage
4ED7LAB13
DEFS 2
2 Bytes of Storage
4ED9LAB14
DEFS 2
2 Bytes of Storage
4EDBLAB15
DEFS 2
2 Bytes of Storage
4EDDLAB16
DEFS 2
2 Bytes of Storage
4EDFNUMB1
DEFS 2
2 Bytes of Storage
4EE1VARPTR
DEFS 2
2 Bytes of Storage

4EE3H - RETJUL - Julian Date Conversion Routine Entry Point.

4EE3RETJUL
LD HL,(4272H)LD HL,(BASIC1)
Fetch the text pointer (held in memory location 4272H) and store it into Register Pair HL.
Original Source Code Comment: GET THE TEXT POINTER
4EE6
4EE7
RST 08H
2C
RST 08H is used to look for expected characters (in this case, a ,) in a string and then return with (HL) pointing to the next non-blank character.

It is a COMPARE SYMBOL routine which comparess the symbol in the input string pointed to by HL register to the value in the location following the RST 08 call.

If there is a match, control is returned to address of the RST 08 instruction 2 with the next symbol in the A register and HL incremented by one. If the two characters do not match, a syntax error message is given.
Original Source Code Comment: MUST HAVE ','
4EE8
Call the Model III ROM Routine to evaluate a BASIC expression at 2337H. This routine evaluates a BASIC expression pointed to by the HL and stores the result in the ACC. The expression must be terminated with zero byte, comma, right bracket or colon. After execution, HL will point to the delimiter and, in the case of string expressions, the ACC will contain the address of the first of three bytes that contain string length and string address..
Original Source Code Comment: GO EVULATE THE EXPRESION
4EEB
PUSH HL
Save the text pointer (held in Register Pair HL after that CALL) to the top of the stack.
Original Source Code Comment: SAVE TEXT POINTER
4EEC
Call the Model III ROM Routine at 29D7H to get a string's VARPTR and put it in HL and the string's length into Register A.
Original Source Code Comment: GET A POINTER TO THE STRING
4EEF
LD A,(HL)
Fetch the byte count of the string into Register A.
Original Source Code Comment: GET THE BYTE COUNT
4EF0
OR A
Since a LD command does not set any FLAGS, Set FLAGS based on the contents of Register A (and, in all events, clear the CARRY FLAG).
Original Source Code Comment: NULL STRINGS NOT ALLOWED
4EF1
If string length is 0, then return to BASIC with a "?FC ERROR" via a JUMP to 1E4AH.
Original Source Code Comment: YES, EXIT
4EF4
INC HL
INCrement the value stored in Register Pair HL by 1 so that HL will now point to the LSB of the RAM ADDRESS of the string.
Original Source Code Comment: BUMP TO THE ADDRESS
4EF5
LD E,(HL)
Fetch the LSB of the RAM LOCATION OF THE STRING into Register E.
Original Source Code Comment: GET THE STRING ADDRESS
4EF6
INC HL
INCrement the value stored in Register Pair HL by 1 so that HL will now point to the MSB of the RAM ADDRESS of the string.
4EF7
LD H,(HL)
Fetch the MSB of the RAM LOCATION OF THE STRING into Register H.
4EF8
LD L,E
Copy the LSB of the RAM LOCATION OF THE STRING (held in Register E) into Register L so that HL now points to the RAM ADDRESS of the string.
4EF9
LD A,(HL)
Fetch the character at the RAM LOCATION OF THE STRING and store it into Register A.
Original Source Code Comment: GET NEXT CHAR
4EFA
CP 2DHCP "-"
Compare the value held in Register A against 2DH (ASCII: -). If that character is a - then ...
Original Source Code Comment: CHANGE JUL TO DATE?
4EFC
... the user wants to convert JULIAN to GREGORIAN. JUMP to 4F92H.
Original Source Code Comment: YES, DO IT
4EFF
Otherwise, the user wants to covert a GREGORIAN date to JULIAN. Start via a GOSUB to 50BCH to fetch the user-supplied MONTH.
Original Source Code Comment: GET THE MONTH VALUE
4F02
CP 0DH
Compare the user-supplied month (held in Register A) against 0DH (Decimal: 13). If the user supplied month >= 13, then we have an invalid month so ...
Original Source Code Comment: SILLY MONTH?
4F04
... return to BASIC with a "?SN ERROR" via a JUMP to 1997H.
Original Source Code Comment: YES, EXIT
4F07
LD (5588H),ALD (MT),A
Store the user-supplied month (held in Register A) into memory location 5588H.
Original Source Code Comment: SAVE IT
4F0A
GOSUB to 50BAH to fetch the user-supplied DAY.
Original Source Code Comment: GET THE DAY VALUE
4F0D
CP 20H
Compare the user-supplied day (held in Register A) against 20H (Decimal: 32). If the user-supplied day >= 32, then we have an invalid day so ...
Original Source Code Comment: SILLY DAY?
4F0F
... return to BASIC with a "?SN ERROR" via a JUMP to 1997H.
Original Source Code Comment: YES, EXIT
4F12
LD (5589H),ALD (DY),A
Store the user-supplied day (held in Register A) into memory location 5589H.
Original Source Code Comment: SAVE IT
4F15
GOSUB to 50BAH to fetch the user-supplied YEAR.
Original Source Code Comment: GET THE YEAR VALUE
4F18
CP 64H
Compare the user-supplied year (held in Register A) against 64H (Decimal: 100). If the user-supplied year >= 100, then we have an invalid year so ...
Original Source Code Comment: SILLY YEAR?
4F1A
... return to BASIC with a "?SN ERROR" via a JUMP to 1997H.
Original Source Code Comment: YES, EXIT
4F1D
LD (5587H),ALD (YR),A
Store the value held in Register A into memory location 5587H.
Original Source Code Comment: SAVE IT
4F20
PUSH HL
Save the text pointer (held in Register Pair HL) to the top of the stack.
Original Source Code Comment: SAVE THE TEXT POINTER
4F21
AND 03H
Test for a leap year. First, MASK the value of Register A against 03H (0000 0011) to leave only bits 1 and 0 active.
Original Source Code Comment: LEAP YEAR?
4F23
LD D,00H
Set up for a counter by initializing Register D to 00H.
Original Source Code Comment: CLEAR THE MSB OF A COUNTER
4F25
LD IX,0000H
Set up for an accumulator by initializing Special Index Register IX to 0000H.
Original Source Code Comment: START AN ACCUMULATOR
4F29
If AND caused Register A to be 00, then this was not a leap year, so skip over the leap year adjustment by JUMPing to 4F34H.
Original Source Code Comment: NO, CONTINUE
4F2B
LD A,(5588H)LD A,(MT)
Fetch the month (held in memory location 5588H) and store it into Register A.
Original Source Code Comment: GET THE MONTH
4F2E
CP 03H
Compare the month (held in Register A) against 03H. If the month is < 3 (so either January or February) ...
Original Source Code Comment: PAST FEB?
4F30
... skip over the leap year adjustment by JUMPing to 4F34H.
Original Source Code Comment: NO, DON'T INC FOR LEAP YEAR
4F32
INC IX
If we're here, then we need to account for the leap year by adding a single day, so INCrement the value stored in Special Index Register IX by 1.
Original Source Code Comment: ADD IN THE LEAP YEAR DAY
4F34RETJU1
LD HL,0269HLD HL,MAXTIM+3
Let Register Pair HL equal 0269H, which is the Model III ROM location which starts off the length of each of the 12 months (1F 1C 1F 1E 1F 1E 1F 1F 1E 1F 1E 1F).
Original Source Code Comment: HL => JANUARY VALUE
4F37
LD A,(5588H)LD A,(MT)
Fetch the month from memory location 5588H and store it into Register A.
Original Source Code Comment: GET THE MONTH
4F3A
LD B,A
Copy the month into Register B.
Original Source Code Comment: INTO B
4F3B
DEC B
DECrement the value stored in Register B by 1 to correct for 1's offset.
Original Source Code Comment: CORRECT FOR 1'S OFFSET
4F3C
If the month was January, then the DEC caused the Z FLAG to trigger, so HL is already pointing to the right entry (January at 0269H). Skip over the month length lookup and JUMP directly to 4F45H.
Original Source Code Comment: WAS 'JAN' JUST PICK UP THE DAY
4F3ERETJU2
LD A,(HL)
Top of a DJNZ loop. Fetch the number of day in the month pointed to by HL into Register A.
Original Source Code Comment: GET THE VALUE FOR THE MONTH
4F3F
INC HL
INCrement HL to the next month.
Original Source Code Comment: BUMP TO NEXT VALUE
4F40
LD E,A
Copy the prior fetched number days in the month (held in Register A) into Register E.
Original Source Code Comment: INTO DE
4F41
ADD IX,DE
LET Register Pair IX = Register Pair IX + Register DE (i.e., the day counter).
Original Source Code Comment: ADD TO THE DAY COUNTER
4F43
LOOP back to 4F3EH, reducing Register B each time, and continue to LOOP until Register B has been reduced to ZERO, in which case, continue with the next instruction.
Original Source Code Comment: LOOP FOR MONTH
4F45RETJU3
LD A,(5589H)LD A,(DY)
Fetch the user-supplied day (held in memory location 5589H) and store it into Register A.
Original Source Code Comment: GET THE DAY
4F48
LD E,A
Copy the day (held in Register A) into Register E.
Original Source Code Comment: INTO DE
4F49
ADD IX,DE
Determine the JULIAN DATE (in hex) by setting Register Pair IX = Register Pair IX + the user supplied date (held in Register DE).
Original Source Code Comment: IX = JULIAN DAY (HEX)
4F4B
PUSH IX
Let Register Pair HL = the JULIAN DATE (held in Special Index Register IX) ... Part 1.
Original Source Code Comment: MOVE THE VALUE TO HL
4F4D
POP HL
... Part 2
4F4E
Convert the hex JULIAN DATE to ASCII and edit the spaces via a GOSUB to 50E6H.
Original Source Code Comment: CHANGE TO ASCII AND EDIT SPACES
4F51
LD HL,4133HLD HL,FACLO+18
Let Register Pair HL equal 4133H, which is where the JULIAN DATE is now stored in ASCII.
Original Source Code Comment: HL => JULIAN DATE IN ASCII
4F54
LD DE,558AHLD DE,RTEMP
Let Register Pair DE equal 558AH, which is a temporary storage location.
Original Source Code Comment: TEMP STORAGE
4F57
LD BC,0003H
Since a Julian date is 3 digits, set Register Pair BC equal 0003H.
Original Source Code Comment: NUMBER OF BYTES
4F5A
LDIR
Transfers a byte of data from the memory location pointed to by HL to the memory location pointed to by DE. Then HL and DE are incremented and BC is decremented. If BC is not zero, this operation is repeated. Interrupts can trigger while this instruction is processing.
Original Source Code Comment: SAVE THE DATE
4F5C
POP HL
Restore the TEXT POINTER from the top of the stack into Register Pair HL, and then remove the entry from the stack.
Original Source Code Comment: GET TEXT POINTER BACK
4F5D
POP HL
Clear the stack.
Original Source Code Comment: GET THE TEXT POINTER BACK
4F5E
RST 08H
2C
RST 08H is used to look for expected characters (in this case, a ,) in a string and then return with (HL) pointing to the next non-blank character.

It is a COMPARE SYMBOL routine which comparess the symbol in the input string pointed to by HL register to the value in the location following the RST 08 call.

If there is a match, control is returned to address of the RST 08 instruction 2 with the next symbol in the A register and HL incremented by one. If the two characters do not match, a syntax error message is given.
Original Source Code Comment: MUST HAVE COMMA
4F60
Get the pointer to the variable by GOSUBing to the Model III ROM FIND ADDRESS OF VARIABLE routine at 260DH which searches the Variable List Table for a variable name which matches the name in the string pointed to in HL, and return the address of that variable in DE (and if there is no variable, it creates it, zeroes it, and returns THAT location).
Original Source Code Comment: GET A POINTER TO THE VARIABLE
4F63
Call the Model III ROM routine at 0AF4H to force REG1 to be a STRING. The routine calls 20H (RST 20H) and returns if NTF=3 (string) else if NTF is not 3 then it generates a ?TM ERROR.
Original Source Code Comment: FORCE THE FAC TO STRING VARIABLE
4F66
PUSH HL
Save the TEXT POINTER (held in Register Pair HL) to the top of the stack.
Original Source Code Comment: SAVE TEXT POINTER
4F67
LD A,(DE)
Fetch the length of the string (held at the memory location pointed to by Register Pair DE) and store it into Register A.
Original Source Code Comment: GET THE LENGTH OF STRING?
4F68
OR A
Since a LD command does not set any FLAGS, Set FLAGS based on the contents of Register A (and, in all events, clear the CARRY FLAG).
Original Source Code Comment: NEW STRING?
4F69
If the length of the string was 0 then we need to allocate string space via a JUMP to 4F74H.
Original Source Code Comment: YES, GET SOME STRING SPACE
4F6B
PUSH DE
Save the pointer (held in Register Pair DE) to the top of the stack.
Original Source Code Comment: SAVE THE POINTER
4F6C
EX DE,HL
Let HL = the pointer (held in Register Pair DE).
Original Source Code Comment: MOVE THE POINTER TO HL
4F6D
INC HL
INCrement the value stored in Register Pair HL by 1 to now point to the address of the string.
Original Source Code Comment: BUMP TO ADDRESS OF STRING
4F6E
LD E,(HL)
Fetch the LSB of the address of the string (held in the memory location pointed to by Register Pair HL) and store it into Register E.
Original Source Code Comment: GET IT
4F6F
INC HL
INCrement the value stored in Register Pair HL by 1 to now point to the MSB of the address of the string.
4F70
LD D,(HL)
Fetch the MSB of the address of the string (held in the memory location pointed to by Register Pair HL) and store it into Register D.
4F71
POP HL
Put the value held at the top of the STACK into Register Pair HL, and then remove the entry from the stack.
Original Source Code Comment: GET THE POINTER BACK
4F72
Continue via a JUMP to 4F7FH.
Original Source Code Comment: AND CONTINUE

4F74H - RETJU4 - Julian Date Conversion Routine. Jumped to if we need to allocate string space because the current length was 0.

4F74RETJU4
PUSH DE
Save the pointer to the variable (held in Register Pair DE) to the top of the stack.
Original Source Code Comment: SAVE POINTER TO VARIABLE
4F75
LD A,03H
We need to clear 3 bytes of storage so start by setting Register A to 03H.
Original Source Code Comment: CLEAR 3 BYTES FOR STRING
4F77
Set Up a String by GOSUBing to the Model III ROM Routine at 2857H. For that routine, Register A needs to hold the length of the string to be created.
Original Source Code Comment: GET US SOME STRING SPACE
4F7A
LD HL,(40D4H)LD HL,(DSCTMP+1)
Fetch the address of the string being created (held at 40D4H) into Register Pair HL. 40D3H is the VARPTR storage area for string currently being created by BASIC. 40D3H is the length, 40D4H is the LSB of the address of the string, and 40D5H is the MSB of the address of the string.
Original Source Code Comment: GET THE ADDRESS TO THE SPACE
4F7D
POP DE
Restore the address of the variable held at the top of the STACK into Register Pair DE, and then remove the entry from the stack.
Original Source Code Comment: GET POINTER BACK
4F7E
EX DE,HL
Put the pointer to the variable into Register Pair HL and the address of the variable into Register Pair DE.
Original Source Code Comment: PUT THE POINTER INTO HL
4F7FRETJU5
LD (HL),03H
Set the length of the string to 03H (which is the length of a JULIAN DATE).
Original Source Code Comment: LENGTH OF THE JULIAN DAY
4F81
INC HL
INCrement the value stored in Register Pair HL by 1 to now point to the LSB of the string.
4F82
LD (HL),E
Store the value held in Register E as the LSB of the string.
Original Source Code Comment: SET IT'S ADDRESS
4F83
INC HL
INCrement the value stored in Register Pair HL by 1 to now point to the MSB of the string.
4F84
LD (HL),D
Store the value held in Register D as the LSB of the string.
4F85
LD HL,558AHLD HL,RTEMP
Let Register Pair HL equal 558AH which is where the DATE is stored.
Original Source Code Comment: HL => SAVED DATE
4F88
LD BC,0003H
Prepare for a LDIR by setting the bytes to move to 3.
Original Source Code Comment: NUMBER OF CHARS TO MOVE
4F8B
LDIR
Transfers a byte of data from the memory location pointed to by HL to the memory location pointed to by DE. Then HL and DE are incremented and BC is decremented. If BC is not zero, this operation is repeated. Interrupts can trigger while this instruction is processing.
Original Source Code Comment: MOVE THE DATE
4F8D
POP HL
Restore the TEXT POINTER (held at the top of the STACK) into Register Pair HL, and then remove the entry from the stack.
Original Source Code Comment: GET THE TEXT POINTER BACK
4F8ERETEXT
LD (4272H),HLLD (BASIC1),HL
Store the TEXT POINTER (held in Register Pair HL) into memory location 4272H.
Original Source Code Comment: SAVE THE TEXT POINTER
4F91
RET
RETurn to the caller.
Original Source Code Comment: EXIT

4F92H - RETDAT - Julian Date Conversion Routine. Jumped point to convert JULIAN to GREGORIAN.

4F92RETDAT
INC HL
INCrement the TEXT POINTER (stored in Register Pair HL) by 1 to move past the -.
Original Source Code Comment: BUMP PAST THE MINUS SIGN
4F93
Get the YEAR via a GOSUB to 50BCH.
Original Source Code Comment: GET THE YEAR
4F96
CP 64H
Compare the user-supplied year (held in Register A) against 64H (Decimal: 100). If the user-supplied year >= 100, then we have an invalid year so ...
Original Source Code Comment: SILLY YEAR?
4F98
... return to BASIC with a "?SN ERROR" via a JUMP to 1997H.
Original Source Code Comment: YES, EXIT
4F9B
LD (5587H),ALD (YR),A
Store the year (held in Register A) into memory location 5587H.
Original Source Code Comment: SAVE THE YEAR
4F9E
Get the next 2 characters via a GOSUB to 50BAH.
Original Source Code Comment: GET THE NEXT 2 CHARS
4FA1
PUSH AF
Save the first two digits (held in Register A) to the top of the stack.
Original Source Code Comment: SAVE THE 1ST TWO DIGITS
4FA2
Get 1 more character via a GOSUB to 50D3H.
Original Source Code Comment: GET THE FINAL CHAR
4FA5
POP BC
Restore the first two digits (held at the top of the STACK) into Register Pair BC, and then remove the entry from the stack.
Original Source Code Comment: GET THE 1ST TWO DIGITS BACK
4FA6
PUSH HL
Save the TEXT POINTER (held in Register Pair HL) to the top of the stack.
Original Source Code Comment: SAVE TEXT POINTER

Start moving the characters around.

4FA7
LD L,B
Copy the first digit (held in Register B) into Register L.
Original Source Code Comment: 1ST TWO INTO HL
4FA8
LD H,00H
Let Register H equal 00H, so now Register Pair HL = the first digit.
4FAA
LD E,A
Copy the last digit (held in Register A into Register E.
Original Source Code Comment: LAST INTO DE
4FAB
LD D,H
Set Register D to 00H.
Original Source Code Comment: CLEAR D AS WELL
4FAC
PUSH HL
Copy the first two digits (held in Register Pair HL) to Register Pair BC ... Part 1
Original Source Code Comment: MIRROR 1ST TWO INTO BC
4FAD
POP BC
... Part 2

HL = HL * 10 ... to make it the first 2 digits into 100s and 10s digits.

4FAE
ADD HL,HL
LET Register Pair HL = Register Pair HL + Register HL.
Original Source Code Comment: TIMES 2
4FAF
ADD HL,HL
LET Register Pair HL = Register Pair HL + Register HL.
Original Source Code Comment: 4
4FB0
ADD HL,BC
LET Register Pair HL = Register Pair HL + Register BC.
Original Source Code Comment: 5
4FB1
ADD HL,HL
LET Register Pair HL = Register Pair HL + Register HL.
Original Source Code Comment: 10

HL = HL + the 1s Digit.

4FB2
ADD HL,DE
LET Register Pair HL = Register Pair HL + Register DE.
Original Source Code Comment: ADD IN THE LAST DIGIT
4FB3
EX DE,HL
Swap DE and HL.
Original Source Code Comment: PUT RESULT INTO DE
4FB4
LD A,D
Since the Z-80 cannot test Register Pair DE against zero, the common trick is to set Register A to equal to Register D, and then OR A against Register E. Only if both Register D and Register E were zero can the Z FLAG be set.
Original Source Code Comment: DAY 0?
4FB5
OR E
... Part 2
4FB6
If the Z FLAG (Zero) has been set then the DAY was 0, so return to BASIC with a "?SN ERROR" via a JUMP to 1997H.
Original Source Code Comment: YES, EXIT
4FB9
LD HL,016EH
Let Register Pair HL equal 016EH (Decimal: 366), which is the maximum number of JULIAN days.
Original Source Code Comment: MAX NUMBER OF JUL DAYS
4FBC
LD A,(5587H)LD A,(YR)
Fetch the value held in memory location 5587H and store it into Register A.
Original Source Code Comment: GET THE YEAR
4FBF
AND 03H
Test for a leap year by MASKing the value of Register A against 03H.
Original Source Code Comment: LEAP YEAR?
4FC1
If that mask leaves a ZERO then the value was 4 and we have a leap year ... so skip over the next instruction by JUMPing to 4FC4H.
Original Source Code Comment: YES, CONTINUE
4FC3
DEC HL
DECrement the value stored in Register Pair HL by 1 to now be 365, which is the maximum number of JULIAN days without a leap year.
Original Source Code Comment: NO, 365 IS MAX
4FC4REDA00
OR A
Clear the CARRY FLAG.
Original Source Code Comment: CLEAR CARRY
4FC5
SBC HL,DE
Ensure that the number of days is not longer than the maximum (either 366 or 365) by SUBtracting the value stored in Register Pair DE and the carry flag from the value stored in Register Pair HL.
Original Source Code Comment: IS IT BEYOND MAX
4FC7
If the C FLAG (Carry) has been set then days exceeded the maximum possible days in a year, so return to BASIC with a "?SN ERROR" via a JUMP to 1997H.
Original Source Code Comment: YES, EXIT
4FCA
If the NZ FLAG (Not Zero) has been set, then it is not the last day of the year, so JUMP to 4FD9H.
Original Source Code Comment: NOT END OF YEAR. CONTINUE

If we pass through, then it is December 31, so just hard code that date.

4FCC
LD A,0CH
Let Register A equal 0CH (Decimal: 12).
Original Source Code Comment: SET THE END MONTH
4FCE
LD (5588H),ALD (MT),A
Store the a 12 into memory location 5588H.
4FD1
LD A,1FH
Let Register A equal 1FH (Decimal: 31).
Original Source Code Comment: SET THE END DAY
4FD3
LD (5589H),ALD (DY),A
Store the 31 held in Register A into memory location 5589H.
4FD6
Exit the routine via a JUMP to 5043H.
Original Source Code Comment: AND EXIT

4FD9H - REDA0X - Continuation of the routine to convert JULIAN to GREGORIAN. Jumped here if we are not at the last day of the calendar year.

4FD9REDA0X
LD HL,0269HLD HL,MAXTIM+3
Let Register Pair HL equal 0269H, which is the Model III ROM location which starts off the length of each of the 12 months (1F 1C 1F 1E 1F 1E 1F 1F 1E 1F 1E 1F).
Original Source Code Comment: HL => MONTH LENGTH'S
4FDC
LD IX,0000H
Set up for an counter by initializing Special Index Register IX to 0000H.
Original Source Code Comment: SET A COUNTER

Top of Loop

4FE0RETDA1
LD C,(HL)
Fetch the length of the month from the table in the Model III ROM pointed to by Register Pair HL and store it into Register C.
Original Source Code Comment: GET THE MONTH LENGTH
4FE1
LD B,00H
Set Register B to 00H so now Register Pair BC holds the length of the month.
Original Source Code Comment: CLEAR B
4FE3
INC HL
INCrement the pointer to the month lengths held in the Model III ROM by 1.
Original Source Code Comment: BUMP TO NEXT VALUE
4FE4
INC IX
INCrement the month counter tracked by Special Index Register IX by 1.
Original Source Code Comment: BUMP TO NEXT MONTH
4FE6
EX DE,HL
EXchange the value stored in Register Pair DE and HL.
Original Source Code Comment: PUT VALUE INTO HL
4FE7
OR A
Clear the CARRY FLAG.
Original Source Code Comment: CLEAR CARRY
4FE8
SBC HL,BC
Subtracts the value stored in Register Pair BC (the month) and the carry flag from the value stored in Register Pair HL.
Original Source Code Comment: SUBTRACT THIS MONTH
4FEA
EX DE,HL
EXchange the value stored in Register Pair DE and HL.
Original Source Code Comment: VALUE BACK INTO DE
4FEB
If the C FLAG (Carry) has been set then we have found the month! JUMP to 4FF5H to exit.
Original Source Code Comment: FOUND. EXIT
4FED
LD A,D
Since the Z-80 cannot test Register Pair DE against zero, the common trick is to set Register A to equal to Register D, and then OR A against Register E. Only if both Register D and Register E were zero can the Z FLAG be set.
Original Source Code Comment: WE AT 0?
4FEE
OR E
... Part 2.
4FEF
If the NZ FLAG (Not Zero) has been set, then we are NOT at "0", so JUMP to 4FE0H to continue.
Original Source Code Comment: NO, CONTINUE

End of Loop

4FF1
INC IX
INCrement the value stored in Special Index Register IX by 1 because the next dump is to a DEC IX.
Original Source Code Comment: BUMP FOR THE FOLLOWING DEC IX
4FF3
JUMP to 4FFEH.

4FF5H - RETDA8 - Continuation of the routine to convert JULIAN to GREGORIAN. Jumped here if have calculated the MONTH.

4FF5RETDA8
DEC HL
DECrement the month (stored in Register Pair HL) by 1.
Original Source Code Comment: BACK UP TO THE MONTH THAT DID IT
4FF6
LD C,(HL)
Fetch the number of days in the revised month.
Original Source Code Comment: GET THE VALUE AGAIN
4FF7
EX DE,HL
EXchange the value stored in Register Pair HL with the value stored in Register Pair DE.
4FF8
ADD HL,BC
LET Register Pair HL = Register Pair HL + Register BC.
Original Source Code Comment: BRING BACK TO POSITIVE
4FF9
LD A,H
Since the Z-80 cannot test Register Pair HL against zero, the common trick is to set Register A to equal to Register H, and then OR A against Register L. Only if both Register H and Register L were zero can the Z FLAG be set. Part 1 ...
Original Source Code Comment: ON MONTH BOUNDARY?
4FFA
OR L
... part 2
4FFB
If the NZ FLAG (Not Zero) has been set, then we are not on a month boundary, so JUMP to 5002H.
Original Source Code Comment: NO, CONTINUE
4FFD
EX DE,HL
Put the MONTH into Register Pair HL.
Original Source Code Comment: HL => MONTH
4FFERETDA9
DEC HL
DECrement the month (stored in Register Pair HL) by 1.
Original Source Code Comment: BACK UP ONE
4FFF
LD L,(HL)
Fetch the number of days in the revised month.
Original Source Code Comment: PICK IT UP
5000
DEC IX
DECrement the counter of the months stored in Special Index Register IX by 1.
Original Source Code Comment: BACK THE MONTH UP ONE
5002RETDA0
LD A,L
Copy the DAY (held in Register L) into Register A.
Original Source Code Comment: GET THE DAY
5003
LD (DY),A
Store the value held in Register A into memory location 5589H.
Original Source Code Comment: SAVE IT
5006
PUSH IX
Copy the month counter from Register Pair IX ...
Original Source Code Comment: MOVE COUNTER TO HL
5008
POP HL
... to Register Pair HL.
5009
LD A,L
Copy the MONTH (thanks to the counter of IX) into Register A.
Original Source Code Comment: GET THE MONTH
500A
LD (5588H),ALD (MT),A
Store the value held in Register A into memory location 5588H.
Original Source Code Comment: SAVE IT
500D
LD A,(5587H)LD A,(YR)
Fetch the YEAR (held in memory location 5587H) and store it into Register A.
Original Source Code Comment: GET THE YEAR
5010
AND 03H
MASK the value of Register A against 03H to test for a leap year (Z FLAG) or not (NZ FLAG).
Original Source Code Comment: IS THIS A LEAP YEAR?
5012
If the NZ FLAG (Not Zero) has been set it is not a leap year, so JUMP to 5043H.
Original Source Code Comment: NO, CONTINUE
5014
LD A,(5588H)LD A,(MT)
Fetch the MONTH from memory location 5588H and store it into Register A.
Original Source Code Comment: GET THE MONTH
5017
CP 03H
Compare the month (held in Register A) against 03H. If the month is < 3 (so either January or February) ...
Original Source Code Comment: FEB?
5019
... JUMP to 5043H.
Original Source Code Comment: NO, CONTINUE
501B
LD A,(5589H)LD A,(DY)
Fetch the DAY (held in memory location 5589H) and store it into Register A.
Original Source Code Comment: GET THE DAY
501E
DEC A
DECrement the DAY by 1.
Original Source Code Comment: DEC IT
501F
LD (5589H),ALD (DY),A
Store the decremented DAY into memory location 5589H.
Original Source Code Comment: SAVE NEW VALUE
5022
If the NZ FLAG (Not Zero) has been set, then we were not at the 1st of the month, so JUMP to 5043H.
Original Source Code Comment: WASN'T THE 1ST OF THE MONTH
5024
LD A,(5588H)LD A,(MT)
Fetch the month (held in memory location 5588H) and store it into Register A.
Original Source Code Comment: GET THE MONTH
5027
DEC A
DECrement the month by 1.
Original Source Code Comment: BACK UP ONE
5028
LD (5588H),ALD (MT),A
Store decremented MONTH into memory location 5588H.
Original Source Code Comment: NEW MONTH
502B
LD E,A
Let DE = the decremented month ... Part 1
Original Source Code Comment: SET AS OFFSET INTO DE
502C
LD D,00H
... Part 2
502E
LD HL,0268HLD HL,MAXTIM+2
Let Register Pair HL equal 0268H which is one byte before the Model III ROM location which starts off the length of each of the 12 months.
Original Source Code Comment: WHERE MONTH LENGTHS ARE IN ROM
5031
ADD HL,DE
LET Register Pair HL = the ROM Month Length List position minus 1 (held in Register Pair HL) + the decremented month (held in Register DE). This is the new month pointer.
Original Source Code Comment: HL => NEW MONTH
5032
LD A,(HL)
Fetch the number of days in the new month from the ROM chart and store it into Register A.
Original Source Code Comment: GET THE MAX DAY
5033
LD (5589H),ALD (DY),A
Store that as the new number of days into memory location 5589H.
Original Source Code Comment: SET AS NEW DAY
5036
LD L,A
Save the number of days into Register L.
Original Source Code Comment: SAVE THE DAY
5037
LD A,(5588H)LD A,(MT)
Fetch the value held in memory location 5588H and store it into Register A.
Original Source Code Comment: GET THE MONTH
503A
CP 02H
Compare the month (held in Register A) against 02H. If the month is => 2 (so February and on) ...
Original Source Code Comment: IS THIS FEB?
503C
... we are good so JUMP to 5043H.
Original Source Code Comment: NO, EVERYTHING IS COOL

If we are here then we need to add in the leap day.

503E
INC L
INCrement the number of days in the month (stored in Register L) by 1 for the leap day.
Original Source Code Comment: YES, ADD IN THE LEAP DAY
503F
LD A,L
Copy the updated number of days into Register A.
Original Source Code Comment: AND SAVE IT
5040
LD (5589H),ALD (DY),A
Store the value held in Register A into memory location 5589H.
5043RETDA2
POP HL
Put the TEXT POINTER (held at the top of the STACK) into Register Pair HL, and then remove the entry from the stack.
Original Source Code Comment: GET TEXT POINTER BACK
5044
POP HL
Clean the stack.
Original Source Code Comment: GET TEXT POINTER BACK
5045
RST 08H
2C
RST 08H is used to look for expected characters (in this case, a ,) in a string and then return with (HL) pointing to the next non-blank character.

It is a COMPARE SYMBOL routine which comparess the symbol in the input string pointed to by HL register to the value in the location following the RST 08 call.

If there is a match, control is returned to address of the RST 08 instruction 2 with the next symbol in the A register and HL incremented by one. If the two characters do not match, a syntax error message is given.
Original Source Code Comment: MUST HAVE ','
5047
PUSH HL
Save the TEXT POINTER to the top of the stack.
Original Source Code Comment: SAVE TEXT POINTER
5048
LD A,(MT)
Fetch the MONTH from memory location 5588H and store it into Register A.
Original Source Code Comment: GET THE MONTH
504B
LD L,A
Copy the MONTH into Register Pair HL. First load A into L
Original Source Code Comment: INTO HL
504C
LD H,00H
Set H to 00H, making A a 16 bit number held in HL
504E
Convert the MONTH to ASCII via a GOSUB to 50E6H.
Original Source Code Comment: MAKE IT ASCII
5051
LD DE,558AHLD DE,RTEMP
Let Register Pair DE equal 558AH as temporary storage for the ASCII converted MONTH.
Original Source Code Comment: TEMP AREA
5054
Move the ASCII MONTH to the temp area pointed to by DE via a GOSUB to 50A6H.
Original Source Code Comment: MOVE THE ASCII INTO TEMP AREA
5057
PUSH DE
Save the pointer to the temporary storage area holding the ASCII converted MONTH to the top of the stack.
Original Source Code Comment: SAVE TEMP POINTER
5058
LD A,(5589H)LD A,(DY)
Fetch the DAY from memory location 5589H and store it into Register A.
Original Source Code Comment: GET THE DAY
505B
LD L,A
Copy the DAY into Register Pair HL. First load A into L
Original Source Code Comment: INTO HL
505C
LD H,00H
Set H to 00H, making A a 16 bit number held in HL
505E
Convert the DAY to ASCII via a GOSUB to 50E6H.
Original Source Code Comment: MAKE IT ASCII
5061
POP DE
Put the TEMP POINTER (held at the top of the STACK) into Register Pair DE, and then remove the entry from the stack.
Original Source Code Comment: GET TEMP POINTER BACK
5062
Move the ASCII DAY to the temp area pointed to by DE via a GOSUB to 50A6H.
Original Source Code Comment: MOVE THE ASCII
5065
PUSH DE
Save the pointer to the temporary storage area holding the ASCII converted DAY to the top of the stack.
Original Source Code Comment: SAVE TEMP POINTER
5066
LD A,(5587H)LD A,(YR)
Fetch the YEAR from memory location 5588H and store it into Register A.
Original Source Code Comment: GET THE YEAR
5069
LD L,A
Copy the YEAR into Register Pair HL. First load A into L
Original Source Code Comment: INTO HL
506A
LD H,00H
Set H to 00H, making A a 16 bit number held in HL
506C
Convert the YEAR to ASCII via a GOSUB to 50E6H.
Original Source Code Comment: MAKE IT ASCII
506F
POP DE
Put the TEMP POINTER (held at the top of the STACK) into Register Pair DE, and then remove the entry from the stack.
Original Source Code Comment: GET TEMP POINTER
5070
Move the ASCII YEAR to the temp area pointed to by DE via a GOSUB to 50A6H.
Original Source Code Comment: MOVE IT INTO TEMP
5073
POP HL
Put the TEMP POINTER (held at the top of the STACK) into Register Pair HL, and then remove the entry from the stack.
Original Source Code Comment: GET TEXT POINTER BACK
5074
Get the pointer to the variable by GOSUBing to the Model III ROM FIND ADDRESS OF VARIABLE routine at 260DH which searches the Variable List Table for a variable name which matches the name in the string pointed to in HL, and return the address of that variable in DE (and if there is no variable, it creates it, zeroes it, and returns THAT location).
Original Source Code Comment: GET A POINTER TO THE VARIABLE
5077
Call the Model III ROM routine at 0AF4H to force REG1 to be a STRING. The routine calls 20H (RST 20H) and returns if NTF=3 (string) else if NTF is not 3 then it generates a ?TM ERROR.
Original Source Code Comment: FORCE THE FAC TO STRING VARIABLE
507A
PUSH HL
Save the TEXT POINTER to the top of the stack.
Original Source Code Comment: SAVE TEXT POINTER
507B
LD A,(DE)
Fetch the length of the string (held in the memory location pointed to by Register Pair DE) and store it into Register A.
Original Source Code Comment: GET THE LENGTH OF THE STRING
507C
CP 08H
Compare the value held in Register A against 08H to see if it is a new or smaller string. If the string length < 08H...
Original Source Code Comment: NEW OR SMALL STRING?
507E
... create some string space via a JUMP to 5089H.
Original Source Code Comment: YES, CREATE SOME STRING SPACE
5080
PUSH DE
Save the variable pointer to the top of the stack.
Original Source Code Comment: SAVE THE POINTER
5081
EX DE,HL
Put the variable pointer into Register Pair HL.
Original Source Code Comment: MOVE POINTER TO HL
5082
INC HL
INCrement the value stored in Register Pair HL by 1 so as to now point to the LSB of the memory address for that string.
Original Source Code Comment: BUMP TO ADDRESS OF STRING
5083
LD E,(HL)
Fetch the LSB of the memory address for that string and put it into Register E.
Original Source Code Comment: GET IT'S ADDRESS
5084
INC HL
INCrement the value stored in Register Pair HL by 1 so as to now point to the MSB of the memory address for that string.
5085
LD D,(HL)
Fetch the MSB of the memory address for that string and put it into Register D.
5086
POP HL
Restore the variable pointer to the top of the stack into Register Pair HL, and then remove the entry from the stack.
Original Source Code Comment: GET THE POINTER BACK
5087
Continue processing via a JUMP to 5094H.
Original Source Code Comment: AND CONTINUE

5089H - RETDA3 - Create a variable of 8 bytes to house the ASCII DATE.

5089RETDA3
PUSH DE
Save the variable pointer to the top of the stack.
Original Source Code Comment: SAVE POINTER TO VARIABLE
508A
LD A,08H
Prepare to clear 8 bytes of string space by setting Register A to 08H.
Original Source Code Comment: CLEAR 8 BYTES OF STRING SPACE
508C
Set Up a String by GOSUBing to the Model III ROM Routine at 2857H. For that routine, Register A needs to hold the length of the string to be created.
Original Source Code Comment: GET US SOME STRING SPACE
508F
LD HL,(40D4H)LD HL,(DSCTMP+1)
Fetch the RAM address for that new space from memory location 40D4H.
Original Source Code Comment: GET THE ADDRESS TO THE SPACE
5092
POP DE
Put the variable pointer (held at the top of the STACK) into Register Pair DE, and then remove the entry from the stack.
Original Source Code Comment: GET POINTER BACK
5093
EX DE,HL
EXchange the value stored in Register Pair HL (the RAM address for that new space) with the value stored in Register Pair DE (the variable pointer).
Original Source Code Comment: SWAP THEM

5094H - RETDA4 - Store the 8 byte ASCII DATE into a variable.

5094RETDA4
LD (HL),08H
Set the length of the string by storing 08H into the memory location pointed to by Register Pair HL.
Original Source Code Comment: LENGTH OF STRING
5096
INC HL
INCrement the value stored in Register Pair HL by 1 so as to point to the LSB of the RAM address for the new string.
Original Source Code Comment: BUMP TO ADDRESS OF STRING
5097
LD (HL),E
Store the LSB of the RAM address for that new space into the memory location pointed to by Register Pair HL.
Original Source Code Comment: SET IT
5098
INC HL
INCrement the value stored in Register Pair HL by 1 so as to point to the MSB of the RAM address for the new string.
5099
LD (HL),D
Store the MSB of the RAM address for that new space into the memory location pointed to by Register Pair HL.
509A
LD HL,558AHLD HL,RTEMP
Let Register Pair HL equal 558AH which is where the ASCII DATE is stored.
Original Source Code Comment: ASCII DATE
509D
LD BC,0008H
Let Register Pair BC equal 0008H, for 8 bytes to move.
Original Source Code Comment: NUMBER OF CHARS
50A0
LDIR
Transfers a byte of data from the memory location pointed to by HL to the memory location pointed to by DE. Then HL and DE are incremented and BC is decremented. If BC is not zero, this operation is repeated. Interrupts can trigger while this instruction is processing.
Original Source Code Comment: MOVE IT TO STRING SPACE
50A2
POP HL
Put the TEMP POINTER (held at the top of the STACK) into Register Pair HL, and then remove the entry from the stack.
Original Source Code Comment: GET TEXT POINTER BACK
50A3
Exit via a JUMP to 4F8EH.
Original Source Code Comment: AND EXIT

50A6H - MOVIT - Move the value held in the temp area (4134H) to the memory location pointed to by Register Pair DE.

50A6MOVIT
LD HL,4134HLD HL,FACLO+16+3
Let Register Pair HL equal 4134H which is the last 2 bytes.
Original Source Code Comment: HL => LAST TWO BYTES
50A9
LD A,(HL)
Fetch the value held in the memory location pointed to by Register Pair HL and store it into Register A.
Original Source Code Comment: GET 1ST BYTE
50AA
CP 30H
Compare the byte at 4134H against 30H (ASCII: 0). If A >= 0 ...
Original Source Code Comment: SPACE CHAR?
50AC
... skip the next instruction by JUMPing to 50B0H.
Original Source Code Comment: NO, CONTINUE
50AE
LD (HL),30H
Put in a leading zero by storing a 0 into the memory location pointed to by Register Pair HL.
Original Source Code Comment: LEADING ZERO'S
50B0MOVIT1
LD BC,0002H
Prepare to move TWO bytes into a temp area.
Original Source Code Comment: NUMBER OF BYTES TO MOVE
50B3
LDIR
Transfers a byte of data from the memory location pointed to by HL to the memory location pointed to by DE. Then HL and DE are incremented and BC is decremented. If BC is not zero, this operation is repeated. Interrupts can trigger while this instruction is processing.
Original Source Code Comment: MOVE IT INTO TEMP
50B5
LD A,2FH
Let Register A equal 2FH (ASCII: /).
Original Source Code Comment: ADD A DELIMITER
50B7
LD (DE),A
Store the / delimeter into the memory location pointed to by Register Pair DE.
50B8
INC DE
INCrement the value stored in Register Pair DE by 1 to be after the /.
Original Source Code Comment: BUMP TO NEXT SLOT
50B9
RET
RETurn to the caller.

50BAH - GETNXT - Fetch 2 user supplied numbers (such as the day or year), which must follow a "/", into Register A.

50BA
50BBGETNXT
RST 08H
2F
RST 08H is used to look for expected characters (in this case, a /) in a string and then return with (HL) pointing to the next non-blank character.

It is a COMPARE SYMBOL routine which comparess the symbol in the input string pointed to by HL register to the value in the location following the RST 08 call.

If there is a match, control is returned to address of the RST 08 instruction 2 with the next symbol in the A register and HL incremented by one. If the two characters do not match, a syntax error message is given.
Original Source Code Comment: MUST HAVE '/'
50BCGETNX1
Get the next character into Register Avia a GOSUB to 50D3H.
Original Source Code Comment: GET NEXT CHARACTER
50BF
LD C,A
Store the character into Register C.
Original Source Code Comment: INTO C
50C0
Get the next character into Register Avia a GOSUB to 50D3H.
Original Source Code Comment: GET NEXT CHARACTER
50C3
LD B,A
Store the character into Register B.
Original Source Code Comment: INTO B
50C4
PUSH HL
Save the TEXT POINTER (held in Register Pair HL) to the top of the stack.
Original Source Code Comment: SAVE TEXT POINTER
50C5
LD H,00H
Let Register Pair HL = Register C - Part 1.
50C7
LD L,C
... Part 2
Original Source Code Comment: GET THE LSB
50C8
PUSH HL
Copy HL to DE - Part 1.
Original Source Code Comment: MIRROR TO DE
50C9
POP DE
... Part 2
50CA
ADD HL,HL
LET Register Pair HL = Register Pair HL * 2.
Original Source Code Comment: * 2
50CB
ADD HL,HL
LET Register Pair HL = Register Pair HL * 2 again (now * 4).
Original Source Code Comment: * 4
50CC
ADD HL,DE
LET Register Pair HL = Register Pair HL + Register DE (now * 5).
Original Source Code Comment: * 5
50CD
ADD HL,HL
LET Register Pair HL = Register Pair HL * 2 (now * 10).
Original Source Code Comment: * 10
50CE
LD E,B
Copy the MSB (held in Register B) into Register E.
Original Source Code Comment: GET THE MSB
50CF
ADD HL,DE
Add the MSB to HL.
Original Source Code Comment: ADD IT IN
50D0
LD A,L
Copy the result (held in Register L) into Register A.
Original Source Code Comment: GET THE RESULT
50D1
POP HL
Restore the TEXT POINTER (held at the top of the STACK) into Register Pair HL, and then remove the entry from the stack.
Original Source Code Comment: GET TEXT POINTER BACK
50D2
RET
RETurn to the caller.

50D3H - GETACR - Fetch 1 user supplied number, into Register A. If not a number, exit with a SYNTAX ERROR.

50D3GETACR
LD A,(HL)
Fetch the value held in the memory location pointed to by Register Pair HL and store it into Register A.
Original Source Code Comment: GET THE CHARACTER
50D4
INC HL
INCrement the TEXT POINTER (held in Register Pair HL) by 1.
Original Source Code Comment: BUMP TO NEXT CHAR
50D5
CP 20H
Compare the value held in Register A against 20H (ASCII: SPACE). If the character is NOT a SPACE ...
Original Source Code Comment: SPACE?
50D7
... skip the next instruction by JUMPing to 50DBH.
Original Source Code Comment: NO, CONTINUE
50D9
LD A,30H
Let Register A equal 0.
Original Source Code Comment: SUBSTITUTE A ZERO
50DBGETAC1
SUB 30H
SUBtract the value 30H from Register A to test for a bad character. If it was < "0" then the value was bad ...
Original Source Code Comment: MASK OFF ASCII
50DD
... return to BASIC with a "?SN ERROR" via a JUMP to 1997H.
Original Source Code Comment: EXIT IF NON-NUMERIC
50E0
CP 0AH
Compare the value held in Register A against 0AH (Decimal: 10). If the character is >= 10 then the value was bad ...
Original Source Code Comment: SEE IF GREATER THAN NUMBER
50E2
... return to BASIC with a "?SN ERROR" via a JUMP to 1997H.
Original Source Code Comment: YES, ERROR
50E5
RET
RETurn to the caller.

50E6H - EDITM - Convert the hex JULIAN DATE to ASCII and edit the spaces.

50E6EDITM
OR 37H
OR Register A against 37H (0011 0111). This has the effect of turning on bits 5, 4, 2, 1, 0, leaving only 8 possible remaining numbers. 37H If the 0'd bits were 000, 3FH (001), 77H (010), 7FH (011), 87H (100), 8FH (101), C7H (110), and CFH (111).
Original Source Code Comment: CLEAR CARRY BY OR'ing IN NEXT BYTE
50E8
PUSH AF
Save the contents of Register Pair AF, which would be a flag to supress editing, to the top of the stack.
Original Source Code Comment: SAVE SUPRESS FLAG
50E9
GOSUB to 0A9AH in the Model III ROM routine to put the value in HL into the single precision number storage area of 4121H and is flagged as an INTEGER.
Original Source Code Comment: MAKE THE VALUE AN INTEGER
50EC
XOR A
Set Register A to ZERO for no ascii editing.
Original Source Code Comment: SET FOR NO ASCII EDITING
50ED
GOSUB to 1034H to turn off the EDIT flag and initialize the 4130H input buffer for a FLOATING POINT to ASCII conversion by putting a SPACE into 4130H.
Original Source Code Comment: SET THE EDITING MODE
50F0
OR (HL)
Set the flags by merging the value held in Register A against the byte of the program pointed to by Register Pair HL. This also clears the CARRY FLAG.
Original Source Code Comment: CLEAR CARRY
50F1
GOSUB to 0FD9H in the Model III ROM to convert the integer value in 4124H to an ASCII string pointed to by Register Pair HL.
Original Source Code Comment: CONTERT TO INTEGER ASCII
50F4
POP AF
Put the value held at the top of the STACK into Register Pair AF, and then remove the entry from the stack.
Original Source Code Comment: GET THE SUPPRESS FLAG BACK
50F5
RET C
If the C FLAG (Carry) has been set, then no editing is wanted, so RETurn to the caller.
Original Source Code Comment: EXIT IF NO EDITING IS WANTED
50F6
LD HL,4131HLD HL,FACLO+16
OTHERWISE ... let Register Pair HL equal 4131H to opint to the ASCII character.
Original Source Code Comment: POINT TO THE ASCII NUMBER

Top of Loop.

50F9EDITM1
LD A,(HL)
Fetch the ASCII character into Register A.
Original Source Code Comment: GET A CHARACTER
50FA
CP 20H
Compare the value held in Register A against 20H (ASCII: SPACE). If the characeter is NOT a SPACE ...
Original Source Code Comment: SPACE?
50FC
RET NZ
... we are done, so RETurn to the caller.
Original Source Code Comment: NO, DONE
50FD
LD (HL),30H
Store a 0 over the SPACE.
Original Source Code Comment: YES, SUBSTITUTE A ZERO
50FF
INC HL
INCrement the value stored in Register Pair HL by 1 to point to the next character.
Original Source Code Comment: BUMP TO NEXT CHAR
5100
Loop back 5 instructions to 50F9H.
Original Source Code Comment: LOOP TILL CONVERTED

End of Loop.

5102H - CROSS - "CROSS REFERENCE" Routine.

5102CROSS
Poll the line printer port.
Original Source Code Comment: GET THE PRINTER PORT
5104
AND 0E0H
MASK the value of Register A against E0H (1110 0000) to leave only bits 7, 6, 5 active. Bit 5: Device Select, Bit 6: Not Out of Paper, and Bit 7: Not Busy.
Original Source Code Comment: MASK ALL BUT HIGH BITS
5106
If any of bits 7, 6, and 5 are ON, skip the next instruction by JUMPing to 510BH.
Original Source Code Comment: YES, CONTINUE
5108
LD (51B4H),ALD (PRTAVL),A
If bits 7, 6, and 5 were all OFF then printer is not available, so store the value held in Register A into memory location 51B4H to indicate that.
Original Source Code Comment: SET THE 'NOT AVAILABLE' FLAG
510BCROSS1
LD HL,(4272H)LD HL,(BASIC1)
Fetch the TEXT POINTER (held in memory location 4272H) and store it into Register Pair HL.
Original Source Code Comment: GET THE TEXT POINTER
510E
RST 08H
2C
RST 08H is used to look for expected characters (in this case, a ,) in a string and then return with (HL) pointing to the next non-blank character.

It is a COMPARE SYMBOL routine which comparess the symbol in the input string pointed to by HL register to the value in the location following the RST 08 call.

If there is a match, control is returned to address of the RST 08 instruction 2 with the next symbol in the A register and HL incremented by one. If the two characters do not match, a syntax error message is given.
Original Source Code Comment: MUST HAVE A COMMA
5110
LD A,(HL)
Fetch the first byte (held in the memory location pointed to by Register Pair HL) and store it into Register A.
Original Source Code Comment: GET THE 1ST BYTE
5111
AND 80H
MASK the value of Register A against 80H (1000 0000), leaving only Bit 7 active to test for a reserved word.
Original Source Code Comment: RESERVED WORD?
5113
LD BC,0001H
Initialize Register Pair BC to 0001H in case we have only 1 character.
Original Source Code Comment: SET FOR 1 CHAR IN CASE
5116
If Register A is NOT a reseved word (Bit 7 was 0), then JUMP to 511FH.
Original Source Code Comment: NO, NOT RESERVED WORD
5118
INC HL
If we're here, then Register A is holding a reserved word, so bump past it by INCrementing the value stored in Register Pair HL by 1.
Original Source Code Comment: BUMP PAST RESERVED WORD
5119
LD (4272H),HLLD (BASIC1),HL
Store the current location (1 past a reserved word) into the TEXT POINTER.
Original Source Code Comment: SET TEXT POINTER
511C
DEC HL
Back up to before the reserved word held in Register A by DECrementing the value stored in Register Pair HL by 1.
Original Source Code Comment: BACK UP TO THE RESERVED WORD
511D
Do the cross reference by JUMPing to 5135H.
Original Source Code Comment: AND DO THE CROSS REFERENCE

511FH - CROSS2 - "CROSS REFERENCE" Routine. Jumped here if the character we just fetched into Register A was not a reserved word.

511FCROSS2
GOSUB to 2337H to evaluate the BASIC expression pointed to by HL and return with the result in REG 1.
Original Source Code Comment: EVULATE WHAT WE HAVE
5122
LD (4272H),HLLD (BASIC1),HL
Store the TEXT POINTER (held in Register Pair HL) into memory location 4272H.
Original Source Code Comment: STORE THE TEXT POINTER
5125
GOSUB to 29D7H to check to see if there is enough memory for the string.
Original Source Code Comment: FREE UP ANY TEMP STRING
5128
LD A,(HL)
Fetch the length of the string (held in the memory location pointed to by Register Pair HL) and store it into Register A.
Original Source Code Comment: GET THE LENGTH OF THE STRING
5129
OR A
Since a LD command does not set any FLAGS, Set FLAGS based on the contents of Register A.
Original Source Code Comment: NULL STRING?
512A
If Register A is 0, then we have a null string, which is bad, so exit with a "?FC ERROR" via a JUMP to 1E4AH.
Original Source Code Comment: YES, EXIT, ERROR
512D
512E
LD C,A
LD B,00H
Let Register Pair BC = A (i.e., the length of the string)
Original Source Code Comment: NO, SET THE LENGTH
5130
INC HL
INCrement the value stored in Register Pair HL by 1 to now point to the address of the string.
Original Source Code Comment: BUMP TO ADDRESS OF STRING
5131
LD E,(HL)
Fetch the LSB of the address of the string (held in the memory location pointed to by Register Pair HL) and store it into Register E.
Original Source Code Comment: PICK UP THE ADDRESS
5132
INC HL
INCrement the value stored in Register Pair HL by 1 to now point to the MSB of the address of the string.
5133
LD D,(HL)
Fetch the MSB of the address of the string (held in the memory location pointed to by Register Pair HL) and store it into Register D.
5134
EX DE,HL
EXchange the value stored in Register Pair HL with the value stored in Register Pair DE (the address of the string in RAM).
Original Source Code Comment: HL => STRING TO CROSS
5135DOCROS
LD (4ED5H),BCLD (NUMB0),BC
Store the length of the string (held in Register Pair BC) into memory location 4ED5H.
Original Source Code Comment: SAVE THE LENGTH
5139
LD (4EDBH),HLLD (LAB15),HL
Store the pointer to the search arguments (held in Register Pair HL) into memory location 4EDBH.
Original Source Code Comment: SAVE THE POINTER TO THE SEARCH ARG
513C
LD HL,(40A4H)LD HL,(TXTTAB)
Fetch the value held in memory location 40A4H and store it into Register Pair HL.
NOTE: 40A4H is the storage location for the BEGINNING OF THE BASIC PROGRAM IN RAM.
Original Source Code Comment: GET THE BEGIN OF THE PROGRAM
513F
LD (4EE1H),HLLD (VARPTR),HL
Store the address of the buffer pointer (held in Register Pair HL) into memory location 4EE1H.
Original Source Code Comment: INIT THE POINTER

Top of a loop.

5142DOCRO1
LD HL,(4EE1H)LD HL,(VARPTR)
Fetch the buffer pointer (held in memory location 4EE1H) and store it into Register Pair HL.
Original Source Code Comment: GET THE BUFFER POINTER
5145
LD A,(HL)
Fetch the address (at the memory location pointed to by Register Pair HL) and store it into Register A.
Original Source Code Comment: GET THE ADDRESS
5146
INC HL
INCrement the buffer pointer value stored in Register Pair HL by 1 to point to the byte after the one we just fetched into Register A.
5147
OR (HL)
Test to see if the next character is 00H by OR'ing Register A against the value of the next character in the program. If that next character was 00H then Register A will be unchanged, and the Z Flag will be set.
Original Source Code Comment: END OF PROGRAM?
5148
If the NZ FLAG (Not Zero) has been set then the next character was not a 00H, so we continue by JUMPing to 514FH.
Original Source Code Comment: NO, CONTINUE
514A
LD A,0DH
If we passed through to here, then we are at the end of the program. Let Register A equal CARRIAGE RETURN..
Original Source Code Comment: YES, OUTPUT FINAL CR
514C
Display the CARRIAGE RETURN and RETurn via a JUMP to 51B2H.
Original Source Code Comment: TO VIDEO AND RET

End of the loop.

514FH - DOCR00 - "CROSS REFERENCE" Routine. Continued here as we narrow down the validity of the character and End-of-Line status.

514FDOCR00
INC HL
INCrement the POINTER TO THE POSITION IN THE BASIC PROGRAM (held in Register Pair HL) so as to now point to the LINE NUMBER.
Original Source Code Comment: BUMP TO LINE NUMBER
5150
LD (4EDFH),HLLD (NUMB1),HL
Store the LINE NUMBER into memory location 4EDFH just in case we are going to need to track it.
Original Source Code Comment: SAVE IT IN CASE
5153
5154
INC HL
INC HL
Bump POINTER TO THE POSITION IN THE BASIC PROGRAM (held in Register Pair HL) by TWO to pass the line number and the SPACE.
Original Source Code Comment: BUMP PAST LINE NUMBER
5155DOCRO2
LD A,(HL)
Fetch the next character in the program (held in the memory location pointed to by Register Pair HL) and store it into Register A.
Original Source Code Comment: WE AT END OF LINE?
5156
OR A
Since a LD command does not set any FLAGS, Set FLAGS based on the contents of Register A.
5157
If it OR wasn't 00H then we are not at the end of the line, and need to keep processing, so JUMP to 515FH.
Original Source Code Comment: NO, CONTINUE
5159
INC HL
If we didn't jump away, we are at the end of a line. INCrement the value stored in Register Pair HL by 1 to move to the beginning of the next line.
Original Source Code Comment: BUMP TO START OF NEXT LINE
515A
LD (4EE1H),HLLD (VARPTR),HL
Store the POINTER TO THE POSITION IN THE BASIC PROGRAM (held in Register Pair HL) into memory location 4EE1H.
515D
JUMP to 5142H.
Original Source Code Comment: AND LOOP THROUGH PROGRAM

515FH - DOCRO3 - "CROSS REFERENCE" Routine. Continued here as we narrow down the validity of the character and End-of-Line status.

515FDOCRO3
LD DE,(4EDBH)LD DE,(LAB15)
Fetch the pointer to the SEARCH ARGUMENT (held in memory location 4EDBH) and store it into Register Pair DE.
Original Source Code Comment: GET THE POINTER TO THE SEARCH ARG
5163
LD BC,(4ED5H)LD BC,(NUMB0)
Fetch the length (held in memory location 4ED5H) and store it into Register Pair BC.
Original Source Code Comment: GET IT'S LENGTH
5167
Compare them via a GOSUB to 51C1H.
Original Source Code Comment: DO THE COMPARE
516A
If the Z FLAG (Zero) has been set, then they match. JUMP to 516FH to display them.
Original Source Code Comment: DISPLAY LINE IF MATCH
516C
INC HL
If we passed through then there was no match, so move onto the next character in the program by INCrementing the value stored in Register Pair HL by 1.
Original Source Code Comment: NO, BUMP TO NEXT CHAR
516D
Loop back to continue via a JUMP to 5155H.
Original Source Code Comment: LOOP THROUGH LINE

516FH - DISPLY - "CROSS REFERENCE" Routine DISPLAY routine. Starts by moving to the end of the program line.

516FDISPLY
LD A,(HL)
Fetch a byte from the program held in the memory location pointed to by Register Pair HL and store it into Register A.
Original Source Code Comment: MOVE TO THE END OF THIS LINE
5170
OR A
Since a LD command does not set any FLAGS, Set FLAGS based on the contents of Register A (and, in all events, clear the CARRY FLAG).
Original Source Code Comment: END OF LINE?
5171
If the Z FLAG (Zero) has been set then we have reached the end of a program line, so JUMP to 5176H.
Original Source Code Comment: YES, SET FOR NEXT LINE
5173
INC HL
If not, move to the next byte of the program by 1 by INCrementing the value stored in Register Pair HL (POINTER TO THE POSITION IN THE BASIC PROGRAM) by 1.
Original Source Code Comment: NO, CONTINUE THROUGH LINE
5174
Loop back to the top of this routine to keep processing characters by JUMPing to 516FH.

5176H - DISPL1 - "CROSS REFERENCE" Routine DISPLAY routine. Continues once we are at the end of a program line.

5176DISPL1
INC HL
Since we entered this routine with HL at the end of the line, bump it by 1 to move to point to the next line in the program.
Original Source Code Comment: BUMP TO START OF NEXT LINE
5177
LD (4EE1H),HLLD (VARPTR),HL
HL now points to a line number. Store the POINTER TO THE POSITION IN THE BASIC PROGRAM (held in Register Pair HL) into memory location 4EE1H.
Original Source Code Comment: SAVE THE POINTER
517A
LD HL,(4EDFH)LD HL,(NUMB1)
Fetch the line number (held in memory location 4EDFH) and store it into Register Pair HL.
Original Source Code Comment: GET THE LINE NUMBER
517D
LD E,(HL)
Fetch the LSB of the line number pointer (held in the memory location pointed) to by Register Pair HL and store it into Register E.
Original Source Code Comment: GET THE LINE NUMBER POINTER
517E
INC HL
INCrement the value stored in Register Pair HL by 1.
517F
LD D,(HL)
Fetch the MSB of the line number pointer (held in the memory location pointed) to by Register Pair HL and store it into Register D.
5180
EX DE,HL
EXchange the value stored in Register Pair HL (i.e., the MSB of the line number) with the value stored in Register Pair DE (i.e., the line number pointer).
Original Source Code Comment: INTO HL
5181
Convert it to ASCII via a GOSUB to 50E7H.
Original Source Code Comment: CONVERT IT TO ASCII
5184
INC HL
Move past the SPACE after the line number by INCrementing the value stored in Register Pair HL by 1.
Original Source Code Comment: BUMP PAST LEADING SPACE
5185
LD B,05H
Since a line number is up to 5 characters, let Register B equal 05H for a DJNZ loop.
Original Source Code Comment: LENGTH OF THE LINE NUMBER

Start of a DJNZ loop of 5.

5187DISPL2
LD A,(HL)
Fetch a digit from the line number (held in the memory location pointed to by Register Pair HL) and store it into Register A.
Original Source Code Comment: GET A DIGIT
5188
OR A
Since a LD command does not set any FLAGS, Set FLAGS based on the contents of Register A (and, in all events, clear the CARRY FLAG).
Original Source Code Comment: END OF DIGITS?
5189
Was the digit in the line number a 00H (end of line number?). If so, the Z FLAG (Zero) has been set and we JUMP out of the loop to 5191H.
Original Source Code Comment: YES, EXIT
518B
If the line number digit was not a 00H, then output the byte held in Register A to the screen (and if requested, the printer) via a GOSUB to 51B2H.
Original Source Code Comment: DISPLAY IT
518E
INC HL
INCrement the value stored in Register Pair HL by 1 to point to the next character in the line number.
Original Source Code Comment: BUMP TO NEXT CHAR
518F
LOOP back to 5187H, reducing Register B each time, and continue to LOOP until Register B has been reduced to ZERO, in which case, continue with the next instruction.
Original Source Code Comment: LOOP FOR ALL DIGITS

End of the DJNZ loop.

5191DISP22
LD A,(4020H)LD A,(CURSOR)
Fetch the value held in memory location 4020H and store it into Register A.
NOTE: 4020H is the storage location for the CURSOR POSITION ON SCREEN.
Original Source Code Comment: GET THE CURSOR POSITION
5194
AND 3FH
MASK the value of Register A against 3FH (0011 1111) which, when applied to a location on the screen, isolates the COLUMN.
Original Source Code Comment: MASK FOR ONE ROW ONLY
5196
CP 3AH
Compare the value held in Register A against 3AH (Decimal: 58) to see if we need to display a CARRIAGE RETURN). If A < 58, the CARRY FLAG will be set and we have room to display another set of information. If A >= 58, the NO CARRY FLAG will be set and we don't have room.
Original Source Code Comment: SEE IF WE NEED A CR
5198
If the C FLAG (Carry) has been set, then we have room ...JUMP to 51A2H.
Original Source Code Comment: NO, OUTPUT TAB
519A
LD A,0DH
Let Register A equal CARRIAGE RETURN.
Original Source Code Comment: YES, OUTPUT NEW LINE
519C
Output the CARRIAGE RETURN held in Register A to the screen (and if requested, the printer) via a GOSUB to 51B2H.
519F
JUMP to 5142H to process the next line of the program.
Original Source Code Comment: DO NEXT LINE

51A2H - DISPL3 - "CROSS REFERENCE" Routine DISPLAY routine. Move to a tab column.

51A2DISPL3
NEG
Negate the contents of Register A (which is the same as -A).
Original Source Code Comment: FLIP IT UPSIDE DOWN
51A4
AND 07H
MASK the value of Register A against 07H (0000 0111) to get a number which is no greater than 7 (because TAB columns are 8 characters).
Original Source Code Comment: MASK FOR COLUMN OF 8
51A6
INC A
We NEVER want a 0 value, so INCrement the value stored in Register A by 1.
Original Source Code Comment: NO 0'S ALLOWED
51A7
LD B,A
Copy the contents of Register A into Register B for a DJNZ loop.
Original Source Code Comment: INTO B FOR COUNTER

Start of a DJNZ loop of up to 8 spaces.

51A8DISPL4
LD A,20H
Let Register A equal 20H (ASCII: SPACE).
Original Source Code Comment: OUTPUT A SPACE CHAR
51AA
Output the SPACE held in Register A to the screen (and if requested, the printer) via a GOSUB to 51B2H.
Original Source Code Comment: TO VIDEO AND PRINTER
51AD
LOOP back to 51A8H, reducing Register B each time, and continue to LOOP until Register B has been reduced to ZERO, in which case, continue with the next instruction.
Original Source Code Comment: LOOP FOR COUNT

End of the DJNZ loop.

51AF
JUMP to 5142H to process the next line of the program.
Original Source Code Comment: AND CONTINUE WITH NEXT LINE

51B2H - DISOUT - "CROSS REFERENCE" Routine DISPLAY routine. Subroutine to output the byte held in Register A to the screen (and if requested, the printer).

51B2DISOUT
LD C,A
Copy the byte to display (held in Register A) into Register C.
Original Source Code Comment: SAVE THE CHARACTER
51B3
LD A,00HLD A,0
Let Register A equal the value eplaced into 51B4H (PRTAVL) elsewhere in this Overlay. This is the Printer AVAILABLE/NOT AVAILABLE status flag.
Original Source Code Comment: PRINTER FLAG STORED HERE
51B5
OR A
Since a LD command does not set any FLAGS, Set FLAGS based on the contents of Register A (and, in all events, clear the CARRY FLAG).
Original Source Code Comment: PRINTER AVAILABLE?
51B6
LD A,C
Copy the byte to display (held in Register C) into Register A.
Original Source Code Comment: GET THE CHAR BACK
51B7
If the Z FLAG (Zero) has been set then the printer is NOT available, so skip over the next 3 instructions (which print) and JUMP to 51BEH.
Original Source Code Comment: NO, CONTINUE
51B9
PUSH AF
Save the byte to print (held in Register Pair AF) to the top of the stack.
Original Source Code Comment: SAVE THE CHARACTER
51BA
GOSUB to 003BH.
NOTE: 003BH is the Model III ROM routine to write the byte held in Register A to the printer, including waiting for the printer to be available OR getting a BREAK. Uses Register Pair DE.
Original Source Code Comment: OUTPUT THE CHAR
51BD
POP AF
Restore the byte to print (held at the top of the stack) back into Register A, and then remove the entry from the stack.
Original Source Code Comment: GET THE CHAR BACK
51BEDISOU1
JUMP to 0033H.
NOTE: 0033H is the Model III ROM character print routine; displays the character held in Register A at the current cursor position. Since this was JUMPED to instead of CALLed, the RET at the end of this ROM routine will then RETurn to the caller of this subroutine instead of returning to this place.
Original Source Code Comment: DISPLAY AND RETURN

51C1H - COPARE - "CROSS REFERENCE" Routine Subroutine to compare the contents of DE and HL.

51C1COPARE
PUSH BC
Save the contents of Register Pair BC to the top of the stack.
Original Source Code Comment: SAVE REGISTERS
51C2
PUSH DE
Save the contents of Register Pair DE to the top of the stack.
51C3
PUSH HL
Save the contents of Register Pair HL to the top of the stack.

Top of a loop.

51C4STRCM1
LD A,(DE)
Fetch a byte from DE store it into Register A.
Original Source Code Comment: GET A BYTE
51C5
CP (HL)
Compare the DE byte with the HL byte. If they are different ...
Original Source Code Comment: MATCH?
51C6
... EXIT by JUMPing to 51CEH to restore the stack and RETurn.
Original Source Code Comment: NO, EXIT
51C8
LDI
If they are the same, then move to the 2nd character of both HL and DE via LDI command; which copies BC number of characters from (HL) to (DE), dropping BC each time. When BC hits 0, the PE flag is reset.
Original Source Code Comment: YES, BUMP POINTERS
51CA
If the PARITY/OVERFLOW FLAG has been SET then we have more characters to process, so LOOP BACK to 51C4H.
Original Source Code Comment: AND LOOK AT NEXT ONE

End of the loop.

51CD
XOR A
Set Register A to ZERO and clear all Flags to signal a match (success!).
Original Source Code Comment: SET 'Z'
51CESTRCM2
POP HL
Put the value held at the top of the STACK into Register Pair HL, and then remove the entry from the stack.
Original Source Code Comment: RESTORE REGISTERS
51CF
POP DE
Put the value held at the top of the STACK into Register Pair DE, and then remove the entry from the stack.
51D0
POP BC
Put the value held at the top of the STACK into Register Pair BC, and then remove the entry from the stack.
51D1
RET
RETurn to the caller.
 
END 4E00H
That's it!