Model I ROM Explained – Part 3

Page Customization:

Display OPCodes
Display Labels




2003 – UE ERROR entry point – “GOERR”

2003-2004
 ↳ GOERR
LD E,26HLD E,ERRUE1E 26
Load Register E with the ERROR code for a ?UE ERROR
2005-2007
Go to the Level II BASIC error routine and display the appropriate error message

2008-2038 – LEVEL II BASIC AUTO ROUTINE – “AUTO”

According to the original ROM source code, the AUTO [beginning line,[increment]] command is used to automatically generate line number for lines to be inserted. The beginning line is used to specify the initial line (and if omitted, defaults to 10) and the increment is used to specify the increment used to generate the next line number. If only a comma is used after the beginning line, the old increment is used.

On entry, Z will be set if there was nothing following the command.
2008-200A
 ↳ AUTO
LD DE,000AH11 0A 00
Load DE with a default starting line number of ten
200B
PUSH DED5
Save the default STACK line number in DE to the STACK
200C-200D
Jump down to 2025H if this is the end of the AUTO statement (meaning that no parameters were provided). This will default to AUTO 10,10
200E-2010
If we are here, then there were parameters after the AUTO statement so we need to GOSUB to 1E4FH to evaluate the line number at the current location of the BASIC program pointer in HL and return with the result in DE. The Z flag will be set if that was the end of the command
2011
EX DE,HLEB
Since there is no such Z-80 command as EX (SP),DE we now need to do some swapping to get DE into (SP). First, exchange the value of the line number in DE with the value of the current BASIC program pointer in HL
2012
EX (SP),HLE3
Next, exchange the default line number (to the STACK from the above push of DE) with the line number that the user provided (in HL)
At this point, DE points to the current character in the BASIC line being processed, “10” is in HL, and the initial number is on the STACK.
2013-2014
Jump down to 2026H if this is the end of the AUTO statement (meaning that only 1 parameter was provided). This will default to 10
2015
EX DE,HLEB
Load HL with the value of the current BASIC program pointer in DE
2016-2017
If we are here, then we have an AUTO command with one parameter (starting line number) and we have not finished with the command. Since the only valid addition to that would be a trailing ,, we need to test the current BASIC program pointer in HL for a COMMA (=2CH), by calling the COMPARE SYMBOL at RST 08H.

NOTE: The RST 08H routine compares 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 the next execution address (i.e, the RST 08H 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 and control returns to the Input Phase).
2018
EX DE,HLEB
If we are here, then it matched (a ?SN ERROR would have occurred otherwise) so load DE with the value of the current BASIC program pointer in HL
2019-201B
LD HL,(40E4H)LD HL,(AUTINC)2A E4 40
Load HL with the last provided AUTO increment value.
Note: 40E4H-40E5H holds AUTO increment
201C
EX DE,HLEB
Exchange the value of the current BASIC program pointer in DE with the last AUTO increment value in HL
201D-201E
Jump to 2025H if this is the end of the BASIC statement (meaning, we got AUTO nn, but no further parameter). This will then use the last provided increment
201F-2021
If we are here, there was a second parameter so we GOSUB to 1E5AH to get the second parameter as the routine at 1E5A converts the ASCII string pointed to by HL to an integer deposited into DE. If the routine finds a non-numerica character, the conversion is stopped
2022-2024
If that prior GOSUB found a non-numeric character it aborted with a NZ, so if there is a NZ, jump to 1997H to show a ?SN ERROR
2025
 ↳ SNGAUT
EX DE,HLEB
Exchange the AUTO increment number in DE with the value of the current BASIC program pointer in HL. HL should now hold the AUTO increment
2026
 ↳ SNGAU1
LD A,H7C
Prepare to test to see if it is zero. First, load Register A with the MSB of the AUTO increment number in Register H. (This is step 1 of a test to see if HL is zero)
2027
OR LB5
Combine the LSB of the AUTO increment number in Register L with the MSB of the AUTO increment number in Register A. (This is step 2 of a test to see if HL is zero)
2028-202A
That all tested the value of HL to see if it was zero. If it was, jupm to 1E4AH to show a ?FC ERROR message
202B-202D
LD (40E4H),HLLD (AUTINC),HL22 E4 40
Save the value of the AUTO increment number in HL.
Note: 40E4H-40E5H holds AUTO increment
202E-2030
LD (40E1H),ALD (AUTFLG),A32 E1 40
Set the AUTO flag to non-zero. We know A is non-zero because we would have jumped 2 instruction ago if it was
2031
POP HLE1
Get the starting line number from the STACK and put it in HL
2032-2034
LD (40E2H),HLLD (AUTLIN),HL22 E2 40
Save the line number in HL as the next AUTO line number.
Note: 40E2H-40E3H holds Current BASIC line number
2035
POP BCC1
Clean up the return address of NEWSTT from the STACK
2036-2038
Jump to the Level II BASIC command mode

2039-2066 – LEVEL II BASIC IF ROUTINE – “IF”

2039-203B
 ↳ IF
GOSUB to 2337H to evaluate the BASIC expression pointed to by HL and return with the result in ACCumulator
203C
LD A,(HL)7E
Load Register A with the character at the location of the current BASIC program pointer in HL
203D-203E
CP 2CHFE 2C
Check to see if the character at the location of the current BASIC program pointer in Register A is a ,. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
203F-2041
If the character at the location of the current BASIC program pointer in Register A is a , then go bump the value of the current BASIC program pointer in HL until it points to the next character
2042-2043
CP 0CAHFE CA
Check to see if the character at the location of the current BASIC program pointer in Register A is a THEN token
. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
2044-2046
If Z flag is set, the character at the location of the current BASIC program pointer in Register A is a THEN token, so we need to bump the value of the current BASIC program pointer until it points to the next character
2047
DEC HL2B
Decrement the value of the current BASIC program pointer in HL so that we are still positioned at the THEN token
2048
 ↳ OKGOTO
PUSH HLE5
Save the value of the current BASIC program pointer to the STACK
2049-204B
GOSUB to 0994H to see if the expression after the IF token was true or false
204C
POP HLE1
Restore the address of the current position in the current statement (from the STACK) into HL
204D-204E
Jump down to 2056H if the expression was false
204F
 ↳ DOCOND
We need the next character in the BASIC program so call the EXAMINE NEXT SYMBOL routine at RST 10H.

The RST 10H routine parses the characters starting at HL+1 for the first non-SPACE,non-09H,non-0BH character it finds. On exit, Register A will hold that character, and the C FLAG is set if its alphabetic, and NC FLAG if its alphanumeric. All strings must have a 00H at the end.
2050-2052
Jump to the GOTO routine if the character at the location of the current BASIC program pointer in HL is numeric
2053-2055
Jump to the execution driver at 1D5FH to evaluate the rest of the statement string

2056H – LEVEL II BASIC ELSE ROUTINE – “FALSIF”

2056-2057
 ↳ FALSIF
LD D,01H16 01
Load Register D with the scan counter as we will need to count the number of ELSEs. The “DATA” routine increments this counter ever time it finds an IF statement
2058-205A
 ↳ SKPMRF
Go scan the BASIC statement to skip a statement. A “:” is placed in front of each ELSE so that the DATA routine will stop before an ELSE clause
205B
OR AB7
Since a LD command does not affect the flags, OR A is commonly used to set the flags based on A. This is to check to see if this is the end of the BASIC line
205C
RET ZC8
If this is the end of the BASIC statement then there isn’t going to be an ELSE, so RETurn to CALLer
205D
We need the next character in the BASIC program so call the EXAMINE NEXT SYMBOL routine at RST 10H.

The RST 10H routine parses the characters starting at HL+1 for the first non-SPACE,non-09H,non-0BH character it finds. On exit, Register A will hold that character, and the C FLAG is set if its alphabetic, and NC FLAG if its alphanumeric. All strings must have a 00H at the end.
205E-205F
CP 95HCP $ELSEFE 95
Check to see if the character at the location of the current BASIC program pointer in Register A is an ELSE token. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
2060-2061
If this wasn’t an ELSE then we are still in the THEN clause, so loop back to 2058H until an ELSE token is found
2062
DEC D15
Decrement the number of ELSE statements that have been found
2063-2064
If that DEC didn’t hit ZERO, then we haven’t found them all, so loop back to 2058H until all of the ELSE tokens have been found
2065-2066
If we are here, then we have found the right ELSE statement! Jump to 204FH to evaluate the rest of the expression

2067-206E – LEVEL II BASIC LPRINT ROUTINE – FOR v1.0 ONLY– “LPRINT”

2067-2068
 ↳ LPRINT
LD A,01H3E 01
Load Register A with the output device code for the printer
2069-206B
LD (409CH),ALD (PRTFLG),A32 9C 40
Save the value in Register A as the current output device type number (-1=cassette, 0=video; or 1=printer)
206C-206E
Jump to 209BH to analyze the rest of the statement

206F-2177 – LEVEL II BASIC PRINT@ ROUTINE – FOR v1.0 ONLY – “PRINT”

206F-2071
 ↳ PRINT
CALL 41CAHCALL FILGETCD CA 41
Do a DOS Vector call in case this is to go to a disk file
2072-2073
CP 40HFE 40
Check the character at the location of the current BASIC program pointer in Register A to see if it’s an @. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
2074-2075
Jump to 208FH if the character at the location of the current BASIC program pointer in Register A isn’t an @
2076-2078
GOSUB to 2B01H to evaluate the PRINT@ expression (which is at the location of the current BASIC program pointer in HL and return with the result in DE)
2079-207A
CP 04FE 04
Check to see if the location in DE is greater than 1023H. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
207B-207D
If that check resulted in no CARRY flag, jump to 1E4AH to show a ?FC error
207E
PUSH HLE5
Push the current code string address (held in HL) to the STACK
207F-2081
LD HL,3C00H21 00 3C
Load HL with the start of the display area
2082
ADD HL,DE19
Add DE to HL so that HL now will be the start of the diplay area PLUS the PRINT@ offset position
2083-2085
LD (4020H),HLLD (CURSOR),HL22 20 40
Store the cursor position of the screen address matching the PRINT@ position into the display DCB held in memory location 4020H (which holds the video memory address of the current cursor position)
2086
LD A,E7B
E is the current position within the line
2087-2088
AND 3FHE6 3F
Make it not exceed 63 and then save it
2089
LD (40A6H),ALD (TTYPOS),A32 A6 40
. into the current cursor offset (which is held in 40A6H)
208C
POP HLE1
Restore the code string address to HL
208D
RST 08H ⇒ 2CCF 2C
At this point we have a PRINT@nnnn so the only valid next character is a , so we need to call RST 08H to check against 2C, the code for comma.

NOTE: The RST 08H routine compares 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 the next execution address (i.e, the RST 08H 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 and control returns to the Input Phase).
208F
 ↳ PNOTAT
CP 23HFE 23
We also need to look for a # character. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
2091
If it is not a # character (meaning this is not a PRINT#, jump to 209BH
2093
If we are here, we had a PRINT# so GOSUB to 0284H to analyze the rest of the string
2096
LD A,80H3E 80
Set A to 80H (the write to cassette flag)
2098
LD (409CH),ALD (PRTFLG),A32 9C 40
Load the cassette flag at (409CH) with 80H
209B
 ↳ NEWCHR
DEC HL2B
Backspace over the previous symbol in the input stream
209C
Re-analyze the next character in the input stream
209D
If that test resulted in a zero, GOSUB to 20FEH to print a carriage return/end of statement and then flush the line to the device
20A0
 ↳ PRINTC
Jump to 2169H to write the sync bytes and clear output
20A3
CP 0BFHCP USINTKFE BF
Check to see if we have a USING token. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
20A5
. if so, go to the PRINUS handler routine to continue processing
20A8
CP BCHCP TABTKFE BC
Test for a TAB token. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
20AA
and if it is a TAB token (meaning the command is PRINT TAB, jump down to 2137H
20AD
PUSH HLE5
Continuing on a PRINT#, save the current position in the BASIC program being processed to the top of the STACK
20AE
CP 2CHFE 2C
Test for a ,. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
20B0
If there is a comma, jump down to 2108H to get the next item
20B3
CP 3BHFE 3B
Since its not a comma, next we need to check for a ;. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
20B5
If it is a ;, jump down to 2164H to process
20B8
POP BCC1
It wasn’t a , or a ; so we just discard the old pointer to the BASIC line bring processed
20B9
Get the address or value of the next item to be printed by calling the formula evaluator at 2337H
20BC
PUSH HLE5
Save the location on the BASIC line being processed to the top of the STACK
20BD
Check its data type with a call to RST 20H.
NOTE: The RST 20H routine determines the type of the current value in ACCumulator and returns a combination of STATUS flags and unique numeric values in the A Register according to the data mode flag (40AFH). The results are returned as follows:
  • Integer = NZ/C/M/E and A is -1
  • String = Z/C/P/E and A is 0
  • Single Precision = NZ/C/P/O and A is 1
  • and Double Precision is NZ/NC/P/E and A is 5.
20BE
If it is a string, jump down to 20F2H to handle that case
20C0
GOSUB to the routine at 0FBDH to convert the number to an ASCII string and move to the print buffer
20C3
GOSUB to the routine at 2865H to build a literal string pool entry for the ASCII number
20C6
CALL 41CDHCALL EXDSKLCD CD 41
GOSUB to DOS to see if DOS wants to do anything here
20C9
LD HL,(4121H)LD HL,(FACLO)2A 21 41
Put the address of the pointer to the current print string into HL
20CC
LD A,(409CH)LD A,(PRTFLG)3A 9C 40
Get the output device type flag and put it into A.
  • Note: 409CH holds the current output device type number (-1=cassette, 0=video; or 1=printer)
20CF
OR AB7
Since a LD command does not affect the flags, OR A is commonly used to set the flags based on A. This is to test the output device type flag
20D0
If we writing to a cassette (i.e., PRINT#) jump to 20E9H
20D3
If, instead, we do NOT have a LPRINT, jump down to 20DDH
20D5-20D7
LD A,(409BH)LD A,(LPTPOS)3A 9B 40
If we are here, we have a LPRINT so load A with the current carriage position.
Note: 409BH holds the printer carriage position
20D8
 ↳ LPTCD2
ADD A,(HL)86
Add the length of the string to be sent to the printer at the location of the memory pointer in HL to the current carriage position in Register A
20D9-20DA
CP 84HCP LPTLENFE 84
Check to see if the adjusted length in Register A is greater than 132. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
20DB-20DC
Jump forward to 20E6H

20DDH – LEVEL II BASIC PRINT@ ROUTINE – Jumped here if we are sure we are using the display – “ISTTY”

20DD-20DF
 ↳ ISTTY
LD A,(409DH)LD A,(LINLEN)3A 9D 40
Load Register A with the video line size.
Note: 409DH holds the size of line on the video display
20E0
LD B,A47
Load Register B with the video line size in Register A
20E1-20E3
LD A,(40A6H)LD A,(TTYPOS)3A A6 40
Load Register A with the current video line position.
Note: 40A6H holds the current cursor line position
20E4
ADD A,(HL)86
Add the length of the string to be sent to the video display at the location of the memory pointer in HL to the value of the current video line position in Register A
20E5
 ↳ LINPT3
CP BB8
Check to see if the length in Register A is greater than the video line length. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
20E6-20E8
 ↳ LINCHK
If NC is set, the new line will overflow the buffer so send a carriage return to the current output device
20E9-20EB
 ↳ LINCH2
Go send the string to the current output device
20EC-20ED
LD A,20H3E 20
Load Register A with a SPACE
20EE-20F0
Go send the space in Register A to the current output device
20F1
OR AB7
Since a LD command does not affect the flags, OR A is commonly used to set the flags based on A. This is to check to see if Register A is equal to zero
20F2-20F4
 ↳ STRDON
If necessary go send the string to the current output device
20F5
POP HLE1
Restore the current code string to HL
20F6-20F8
For ROM v1.0 – Loop to 209BH until an end of statement code is found. Going to 209BH parses only for PRINT TAB or PRINT #, but not PRINT @, so it was not possible, under ROM v1.0, to have a PRINT@ appear later in a PRINT command than a PRINT TAB or PRINT #
*20F6-20F8
For ROM v1.2 – Loop to 207CH until an end of statement code is found. Going all the way back to 207CH will also test for a PRINT @, thus permitting a PRINT @ to appear other than first
20F9-20FB
 ↳ CRDONZ
LD A,(40A6H)LD A,(TTYPOS)3A A6 40
Load Register A with the number of characters printed on the current line.
Note: 40A6H holds the current cursor line position
20FC
OR AB7
Since a LD command does not affect the flags, OR A is commonly used to set the flags based on A. This is to check to see if any characters have been printed on the current line
20FD
RET ZC8
Return out of this routine if we are at the start of a line

20FE – This routine outputs a carriage return (0DH) to a device determined by flag stored at (409CH) – “CRDO”

NOTE: This routine may be CALLed at 20F9H, in which case it will not perform the above action if the video display cursor is already positioned at the beginning of a line, as determined by checking the contents of the cursor position flag at 40A6H (if zero, cursor is at start of line). This routine CALLs the routine at 032AH and also CALLs a Disk BASIC link at 41D0H.
20FE-20FF
 ↳ CRDO
LD A,0DH3E 0D
Otherwise, we need to skip to the next line so load Register A with a carriage return
2100-2102
Go send the carriage return in Register A to the current output device
2103-2105
 ↳ CRFIN
CALL 41D0HCALL EXDSCRCD D0 41
GOSUB to the DOS routine at 41D0H to deal with screen wrap
2106
XOR AAF
Zero Register A and the carry flags
2107
RETC9
Return back to the calling routine

2108 – This is the jump point for a continuation of the PRINT# code – “COMPRT”.

2108-210A
 ↳ COMPRT
CALL 41D3HCALL EXPDOSCD D3 41
Jump to DOS to see if DOS wants to modify the behavior
210B-210D
LD A,(409CH)LD A,(PRTFLG)3A 9C 40
Load Register A with the value of the current output device flag.
  • Note: 409CH holds the current output device type number (-1=cassette, 0=video; or 1=printer)
210E
OR AB7
Test the value of the current output device flag in Register A.
  • M will be set if the value in A is negative.
  • P will be set if the value in A is positive or zero.
210F-2111
Jump down a few instructions to 2119H if the printer or the video display is the current output device
2112-2113
LD A,2CH3E 2C
So now that we know the current device is cassette, we will load Register A with a ,
2114-2116
Send the , in Register A to current output device. In this case, it is the cassette recorder because we otherwise would have jumped away at 210FH
2117-2118
Jump forward to 2164H to fetch the next character from the code string
2119-211A
 ↳ NTCAS
We landed here from 210FH knowing that the current output device flag was either video or printer. Now we need to break that down too, so if the device flag is the video display, jump down to 2123H
211B-211D
 ↳ LPTCD3
LD A,(409BH)LD A,(LPTPOS)3A 9B 40
We’re here because the output device is a printer. First, load Register A with the current carriage position.
Note: 409BH holds the printer carriage position
211E-211F
 ↳ NLPPOS
CP 70HCP NLPPOSFE 70
Check to see if the current carriage position in Register A is greater than 112. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
2120-2122
Jump forward a few instructions to 212BH
2123-2125
 ↳ ISCTTY
LD A,(409EH)LD A,(CLMLST)3A 9E 40
We were jumped to this point because the output device is the video display. So load Register A with the video line length.
Note: 409EH holds the size of line on the printer
2126
LD B,A47
Load Register B with the video line length in Register A
2127-2129
LD A,(40A6H)LD A,(TTYPOS)3A A6 40
Load Register A with the current video line position.
Note: 40A6H holds the current cursor line position
212A
 ↳ NCMPOS
CP BB8
Test to see if there is room on this line by checking to see if the current video line position in Register A is equal to the video line length in Register B. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
212B-212D
 ↳ CHKCOM
If the NC is set, there is no room on the current line, so we need to GOSUB to 20FEH to print a carriage return on the current output device
212E-212F
If we are beyond the last comma field, quit via a JUMP to 2164H
2130-2131
 ↳ MORCOM
SUB 10HSUB CLMWIDD6 10
Calculate A MOD CLDMWID to see if there are at least 16 spaces left on the current line for the current output device
2132-2133
Loop back until there are at least 16 spaces left on the current line
2134
CPL2F
Figure the number of spaces to be sent to the current output device so that we have an even CLMWID
2135-2136
Jump to 215AH to print Register A + 1 number of spaces/blanks

2137 – TAB logic – “TABER”

This routine is the TAB function for video or printer (determined by flag at 409CH). On entry: E Register contains desired TAB position, HL points to start of message to be displayed (or zero byte if no message). This routine does extensive string processing and may not be the most efficient method of achieving the desired result, particularly if it is desired only to tab over a number of spaces. Also, this routine CALLs several Disk BASIC links which may have to be “plugged”. 2169 – Reset device type flag at 409CH to zero (output to video display), also turns off cassette drive if necessary. CALLs Disk BASIC link at 41BEH prior to return.
2137-2139
 ↳ TABER
GOSUB forward to 2B1BH to evaluate the tab number at the location of the current BASIC program pointer in HL and return with the result in Register A
213A-213B
AND 3FHE6 3F
The results are in A so mask the tab number in Register A so that it doesn’t exceed 63
213C
LD E,A5F
Load Register E with the value of the tab number from Register A
213D-213E
RST 08H ⇒ 29SNCHK “)”CF 29
At this point, we have a TAB(nn, so the next character needs to be a ). Since the character at the location of the current BASIC program pointer in HL must be a “)”, call the COMPARE SYMBOL at RST 08H.

NOTE: The RST 08H routine compares 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 the next execution address (i.e, the RST 08H 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 and control returns to the Input Phase).
213F
DEC HL2B
Decrement the value of the current BASIC program pointer in HL so that it points to the (
  • NOTE 1: The cursor position cannot be moved backward by this procedure. If n is not greater than the current cursor position on the line, no change will occur.
  • NOTE 2: To locate the cursor at a given position on the screen (the function of the PRINT@ command in BASIC), the simplest procedure is to modify the cursor position bytes, which are located at 4020H-4021H. The address contained in these memory cells is that of the position in video memory (3C00H-3FFFH) at which the (abstract) cursor resides. This cursor position controls subsequent printing via the subroutine at 28A7H
  • DISK SYSTEM CAUTION: The subroutine at 213FH has three exits to DISK BASIC, with RAM transfer points at 41BEH, 41C1H, and 41D3H. To use this routine safely, either be certain that DISK BASIC is in place, or have your assembly language program fill locations 41BEH, 41C1H, and 41D3H with RET’s (C9H), before calling the routine.
2140
PUSH HLE5
Save the value of the current BASIC program pointer in HL to the STACK
2141
CALL 41D3HCALL EXPDOSCD D3 41
Jump to DOS to see if DOS wants to modify the behavior
2144-2146
LD A,(409CH)LD A,(PRTFLG)3A 9C 40
Load Register A with the value of the current output device flag.
  • Note: 409CH holds the current output device type number (-1=cassette, 0=video; or 1=printer)
2147
OR AB7
Test the value of the current output device flag in Register A. A NZ means line printer
2148-214A
Since you cannot send a tab to the cassette, display a ?FC ERROR message if the current output device is the cassette recorder
214B-214D
Jump forward a few instructions to 2153H if the current output device is the video display
214E-2150
LD A,(409BH)LD A,(LPTPOS)3A 9B 40
Since we have already jumped away if the current output device is to cassette or screen, if we are here we know that this is to go to the printer, so load Register A with the current carriage position.
Note: 409BH holds the printer carriage position
2151-2152
Jump over the next instruction (which is a video instruction)


2153H – Displaying to Screen – “TTYIST”
2153-2155
 ↳ TTYIST
LD A,(40A6H)LD A,(TTYPOS)3A A6 40
Load Register A with the current video line position.
Note: 40A6H holds the current cursor line position
2156
 ↳ DOSIZT
CPL2F
When we land here, A holds either the current carriage position (printer) or the current line position (video). Regardless, complement (make negative) that value in preparation to determine how many spaces to print (which would be Register E – Register A)
2157
ADD A,E83
Add the tab number in Register B to the adjusted line position in Register A so that A=-current position + tab
2158-2159
If we we have a negative number of spaces to print, then we aren’t going to print any, so jump forward a few instructions to 2164H to skip over the actual TAB effectuation routine
215A
 ↳ ASPA2
INC A3C
Bump the number of spaces to be printed in Register A
215B
 ↳ ASPAC
LD B,A47
Load Register B with the number of spaces to be printed in Register A
215C-215D
LD A,20H3E 20
Load Register A with a SPACE
215E-2160
 ↳ REPOUT
Send the space in Register A to the current output device
2161
DEC B05
Decrement the number of SPACE‘s to be displayed (counter in Register B)
2162-2163
Loop back to 215EH until all of the spaces have been displayed/printed
2164
 ↳ NOTABR
POP HLE1
Restore the position in of the current BASIC program pointer (from the STACK) into HL
2165
We need the next character in the BASIC program so call the EXAMINE NEXT SYMBOL routine at RST 10H.

The RST 10H routine parses the characters starting at HL+1 for the first non-SPACE,non-09H,non-0BH character it finds. On exit, Register A will hold that character, and the C FLAG is set if its alphabetic, and NC FLAG if its alphanumeric. All strings must have a 00H at the end.
2166-2168
Jump back to 20A0H to process the rest of the PRINT TAB statement

2169 – This routine resets the device type flag at 409CH to zero (output to video display), also turns off cassette drive if necessary. CALLs Disk BASIC link at 41BEH prior to return – “FINPRT”.

2169-216B
 ↳ FINPRT
LD A,(409CH)LD A,(PRTFLG)3A 9C 40
If we land here, we need to turn off the cassette and reset the current output device to be video. To do this we first load Register A with the current output device flag.
  • Note: 409CH holds the current output device type number (-1=cassette, 0=video; or 1=printer)
216C
OR AB7
Test the value of the current output device flag in Register A. If the M flag is set, A was negative
216D-216F
If the current output device flag is the cassette recorder, GOSUB to 01F8H to turn it off
2170
XOR AAF
Clear Register A (which will set A to 0) and clear the status flags
2171-2173
LD (409CH),ALD (PRTFLG),A32 9C 40
Save the value in Register A (which is 0) as the current value of the output device flag.
  • Note: 409CH holds the current output device type number (-1=cassette, 0=video; or 1=printer)
2174
CALL 41BEHCALL FINDRTCD BE 41
GOSUB to DOS to see if DOS wants to do anything here
2177
RETC9
RETurn to CALLer

2178-217E – MESSAGE STORAGE LOCATION FOR REDO MESSAGE
– “TRYAGN”

2178-217E
 ↳ TRYAGN
“?REDO” + CRLF + 00H
The ?REDO message is stored here

217F-2285 – LEVEL II BASIC INPUT AND READ ROUTINES– “TRMNOK”

This is a multi-purpose processing routine. We can wind up here because DATA was typed in or DATA statements were improperly formatted. We can also wind up here where we want an INPUT to start again. If we are here because of a READ, throw a ?SN ERROR at the data line.
217F-2181
 ↳ TRMNOK
LD A,(40DEH)LD A,(FLGINP)3A DE 40
Load Register A with the READ flag to help us try to figure out if this was a READ or an INPUT.
Note: 40DEH holds READ flag
2182
OR AB7
Check to see if the read flag is set. If Z FLAG then it was INPUT
2183-2185
If the read flag is set, go give a ?SN ERROR
2186-2188
LD A,(40A9H)LD A,(CASFLG)3A A9 40
Now we know the read flag is NOT set, so we need to load Register A with the INPUT type flag.
Note: 40A9H holds Cassette input flag
2189
OR AB7
Check to see if the cassette recorder is the current input device, as we will need to give a FILE DATA error
218A-218B
LD E,2AH1E 2A
Load Register E with the ?FD ERROR code
218C-218E
If the current input device is the cassette recorder, go give a ?FD ERROR
218F
POP BCC1
Clean up the STACK (discards the pointer into the variable list)
2190-2192
 ↳ RDOINP
LD HL,2178HLD HL,TRYAGN21 78 21
Load HL with the starting address of the ?REDO message
2193-2195
CALL 28A7HCALL STROUTCD A7 28
Display the “?REDO FROM START” message
2196-2198
LD HL,(40E6H)LD HL,(SAVTXT)2A E6 40
Get the value of the current BASIC program pointer in HL.
Note: 40E6H-40E7H is a common temporary storage location
2199
RETC9
Return out of this routine back to NEWSTT of the INPUT statement

219A – INPUT logic – “INPUT”

219A-219C
 ↳ INPUT
Check to see if there is an illegal direct in the input statement
219D
LD A,(HL)7E
Load Register A with the character at the location of the current BASIC program pointer in HL
219A-219C
Check to see if there is an illegal direct in the input statement
21A1-21A2
SUB 23HD6 23
Check to see if the character at the location of the current BASIC program pointer in Register A is a #
21A3-21A5
LD (40A9H),ALD (CASFLG),A32 A9 40
Set the current input device flag for the cassette recorder.
Note: 40A9H holds cassette input flag
21A6
LD A,(HL)7E
Load Register A with the character at the location of the current BASIC program pointer in HL
21A7-21A8
Jump to 21C9H if there is keyboard input
21A9-21AB
If we are here, then the input is coming from the cassette, so GOSUB to 0293H to read the cassette leader and find the sync byte
21AC
PUSH HLE5
Save the current BASIC program pointer in HL to the STACK
21AD-21AE
LD B,FAH06 FA
Load Register B with 250, which is the maximum number of characters which can be read
21AF-21B1
LD HL,(40A7H)LD HL,(BUFPNT)2A A7 40
Load HL with the starting address of the input buffer.
Note: 40A7H-40A8H holds the input Buffer pointer
21B2-21B4
 ↳ FILBUF
Top of a DJNZ Loop. Calls the READ ONE BYTE FROM CASSETTE routine at 0235H (which reads one byte from the cassette drive specified in Register A, and returns the byte in Register A)
21B5
LD (HL),A77
Save the byte read from the cassette recorder in Register A at the location of the input buffer pointer in HL
21B6
INC HL23
Bump the value of the input buffer pointer in HL
21B7-21B8
CP 0DHFE 0D
Check to see if the character read from the cassette recorder in Register A is a carriage return. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
21B9-21BA
Jump out of this routine if the character read from the cassette recorder in Register A is a carriage return
21BB-21BC
Loop back to 21B2H until the input buffer is full
21BD
 ↳ ENDREC
DEC HL2B
Decrement the value of the input buffer pointer in HL to make room in the buffer for a terminator character
21BE-21BF
LD (HL),00H36 00
Save a zero (which is a terminator)( at the location of the input buffer pointer in HL
21C0-21C2
GOSUB to 01F8H to put a 00H at the end of the tape and turn the cassette recorder off
21C3-21C5
LD HL,(40A7H)LD HL,(BUFPNT)2A A7 40
Load HL with the starting address of the input buffer.
Note: 40A7H-40A8H holds the input Buffer pointer
21C6
DEC HL2B
Decrement the value of the input buffer pointer in HL
21C7-21C8
Jump to 21EBH to store a comma there so we can use the READ processing
21C9-21CB
 ↳ INTCAS
LD BC,21DBHLD BC,NOTQTI01 DB 21
Load BC with a return address of 21DBH for where to go when done dealing with a quoted string
21CC
PUSH BCC5
Save the value of the return address in BC to the STACK
21CD-21CE
 ↳ QTINP
CP 22HFE 22
Check to see if the character at the location of the current BASIC program pointer in Register A is a quote. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
21CF
RET NZC0
Return to 21DBH if the character at the location of the current BASIC program pointer in Register A isn’t a quote
21D0-21D2
Go set up pointers for the prompting message in the temporary string work area
21D3-21D4
Since the character at the location of the current BASIC program pointer in HL must be a “;”, call the COMPARE SYMBOL routine at RST 08H.

NOTE: The RST 08H routine compares 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 the next execution address (i.e, the RST 08H 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 and control returns to the Input Phase).
21D5
PUSH HLE5
Save the value of the current BASIC program pointer in HL to the STACK
21D6-21D8
Go display the prompting message
21D9
POP HLE1
Restore the code string address (from the STACK) into HL
21DA
RETC9
Return to 21DBH
21DB
 ↳ NOTQTI
PUSH HLE5
Save the value of the current BASIC program pointer in HL to the STACK
21DC-21DE
 ↳ GETAGN
Print the ? prompt and get the input from the keyboard
21DF
POP BCC1
Remove the value of the current BASIC program pointer from the STACK, as we may be exiting
21E0-21E2
The CARRY FLAG will be set if a BREAK was hit (meaning we got no input). Jump back to 1DBEH if the BREAK key was pressed
21E3
INC HL23
Bump the value of the input buffer pointer in HL
21E4
LD A,(HL)7E
Load Register A with the character at the location of the input buffer pointer in HL
21E5
OR AB7
Test the value of the character at the location of the input buffer pointer in Register A
21E6
DEC HL2B
Decrement the value of the input buffer pointer in HL
21E7
PUSH BCC5
Since it turns out we didn’t exit, put the return address back onto to the STACK
21E8-21EA
Skip to the next statement if the character at the location of the input buffer pointer in Register A is an end of the input character (i.e., a CARRIAGE RETURN
21EB-21EC
 ↳ INPCN3
LD (HL),2CH36 2C
Save a “,” at the location of the current input buffer pointer in HL
21ED-21EE
Jump to 21F4H (which address uses a Z-80 trick)

21EF – READ logic – “READ”

21EF
 ↳ READ
PUSH HLE5
Save the current BASIC program pointer in HL
21F0-21F2
LD HL,(40FFH)LD HL,(DATPTR)2A FF 40
Load HL with the location of the last DATA statement read.
Note: 40FFH-4100H holds READ pointer
21F3-21F4
OR 0AFHOR 1010 1111F6 AF
Turn on some bits in Register A to set Register A to a non-zero value if entered from the READ routine and, due to a Z-80 trick, set to zero if entered from the INPUT routine
21F4
 ↳ INPCON
XOR AAF
Set the flag to indicate that this is an INPUT
21F5-21F7
LD (40DEH),ALD (FLGINP),A32 DE 40
Save the value of the input type flag in Register A.
Note: 40DEH holds READ flag
A note in the original ROM source code indicates that when processing DATA and READ, we keep one pointer which points to the data being fetched, and another pointer which points to the lists of variables. The data pointer will always start by pointing to a terminator (either a “,” a “:” or an END OF LINE).
21F8
EX (SP),HLE3
Swap HL and the top of STACK, so that the DATA POINTER goes to the top of the STACK, and HL will now hold the variable list pointer
21F9-21FA
Skip over the next instruction
21FB-21FC
 ↳ LOPDT2
RST 08H ⇒ 2CSYNCHK “,”CF 2C
Since the character at the location of the current BASIC program pointer in HL must be a ,, call the COMPARE SYMBOL at RST 08H.

NOTE: The RST 08H routine compares 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 the next execution address (i.e, the RST 08H 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 and control returns to the Input Phase).
21FD-21FF
 ↳ LOPDAT
Call the 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)
2200
EX (SP),HLE3
Swap HL and the top of STACK, so that the Variable List Pointer goes to the top of the STACK and HL will hold the DATA LIST POINTER
A note in the original ROM source code indicates that if we are here, we have a variable which is expecting data, so we only have two choices – get it some data or complain about it not getting expected data.
2201
PUSH DED5
Save the pointer to the variable we are about to load with a value (held in Register Pair DE)
2202
LD A,(HL)7E
Load Register A with the character at the location of the DATA LIST POINTER. This could be a terminator if its the first read
2203-2204
CP 2CHFE 2C
Check to see if the character at the location of the input buffer pointer Register A is a ,. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
2205-2206
Jump to 222DH to fetch the impending data if we know that the character at the location of the input buffer pointer in Register A is a ,
2207-2209
LD A,(40DEH)LD A,(FLGINP)3A DE 40
Load Register A with the input type flag so we can see what kind of statement called this routine (READ or INPUT).
Note: 40DEH holds READ flag
220A
OR AB7
Since a LD command does not affect the flags, OR A is commonly used to set the flags based on A. This is to Check for READ or INPUT
220B-220D
Jump to 2296H if the input type flag in Register A indicates READ meaning we need to go search for another data statement
220E-2210
LD A,(40A9H)LD A,(CASFLG)3A A9 40
Load Register A with the value of the cassette input flag.
Note: 40A9H holds Cassette input flag
2211
OR AB7
Check to see if the input is from the cassette recorder, because if it is, then we have run out of data when we needed it
2212-2213
LD E,06HLD E,ERROD1E 06
Load Register E with an ?OD ERROR code
2214-2216
Go to the Level II BASIC error routine and display an ?OD ERROR message if the input is from the cassette recorder
2217-2218
LD A,3FH3E 3F
Load Register A with a “?”
2219-221B
GOSUB to 032AH which is a general purpose output routine that outputs a byte from the A Register to video, tape or printer (based on what is in 409CH)
221C-221E
Go get the keyboard line input using the routine that will also print a “?” as we want “??” when we need more input
221F
POP DED1
Get the address of VARIABLE POINT (the variable to be set) from the STACK and put it in DE
2220
POP BCC1
Get the return address from the STACK and put it in BC because we might be exiting this routine
2221-2223
Exit this routine via a jump to 1DBEH if we have an empty input (such as if the BREAK key was pressed)
2224
INC HL23
Since we got no input, get ready to exit. First, bump the value of the input buffer pointer in HL
2225
LD A,(HL)7E
Load Register A with the character at the location of the input buffer pointer in HL
2226
OR AB7
Check to see if the character at the location of the input buffer pointer in Register A is an end of the input character
2227
DEC HL2B
Decrement the value of the input buffer pointer in HL
2228
PUSH BCC5
Save the RETurn address back to the top of the STACK because we didn’t actually exit
2229-222B
Jump if the character at the location of the input buffer pointer in Register A is an end of the input character (i.e., a CARRIAGE RETURN)
222C
PUSH DED5
Save the variable pointer (the variable’s address) in DE to the STACK. At this point, the DATA will now start at the beginning of the buffer and QINLIN will leave HL set to point to that buffer
222D-222F
 ↳ DATABK
JP Z,1F04HCALL FILINDCD DC 41
Check with DOS to see if it wants to do anything here
2230
We need to know if this is a string, so check the value of the current number type flag by calling the TEST DATA MODE routine at RST 20H.
NOTE: The RST 20H routine determines the type of the current value in ACCumulator and returns a combination of STATUS flags and unique numeric values in the A Register according to the data mode flag (40AFH). The results are returned as follows:
  • Integer = NZ/C/M/E and A is -1
  • String = Z/C/P/E and A is 0
  • Single Precision = NZ/C/P/O and A is 1
  • and Double Precision is NZ/NC/P/E and A is 5.
2231
PUSH AFF5
Save the number type of the variable to the STACK
2232-2233
If that test shows we do NOT have a STRING, jump to 224DH. Note that we do not check the contents, so an unquoted string could contain all digits
2234
We need the next character in the BASIC program so call the EXAMINE NEXT SYMBOL routine at RST 10H.

The RST 10H routine parses the characters starting at HL+1 for the first non-SPACE,non-09H,non-0BH character it finds. On exit, Register A will hold that character, and the C FLAG is set if its alphabetic, and NC FLAG if its alphanumeric. All strings must have a 00H at the end.
2235
LD D,A57
We are going to assume we have a quoted string here. First, load Register D with the character at the location of the input buffer pointer in Register A
2236
LD B,A47
Load Register B with the character at the location of the input buffer pointer in Register A
2237-2238
CP 22HFE 22
Check to see if the character at the location of the input buffer pointer in Register A is a quote. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
2230-223A
Jump to 2240H if the character at the location of the input buffer pointer in Register A is a quote
223B-223C
LD D,3AH16 3A
Load D with the character :, which could act as an unquoted string terminator
223D-223E
LD B,2CH06 2C
Load Register B with the character , which could ALSO act as an unquoted string terminator
223F
DEC HL2B
Decrement the pointer to the BASIC line being interpreted since we need this starting character to be included in the quoted string
2240-2242
 ↳ NOWGETR
Set up a string descriptor for the value and copy it if necessary
2243
 ↳ DOASIG
POP AFF1
Discard the number type for the variable from the STACK and put it in Register A
2244
EX DE,HLEB
Load DE with the pointer to the BASIC line being processed
2245-2247
LD HL,225AHLD HL,STRDN221 5A 22
Load HL with the value of a RETurn address
2248
EX (SP),HLE3
Exchange HL and the top of the STACK, so that HL now points to the place to store the variable value
2249
PUSH DED5
Save the pointer to the BASIC line being processed to the STACK
224A-224C
Go set the variable to the value of the string
224D
 ↳ NUMINS
We need the next character in the BASIC program so call the EXAMINE NEXT SYMBOL routine at RST 10H.

The RST 10H routine parses the characters starting at HL+1 for the first non-SPACE,non-09H,non-0BH character it finds. On exit, Register A will hold that character, and the C FLAG is set if its alphabetic, and NC FLAG if its alphanumeric. All strings must have a 00H at the end.
224E
POP AFF1
Load Register A with the number type for the variable to be set
224F
PUSH AFF5
Save it back to to the STACK
2250-2252
LD BC,2243HLD BC,DOASIG01 43 22
Load BC with the value of the return address so that the assignment will jump to the LET routine
2253
PUSH BCC5
Save the return address in BC to the STACK
2254-2256
If the current number type is integer or single precision (i.e., NOT double precision), call the ASCII TO BINARY routine at 0E6C (which converts the ASCII string pointed to by HL to binary with the result in ACCumulator and the mode flag will have changed)
2257-2259
If the current number type is double precision, jump to the ASCII TO DOUBLE routine at 0E65H.
  • NOTE: 0E65H converts the ASCII string pointed to by HL to its double precision equivalent; with output left in ACCumulator).
225A
 ↳ STRDN2
DEC HL2B
Decrement the value of the pointer to the BASIC line being processed by 1 character
225B
We need the next character in the BASIC program so call the EXAMINE NEXT SYMBOL routine at RST 10H.

The RST 10H routine parses the characters starting at HL+1 for the first non-SPACE,non-09H,non-0BH character it finds. On exit, Register A will hold that character, and the C FLAG is set if its alphabetic, and NC FLAG if its alphanumeric. All strings must have a 00H at the end.
225C-225D
Jump to 2263H if the character at the location of the input buffer pointer in HL is an end of the input character
225E-225F
CP 2CHFE 2C
Check to see if the character at the location of the input buffer pointer in Register A is a comma. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
2260-2262
Jump to 217FH if the character at the location of the input buffer pointer in Register A isn’t a comma
2263
 ↳ TRMOK
EX (SP),HLE3
Exchange the value of the input buffer pointer in HL with the value of the current BASIC program pointer to the STACK
2264
DEC HL2B
Decrement the value of the current BASIC program pointer in HL to point to the terminator character
2265
We need the next character in the BASIC program so call the EXAMINE NEXT SYMBOL routine at RST 10H.

The RST 10H routine parses the characters starting at HL+1 for the first non-SPACE,non-09H,non-0BH character it finds. On exit, Register A will hold that character, and the C FLAG is set if its alphabetic, and NC FLAG if its alphanumeric. All strings must have a 00H at the end.
2266-2268
If Z FLAG is set, then we are not ending, so we will need to check for a “,” and get another variable to fill with data
2269
POP DED1
Remove the pointer to the data location from the STACK

226A-226E – For ROM v1.0 – Test for FD Error
Removed in ROM v1.2 because this was not needed.

Note: There is no ROM call to this location; it operates only as passing down from the above routine. A FD ERROR means that bad file data was read as part of the READ command reading from cassette.
226A-226C
LD A,(40A9H)LD A,(CASFLG)3A A9 40
Check to see if we were working off of data stored on cassette by loading Register A.
Note: 40A9H holds Cassette input flag
226D
OR AB7
Check to see if the error flag in Register A indicates an error
226E
RET ZC8
Return to the BASIC interpreter if the error flag in Register A doesn’t indicate an error

*226A-226E – For ROM v1.2 – Replaced with NOPS

226F-2271
LD A,(40DEH)LD A,(FLGINP)3A DE 40
Load Register A with the value of the input type flag to see if we are here because of READ or because of INPUT.
Note: 40DEH holds READ flag
2272
OR AB7
Check to see if the input type is READ or INPUT
2273
EX DE,HLEB
Load DE with the value of the current BASIC program pointer in HL
2274-2276
Jump if the input type flag is set for READ so we can set the DATA POINTER
2277
PUSH DED5
Save the current BASIC program pointer in DE to the STACK
2278-227A
CALL 41DFHCALL EXCHDSCD DF 41
GOSUB to DOS to see if DOS wants to modify any behavior
227B
OR (HL)B6
Check to see if this is the end of the input (which could be a “,” or a “:”)
227C-227E
LD HL,2286HLD HL,EXIGNT21 86 22
Load HL with the starting address of the ?EXTRA IGNORED message
227F-2281
If the Z FLAG was set, then we weren’t really at the end, so We need to display the ?EXTRA IGNORED message, so we call the WRITE MESSAGE routine at 28A7H.
NOTE:
  • The routine at 28A7 displays the message pointed to by HL on current system output device (usually video).
  • The string to be displayed must be terminated by a byte of machine zeros or a carriage return code 0D.
  • If terminated with a carriage return, control is returned to the caller after taking the DOS exit at 41D0H (JP 5B99H).
2282
 ↳ FINPRG
POP HLE1
Get the value of the pointer to the BASIC line being processed from the STACK and put it in HL
2283-2285
Go turn off the cassette recorder and return to the BASIC interpreter

2286-2295 – MESSAGE STORAGE LOCATION – “EXIGNT”

2286-2295
 ↳ EXIGNT
“?Extra ignored” + 0DH + 00H3F
The EXTRA IGNORED message is stored here

2296-22B5 – FIND THE NEXT DATA STATEMENT ROUTINE – “DATLOP”

The original ROM source notes that the search is mad by uising the execution code for DATA to skp over statements. The start word of each statement is compared against $DATA. Each new line number is stored in DATLIN so that if an error occurs while reading data, the error message can give the line number of the bad formatted data.
2296-2298
 ↳ DATLOP
Go find the next DATA statement
2299
 ↳ DATFND
OR AB7
Check to see if this is the end of the BASIC line
229A-229B
Jump to 22AEH if the BASIC statement is terminated with a :
229C
INC HL23
Bump the value of the current BASIC program pointer in HL
229D
LD A,(HL)7E
Load Register A with the LSB of the line address at the location of the current BASIC program pointer in HL
229E
INC HL23
Bump the value of the current BASIC program pointer in HL
229F
OR (HL)B6
Combine the MSB of the line address at the location of the current BASIC program in HL with the LSB of the line address in Register A
22A0-22A1
LD E,06H1E 06
Load Register E with an ?OD ERROR code
22A2-22A4
Go to the Level II BASIC error routine and display an OD ERROR message if this is the end of the BASIC program
22A5
INC HL23
Bump the value of the current BASIC program pointer in HL
22A6
LD E,(HL)5E
Load Register E with the LSB of the BASIC line number at the location of the current BASIC program pointer in HL
22A7
INC HL23
Bump the value of the current BASIC program pointer in HL
22A8
LD D,(HL)56
Load Register D with the MSB of the BASIC line number at the location of the current BASIC program pointer in HL
22A9
EX DE,HLEB
Exchange the value of the current BASIC program pointer in HL with the value of the BASIC line number in DE
22AA-22AC
LD (40DAH),HLLD (DATLIN),HL22 DA 40
Save the BASIC line number in HL.
Note: 40DAH-40DBH holds DATA line number
22AD
EX DE,HLEB
Exchange the value of the current BASIC program pointer in DE with the value of the BASIC line number in HL
22AE
 ↳ NOWLIN
We need the next character in the BASIC program so call the EXAMINE NEXT SYMBOL routine at RST 10H.

The RST 10H routine parses the characters starting at HL+1 for the first non-SPACE,non-09H,non-0BH character it finds. On exit, Register A will hold that character, and the C FLAG is set if its alphabetic, and NC FLAG if its alphanumeric. All strings must have a 00H at the end.
22AF-22B0
CP 88HCP $DATAFE 88
Check to see if the character at the location of the current BASIC program pointer in Register A is a DATA token. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
22B1-22B2
Jump to 2296H (=find the next DATA statement routine) if the character at the location of the current BASIC program pointer in Register A isn’t a DATA token
22B3-22B5
Now we know that the current BASIC program pointer is pointing to a DATA token, so jump to 222DH to read it

22B6-2336 – LEVEL II BASIC NEXT ROUTINE – “NEXT”

The original ROM source notes that a FOR entry on the STACK has the following format:
  • LOW ADDRESS
    • Token ($FOR in high byte) – 1 Byte
    • Pointer to the loop variable – 2 Bytes
    • A Byte reflecting the sign of the increment – 1 Byte
    • Step value – 4 bytes
    • Upper limit of FOR loop – 4 bytes
    • Line number of the FOR statement – 2 bytes
    • Text pointer to the FOR statement – 2 bytes
  • HIGH ADDRESS
22B6-22B8
 ↳ NEXT
LD DE,0000H11 00 00
Load DE with the default for cases where NEXT doesn’t include a variable name (such as “NEXT X”). By doing this, FINDFOR will be called with DE = 0
22B9-22BB
 ↳ NEXTC
Get the pointer to variable which follows the NEXT token, call the 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)
22BC-22BE
LD (40DFH),HLLD (TEMP),HL22 DF 40
Save the value of the current BASIC program pointer (contained in 40DFH) in H into a common temporary storage area
22BF-22C1
Go search the STACK for the appropriate FOR entry that matches the variable name being used here
22C2-22C4
If FNDFOR found nothing, then display a NF ERROR message if the appropriate FOR push wasn’t found
22C5
LD SP,HLF9
Clean up the STACK. First set the STACK pointer with the value of the memory pointer in HL
22C6-22C8
LD (40E8H),HLLD (SAVSTK),HL22 E8 40
Save the value in HL to the STACK pointer pointer
22C9
PUSH DED5
Save the pointer to the variables address (in DE) to the STACK
22CA
LD A,(HL)7E
Load Register A with the value of the sign for the STEP value
22CB
INC HL23
Bump the value of the memory pointer in HL
22CC
PUSH AFF5
Save the value of the sign for the STEP value in Register A to the STACK
22CD
PUSH DED5
Save the pointer to the loop variable (in DE) to the STACK
22CE
LD A,(HL)7E
Load Register A with the number type flag for the STEP value to help determine if it is an integer
22CF
INC HL23
Bump the value of “FOR” entry pointer in HL
22D0
OR AB7
Check the value of the number type flag for the STEP flag in Register A. The MINUS FLAG will be set if it is an integer
22D1-22D3
Jump to 22EAH if the STEP value is an integer
22D4-22D6
Move the step value into the ACC via a GOSUB to 09B1H (which moves a SINGLE PRECISION number pointed to by HL to ACCumulator)
22D7
EX (SP),HLE3
Exchange the top of the STACK with HL, so that the pointer for the LOOP variable goes into HL and the pointer for the FOR entry goes to the top of the STACK
22D8
PUSH HLE5
Save the pointer to the loop variable’s address in HL to the STACK
22D9-22DB
Add the single precision value at the location of the memory pointer in HL to the single precision STEP value in Register Pairs BC and DE. Return with the result in ACCumulator
22DC
POP HLE1
Get the pointer to the loop variable from the STACK and put it in HL
22DD-22DF
Go move the single precision result from ACCumulator to the loop variable’s address in HL
22E0
POP HLE1
Get the ENTRY POINTER from the STACK and put it in HL
22E1-22E3
Get the final looop number into the registers via a GOSUB to 09C2H (which loads a SINGLE PRECISION value pointed to by HL into Register Pairs BC and DE)
22E4
PUSH HLE5
Save the ENTRY POINTER to the STACK
22E5-22E7
Compare the numbers returning 377 if the ACC is less than the registers, 0 if equal, and otherwise 1. This is done by a GOSUB to the SINGLE PRECISION COMPARISON routine at 0A0CH.

NOTE: The routine at 0A0CH algebraically compares the single precision value in BC/DE to the single precision value ACCumulator.
The results are stored in A as follows:
  • A=0 if ACCumulator = BCDE
  • A=1 if ACCumulator>BCDE; and
  • A=FFH if ACCumulator<BCDE.
22E8-22E9
Jump forward to to 2313H to skip over the integer processing code

22EAH – Part of the NEXT code, where we process the variable as an integer – “INTNXT”

22EA
 ↳ INTNXT
INC HL23
Since we are dealing with an integer, and not a single precision number, we need to skip 4 bytes of the TO value
22EB
INC HL23
Bump the value of the memory pointer in HL
22EC
INC HL23
Bump the value of the memory pointer in HL
22ED
INC HL23
Bump the value of the memory pointer in HL
22EE
LD C,(HL)4E
Load Register C with the LSB of the STEP value (held at the location of the memory pointer in HL)
22EF
INC HL23
Bump the value of the memory pointer in HL to be the MSB of the STEP value
22F0
LD B,(HL)46
Load Register B with the MSB of the STEP value at the location of the memory pointer in HL
22F1
INC HL23
Bump the value of the memory pointer in HL so that it is the STACK address of the TO limit
22F2
EX (SP),HLE3
Exchange HL and the value at the top of the STACK, so that HL will point to the loop’s variable and the ENTRY POINTER will be at the top of the STACK
22F3
LD E,(HL)5E
Next we need to get thee loop’s variable value into Register Pair DE. First, load Register E with the LSB of the loop variable
22F4
INC HL23
Bump the value of the memory pointer in HL to point to the MSB of the index
22F5
LD D,(HL)56
Load Register D with the MSB of the loop variable
22F6
PUSH HLE5
Save the pointer to the loop variable value to the STACK
22F7
LD L,C69
Next, we are going to need to add DE to HL. First, load Register L with the LSB of the STEP value in Register C
22F8
LD H,B60
Load Register H with the MSB of the STEP value in Register B
22F9-22FB
With the STEP value in HL, call the INTEGER ADD routine at 0BD2H (which adds the integer value in DE to the integer in HL. The sum is left in HL and the orginal contents of DE are preserved. If overflow occurs (sum exceeds 2**15), both values are converted to single precision and then added. The result would be left in ACCumulator and the mode flag would be updated)
22FC-22FE
LD A,(40AFH)LD A,(VALTYP)3A AF 40
Load Register A with the current value of the data type flag, as we want to check for an overflow.
Note: 40AFH holds Current number type flag
22FF
CP 04HFE 04
Check to see if the current value in ACCumulator was turned into single precision. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
2301-2303
Show an ?OV ERROR message if the index (i.e., the current value in ACCumulator) has overflowed to be a single precision number instead of an integer
2304
EX DE,HLEB
Swap DE and HL so that DE will now hold the new loop variable value
2305
POP HLE1
Restore the pointer to the loop variable back into HL
2306
LD (HL),D72
Save the MSB of the result in Register D at the location of the memory pointer in HL
2307
DEC HL2B
Decrement the value of the memory pointer in reg� ister pair HL
2308
LD (HL),E73
Save the LSB of the result in Register E at the location of the memory pointer in HL
2309
POP HLE1
Restore the pointer for the FOR entry back into HL
230A
PUSH DED5
Save the value of the loop’s variable (the index) in DE to the STACK
230B
LD E,(HL)5E
We need DE to hold the final value, so first load Register E with the LSB of the TO value at the location of the memory pointer in HL
230C
INC HL23
Bump the value of the memory pointer in HL to point to the MSB of the TO value
230D
LD D,(HL)56
Load Register D with the MSB of the TO value at the location of the memory pointer in HL
230E
INC HL23
Bump the value of the memory pointer in HL so now it points to the line number
230F
EX (SP),HLE3
Swap the TO value at the memory location pointed to by the STACK with the address of the binary line number for the FOR statement (now in HL)
2310-2312
We need to compare the new index to the limit so we call the INTEGER COMPARISON routine at 0A39H (which algebraically compares two integer values in DE and HL. The contents of DE and HL are left intact. The result of the comparison is left in the A Register and status Register as:
If DE > HL then A will be -1;
If DE < HL then A will b +1; and
If DE = HL then A will be 0

2313H – Part of the NEXT code, jumped to continue after skipping over the integer processing – “FINNXT”

2313
 ↳ FINNXT
POP HLE1
Restore the “FOR” entry pointer (which is now pointing past the final value) into HL
2314
POP BCC1
Get the value of the sign from the STACK and put it in BC
2315
SUB B90
We need to see if the sign is the sign we expected so we subtract the value of the sign in Register B from the value in Register A (which is currently set to CURRENT VALUE – FINAL VALUE)
2316-2318
Call 09C2H (which loads a SINGLE PRECISION value pointed to by HL into Register Pairs BC and DE)
2319-231A
Jump to 2324H if the index does not equal the TO limit (meaning the FOR . NEXT loop has not been completed)
231B
EX DE,HLEB
Load HL with the BASIC line number of the FOR statement in DE
231C-231E
LD (40A2H),HLLD (CURLIN),HL22 A2 40
Save the BASIC line number in HL as the current BASIC line number (which is stored at 40A2H-40A3H).
231F
LD L,C69
Set up the pointer to the current character in the BASIC program being processed by first loading Register L with the LSB of the current BASIC program pointer in Register C
2320
LD H,B60
Load Register H with the MSB of the current BASIC program pointer in Register B
2321-2323
Jump to 1D1AH to continue execution and restore the FOR token and GAP for FOR

2313H – Part of the NEXT code, jumped if we haven’t hit the TO counter yet – “LOOPDN”

2324
 ↳ LOOPDN
LD SP,HLF9
We are going to need to eliminate the FOR entry since HL already moved all the way down the entry
2325-2327
LD (40E8H),HLLD (SAVSTK),HL22 E8 40
Reset the STACK pointer pointer
2328-232A
LD HL,(40DFH)LD HL,(TEMP)2A DF 40
Save the value of the current BASIC program pointer in HL into a common temporary storage area
232B
LD A,(HL)7E
We are going to need to check for a “,” so first load Register A with the next token (i.e., the character at the location of the current BASIC program pointer in HL)
232C-232D
CP 2CHFE 2C
Check to see if the character at the location of the current BASIC program pointer in Register A is a ,. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
232E-2330
If the character at the location of the current BASIC program pointer in Register A isn’t a , then we need to look at another variable name for the NEXT, so JUMP to NEWSTT
2331
We need the next character in the BASIC program so call the EXAMINE NEXT SYMBOL routine at RST 10H.

The RST 10H routine parses the characters starting at HL+1 for the first non-SPACE,non-09H,non-0BH character it finds. On exit, Register A will hold that character, and the C FLAG is set if its alphabetic, and NC FLAG if its alphanumeric. All strings must have a 00H at the end.
2332-2334
GOSUB to 22B9H to process NEXT, but do not allow a blank variable name

2335-27C8 – EVALUATE EXPRESSION – “FRMPRN” and “FRMEVL”

According to the original ROM source, this routine starts with HL pointing to the first character of a formula. At the end of the routine HL points to the terminator, and ACC holds the result. Important to note that on exit Register A does not necessarily reflect the terminating character.

The formula evaluator uses the operation table (“OPTAB”) to determine the precedent and to dispatch addresses for each operator.

  • During operation, the STACK has the following format:
    • The RETURN location on completion (RETAOP)
    • The floating point temporary result
    • The address of the operator routine
    • The precedence of the operator
    Another description of this routine is that it 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. Note that the STACK is used frequently and the machine should be formatted for RUN mode in order to use this routine.
  • 2335
     ↳ FRMPRN
    If we chose THIS entry point, we require a parenthesis to start. Since the character at the location of the current BASIC program pointer in HL must be a (, call the COMPARE SYMBOL routine at RST 08H.

    NOTE: The RST 08H routine compares 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 the next execution address (i.e, the RST 08H 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 and control returns to the Input Phase).
    2337
     ↳ FRMEVL
    DEC HL2B
    This would be the entry point if we don’t need a lead-in “(“. First, decrement the value of the current BASIC program pointer in HL
    2338-2339
     ↳ FRMCHK
    LD D,00H16 00
    Load Register D with zero as a dummy precedence for the formula
    233A
     ↳ LPOPER
    PUSH DED5
    Save the value in DE to the STACK
    233B-233C
    LD C,01H0E 01
    Load Register C with the number of bytes of memory required for a return address -1 (so 2 bytes)
    233D-233F
    Since we must make sure that there is enough room for recursive calls, we GOSUB to 1963H to compute the amount of space between HL and the end of memory at FFC6H
    2340-2342
    Go get the value of the next part of the expression at the location of the current BASIC program pointer in HL
    2343-2345
    LD (40F3H),HLLD (TEMP2),HL22 F3 40
    Save the value of the current BASIC program pointer (i.e., the next token) in HL.
    Note: 40F3H-40F4H is a temporary storage location
    2346-2348
     ↳ RETAOP
    LD HL,(40F3H)LD HL,(TEMP2)2A F3 40
    Load HL with the value of the current BASIC program pointer.
    Note: 40F3H-40F4H is a temporary storage location
    2349
     ↳ TSTOP
    POP BCC1
    Get the last PRECEDENCE value from the STACK and put it in BC
    234A
     ↳ NOTSTV
    LD A,(HL)7E
    Load Register A with the character at the location of the current BASIC program pointer in HL
    234B-234C
    LD D,00H16 00
    Load Register D with zero as an assumption that there are no relation operations AND to set up the high order of the index into OPTAB
    234D-234E
     ↳ LOPREL
    SUB D4HSUB GREATKD6 D4
    Check to see if the character at the location of the current BASIC program pointer in Register A is an arithmetic or logical (i.e., relational) token (by subtracting 212 from it)
    234F-2350
    Jump to 2364H if the character at the location of the current BASIC program pointer in Register A is “relational” (i.e., +, , *, /, ?, AND or OR
    2351-2352
     ↳ NMREL
    CP 03HCP NMRELFE 03
    Check to see if the character at the location of the current BASIC program pointer in Register A is really relational (i.e., a >, =, or <. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
    2353-2354
    If the character at the location of the current BASIC program pointer in Register A isn’t a >, =, or <, and it’s jsut BIG, JUMP to ENDREL
    2355-2356
    CP 01HFE 01
    Set the Carry flag if >. Then test for <= or >=
    2357
    RLA17
    Adjust the value in Register A to give > as 1, = as 2, or < as 4
    2358
    XOR DAA
    Combine the current value in Register A with the value of the last token examined to see if this is a legal combination of <= or => or illegal combination of <<, ==, or >>
    2359
    CP DBA
    Check to make sure that the result is bigger and to avoid an illegal combination of operators. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
    235A
    LD D,A57
    Load Register D with the mask in Register A
    235B-235D
    If we have two of the same operators then display a ?SN ERROR
    235E-2360
    LD (40D8H),HLLD (TEMP3),HLLD (TEMP3),HL22 D8 40
    Save the address of the >, =, or < token (held in HL) to 40D8H, which is another temporary storage location
    2361
    We need the next token so call the EXAMINE NEXT SYMBOL routine at RST 10H.

    The RST 10H routine parses the characters starting at HL+1 for the first non-SPACE,non-09H,non-0BH character it finds. On exit, Register A will hold that character, and the C FLAG is set if its alphabetic, and NC FLAG if its alphanumeric. All strings must have a 00H at the end.
    2362-2363
    Jump back to 234DH
    2364
     ↳ ENDREL
    LD A,D7A
    Load Register A with the mask from Register D
    2365
    OR AB7
    Test the value of the operator in Register A against the mask to see if any of the masked operators are present
    2366-2368
    If the NZ FLAG is set, then one of the masked operators (>, =, or <) is present, so JUMP to FINDREL to handle those
    2369
    LD A,(HL)7E
    Load Register A with the character at the location of the current BASIC program pointer in HL
    236A-236C
    LD (40D8H),HLLD (TEMP3),HL22 D8 40
    Save the address of the current BASIC program pointer in HL (which is an arithmetic operator) to 40D8H, which is another temporary storage location
    236D-236E
    SUB 0CDHSUB PLUSTKD6 CD
    Check to see if the operator at the location of the current BASIC program pointer in Register A is an arithmetic token
    236F
    RET CD8
    Return if the character at the location of the current BASIC program pointer in Register A isn’t an arithmetic token
    2370-2371
    CP 07HCP LSTOPKFE 07
    Check to see if the character at the location of the current BASIC program pointer in Register A is a + to OR token. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
    2372
    RET NCD0
    Return if the character at the location of the current BASIC program pointer in Register A isn’t a + to OR token
    2373
    LD E,A5F
    Load Register E with the operator value in Register A (which would be between 0 and 7). This also sets up for a MULTIPLY BY 3 since the table entries are 3 bytes each.
    E   Token
    0   +
    1   
    2   *
    3   /
    4   @@
    5   AND
    6   OR
    2374-2376
    LD A,(40AFH)LD A,(VALTYP)3A AF 40
    Load Register A with the current value of the number type flag.
    Note: 40AFH holds Current number type flag
    2377-2378
    SUB 03HD6 03
    Test for a string by adjusting the value of the number type flag to get a -1 if integer, 0 for a string, 1 for single precision, and 5 for double precision
    2379
    OR EB3
    Combine the operator value in Register E with the adjusted number type flag in Register A. If it turns out to be a “+” then the Z FLAG will be set
    237A-237C
    Jump down to 298FH if the combination of the adjusted number type flag in Register A and the operator value in Register E indicates string addition
    237D-237F
    LD HL,189AHLD HL,OPTAB21 9A 18
    Load HL with the starting address of the table of precedence operator values
    2380
    ADD HL,DE19
    Add the value of the offset in DE to the table of precedence values pointer in HL
    2381
    LD A,B78
    Load Register A with the old precedence (i.e., the precedence value for the last operator) in Register B
    2382
    LD D,(HL)56
    Load Register D with the precedence value for the current operator
    2383
    CP DBA
    Let A = OLD PRECEDENCE minus NEW PRECEDENCE so as to compare the precedence value for the current operator in Register D with the precedence value for the last operator in Register A. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
    2384
    RET NCD0
    We need to apply the old precedence if it has greater or equal precedence to the new one, so if the NC flag is set, RETurn out of this routine
    2385
    PUSH BCC5
    Save the precedence value and the token for the last operator in BC to the STACK
    2386-2388
    LD BC,2346HLD BC,RETAOP01 46 23
    Load BC with the return address in case there is a break in precedence
    2389
    PUSH BCC5
    Save the return address in BC to the STACK
    238A
    LD A,D7A
    Load Register A with the precedence value for the current operator in Register D so that we can test for an exponent
    238B-238C
    CP 7FHCP EXPSTKFE 7F
    Check to see if the precedence value for the current operator in Register A indicates an exponential operator. If so, then we need FRCSNG and a special STACK entry
    238D-238F
    JP Z,23D4HCA D4 23
    Jump down to 23D4H if the precedence value for the current operator in Register A indicates an exponential operator
    238D-238F
    Jump down to 23D4H if the precedence value for the current operator in Register A indicates an exponential operator
    2390-2391
    CP 51HFE 51
    Check to see if the precedence value for the current operator in Register A indicates an “AND” or an “OR” logical operator. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
    2392-2394
    Jump if the precedence value for the current operator in Register A indicates a logical operator
    According to the original ROM source code, the following will push the current value in the ACC onto the STACK EXCEPT in the case of a string, in which case it will throw a TYPE MISMATCH error. Registers D and E are preserved. This routine is also used in the user-defined function value savings
    2395-2397
     ↳ NUMREL
    LD HL,4121HLD HL,FACLO21 21 41
    Load HL with the address of the ACCumulator
    2398
    OR AB7
    Ensure the CARRY FLAG is off
    2399-239B
     ↳ PUSVAL
    LD A,(40AFH)LD A,(VALTYP)3A AF 40
    Load Register A with the type of value we are dealing with.
    Note: 40AFH holds Current number type flag
    239C
    DEC A3D
    Next we need to set the flags without setting CARRY … Adjust the current number type flag in Register A
    239D
    DEC A3D
    Adjust the current number type flag in Register A
    239E
    DEC A3D
    Adjust the current number type flag in Register A. Now A will be -1=Integer, 0=String, 1=Single Precision, 5=Double Precision
    239F-23A1
    Display a ?TM ERROR if the current value in ACCumulator is a string
    23A2
    LD C,(HL)4E
    Get the value at the location of the memory pointer in HL and put it in Register C
    23A3
    INC HL23
    Bump the value of the memory pointer in HL
    23A4
    LD B,(HL)46
    Load Register B with the value at the location of the memory pointer in HL
    23A5
    PUSH BCC5
    Save the FACLO (held in B) to the STACK
    23A6-23A8
    If the data was an integer, then we are done, so in that case JUMP to 23C5H
    23A9
    INC HL23
    It’s not an integer, so lets get the rest of the value by bumping the value of the memory pointer in HL
    23AA
    LD C,(HL)4E
    Load Register C with the value at the location of the memory pointer in HL
    23AB
    INC HL23
    Bump the value of the memory pointer in HL
    23AC
    LD B,(HL)46
    Load Register B with the value at the location of the memory pointer in HL
    23AD
    PUSH BCC5
    Save the value in BC (the rest of the digit) to the STACK
    23AE
    PUSH AFF5
    Save the variable flag (held in value in AF as the type – 3) to the STACK
    23AF
    OR AB7
    Reset the status flags so that we can test if the current number type is double precision
    23B0-23B2
    Jump down to 23C4H if the current number type is single precision
    23B3
    POP AFF1
    Restore the variable flag into Register Pair AF from the STACK
    23B4
    INC HL23
    Bump the value of the memory pointer in HL
    23B5-23B6
    Skip the next instruction if the current number type is single precision
    23B7-23B9
    LD HL,411DHLD HL,DFACLO21 1D 41
    Reset HL to start of ACCumulator for a double density number.
    Note: 411DH-4124H holds REG l
    23BA
     ↳ PUSDVR
    LD C,(HL)4E
    Load Register C with the rest of the double precision value (held at the location of the memory pointer in HL)
    23BB
    INC HL23
    Bump the value of the memory pointer in HL
    23BC
    LD B,(HL)46
    Load Register B with the next digit LSB (at the location of the memory pointer in HL)
    23BD
    INC HL23
    Bump the value of the memory pointer in HL to the next digit
    23BE
    PUSH BCC5
    Save the LSB/NMSB of the double precision value (held in BC) to the STACK
    23BF
    LD C,(HL)4E
    Load Register C with the value at the location of the memory pointer in HL
    23C0
    INC HL23
    Bump the value of the memory pointer in HL
    23C1
    LD B,(HL)46
    Load Register B with the value at the location of the memory pointer in HL
    23C2
    PUSH BCC5
    Save the value in BC to the STACK
    23C3
    LD B,0F1H06 F1
    Z-80 Trick to nullify the next opcode if passing through
    23C4
     ↳ VPSHD1
    POP AFF1
    Restore the variable flag (which is actually the variable flag – 3)
    23C5-23C6
     ↳ VPUSHD
    ADD A,03HC6 03
    Adjust the number type in Register A up 3
    23C7
    LD C,E4B
    Load Register C with the value of the current operator token in Register E (0-7)
    23C8
    LD B,A47
    Load Register B with the number type flag in Register A
    23C9
    PUSH BCC5
    Save these two new things (held in BC) to the STACK
    23CA-23CC
    LD BC,2406HLD BC,APPLOP01 06 24
    Load BC with the return address of 2406H which is the APPLOP general operator application routine to do type conversions
    23CD
     ↳ FINTMP
    PUSH BCC5
    Save the return address in BC to the STACK
    23CE-23D0
    LD HL,(40D8H)LD HL,(TEMP3)2A D8 40
    Load HL with the value of the current BASIC program pointer.
    Note: 40D8H-40D9H holds Temporary storage location
    23D1-23D3
    Jump back to 233AH to continue reading the formula

    23D4-23D6 – Part of the Evaluation Routine – “EPSTK”

    Per the original ROM source, for exponentiation, we want to force the current value in the ACCumulator to be single precision. When application time comes, we force the right hand operand to single precision as well.
    23D4-23D6
     ↳ EXPSTK
    Call the CONVERT TO SINGLE PRECISION routine at 0AB1H (which converts the contents of ACCumulator from integer or double precision into single precision)
    23D7-23D9
    Call 09A4 which moves the SINGLE PRECISION value in the ACCumulator to the STACK (stored in LSB/MSB/Exponent order)
    23DA-23DC
    LD BC,13F2HLD BC,FPWRQ01 F2 13
    Load BC with the address of the exponential X^Y routine at 13F2H
    23DD-23DE
    LD D,7FH16 7F
    Load Register D with the precedence value for an exponential operator
    23DF-23E0
    Jump back to 23CDH to continue expression evaluation

    23D4-23D6 – Part of the Evaluation Routine – “ANDORD”

    According to the original ROM source, for AND and OR and \ and MOD we want to force the current value in the ACCumulator to be an integer, and at application time force the right hand operator to be an integer as well.
    23E1
     ↳ ANDORD
    PUSH DED5
    Save the precedence value and the operator token in DE to the STACK
    23E2-23E4
    Call the CONVERT TO INTEGER routine at 0A7FH (where the contents of ACCumulator are converted from single or double precision to integer and deposited into HL)
    23E5
    POP DED1
    Get the precedence value and the operator token from the STACK and put it in DE
    23E6
    PUSH HLE5
    Save the left hand operand in HL to the STACK
    23E7-23E9
    LD BC,25E9HLD BC,DANDOR01 E9 25
    Load BC with a return address of 25E9H to handle AND and OR
    23EA-23EB
    Jump back to 23CDH to push this address, push precedence, and then keep processing the expression.

    23D4-23D6 – Part of the Evaluation Routine – “FINREL”

    According to the original ROM source, this routine will build an entry for a relational operator strings are treated specially. Numeric compares are different from most operator entries only in the fact that at the bottom instead of having RETAOP, DOCMP and the relational bits are stored. Strings have STRCMP, the pointer at the string descriptor, DOCMP and the relational bits.
    23EC
     ↳ FINREL
    LD A,B78
    Load Register A with the precedence value for the PRIOR operator in Register B
    23ED-23EE
    CP 64HFE 64
    Check to see if the last operator was a logical/relational operator, as those have a value of 100. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
    23EF
    RET NCD0
    If the PRIOR operator has a higher precedentnce then apply that one instead via a RETurn
    23F0
    PUSH BCC5
    Save the precedence value and the operator token for the PRIOR operator in BC to the STACK
    23F1
    PUSH DED5
    Save the precedence value (D) and the token (E) for the current operator from DE (either a 6, 5, or 3) to the STACK
    23F2-23F4
    LD DE,6404HLD DE,256 * 100 + OPCNT11 04 64
    Load DE with the precedence value (of 100) and the displatch offset of the token for the new operator
    23F5-23F7
    LD HL,25B8HLD HL,DOCMP21 B8 25
    LD HL with the routine to take compare routine results and relation bits and return the answer; routine will do a JUMP to DOCMP when complete
    23F8
    PUSH HLE5
    and push it to the STACK
    23F9
    We need to check the value of the current number type flag, so we call the TEST DATA MODE routine at RST 20H.
    NOTE: The RST 20H routine determines the type of the current value in ACCumulator and returns a combination of STATUS flags and unique numeric values in the A Register according to the data mode flag (40AFH). The results are returned as follows:
    • Integer = NZ/C/M/E and A is -1
    • String = Z/C/P/E and A is 0
    • Single Precision = NZ/C/P/O and A is 1
    • and Double Precision is NZ/NC/P/E and A is 5.
    23FA-23FC
    If that test shows we do NOT have a STRING (i.e., we have numbers), jump back to 2395H to build an APPLOP entry
    23FD-23FF
    LD HL,(4121H)LD HL,(FACLO)2A 21 41
    If we are here then we have a string, so first load HL with the string address held at the memory location pointed to by ACCumulator
    2400
    PUSH HLE5
    Save the string’s address in HL to the STACK so that STRCMP can use it.
    2401-2303
    LD BC,258CHLD BC,STRCMP01 8C 25
    Load BC with the address of the string comparison routine
    2404-2405
    Jump back to 23CDH which will push BC, re-get the text pointer, save the precedence, and then scan more of the expression.

    2406 – Part of the Evaluation Routine – “APPLOP”

    According to the original ROM source code, APPLOP is returned to when it is time to apply an arithmetic or numeric comparison operation. The STACK has a double byte entry with the operator number and the VALTYP of the value on the STACK. APPLOP decides what value level the operation will occur at, and converts the arguments. APPLOP uses different calling conventions for each value type:
    • integers: left in [d,e] right in [h,l]
    • singles: left in [b,c,d,e] right in the fac
    • doubles: left in fac right in arg
    2406
     ↳ APPLOP
    POP BCC1
    Get the operand value type into B and the Operator Offset (i.e., token) for the last operator from the STACK and put it in C
    2407
    LD A,C79
    Load Register A with the operator token in Register C
    2408-240A
    LD (40B0H),ALD (DORES),A32 B0 40
    Save the operator token in Register A.
    Note: 40B0H holds Temporary storage location
    240B
    LD A,B78
    Load Register A with the operand value type for the value held in the STACK (held in Register B)
    240C-240D
    CP 08HFE 08
    Check the precision type of the number in the STACK against 08H. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
    240E-240F
    Jump forward to 2438H to force the number in the STACK to double precision
    2410-2412
    LD A,(40AFH)LD A,(VALTYP)3A AF 40
    Load Register A with the number type for the current result in ACCumulator.
    Note: 40AFH holds Current number type flag
    2413-2414
    CP 08HFE 08
    Check to see if the current result in ACCumulator is double precision. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
    2415-2417
    Jump forward to 2460H if the current value in ACCumulator is double precision so that we can convert the STACK operand to double density
    2418
    LD D,A57
    Load Register D with the current data type flag for the value in the ACCumulator held in Register A
    2419
    LD A,B78
    Load Register A with value type of the value in the STACK entry (looking for single precision)
    241A-241B
    CP 04HFE 04
    Check to see if the number type in the STACK is single precision. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
    241C-241E
    If so, jump forward to 2472H to convert he ACCumulator number to single precision
    241F
    LD A,D7A
    Load Register A with the number type flag for the value in ACCumulator for single precision.
    2420-2421
    CP 03HFE 03
    Check to see if the current value in ACCumulator is a string. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
    2422-2424
    Display a ?TM ERROR message if the current value in ACCumulator is a string
    2325-2427
    Jump forward to 247CH if the current value in ACCumulator is single precision to convert the value in the STACK to single precision.
    At this point, the number in the STACK MUST be an integer.
    2428-242A
    LD HL,18BFHLD HL,INTDSP21 BF 18
    Load HL with the starting address of the arithmetic jump table
    242B-242C
    LD B,00H06 00
    Load Register B with zero
    242D
    ADD HL,BC09
    Add the operator’s token in BC to the value of the arithmetic jump table pointer in HL
    242E
    ADD HL,BC09
    Add the operator’s token in BC to the value of the arithmetic jump table pointer in HL. HL will now point to where to go to process.
    242F
    LD C,(HL)4E
    Now that HL points to the token, we need to get the address from the lookup table. Load Register C with the LSB of the jump address at the location of the arithmetic jump table pointer in HL
    2430
    INC HL23
    Bump the value of the arithmetic jump table pointer in HL
    2431
    LD B,(HL)46
    Load Register B with the MSB of the jump address at the location of the arithmetic jump table pointer in HL
    2432
    POP DED1
    Get the left hand operand from the STACK and put it into Register Pair DE
    2433-2435
    LD HL,(4121H)LD HL,(FACLO)2A 21 41
    Get the right hand operand from (FACLO) and put it into Register Pair DE
    2436
    PUSH BCC5
    Save the arithmetic routine’s jump address in register pair BC to the STACK
    2437
    RETC9
    RETurn to the arithmetic routine of choice.

    2438 – Part of the Evaluation Routine – “STKDBL”

    According to the original ROM source code, at this point we know the STACK operand is double precision, so the number in the ACC must be forced into double precision, then moved into ARG and the STACK value POPped into ACC.
    2438-243A
     ↳ STKDBL
    Make the ACCumulator double precision via a call to the CONVERT TO DOUBLE PRECISION routine at 0ADBH (where the contents of ACCumulator are converted from integer or single precision to double precision)
    243B-243D
    Move the ACC into the ARG
    243E
    POP HLE1
    Get the STACK operand into the ACCumulator …POP the STACK and put it in HL
    243F-2441
    LD (411FH),HLLD (DFACLO+2),HL22 1F 41
    Save the value in HL near the end of the ACCumulator
    2442
    POP HLE1
    Get the value from the STACK and put it in HL
    2443-2445
    LD (411DH),HLLD (DFACLO),HL22 1D 41
    Save the value in HL in the ACCumulator.
    Note: 411DH-4124H holds the ACCumulator
    2446
     ↳ SNGDBL
    POP BCC1
    Next we need 4 bytes from the STACK so … get the value from the STACK and put it in BC
    2447
    POP DED1
    Get the value from the STACK and put it in DE
    2448-244A
    Put those 4 bytes into the ACCumulator via a call 09B4H (which moves the SINGLE PRECISION value in DC/DE into ACCumulator). This moves DE to (4121H) and BC to (4123H)
    244B-244D
     ↳ SETDBL
    Convert the first value to double precision by calling the CONVERT TO DOUBLE PRECISION routine at 0ADBH (where the contents of ACCumulator are converted from integer or single precision to double precision)
    244E-2450
    LD HL,18ABHLD HL,DBLDSP21 AB 18
    Load HL with the double precision arithmetic jump table’s starting address
    2451-2453
     ↳ DODSP
    LD A,(40B0H)
    LD A,(DORES)3A B0 40
    Load Register A with the operator token in Register A.
    Note: 40B0H holds Temporary storage location
    2454
    RLCA07
    Multiply the value of the operator token in Register A by two since each byte of the table is 2 bytes.
    2455
    PUSH BCC5
    Save the value in BC to the STACK so we can use it for 16 bit arithmetic.
    2456
    LD C,A4F
    Load Register C with the adjusted value of the operator token in Register A (i.e., 2 x token)
    2457-2458
    LD B,00H06 00
    Load Register B with zero
    2459
    ADD HL,BC09
    Add the value of the adjusted operator token in BC (which is token value * 2) to 18ABH (which is the double precision arithmetic jump table’s starting address) in HL
    245A
    POP BCC1
    Restore BC from the STACK and put it in BC in preparation for single precision math
    245B
    LD A,(HL)7E
    Load Register A with the LSB of the jump address at the location of the arithmetic jump table pointer in HL
    245C
    INC HL23
    Bump the value of the arithmetic jump table pointer in HL
    245D
    LD H,(HL)66
    Load Register H with the MSB of the jump address at the location of the arithmetic jump table pointer in HL
    245E
    LD L,A6F
    Load Register L with the LSB of the jump address in Register A
    245F
    JP (HL)E9
    Jump to the routine held in (HL).

    2460H – Part of the Evaluation Routine – “FACDBL”

    According to the original ROM source code, at this point the ACCumulator holds a double precision numbe, and the STACK holds either an integer or a single precision number, so we need to convert it.
    2460
     ↳ FACDBL
    PUSH BCC5
    Save the number type of the value held in the STACK
    2461-2463
    Move the value in the ACCumulator into ARG
    2464
    POP AFF1
    Load Register A with the value type of the number in the STACK
    2465-2467
    LD (40AFH),ALD (VALTYP),A32 AF 40
    Save the value of the current number type flag in Register A.
    Note: 40AFH holds Current number type flag
    2468-2469
    CP 04HFE 04
    Check to see if the current result in ACCumulator is single precision. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
    246A-246B
    Jump back to 2446H if the current result in ACCumulator is single precision. That will POP BC and DE, and then CALL MOVFR to continue
    246C
    POP HLE1
    Get the integer value from the STACK and put it in HL
    246D-246F
    LD (4121H),HLLD (FACLO),HL22 21 41
    Save the integer value in HL in the ACCumulator
    2470-2471
    Jump back to 244BH to set it up

    2472H – Part of the Evaluation Routine – “STKSNG”

    According to the original ROM source code, at this point the STACK holds a single precision number, we know that the ACCumulator holds either an integer or a single precision number, so we need to convert it.
    2472-2474
     ↳ STKSNG
    Convert the ACCumulator if necessary via a call to the CONVERT TO SINGLE PRECISION routine at 0AB1H (which converts the contents of ACCumulator from integer or double precision into single precision)
    2475
    POP BCC1
    Get the left hand operand into the registers. First POP the value from the STACK and put it in BC
    2476
    POP DED1
    and then get the value from the STACK and put it in DE
    2477-2479
     ↳ SNGDO
    LD HL,18B5HLD HL,SNGDSP21 B5 18
    Load HL with the starting address of the single precision arithmetic jump table
    247A-247B
    Jump back to 2451H to perform the operation held in Registe Pair HL

    247CH – Part of the Evaluation Routine – “FACSNG”

    According to the original ROM source code, at this point the ACCuumulator holds a single precision number and the STACK holds an integer.
    247C
     ↳ FACSNG
    POP HLE1
    Get the integer value from the STACK and put it in HL
    247D-247F
    Call 09A4 which moves the SINGLE PRECISION value in ACCumulator to the STACK (stored in LSB/MSB/Exponent order)
    2480-2482
    Go convert the integer value in HL to single precision
    2483-2485
    Call 09BF which loads the SINGLE PRECISION value (tyhe left hand operator) in ACCumulator into BC/DE
    2486
    POP HLE1
    Get the ACCumulator LSB/NMSB from the STACK and put it in HL
    2487-2489
    LD (4123H),HLLD (FAC-1),HL22 23 41
    Save the value in HL in ACCumulator
    248A
    POP HLE1
    Get the MSB and exponent from the STACK and put it in HL
    248B-248D
    LD (4121H),HLLD (FACLO),HL22 21 41
    Save the value in HL in ACCumulator
    248E-248F
    Jump back to 2477H to perform the operation

    2490 – Integer divide – “INTDIV”

    (ACC=DE / HL) Result will be in single-precision (NTF=4) and will be in the ACC.
    Divides DE by HL. Both values are converted to single precision before the division is started. The quotient is left in REG l; the mode flag is updated. The orginal contents of the DE and HL Register sets are lost

    The original ROM source code points that we can’t just live in integer world here, because we want 1/3 to be .3333 and not 0! So all arguments must be single precision even if they are integer

    Integer Division: Divides DE by HL. Both values are converted to single precision before the division is started. The quotient is left in the ACCumulator; the mode flag is updated. The orginal contents of the DE and HL Register sets are lost

    Single Precision Divide Divides the single precision value in (BC/DE) by the single precision value in the ACCumulator. The quotient is left in the ACCumulator.
    2490
     ↳ INTDIV
    PUSH HLE5
    Save the right hand argument (in HL) to the STACK
    2491
    EX DE,HLEB
    Exchange the left hand argument into HL and the right hand argument into DE
    2492-2494
    Go convert the integer value in HL to single precision and return with the result in the ACCumulator
    2495
    POP HLE1
    Get the right hand argument from the STACK and put it in HL
    2496-2498
    Call 09A4 which moves the SINGLE PRECISION value the ACCumulator (i.e., the converted left hand argument) to the STACK (stored in LSB/MSB/Exponent order)
    2499-249B
    Go convert the integer value in HL (i.e., the right hand argument) to single precision and return with the result the ACCumulator
    249C-249E
    Go do a single precision divide

    249F – Evaluate a Variable, Constant, or Function Call – “EVAL”

    249F
     ↳ EVAL
    We need the next character in the BASIC program so call the EXAMINE NEXT SYMBOL routine at RST 10H.

    The RST 10H routine parses the characters starting at HL+1 for the first non-SPACE,non-09H,non-0BH character it finds. On exit, Register A will hold that character, and the C FLAG is set if its alphabetic, and NC FLAG if its alphanumeric. All strings must have a 00H at the end.
    24A0-24A1
    LD E,28H1E 28
    Load Register E with a ?MO ERROR code
    24A2-24A4
    Display a ?MO ERROR if we are at the end of the string
    24A5-24A7
    If the character at the location of the current BASIC program pointer in HL is numeric, call the ASCII TO BINARY routine at 0E6C (which converts the ASCII string pointed to by HL to binary with the result in ACCumulator and the mode flag will have changed)
    24A8-24AA
    Check to see if the character at the location of the current BASIC program pointer in HL is alphabetic (as we are also looking to see if we have a variable name)
    24AB-24AD
    If the character at the location of the current BASIC program pointer in HL is alphabetic then we have a variable, so JUMP to 1E3DH to deal with that.
    24AE-24AF
    CP 0CDHCP PLUSTKFE CD
    Check to see if the character at the location of the current BASIC program pointer in Register A is a + token. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
    24B0-24B1
    We want to ignore any + token here, so if we have one, JUMP back to the top of this EVAL routine and keep parsing.
    24B2-24B3
    CP 2EHFE 2E
    Check to see if the character at the location of the current BASIC program pointer in Register A is a decimal point. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
    24B4-24B6
    If the character at the location of the current BASIC program pointer in HL is a decimal point, call the ASCII TO BINARY routine at 0E6C (which converts the ASCII string pointed to by HL to binary with the result in ACCumulator and the mode flag will have changed)
    24B7-24B8
    CP 0CEHCP MINUTKFE CE
    Check to see if the character at the location of the current BASIC program pointer in Register A is a token. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
    24B9-24BB
    Process a negation via a jump to 2532H if the character at the location of the current BASIC program pointer in Register A is a token
    24BC-24BD
    CP 22HFE 22
    Check to see if the character at the location of the current BASIC program pointer in Register A is a .

    Notes:

    • 22H is a . If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
    24BE-24C0
    If the character is a quote then we have a string constant, so jump to 2866H if the character at the location of the current BASIC program pointer in Register A is a
    24C1-24C2
    CP 0CBHCP NOTTKFE CB
    Check to see if the character at the location of the current BASIC program pointer in Register A is a NOT token. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
    24C3-24C5
    Jump to 25C4H if the character at the location of the current BASIC program pointer in Register A is a NOT token
    24C6-24C7
    CP 26HFE 26
    Check to see if the character at the location of the current BASIC program pointer in Register A is a &. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
    24C8-24CA
    Just to DOS to handle a &O; and &H;
    24CB-24CC
    CP 0C3HCP ERCTKFE C3
    Check to see if the character at the location of the current BASIC program pointer in Register A is an ERR token.

    Notes:

    • C3H is a ERR token.
    • A CP will return Z if there is a match against Register A, and NZ if not a match against Register A.
    24CD-24CE
    Jump to 24D9H if the character at the location of the current BASIC program pointer in Register A isn’t an ERR token
    24CF
    We now need bump the value of the current BASIC program pointer until it points to the next character, call the EXAMINE NEXT SYMBOL routine at RST 10H.

    The RST 10H routine parses the characters starting at HL+1 for the first non-SPACE,non-09H,non-0BH character it finds. On exit, Register A will hold that character, and the C FLAG is set if its alphabetic, and NC FLAG if its alphanumeric. All strings must have a 00H at the end.
    24D0-24D2
    LD A,(409AH)LD A,(ERRFLG)3A 9A 40
    Load Register A with the value of the current error number.
    Note: 409AH holds the RESUME flag
    24D3
     ↳ NTDERC
    PUSH HLE5
    Save the value of the current BASIC program pointer in HL to the STACK
    24D4-24D6
    Go save the value of the current error number in Register A (as an integer) as the current result in REG l
    24D7
    POP HLE1
    Get the value of the current BASIC program pointer from the STACK and put it in HL
    24D8
    RETC9
    RETurn to CALLer
    24D9-24DA
     ↳ NTERC
    CP C2HCP ERLTKFE C2
    Check to see if the character at the location of the current BASIC program pointer in Register A is a ERL token
    24DB-24DC
    Jump to 24E7H if the character at the location of the current BASIC program pointer in Register A isn’t an ERL token
    24DD
    We need the next character in the BASIC program so call the EXAMINE NEXT SYMBOL routine at RST 10H.

    The RST 10H routine parses the characters starting at HL+1 for the first non-SPACE,non-09H,non-0BH character it finds. On exit, Register A will hold that character, and the C FLAG is set if its alphabetic, and NC FLAG if its alphanumeric. All strings must have a 00H at the end.
    24DE
    PUSH HLE5
    Save the value of the current BASIC program pointer in HL to the STACK
    24DF-24E1
    LD HL,(40EAH)LD HL,(ERRLIN)2A EA 40
    Load HL with the current error line number.
    Note: 40EAH-40EBH holds the line number with error
    24E2-24E3
    Go save the error line number in HL as the current result in REG1
    24E5
    POP HLE1
    Get the value of the current BASIC program pointer from the STACK and put it in HL
    24E6
    RETC9
    RETurn to CALLer

    24E7-24FEVARPTR logic – “NTERL”

    24E7-24E8
     ↳ NTERL
    CP 0C0HCP $VARPTRFE C0
    Check to see if the character at the location of the current BASIC program pointer in Register A is a VARPTR token
    24E9-24EA
    Jump back to 24FFH if the character at the location of the current BASIC program pointer in Register A isn’t a VARPTR token
    24EB
    We need the next character in the BASIC program so call the EXAMINE NEXT SYMBOL routine at RST 10H.

    The RST 10H routine parses the characters starting at HL+1 for the first non-SPACE,non-09H,non-0BH character it finds. On exit, Register A will hold that character, and the C FLAG is set if its alphabetic, and NC FLAG if its alphanumeric. All strings must have a 00H at the end.
    24EC-24ED
    RST 08H ⇒ 28SYNCHK “(“CF 28
    Since the character at the location of the current BASIC program pointer in HL must be a (, call the COMPARE SYMBOL routine at RST 08H.

    NOTE: The RST 08H routine compares 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 the next execution address (i.e, the RST 08H 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 and control returns to the Input Phase).
    24EE-24F0
    Call the 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)
    24F1-24F2
     ↳ VARRET
    RST 08H ⇒ 29SYNCHK “)”CF 29
    Since the character at the location of the current BASIC program pointer in HL must be a ), call the COMPARE SYMBOL routine which compares 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 and control returns to the Input Phase)
    24F3
    PUSH HLE5
    Save the value of the current BASIC program pointer in HL to the STACK
    24F4
    EX DE,HLEB
    Swap DE and HL so that HL now holds the value to return
    24F5
    LD A,H7C
    Load Register A with MSB of the variable’s address in Register H to make sure that it isn’t undefined.
    24F6
    OR LB5
    Combine the LSB of the variable’s address in Register L with the MSB of the variable’s address in Register A. This type of pattern is used to check for something being zero
    24F7-24F9
    Display a ?FC ERROR if the variable’s address in HL is equal to zero, meaning that the variable is undefined
    24FA-24FC
    Save the variable’s address in HL as an integer into ACCumulator
    24FD
    POP HLE1
    Get the value of the current BASIC program pointer from the STACK and put it in HL
    24FE
    RETC9
    Return to the execution driver

    24FF – Other Function Routine – Jumped here if it wasn’t VARPTR to see what else it might have been – “NTVARP”

    24FF-2500
     ↳ NTVARP
    CP 0C1HCP USRTKFE C1
    Check to see if the character at the location of the current BASIC program pointer in Register A is a USR token. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
    2501-2503
    Jump to 27FEH if the character at the location of the current BASIC program pointer in Register A is a USR token
    2504-2505
    CP 0C5HCP INSRTKFE C5
    Check to see if the character at the location of the current BASIC program pointer in Register A is a INSTR token. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
    2501-2503
    If the character at the location of the current BASIC program pointer in Register A is a INSTR token, jump to DOS to deal with it.
    2509-250A
    CP 0C8HCP $MEMFE C8
    Check to see if the character at the location of the current BASIC program pointer in Register A is a MEM token. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
    250B-250D
    If the character at the location of the current BASIC program pointer in Register A is a MEM token, jump to the RETURN AMOUNT OF FREE MEMORY routine at 27C9H which computes the amount of memory remaining between the end of the variable list and the end of the STACK and puts the result in ACCumulator as a SINGLE PRECISION number
    250E-250F
    CP 0C7HCP $TIMEFE C7
    Check to see if the character at the location of the current BASIC program pointer in Register A is a TIME$ token. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
    250B-250D
    If the character at the location of the current BASIC program pointer in Register A is a MEM token, jump to DOS to deal with it.
    2513-2514
    CP 0C6HCP $POINTFE C6
    Check to see if the character at the location of the current BASIC program pointer in Register A is a POINT token. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
    2515-2517
    Jump to 0132H if the character at the location of the current BASIC program pointer in Register A is a POINT token
    2518-2519
    CP 0C9HCP $INKEYFE C9
    Check to see if the character at the location of the current BASIC program pointer in Register A is an INKEY$ token. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
    251A-251C
    Jump to 019DH if the character at the location of the current BASIC program pointer in Register A is an INKEY$ token
    251D-251E
    CP 0C4HCP $STRINGFE C4
    Check to see if the character at the location of the current BASIC program pointer in Register A is a STRING$ token. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
    241F-2421
    Jump to 2A2FH if the character at the location of the current BASIC program pointer in Register A is a STRING$ token
    2522-2523
    CP 0BEHCP FNTKFE BE
    Check to see if the character at the location of the current BASIC program pointer in Register A is a FN token. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
    241F-2421
    JP Z,4155HJP Z,FNDOER7A
    If the character at the location of the current BASIC program pointer in Register A is a FN token, jump to DOS to deal with it.
    2527-2528
    SUB 0D7HSUB ONEFUND6 D7
    Check to see if the character at the location of the current BASIC program pointer in Register A is a function name between the SGN and MID$ token
    2529-252B
    Jump to 254EH if the character at the location of the current BASIC program pointer in Register A is a SGN to MID$ token. The original ROM source notes that there is no need to check for an upper bound because functions are the highest allowed characters

    252CH – Other Function Routine – If we pass through to here, the only other possibility is that it is a function in parenthesis – “PARCHK”

    252C-252E
     ↳ PARCHK
    GOSUB to 2335H to recursively evaluate the expression at the location of the current BASIC program pointer in HL
    252F-2530
    RST 08H ⇒ 29SYNCHK “)”CF 29
    Since the character at the location of the current BASIC program pointer in HL must be a ), call the COMPARE SYMBOL routine at RST 08H.

    NOTE: The RST 08H routine compares 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 the next execution address (i.e, the RST 08H 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 and control returns to the Input Phase).
    2531
    RETC9
    Return out of this routine

    2532 – Binary Minus Routine – “DOMIN”

    2532
     ↳ DOMIN
    LD D,7DH16 7D
    Load Register D with a precedence value below “^” but above everything else since its a uniary minus.
    2534-2536
    GOSUB to 233AH to evaluate the variable at the location of the current BASIC program pointer in HL
    2537-2539
    LD HL,(40F3H)LD HL,(TEMP2)2A F3 40
    Load HL with the value of the current BASIC program pointer.
    Note: 40F3H-40F4H is a temporary storage location
    253A
    PUSH HLE5
    Save the value of the current BASIC program pointer in HL to the STACK so we know where to continue
    253B-253D
    Invert the sign of the current value in ACCumulator
    253E
     ↳ LABBCK
    POP HLE1
    According to the original ROM source, this is where functions that don’t return string values return. Restore the code string address from the STACK and put it in HL. We need this because we return here after executing functions SNG( to MID$(
    253F
    RETC9
    Return to the expression evaluation

    2540 – Math Routine – “ISVAR”

    According to the original ROM source code, this routine loads a variable to the ACC and sets the NTF. The HL must point to the ASCII variable name. After execution the HL will point to the character following the last character of the variable used. The value of the variable will be loaded in the ACC. For strings however (NTF=3), the ACC will contain the address of the first three bytes which contain the string length and string address (see Level II BASIC manual). Also note that if the variable cannot be found it will be created and given a value of zero.
    2540-2542
     ↳ ISVAR
    Get the pointer to the variable held in Register Pair DE by calling the 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)
    2543
     ↳ RETVAR
    PUSH HLE5
    Save the value of the current BASIC program pointer in HL to the STACK
    2544
    EX DE,HLEB
    Swap DE and HL so that the pointer to the variable value is now held in Register Pair HL. This is the pointer to a descriptor, not the actual variable.
    2545-2547
    LD (4121H),HLLD (FACLO),HL22 21 41
    In case it is a string, we will store the pointer to the descriptor in FACLO.
    2548
    We need to check the value of the current number type flag, so we call the TEST DATA MODE routine at RST 20H.
    NOTE: The RST 20H routine determines the type of the current value in ACCumulator and returns a combination of STATUS flags and unique numeric values in the A Register according to the data mode flag (40AFH). The results are returned as follows:
    • Integer = NZ/C/M/E and A is -1
    • String = Z/C/P/E and A is 0
    • Single Precision = NZ/C/P/O and A is 1
    • and Double Precision is NZ/NC/P/E and A is 5.
    2549-254B
    If we had a string, then we are just going to leave a pointer in the ACCumulator. If not, the we need to actually transfer the value into th ACCumulator using the pointer in Register Pair HL. With this, if that test shows we do NOT have a STRING, call 09F7H to move data
    254C
    POP HLE1
    Restore the value of the current BASIC program pointer to Register Pair HL
    254D
    RETC9
    Return to the caller

    254E – This routine processes an expression for SNG( to MID$( – “ISFUN”

    254E-254F
     ↳ ISFUN
    LD B,00H06 00
    Load Register B with zero
    2550
    RLCA07
    Set A to be 2 * (token – D7H)
    2551
    LD C,A4F
    Save the new token
    2552
    PUSH BCC5
    Save 0/2*(token-D7) on STACK
    2553
    Get the next character from the tokenized string by calling RST 10H.

    The RST 10H routine parses the characters starting at HL+1 for the first non-SPACE,non-09H,non-0BH character it finds. On exit, Register A will hold that character, and the C FLAG is set if its alphabetic, and NC FLAG if its alphanumeric. All strings must have a 00H at the end.
    2554
    LD A,C79
    Prepare to look for the function number
    2555
     ↳ NUMGFN
    CP 41HCP NUMGFNFE 41
    Test the adjusted token to see if it is past 2 * LASNUM – 2 * ONEFUN + 1. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
    2557
    If the CARRY FLAG is set, then the function is past that last number, so JUMP to 256FH if the token is SGN( to CHR$(. If not, it is a LEFT$MID$
    2559
    Otherwise, it must be a normal function so GOSUB to 2335H to capture the “(” and the first argument. This routine will evaluate the expression part of the calling sequence (which requires 2 or parameters)
    The original source code has this to say about being here:

    Most functions take a single argument. The return address of these functions is a small routine that checks to make sure valtyp is 0 (numeric) and pops off the text pointer. so normal functions that return string results (i.e. chr$) must pop off the return address of labbck, and pop off the text pointer and then return to FRMEVL.

    The so called “funny” functions can take more than one argument, the first of which must be string and the second of which must be a number between 0 and 256. The text pointer is passed to these functions so additional arguments can be read. The text pointer is passed in Register Pair DE. The close parenthesis must be checked and return is directly to FRMEVL with Register Pair HL setup as the text pointer pointing beyond the “)”.

    The pointer to the descriptor of the string argument is stored on the STACK underneath the value of the integer argument (2 bytes).

    The first argument is ALWAY a string. The second is always an integer.
    255C
    RST 08H ⇒ 2CSYNCHK “,”CF 2C
    We need TWO arguments, so there needs to be a “,”. With this we use RST 08H to test for a ,
    255E
    GOSUB to 0AF4H to ensure the current variable is a string, otherwise it is an error
    2561
    EX DE,HLEB
    Swap DE and HL so that DE will now point to the position in the current BASIC program being evaluated and HL is the address of the current variable (which MUST be a string)
    2562
    LD HL,(4121H)LD HL,(FACLO)2A 21 41
    Load HL with the string descriptor address held at the memory location pointed to by ACCumulator
    2565
    EX (SP),HLE3
    Put the pointer to the string descriptor onto the STACK and put the function number into Register Pair HL
    2566
    PUSH HLE5
    Save function number (i.e., 00 / 2*(token-D7H)) to the STACK
    2567
    EX DE,HLEB
    Swap DE and HL so that HL will now point to the position in the current BASIC program being evaluated.
    2568
    Evaluate n portion of the string function. Register E will contain the value of the formula.
    256B
    EX DE,HLEB
    Swap DE and HL so that HL will now hold the integer value of the second argument and DE will point to the position in the current BASIC program being evaluated.
    256C
    EX (SP),HLE3
    Swap (SP) and HL so that HL will now hold the function number, and the integer value of the second argument will be at the top of the STACK
    256D
    Jump down to 2583H to process the token

    256F-2571
     ↳ OKNORM
    Next we need to check out the argument (and make sure it is followed by a “)”) via a single variable parameter call. First, GOSUB to 252CH to evaluate the expression at the location of the current BASIC program pointer in HL
    2572
    EX (SP),HLE3
    Swap (SP) and HL so that HL will now hold the function number [0 + 2 * (token – D7H)], and the pointer to the position in the current BASIC program being evaluated will be at the top of the STACK.
    The original source code has this to say about being here:

    We next have to check to see if a special coercion must be done for one of the transcendental functions (RND, SQR, COS, SIN, TAN, ATN, LOG, and EXP).

    Since these functions do not look at VALTYP, but rather assume the argument passed in the ACCumulator is single precision, we MUST call FRCSNG before dispatching to them.
    2573
    LD A,L7D
    Load Register A with the function number [i.e., 2 * (token – D7H)]
    2574-2575
     ↳ BOTCON
    CP 0CHCP (SQRTK-ONEFUN)*2FE 0C
    Check to see if the operator token in Register A is one less than SQR. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
    2576-2577
    Jump down to 257FH to avoid forcing the argument if the operator token in Register A is SGN to SQR
    2578-2579
     ↳ TOPCON
    CP 1BHCP (ATNTK-ONEFUN)*2+1FE 1B
    Check to see if the operator token in Register A is bigger than ATN(). If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
    257A
    PUSH HLE5
    Save the function number (i.e., 0 + 2*(token – D7H)) to the stop of the STACK
    257B-257D
    If we are still here, then we need to force the ACCumulator into Single Precision, so CALL the CONVERT TO SINGLE PRECISION routine at 0AB1H (which converts the contents of ACCumulator [4121H] from integer or double precision into single precision)
    257F-2581
     ↳ NOTFRF
    LD DE,253EHLD DE,LABBCK11 3E 25
    Load DE with a return address of 253EH for once the function is executed
    2582
    PUSH DED5
    Save the value of the return address in DE to the STACK so it will act as the return adddress
    2583-2585
     ↳ FINGO
    LD BC,1608HLD BC,FUNDSP01 08 16
    Load BC with the function dispatch/jump table address
    2586
     ↳ DISPAT
    ADD HL,BC09
    Add the jump table pointer in BC (i.e., the offset) with the value of the operator token in HL
    2587
    LD C,(HL)4E
    Load Register C with the LSB of the jump address at the location of the jump table pointer in HL
    2588
    INC HL23
    Bump the value of the jump table pointer in HL
    2589
    LD H,(HL)66
    Load Register H with the MSB of the jump address at the location of the jump table pointer in HL
    258A
    LD L,C69
    Load Register L with the LSB of the jump address in Register C
    258B
    JP (HL)E9
    Perform the function.

    258C – Part of the Formula Evaluation Code – “STRCMP”

    According to the original ROM source, this routine will compare two strings, one with the description in Register Pair DE and the other in FACLO/FACLO+1. On exit:
    • A = 0 if the strings are equal
    • A = 377 if BCDE > FACLO
    • A = 1 if BCDE < FACLO
    This routine will do a relational comparison of two strings.
    It will load A with the length of the first string and BC with the string’s address. Then it will load D with the length of the second string and HL with the string’s address.
    258C-258E
     ↳ STRCMP
    First we need to free up the FAC string and get the pointer to the FAC descriptor into Register Pair HL. We do this via a GOSUB to 29D7H to check to see if there is enough memory for the string
    258F
    LD A,(HL)7E
    Load Register A with the LSB of the length of the string in the FACLO
    2590
    INC HL23
    Bump the value of the string’s VARPTR in HL so that HL points to the LSB of the string address
    2591
    LD C,(HL)4E
    Load Register C with the LSB of the string in the FACLO
    2592
    INC HL23
    Bump the value of the string’s VARPTR in HL so that HL points to the MSB of the string address
    2593
    LD B,(HL)46
    Load Register B with the MSB of the string in the FACLO. Register Pair BC now points to the FACLO string.
    2594
    POP DED1
    Put the STACK string pointer into Register Pair DE
    2595
    PUSH BCC5
    Save the pointer to the FACLO string data
    2596
    PUSH AFF5
    Save the FACLO string’s length in Register A to the STACK
    2597-2599
    CALL 29DEHCALL FRETMPCD DE 29
    Free up the STACK string and RETURN with the pointer to the STACK string descriptor in Register Pair HL.
    259A
    POP DED1
    Get the length of the FACLO string from the STACK and put it in Register D
    259B
    LD E,(HL)5E
    Load Register E with the STACK / BCDE string’s length
    259C
    INC HL23
    Bump the pointer to the STACK / BCDE string’s entry in HL
    259D
    LD C,(HL)4E
    Load Register C with the LSB of the STACK / BCDE string’s address
    259E
    INC HL23
    Bump the pointer to the STACK / BCDE string’s entry in HL
    259F
    LD B,(HL)46
    Load Register B with the MSB of the STACK / BCDE string’s address
    25A0
    POP HLE1
    Get the second character pointer from the STACK and put it in HL
    25A1
     ↳ CSLOOP
    LD A,E7B
    Load Register A with the length of the STACK / BCDE string in Register E
    25A2
    OR DB2
    Combine the FACLO string’s length in Register D with the STACK / BCDE string’s length in Register A
    25A3
    RET ZC8
    If both string lengths are the same, then we are done, so return out of the routine since there aren’t any characters left in either string to be compared
    25A4
    LD A,D7A
    Load Register A with the FACLO string’s length in Register D
    25A5-25A6
    SUB 01HD6 01
    Check to see if the FACLO string’s length in Register A is equal to zero, by setting the CARRY FLAG and turning Register A into 255 if Register D was 0.
    25A7
    RET CD8
    If the CARRY FLAG is set, then the FACLO string has run out of characters, so RETurn
    25A8
    XOR AAF
    If we are here, then FACLO wasn’t out of characters, so we next need to see if the STACK / BCDE string ended first. First we load Register A with zero
    25A9
    CP EBB
    Check to see if the STACK / BCDE string’s length in Register E is equal to zero. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
    25AA
    INC A3C
    Bump the value in Register A for a return code of A = 1
    25AB
    RET NCD0
    Return if there aren’t any more characters in the STACK / BCDE string to be compared
    25AC
    DEC D15
    If we are STILL here, then neither string has ended. First, decrement the value of the FACLO string’s length in Register D
    25AD
    DEC E1D
    Decrement the value of the STACK / BCDE string’s length in Register E
    25AE
    LD A,(BC)0A
    Load Register A with the character at the location of the STACK / BCDE string pointer in BC
    25AF
    CP (HL)BE
    Compare the character at the location of the STACK / BCDE string pointer in Register A with the character at the location of the FACLO string pointer in HL. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
    25B0
    INC HL23
    Bump the value of the first string pointer in HL
    25B1
    INC BC03
    Bump the value of the second string pointer in BC
    25B2-25B3
    Loop back to 25A1H to keep going if the characters match
    25B4
    CCF3F
    If we are here, then the NZ FLAG was set and the strings are NOT equal. Since they are not equal, reverse the CARRY flag
    25B5-25B7
    Jump back to 0960H to set up Register A based on the CARRY FLAG.

    25B8
     ↳ DOCMP
    INC A3C
    Bump the value of the current precedence value in Register A
    25B9
    ADC A,A8F
    Adjust the value of the current precedence value in Register A. Depending on which routine called this this will give either (A) a 1 with a NC if 0 or a 0 with C if FF or (B) 4=Less, 2=Equal, 1=Greater
    25BA
    POP BCC1
    Get the last operator value from the STACK and put it in BC
    25BB
    AND BA0
    Combine the precedence value in Register B with the precedence value in Register A to see if any of the bits match.
    25BC-25BD
    ADD A,FFHC6 FF
    Adjust the value in Register A. This will give a 0 if both are equal and a CARRY if they are unequal
    25BE
    SBC A,A9F
    Check to see if the precedence values in registers A and B match. This will set A=0 if equal, and, depending on the routine which called this, either an A+1 or a A=377 if unequal
    25BF-25C1
    Convert Register A to a signed integer via a CALL to 098DH. This will set the current value to 00 if A is positive, and to FF if A is negative.
    If the values match, set the current result in zero. If they do not match, set the current result to -1
    25C2-25C3
    At this point we want to return from the operator application place so the text pointer will get set up to what it was when LPOPER returned. To do this we jump forward to 25D6H to continue with the expression evaluation

    25C4 – NOT Routine – “NOTER”

    25C4-25C5
     ↳ NOTER
    LD D,5AH16 5A
    NOT has a precedence value of 90, so we need a dummy entry of 90 on the STACK
    25C6-25C8
    Go evaluate the expression with a dummy entry of 90 on the STACK
    25C9-25CB
    We need the argument to be an integer so CALL the CONVERT TO INTEGER routine at 0A7FH (where the contents of ACCumulator are converted from single or double precision to integer and deposited into HL)
    25CC
    LD A,L7D
    The next bunch of instructions are to complement Register Pair HL. First, load Register A with the LSB of the integer value
    25CD
    CPL2F
    Compliment the LSB of the integer value in Register A
    25CE
    LD L,A6F
    Load Register L with the adjusted LSB of the integer value in Register A
    25CF
    LD A,H7C
    Load Register A with the MSB of the integer value in Register H
    25D0
    CPL2F
    Compliment the MSB of the integer value in Register A
    25D1
    LD H,A67
    Load Register H with the adjusted MSB of the integer value in Register A
    25D2-25D4
    LD (4121H),HLLD (FACLO),HL22 21 41
    Save the complimented integer value in HL as the current result in ACCumulator
    25D5
    POP BCC1
    Clean up the STACK
    25D6-25D8
     ↳ RETAPG
    Jump back to 2346H to continue with the expression evaluation. We need to do this because FRMEVL, after seeing a precedence level of 90, thinks it is applying an operator, which it isn’t. It has the text pointer stored in TEXT 2 so we need to JUMP to RETAOP to re-fetch that pointer.

    25D9 – The RST 20H code – “GETYPR”

    This is the TEST DATA MODE, which determines the type of the current value in ACCumulator and returns a combination of STATUS flags and unique numeric values in the A Register according to the data mode flag (40AFH). TYPE   CODE   ZERO   CARRY   NEG   PARITY   A-Register
    INT     02     NZ      C      N      E         -1
    STR     03      Z      C      P      E          0
    SNG     04     NZ      C      P      O          1
    DBL     08     NZ     NC      P      E          5
    25D9-25DBH
     ↳ GETPYR
    LD A,(40AFH)LD A,(VALTYP)3A AF 40
    Load Register A with the current value of the number type flag.
    Note: 40AFH holds Current number type flag
    25DC-25DD
    CP 08HFE 08
    Check to see if the current value in ACCumulator is double precision (02=INT, 03=STR, 04=SNG, 08=DBL). If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
    25DE-25DF
     ↳ CGETYP
    If that test shows that we have a DOUBLE PRECISION number, jump forward to 25E5H
    25E0-25E1
    SUB 03HD6 03
    If the number is not double precision, subtract 3
    25E2
    OR AB7
    Set the status flags of the adjusted number type flag in Register A
    25E3
    SCF37
    Set the Carry flag
    25E4
    RETC9
    RETurn to CALLer
    25E5-25E6
     ↳ NCASE
    SUB 03HD6 03
    We are dealing with a double precision number so adjust the value of the current number type flag in Register A
    25E7
    OR AB7
    Test the value of the current number type flag in Register A, which will exit without the CARRY flag set
    25E8
    RETC9
    RETurn to CALLer

    25E9 – AND and OR Routines – “DANDOR”

    According to the original ROM source, this routine applies the AND and OR operators and should be used to implement all logical operators

    Whenever an operator is applied, its precedence is in Register B

    This fact is used to distinguish between AND and OR

    The right hand argument is coerced to integer, just as the left hand one was when it was pushed on the STACK
    25E9
     ↳ DANDOR
    PUSH BCC5
    B has he precedence value, so save BC to the STACK. The precedence value for OR is 70.
    25EA-25EC
    We need the right hand argument to be an integer, so GOSUB the CONVERT TO INTEGER routine at 0A7FH (where the contents of ACCumulator are converted from single or double precision to integer and deposited into HL)
    25ED
    POP AFF1
    Get the precedence value from the STACK and put it in Register A so that we can detemined between span class=”code”>AND and OR
    25EE
    POP DED1
    Get the left hand argument from the STACK and put it in DE
    25EF-25F1
    LD BC,27FAHLD BC,GIVINT01 FA 27
    Load BC with a return address of 27FAH
    25F2
    PUSH BCC5
    Save the value of the return address in BC to the STACK
    25F3-25F4
    CP 46HFE 46
    Check to see if the operator value in Register A is an OR token. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
    25F5-25F6
    If Register A was not 46H then we have an AND, so jump forward a few instructions to 25FDH (to the AND code) if the operator value in Register A isn’t an OR token

    25F7 – OR logic.

    25F7
    LD A,E7B
    Load Register A with the LSB of the first value in Register E
    25F8
    OR LB5
    Combine the LSB of the first value in Register A with the LSB of the second value in Register L
    25F9
    LD L,A6F
    Load Register L with the ORed value in Register A
    25FA
    LD A,H7C
    Load Register A with the MSB of the second value in Register H
    25FB
    OR DB2
    Combine the MSB of the first value in Register D with the MSB of the second value in Register A
    25FC
    RETC9
    Return to 27FAH (=convert the result to integer and return that integer calue to 2346H)

    25FD – AND logic – “NOTOR”

    25FD
     ↳ NOTOR
    LD A,E7B
    Load Register A with the LSB of the first value in Register E
    25FE
    AND LA5
    Combine the LSB of the first value in Register A with the LSB of the second value in Register L
    25FF
    LD L,A6F
    Load Register L with the ANDed value in Register A
    2600
    LD A,H7C
    Load Register A with the MSB of the second value in Register H
    2601
    AND DA2
    Combine the MSB of the first value in Register D with the MSB of the second value in Register A
    2602
    RETC9
    Return to 27FAH (=Make the result an integer and return to 2346H)

    2603 – Dimension and Variable Searching Routine – “DIMCON”

    2603
     ↳ DIMCON
    DEC HL2B
    Decrement the value of the BASIC program pointer in HL so that we can see what the prior character was
    2604
    We need the next character in the BASIC program so call the EXAMINE NEXT SYMBOL routine at RST 10H.

    The RST 10H routine parses the characters starting at HL+1 for the first non-SPACE,non-09H,non-0BH character it finds. On exit, Register A will hold that character, and the C FLAG is set if its alphabetic, and NC FLAG if its alphanumeric. All strings must have a 00H at the end.
    2605
    RET ZC8
    If the CHGRGET routine returned a Z FLAG, then we have a terminator; so RETurn since this is the end of the BASIC statement
    2606-2607
    RST 08H ⇒ 2CSYNCHK “,”CF 2C
    Since the character at the location of the current BASIC program pointer in HL must be a ,, call the COMPARE SYMBOL routine at RST 08H.

    NOTE: The RST 08H routine compares 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 the next execution address (i.e, the RST 08H 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 and control returns to the Input Phase).

    2608 – DIM logic – “DIM”

    The original ROM source code states that this DIM code sets DIMFLG and then falls into the variable search routine, which then looks at DIMFLG at three different points:
    1. If an entry is found, dimflg being on indicates a “doubly dimensioned” variable
    2. When a new entry is being built dimflg’s being on indicates the indices should be used for the size of each indice. otherwise the default of ten is used.
    3. When the build entry code finishes, only if dimflg is off will indexing be done
    2608-260A
     ↳ DIM
    LD BC,2603HD BC,DIMCON01 03 26
    Load BC with a return address of 2603H
    260B
    PUSH BCC5
    Save the return address of 2603H (in BC) to the STACK
    260C-260D
    OR AFHF6 AF
    This is part of a Z-80 trick. If passed through, then this will just OR A to force A to be non-zero. It will then skip the next instruction

    260D – Variable location and creation logic – “PTRGET”.

    The original ROM source code states that this routine will read the variable name at the current text position and put a pointer to its value in Register Pair DE. Register Pair HL is then updated to point to the character after the variable name and VALTYP is set up. Evaluating subscripts in a variable name can cause recursive calls to PTRGET so at that point all values must be stored on the STACK. On RETurn, [a] does not reflect the value of the terminating character

    This routine will return the address of a variable in memory or create it if it is not found. In order to use this routine, the HL must point to the variable name (ASCII). Then, after execution, HL will point to the character following the variable name and the location of the variable will be returned in the DE Register Pair. For integer, single or doubleprecision (NTF=2, 4 or 8) the address returned in DE will be the same as for the VARPTR command under BASIC. (see Level II BASIC manual on VARPTR) For strings (NTF=3) however the address returned in DE will point to the first of three bytes containing the string length and string address.
    This entry point searches the Variable List Table (VLT) for a variable name which matches the name in the string pointed to by HL. If the variable exists, its address is returned in DE. If it is not defined, then it is created with an initial value ofzero and its address is returned in DE. Dimensioned and non-dimensioned variables may be located, and suffixs for data mode may be included in the name string. A byte of machine zeros must terminate the name string. All registers are used.
    260D
     ↳ PTRGET
    XOR AAF
    If JUMPed here, then A is set to ZERO. As a reminder, if passed through from the above routine, A will be NOT ZERO.
    260E-2610
    LD (40AEH),ALD (DIMFLG),A32 AE 40
    Save the value in Register A as the current variable location/creation flag.
    Note: 40AEH holds LOCATE/CREATE variable flag
    2611
    LD B,(HL)46
    Load Register B with the first character of the variable name
    2612-2614
     ↳ PTRGT2
    GOSUB to 1E3DH to make sure the first character of the variable name is a letter
    2615-2617
    Display a ?SN ERROR if the first character of the variable name isn’t a letter
    2618
    XOR AAF
    Zero Register A
    2619
    LD C,A4F
    Set up to assume that there is no second character by zeroing Register C
    261A
    We need the next character in the BASIC program so call the EXAMINE NEXT SYMBOL routine at RST 10H.

    The RST 10H routine parses the characters starting at HL+1 for the first non-SPACE,non-09H,non-0BH character it finds. On exit, Register A will hold that character, and the C FLAG is set if its alphabetic, and NC FLAG if its alphanumeric. All strings must have a 00H at the end.
    261B-261C
    Jump to 2622H if the character at the location of the current BASIC program pointer in Register A is numeric
    261D-261F
    GOSUB to 1E3DH to check to see if the character at the location of the current BASIC program pointer is a letter. This will set the CARRY FLAG.
    2620-2621
    Jump to 262BH if the character at the location of the current BASIC program pointer in Register A isn’t a letter
    2622
     ↳ ISSEC
    LD C,A4F
    If we are here, then the second character was a number, so save it in Register C
    2623
     ↳ EATEM
    We now need bump the value of the current BASIC program pointer until it points to the next character, call the EXAMINE NEXT SYMBOL routine at RST 10H.

    The RST 10H routine parses the characters starting at HL+1 for the first non-SPACE,non-09H,non-0BH character it finds. On exit, Register A will hold that character, and the C FLAG is set if its alphabetic, and NC FLAG if its alphanumeric. All strings must have a 00H at the end.
    2624-2625
    Loop back one OPCODE to keep eating characters until a non-numeric character is found
    2626-2628
    Go check to see if the character at the location of the current BASIC program pointer in HL is alphabetic
    2629-262A
    Jump back to 2623H if the character at the location of the current BASIC program pointer in HL is alphabetic
    262B-262D
     ↳ NOSEC
    LD DE,2652HLD DE,HAVTYP11 52 26
    Load DE with a return address of 2652H. Done to save time/RAM from using JUMPs instead.
    262E
    PUSH DED5
    Save the value of the return address in DE to the STACK
    262F-2630
    LD D,02H16 02
    Load Register D with an integer number type flag
    2631-2632
    CP 25HFE 25
    Check to see if the character at the location of the current BASIC program pointer in Register A is a %. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
    2633
    RET ZC8
    Return if the character at the location of the current BASIC program pointer in Register A is a %
    2634
    INC D14
    Bump Register D so that it will be equal to a string number type flag (02=INT, 03=STR, 04=SNG, 08=DBL)
    2635-2636
    CP 24HFE 24
    Check to see if the character at the location of the current BASIC program pointer in Register A is a $. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
    2637
    RET ZC8
    Return if the character at the location of current BASIC program pointer in Register A is a $
    2638
    INC D14
    Bump Register D so that it will be equal to a single precision number type flag (02=INT, 03=STR, 04=SNG, 08=DBL)
    2639-263A
    CP 21HFE 21
    Check to see if the character at the location of the current BASIC program pointer in Register A is a !. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
    263B
    RET ZC8
    Return if the character at the location of the current BASIC program pointer in Register A is a !
    263C-263D
    LD D,08H16 08
    Load Register D with a double precision number type flag. We have to do this because 04H (SNG) would bump to 05H if we just did another INC, but we need 08H for DBL
    263E-263F
    CP 23HFE 23
    Check to see if the character at the location of the current BASIC program pointer in Register A is a #. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
    2640
    RET ZC8
    Return if the character at the location of the current BASIC program pointer in Register A is a #
    2641
    LD A,B78
    Load Register A with the first character of the variable name from Register B
    2642-2643
    SUB 41HD6 41
    Adjust the value of the first character of the variable name in Register A so that it is in the range of 0 to 25 for a table offset
    2644-2645
    AND 7FHE6 7F
    Get rid of the user-defined function bit in Register B by ANDing it against 0111 1111
    2646
    LD E,A5F
    Next we need to build a two byte offset so first load Register E with the adjusted first character of the variable name in Register A
    2647-2648
    LD D,00H16 00
    Load Register D with zero
    2649
    PUSH HLE5
    Save the value of the current BASIC program pointer in HL to the STACK
    264A-264C
    LD HL,4101HLD HL,DEFTBL21 01 41
    Load HL with the starting address of the variable declaration table.
    NOTE: 4101H-411AH holds Variable Declaration Table
    264D
    ADD HL,DE19
    Add the offset to the top of the table
    264E
    LD D,(HL)56
    Load Register D with the number type value from the variable declaration table pointer in HL
    264F
    POP HLE1
    Get the value of the current BASIC program pointer from the STACK and put it in HL
    2650
    DEC HL2B
    Decrement the value of the current BASIC program pointer in HL as there was no marking character
    2651
    RETC9
    Return with data type in D

    2652
     ↳ HAVTYP
    LD A,D7A
    Load Register A with the value of the number type flag in Register D
    2653-2655
    LD (40AFH),ALD (VALTYP),A32 AF 40
    Save the number type flag for the current variable name from Register A.
    NOTE: 40AFH holds Current number type flag
    2656
    We want to skip the “type marker” so we need the next character in the BASIC program so call the EXAMINE NEXT SYMBOL routine at RST 10H.

    The RST 10H routine parses the characters starting at HL+1 for the first non-SPACE,non-09H,non-0BH character it finds. On exit, Register A will hold that character, and the C FLAG is set if its alphabetic, and NC FLAG if its alphanumeric. All strings must have a 00H at the end.
    2657-2659
    LD A,(40DCH)LD A,(SUBFLG)3A DC 40
    Load Register A with the FOR flag. Why the FOR flag? It doubles as a “should we allow arrays here” flag!
    265A
    OR AB7
    Test the value of the FOR flag in Register A
    265B-265D
    Jump to 2664H if a arrays are not permitted
    265E
    LD A,(HL)7E
    Re-fetch the next element of the code string by loading Register A with the character at the location of the current BASIC program pointer in HL
    265F-2660
    SUB 28HD6 28
    Next, test for an array by checking to see if the character at the location of the current BASIC program pointer in Register A is a (
    2661-2663
    If the Z FLAG is set then we have an array (meaning, it is a subscripted variable), so JUMP to 26E9H
    2664
     ↳ NOARYS
    XOR AAF
    Zero Register A so that we can allow for parenthesis now
    2665-2667
    LD (40DCH),ALD (SUBFLG),A32 DC 40
    Set the “permit arrays” array flag to ‘no subscript’.
    Note: 40DCH holds FOR flag
    2668
    PUSH HLE5
    Save the value of the current BASIC program pointer in HL to the STACK
    2669
    PUSH DED5
    Save the number type flag for the variable in DE to the STACK
    266A-266C
    LD HL,(40F9H)LD HL,(VARTAB)2A F9 40
    Load HL with the value of the simple variables pointer, which will be t he place to start the search.
    • Note: 40F9H-40FAH holds the starting address of the simple variable storage area.
    266D
     ↳ LOPFND
    EX DE,HLEB
    Swap DE and HL so that DE will not point to the place to start the search. We don’t care what happens to HL
    266E-2670
    LD HL,(40FBH)LD HL,(ARYTAB)2A FB 40
    Load HL with the pointer to the end of simple variables. 40FBH-40FCH holds the starting address of the BASIC array variable storage area
    2671
    Now we need to see if we have reached the end of the table so we compare the value of the simple variables pointer in DE with the array variables pointer in HL, so we call the COMPARE DE:HL routine at RST 10H.

    The RST 10H routine parses the characters starting at HL+1 for the first non-SPACE,non-09H,non-0BH character it finds. On exit, Register A will hold that character, and the C FLAG is set if its alphabetic, and NC FLAG if its alphanumeric. All strings must have a 00H at the end.
    2672
    POP HLE1
    Get the number type flag for the variable from STACK and put it in HL
    2673-2674
    If the Z FLAG is set (because the simple variables pointer in DE is greater than or equal to the array variables pointer) then the variable was not found, and so we need to create a new variable. To do this we JUMP to 268EH
    2675
    LD A,(DE)1A
    Load Register A with the number type flag for the variable at the location of the simple variables pointer in DE
    2676
    LD L,A6F
    Preserve Register A into Register L so we know how many entries to skip.
    2677
    CP HBC
    Compare the number type flag for the variable in Register H to the number type flag in Register A. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
    2678
    INC DE13
    Bump the value of the current simple variables pointer in DE to the 2nd character name for this entry
    2679-267A
    If the NZ FLAG is set then we did not have the right type of variable and need to skip it VIA a JUMP to 2686H
    267B
    LD A,(DE)1A
    Since the type matches, compare the 1st characters by loading Register A with the first character of variable name at the location of the simple variables pointer in DE
    267C
    CP CB9
    Compare the character at the location of the simple variables pointer in Register A with the first character of the variable name in Register C. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
    267D-2637
    Jump to 2686H if the first characters of the variable names don’t match
    267F
    INC DE13
    Bump the value of the current simple variables pointer in DE
    2680
    LD A,(DE)1A
    Load Register A with the second character of the variable name at the location of the simple variables pointer in DE
    2681
    CP BB8
    Compare the character at the location of the simple variables pointer in Register A with the first character of the variable name in Register B. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
    2682-2684
    Jump to 26CCH if the character at the location of the simple variables pointer in Register A matches the first character of the variable name in Register B
    2685-2686
    LD A,13H3E 13
    Z-80 Trick to skip the next INC DE if continuing through
    2686
     ↳ NOTIT1
    INC DE13
    Bump to the next entry in the simple variable list part 1
    2687
    INC DE13
    Bump the value of the simple variables pointer in DE part 2
    2688
    PUSH HLE5
    Save the number type flag for the variable in HL to the STACK so that it can be re-loaded at 2672H
    2689-268A
    LD H,00H26 00
    Load Register H with zero so that Register Pair HL is the number of bytes to skip, but in 16 bits.
    268B
    ADD HL,DE19
    Add the value of the simple variables pointer in DE to the value of the number type flag in HL
    268C-268D
    Loop back to 266DH to keep searching

    268E
     ↳ NOTFNS
    LD A,H7C
    Load Register A with the length for the variable in Register H
    268F
    POP HLE1
    Get the value of the current BASIC program pointer from the STACK and put it in HL
    2690
    EX (SP),HLE3
    Exchange (SP) and HL so that Register Pair HL now holds the return address and the value of the current BASIC program pointer is now at the top of the STACK
    2691
    PUSH AFF5
    Save length of the variable in Register A to the STACK
    2692
    PUSH DED5
    Save the current variable table position from DE to the STACK
    2693-2695
    LD DE,24F1HLD DE,VARRET11 F1 24
    Load DE with a VARPTR locator return address of 24F1H
    2696
    Now we need to check to see if this was a VARPTR or not, so we compare the return address in DE with the return address in HL by calling the COMPARE DE:HL routine at RST 10H.

    The RST 10H routine parses the characters starting at HL+1 for the first non-SPACE,non-09H,non-0BH character it finds. On exit, Register A will hold that character, and the C FLAG is set if its alphabetic, and NC FLAG if its alphanumeric. All strings must have a 00H at the end.
    2697-2698
    If the Z FLAG is set, then this was a VARPTR call, so JUMP forward to 26CFH.
    2699-269B
    LD DE,2543HLD DE,RETVAR11 43 25
    Next we need to see if EVAL called this routine. Load DE with a return address of the find address of variables routine at 2543H
    269C
    We need to see if we were called from the ‘find address of variable’ routine so we need to compare the return address in DE with the return address in HL, so we call the COMPARE DE:HL routine at RST 10H.

    The RST 10H routine parses the characters starting at HL+1 for the first non-SPACE,non-09H,non-0BH character it finds. On exit, Register A will hold that character, and the C FLAG is set if its alphabetic, and NC FLAG if its alphanumeric. All strings must have a 00H at the end.
    269D
    POP DED1
    Restore the current variable table position from the STACK and put it in DE
    269E-269F
    If this routine is called to locate the variables address, we JUMP to 26D5H as we do not need to create a new variable, and instead we zero out the FAC and skip the RETurn.
    26A0
    POP AFF1
    Clear the STACK and put the value of the number type flag for the variable from the STACK and put it in Register A
    26A1
    EX (SP),HLE3
    Swap (SP) and HL so that the value of the current BASIC program pointer is now in Register Pair HL
    26A2
    PUSH HLE5
    Save the value of the current BASIC program pointer in HL to the STACK
    26A3
    PUSH BCC5
    Save the variable’s address in BC to the STACK as we are about to use both Register B and Register C
    26A4
    LD C,A4F
    Load Register C with the value of the number type flag for the variable in Register A
    26A5-26A6
    LD B,00H06 00
    Load Register B with zero so that the number type flag for the variable can be represented in 16 bits
    26A7
    PUSH BCC5
    Save the variable’s number type flag in BC to the STACK
    26A8
    INC BC03
    Bump the value of the variable’s number type flag in BC
    26A9
    INC BC03
    Bump the value of the variable’s number type flag in BC
    26AA
    INC BC03
    Bump the value of the variable’s number type flag in BC. Now the variable’s length includes room for the addresses as well.
    26AB-26AD
    LD HL,(40FDH)LD HL,(STREND)2A FD 40
    Load HL with the value of the free memory pointer.
    Note: 40FDH-40FEH holds Free memory pointer
    26AE
    PUSH HLE5
    Save the value of the free memory pointer in HL to the STACK
    26AF
    ADD HL,BC09
    Add the value of the variable’s number type flag in BC to the value of the free memory pointer in HL
    26B0
    POP BCC1
    Restore the high address from the STACK and put it in BC
    26B1
    PUSH HLE5
    Save the value of the high address pointer in HL to the STACK
    26B2-26B4
    Block transfer the variable information and make sure we do not overflow the STACK space via a GOSUB to BLTU.
    26B5
    POP HLE1
    Get the value of the new free memory pointer (i.e., STREND) from the STACK and put it in HL
    26B6-26B8
    LD (40FDH),HLLD (STREND),HL22 FD 40
    Save the value of the new free memory pointer in HL to lock in that variable space.
    NOTE: 40FDH-40FEH holds Free memory pointer
    26B9
    LD H,B60
    Load Register H with the MSB of the new array variables pointer in Register B
    26BA
    LD L,C69
    Load Register L with the LSB of the new array variables pointer in Register C. HL will now point to the end of the new variable.
    26BB-26BD
    LD (40FBH),HLLD (ARYTAB),HL22 FB 40
    Save the value of the new array variables pointer in HL. 40FBH-40FCH holds the starting address of the BASIC array variable storage area
    26BE
     ↳ ZEROER
    DEC HL2B
    At this point, HL is retuned pointing to the end of the variable, so we need to zero backwards to DE which points to the start of the variable table. First, decrement the value of the array variables pointer in HL
    26BF-26C0
    LD (HL),00H36 00
    Zero the location of the memory pointer in HL
    26C1
    Now we need to check to see if the variable has been completely zeroed, so we call the COMPARE DE:HL routine at RST 10H.

    The RST 10H routine parses the characters starting at HL+1 for the first non-SPACE,non-09H,non-0BH character it finds. On exit, Register A will hold that character, and the C FLAG is set if its alphabetic, and NC FLAG if its alphanumeric. All strings must have a 00H at the end.
    26C2-26CJ
    Loop back to 26BEH until the variable has been cleared
    26C4
    POP DED1
    Get the value of the variable’s number type flag from the STACK and put it in DE
    26C5
    LD (HL),E73
    Save the value of the number type flag in Register E at the location of the memory pointer in HL
    26C6
    INC HL23
    Bump the value of the memory pointer in HL
    26C7
    POP DED1
    Get the 2nd character of the variable’s name from the STACK and put it in DE
    26C8
    LD (HL),E73
    Save the first character of the variable’s name in Register E at the location of the memory pointer in HL
    26C9
    INC HL23
    Bump the value of the memory pointer in HL
    26CA
    LD (HL),D72
    Save the first character of the variable’s name in Register D at the location of the memory pointer in HL
    26CB
    EX DE,HLEB
    Load DE with the value of the variable pointer in from HL
    26CC
     ↳ FINPTR
    INC DE13
    Bump the value of the variable pointer in DE so that it points to the value
    26CD
    POP HLE1
    Restore the value of the current BASIC program pointer from the STACK into Register Pair HL
    26CE
    RETC9
    RETurn to CALLer
    26CF
     ↳ VARNOT
    LD D,A57
    On entry, the Z FLAG was set, meaning that A=0. Zero out Register D with the value of Register AA
    26D0
    LD E,A5F
    Zero out Register E
    26D1
    POP AFF1
    Clean up the STACK (which was the PUSHed DE)
    26D2
    POP AFF1
    Clean up the STACK (which was the length)
    26D3
    EX (SP),HLE3
    Swap (SP) and HL so that the return return is now at the top of the STACK and the pointer in current BASIC program pointer is restored to HL
    26D4
    RETC9
    Return to the VARPTR routine

    26D5 – This routine is ZERO out all variable types and skip any RETurn – “FINZER”

    26D5-26D7
     ↳ FINZER
    LD (4124H),ALD (FAC),A32 24 41
    Zero ACCumulator so that all single-precision and double-precision variables become zero
    26D8
    POP BCC1
    Clean up the STACK (i.e., remove the length of the variable)
    26D9
    LD H,A67
    Zero Register H to clear out integers as well
    26DA
    LD L,A6F
    Zero Register L to clear out integers as well
    26DB-26DD
    LD (4121H),HLLD (FACLO),HL22 21 41
    Zero the string pointer location in ACCumulator
    26DE
    We need to check the value of the current number type flag, so we call the TEST DATA MODE routine at RST 20H.
    NOTE: The RST 20H routine determines the type of the current value in ACCumulator and returns a combination of STATUS flags and unique numeric values in the A Register according to the data mode flag (40AFH). The results are returned as follows:
    • Integer = NZ/C/M/E and A is -1
    • String = Z/C/P/E and A is 0
    • Single Precision = NZ/C/P/O and A is 1
    • and Double Precision is NZ/NC/P/E and A is 5.
    26DF-26E0
    If the NZ FLAG is set then we do NOT have a string, in which case we are done because we have zeroed out all the number types. JUMP to 26E7H
    26E1-26E3
    LD HL,1928HLD HL,REDDY-121 28 19
    If we are here, then we have a string, and need to zero that out. First, load HL with the character before the starting address of the Level II BASIC READY message, which is a 00H!
    26E4-26E6
    LD (4121H),HLLD (FACLO),HL22 21 41
    Save the value in HL as the current string pointer, which is now null.
    26E7
     ↳ POPHR2
    POP HLE1
    Get the value of the current BASIC program pointer from the STACK and put it in HL
    26E8
    RETC9
    RETurn (from the EVAL routine) to CALLer

    26E9 – This routine handles a subscripted variables – “ISARY”

    According to the original ROM source, ARRAYs have the following format:
    • Descriptor – Low Byte – Second Character (200 bit is string)
    • Descriptor – High Byte – First character
    • Length of array in core in bytes
    • Number of dimensions (1 byte)
    • Then, for each dimension starting with the first, a list of the max index+1 (2 bytes each)
    • The associated value
    On entry D = the type of variable, B = the 1st character of the variable name, C = the 2nd character of the variable name, and HL = the current position in the input string.
    26E9
     ↳ ISARY
    PUSH HLE5
    Save the DIMFLG and VALTYP for recursion
    26EA-26EC
    LD HL,(40AEH)LD HL,(DIMFLG)2A AE 40
    Load HL with the value of the locate/create flag.
    Note: 40AEH holds LOCATE/CREATE variable flag and will be a 0 if in locate mode and anything other than zero if in create mode
    26ED
    EX (SP),HLE3
    Swap (SP) and HL so that the the value of the current BASIC program pointer is back into Register Pair HL, and the DIMFLG and VALTYP are moved to the top of the STACK
    26EE
    LD D,A57
    Zero Register D (which will hold the number of dimension)
    26EF
     ↳ INDLOP
    PUSH DED5
    Save the number of dimension (held in Register D) to the STACK
    26F0
    PUSH BCC5
    Save the variable’s name in BC to the STACK
    26F1-26F3
    Go evaluate the array subscript/index at the location of the current BASIC program pointer in HL up to a ) or ,. Return with the binary value in DE
    26F4
    POP BCC1
    Get the variable’s name from the STACK (1st and 2nd character) and put it in BC
    26F5
    POP AFF1
    Get the variable’s number of dimension so far from the STACK and put it in Register A
    26F6
    EX DE,HLEB
    Swap DE and HL, so that DE will now be the value of the current BASIC program pointer and HL will now hold the array subscript
    26F7
    EX (SP),HLE3
    Swap (SP) and HL so that HL will now hold DIMFLG and VALTYP and the array subscript will be at the stop of the STACK
    26F8
    PUSH HLE5
    Save the DIMGFLG and VALTYP (in HL) to the STACK
    26F9
    EX DE,HLEB
    Swap DE and HL so that the value of the current BASIC program pointer is now in Register Pair HL, and the DIMFLG and VALTYP are now in DE.
    26FA
    INC A3C
    Bump the number of dimensions evaluated in Register A
    26FB
    LD D,A57
    Load Register D with the number of dimensions evaluated in Register A
    26FC
    LD A,(HL)7E
    Load Register A with the character at the location of the current BASIC program pointer in HL
    26FD-26FE
    CP 2CHFE 2C
    Check to see if the character at the location of the current BASIC program pointer in Register A is a ,. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
    26FF-2700
    If the character at the location of the current BASIC program pointer in Register A is a ,, then we have more dimensions to process, so JUMP back to INDLOP to process again
    2701-2702
    RST 08H ⇒ 29SYNCHK “)”CF 29
    Since the character at the location of the current BASIC program pointer in HL must be a ), call the COMPARE SYMBOL routine at RST 08H.

    NOTE: The RST 08H routine compares 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 the next execution address (i.e, the RST 08H 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 and control returns to the Input Phase).
    2703-2705
     ↳ SUBSOK
    LD (40F3H),HLLD (TEMP2),HL22 F3 40
    Save the value of the current BASIC program pointer in HL into the TEMP2 storage area.
    2706
    POP HLE1
    Get the DIMFLG and VALTYP from the STACK and put it in HL.
    2707-2709
    LD (40AEH),HLLD (DIMFLG),HL22 AE 40
    Save the value of the DIMFLG and VALTYP into the DIMFLG location in RAM.
    NOTE: 40AEH holds LOCATE/CREATE variable flag
    270A
    PUSH DED5
    Save the number of subscripts/dimensions evaluated (held in DE) to the STACK
    At this point, Register BC holds the variable name, the pointer to the BASIC program is in TEMP2, all of the indexes are on the STACK, as is the number of dimensions.
    270B-270D
    LD HL,(40FBH)LD HL,(ARYTAB)2A FB 40
    We are now going to start the serach! First, load HL with the value of the array variables pointer as the starting point. 40FBH-40FCH holds the starting address of the BASIC array variable storage area
    270E-270F
    LD A,19H3E 19
    Z-80 Trick to skip the next command of ADD HL,DE if falling through
    270F
     ↳ LOPFDA
    ADD HL,DE19
    Advance past the current array as we know it isn’t the correct one. Note: 40FBH-40FCH holds the array variables pointer
    2710
    EX DE,HLEB
    Swap DE and HL so that DE holds the current search point. We don’t care about HL.
    2711-2713
    LD HL,(40FDH)LD HL,(STREND)2A FD 40
    Load HL with the place to STOP the search (i.e., the value of the free memory pointer).
    Note: 40FDH-40FEH holds Free memory pointer
    2714
    EX DE,HLEB
    Swap DE and HL so that DE now holds the place to stop the search and HL holds the current search point.
    2715
    Now we need to see if we have reached the end of the search by comparing the END point to the CURRENT point, so we call the COMPARE DE:HL routine at RST 10H.

    The RST 10H routine parses the characters starting at HL+1 for the first non-SPACE,non-09H,non-0BH character it finds. On exit, Register A will hold that character, and the C FLAG is set if its alphabetic, and NC FLAG if its alphanumeric. All strings must have a 00H at the end.
    2716-2718
    LD A,(40AFH)LD A,(VALTYP)3A AF 40
    Load Register A with the value of the current number type flag.
    Note: 40AFH holds Current number type flag
    2719-271A
    If the Z FLAG is set, then we have run out of places to search and are finished, without finding the array, so JUMP out of this loop to 2742H
    271B
    CP (HL)BE
    Compare the value of the variable’s number type flag in Register A with the value of the number type flag at the location of the array variables pointer in HL. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
    271C
    INC HL23
    Bump the value of the array variables pointer in HL
    271D-271E
    Jump forward (but still in this loop) to 2727H if the number type flags don’t match
    271F
    LD A,(HL)7E
    Load Register A with the first character of the variable name at the location of the array variables pointer in HL
    2720
    CP CB9
    Check to see if the first character of the variable at the location of the array variable pointer in Register A matches the first character of the variable name in Register C. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
    2721
    INC HL23
    Bump the value of the array variables pointer in HL
    2722-2723
    Jump forward (but still in this loop) to 2728H if the first characters of the variable names don’t match
    2724
    LD A,(HL)7E
    Load Register A with the second character of the variable name at the location of the array variables pointer in HL
    2725
    CP BB8
    Compare the second character of the variable name at the location of the array variables pointer in Register A matches the second character of the variable name in Register B. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
    2726-2727
    LD A,23H3E 23
    This part of a Z-80 Trick. Will load A with 23H if passing through, and not do the following INC HL.
    2727
     ↳ NMARY2
    INC HL23
    Bump the value of the array variables pointer in HL
    2728
     ↳ NMARY1
    INC HL23
    Bump the value of the array variables pointer in HL. HL should now point to the LENGTH entry of the array being looked at
    2729
    LD E,(HL)5E
    Load Register E with the LSB of the LENGTH of the array being looked at
    272A
    INC HL23
    Bump the value of the array variables pointer in HL
    272B
    LD D,(HL)56
    Load Register D with the MSB of the LENGTH of the array being looked at
    272C
    INC HL23
    Bump the value of the array variables pointer in HL
    272D-272E
    If the NZ FLAG is set, then we do not have a match ,and we need to skuip this entry and try again via a JUMP back to 270FH
    272F-2731
    LD A,(40AEH)LD A,(DIMFLG)3A AE 40
    Load Register A with the value of the locate/create flag to see if this was a “DIM” instruction.
    Note: 40AEH holds LOCATE/CREATE variable flag
    2732
    OR AB7
    Since a LD command does not set any flags, we must OR A to set the flags against A. In this case, to check the status of the locate/create flag in Register A
    2733-2734
    LD E,12H1E 12
    Prepare for an error if this routine was NOT called by “DIM” by loading Register E with the ?DD ERROR code
    2735-2737
    If the NZ FLAG is set, then this was not called from DIM, and we need to throw a REDIMENTIONED ARRAY error (i.e., ?DD ERROR) since that variable already exists
    At this point TEMP2 still holds the pointer to the position in the BASIC line being evaluated AND we have located the variable we were looking or. HL will point beyond the LENGTH to the number of dimensions. All indices are on the STACK, followed by the number of dimensions.
    2738
    POP AFF1
    Get the number of dimension evaluated from the STACK and put it in Register A
    2739
    SUB (HL)96
    To do the actual erasure we need to make suyre that the number given now and when the array was set up are the same so we compare the number of subscripts evaluated in Register A with the number of subscripts for the array at the location of the array variables pointer in HL (meaning, the number which was DIMmed)
    273A-273C
    If they match then we are done so JUMP down to 2795H to read the indices

    273D – ?BS ERROR entry point – “BSER”

    273D-273E
     ↳ BSER
    LD E,10H1E 10
    Load Register E with a ?BS ERROR code
    273F-2741
    Display a ?BS ERROR message if the number of subscripts evaluated in Register A doesn’t match the number of subscripts for the array at the location of the array variable pointer in HL

    2742 – Part of the ARRAY routines. Jumped here when a variable isn’t found in the ARRAY table – “NOTFDD”

    The original ROM source lays out the steps which the ROM takes to build an entry when a variable isn’t found in the array table:
  • Put down the descriptor
  • Set up the number of dimensions
  • Make sure there is room for the new entry
  • Remember the VARPTR
  • Set the VALTYP
  • Hold 2 bytes for the size
  • Loop
    1. Get an index
    2. Put number+1 down at the VARPTR
    3. Increase the VARPTR
    4. Decmrent the number of DIMs
    5. Go back to the LOOP until the number of DIMs hits Zero
  • Call REASON with Register Pair HL holding the last location of the variable
  • Update STREND
  • Zero out backwards
  • Make the tally include MAXDIMS
  • Put down TALLY
  • If called by DIM, RETurn
  • If not called by DIM, then index into the variable as if it was found when initially searched for.
  • 2742
     ↳ NOTFDD
    LD (HL),A77
    Save the variable type for the array in Register A at the location of the array variables pointer in HL
    2743
    INC HL23
    Bump the value of the array variables pointer in HL so it points to the 2nd character in the variable name (since they are saved in last, first order)
    2744
    LD E,A5F
    Load Register E with the variable type flag for the current variable
    2745-2746
    LD D,00H16 00
    Zero Register D so that Register Pair DE can be the size of one value of the type VALTYP
    2747
    POP AFF1
    Get the number of dimensions evaluated from the STACK and put it in Register A
    2748
    LD (HL),C71
    Save the second character of the variable’s name in Register C at the location of the array variables pointer in HL
    2749
    INC HL23
    Bump the value of the array variables pointer in HL to now point to the 1st character in the variable name (since they are saved in last, first order)
    274A
    LD (HL),B70
    Save the first character of the variable’s name in Register B at the location of the array variables pointer in HL
    274B
    INC HL23
    Bump the value of the array variables pointer in HL to the LSB of the offset to the next entry
    274C
    LD C,A4F
    In preparation for the next CALL, load Register C with the number of two byte entries needed to store the size of each dimension
    274D-274F
    Figure the amount of memory space left between HL and the free memory and get the space needed as set in Register C
    2750
    INC HL23
    Next we need to make room (i.e., skip over) the size of each dimension so … Bump the value of the array variables pointer in HL
    2751
    INC HL23
    Bump the value of the array variables pointer in HL. These 2 INC’s skip over the offset entry
    2752-2754
    LD (40D8H),HLLD (TEMP3),HL22 D8 40
    Next we need to secure space for the dimenion entries by saving the location in which to put the size (which is the address of the maximum number of indices) into a temporary ram location.
    Note: 40D8H-40D9H holds temporary storage location
    2755
    LD (HL),C71
    Save the number of dimension at the location of the array variables pointer in HL
    2756
    INC HL23
    Bump the value of the array variables pointer in HL to point to the first subscript entry in the array table
    2757-2759
    LD A,(40AEH)LD A,(DIMFLG)3A AE 40
    Load Register A with the value of the locate/create flag so we can check to see if this routine was called from a DIM function.
    Note: 40AEH holds LOCATE/CREATE variable flag
    275A
    RLA17
    Set the CARRY flag accordingly
    275B
    LD A,C79
    Load Register A with the number of dimension evaluated in Register C
    275C-275E
     ↳ LOPPTA
    LD BC,000BH01 0B 00
    Top of a loop assuming we did not get here from “DIM”. Load BC with the default number of 11, which is the most entries an array can have without a DIM
    275F-2760
    If the NC flag is set, then we did not arrive here from DIM, so JUMP forward to 2763H if the array is being created because it certainly wasn’t found
    2761
    POP BCC1
    Get a subscript/index from the STACK and put it in BC
    2762
    INC BC03
    Bump the value of the subscript in BC by one for the ZERO entry.
    2763
     ↳ NOTDIM
    LD (HL),C71
    Top of a loop. Save the LSB of the subscript’s value in Register C at the location of the array variables pointer in HL
    2764
    INC HL23
    Bump the value of the array variables pointer in HL
    2765
    LD (HL),B70
    Save the MSB of the subscript’s value in Register B at the location of the array variables pointer in HL
    2766
    INC HL23
    Bump the value of the array variables pointer in HL
    2767
    PUSH AFF5
    Save the number of dimensions evaluated in Register A (and the CARRY aflag results from DIMFLG) to the STACK
    2768-276A
    Go multiply the size of the subscript by the value of the number type flag to determine the amount of memory necessary for the subscript
    276B
    POP AFF1
    Get the number of domensions that the CARRY FLAG (DIMFLG) from the STACK and put it in Register A
    276C
    DEC A3D
    Decrement the counter of the number of dimensions to check by one
    276D-276E
    Jump back to 275CH if there are anymore subscripts to be evaluated
    276F
    PUSH AFF5
    If we are here, then all dimensions have been processed and allocation. Next, save the number of subscripts evaluated (and the DIMFLG) in Register Pair AF to the STACK
    2770
    LD B,D42
    Load Register B with the MSB of the array’s length in Register D
    2771
    LD C,E4B
    Load Register C with the LSB of the array’s length in Register E. Now BC = size of the array in bytes
    2772
    EX DE,HLEB
    Swap DE and HL so that DE now has the start of the values and HL has the end of the values
    2773
    ADD HL,DE19
    Add the length of the array in HL to the value of the array variable pointer in DE
    2774-2775
    If that addition triggered the CARRY FLAG then we are out of RAM so JUMP back to 273DH and throw a ?BS ERROR
    2776-2778
    We now know there is room in RAM, so GOSUB to “REASON” to make sure there is room for the values
    2779-277B
    LD (40FDH),HLLD (STREND),HL22 FD 40
    Update the end of storage pointer with the end of the array (held in HL).
    Note: 40FDH-40FEH holds free memory pointer
    277C
     ↳ ZERITA
    DEC HL2B
    Now we need to zero the new array. First, decrement the value of the array pointer in HL
    277D-277E
    LD (HL),00H36 00
    Zero the location of the array pointer in HL
    277F
    Now we need to compare the array pointer in HL with the array variables pointer in DE, so we call the COMPARE DE:HL routine at RST 10H.

    The RST 10H routine parses the characters starting at HL+1 for the first non-SPACE,non-09H,non-0BH character it finds. On exit, Register A will hold that character, and the C FLAG is set if its alphabetic, and NC FLAG if its alphanumeric. All strings must have a 00H at the end.
    2780-2781
    If the NZ FLAG is set, then we have more entries to ZERO, so loop until the array has been cleared
    2782
    INC BC03
    Load BC with the array’s length in bytes plus one so as to make room for the byte which holds the number of dimensions for this array variable
    2783
    LD D,A57
    Zero Register D
    2784-2786
    LD HL,(40D8H) HL,(TEMP3)2A D8 40
    Load HL with the array variables pointer (=the number of indices).
    Note: 40D8H-40D9H holds Temporary storage location
    2787
    LD E,(HL)5E
    Load Register E with the number of dimension for the array at the location of the array variables pointer in HL
    2788
    EX DE,HLEB
    Swap DE and HL so that HL now holds the number of dimensions and DE holds the value of the array variables pointer
    2789
    ADD HL,HL29
    Multiply the number of subscripts for the array in HL by two
    278A
    ADD HL,BC09
    Add the length of the array in BC (i.e., the size) to the number of subscripts times two in HL so that we have the total number of bytes used
    278B
    EX DE,HLEB
    Swap DE and HL so that DE now holds the total number of bytes to be used for the array and HL holds the value of the array variables pointer
    278C
    DEC HL2B
    We now need to insert the size of the array in bytes into the array holding area, but that is 2 bytes back so … decrement the value of the array variables pointer in HL
    278D
    DEC HL2B
    Decrement the value of the array variables pointer in HL
    278E
    LD (HL),E73
    Save the LSB of the size of the array in Register E at the location of the array variables pointer in HL
    278F
    INC HL23
    Bump the value of the array variables pointer in HL
    2790
    LD (HL),D72
    Save the MSB of size of the array array in Register D at the location of the array variables pointer in HL
    2791
    INC HL23
    Bump the value of the array variables pointer in HL
    2792
    POP AFF1
    Get the value of the DIMFLG (i.e., the CARRY BIT) and a 0 into Register A
    2793-2794
    Jump forward to 27C5H if the array is being created
    At this point, HL points beyond the SIZE of the array to the NUMBER OF DIMENSIONS in the array. So what we need to do next is
    • We need NUMDIM to equal the number of dimensions and CURTOL to be 0
    • Start a loop:
      • Get a new index value
      • Pop the new maximum into CURMAX
      • Make sure the index value isn’t too big
      • Multiply CURTOL by CURMAX
      • Add the index to CURTOL
      • Reduce NUMDIM by 1
      • LOOP BACK if NUMDIM isn’t yet 0
    • Set an OFFSET as CURTOL*4 (which is the VALTYP for extended).
    2795
     ↳ GETDEF
    LD B,A47
    Zero Register B
    2796
    LD C,A4F
    Zero Register C. Now BC = 0 = CURTOL
    2797
    LD A,(HL)7E
    Load Register A with the number of dimensions for the array at the location of the array variables pointer in HL
    2798
    INC HL23
    Bump the value of the array variables pointer in HL to one entry past the number of dimensions
    2799
    LD D,0E1H16 E1
    Z-80 Trick to hide the next instruction (POP HL) if proceeding downward
    279A
     ↳ INLPNM
    POP HLE1
    Get the array variables pointer from the STACK and put it in HL
    279B
    LD E,(HL)5E
    Next, we want DE to be the maximum for the current index entry, so first load Register E with the LSB of the subscript limit at the location of the array variables pointer in HL
    279C
    INC HL23
    Bump the value of the array variables pointer in HL
    279D
    LD D,(HL)56
    Load Register D with the MSB of the subscript limit at the location of the array variables pointer in HL
    279E
    INC HL23
    Bump the value of the array variables pointer in HL
    279F
    EX (SP),HLE3
    Swap HL and (SP) so that HL now points to the currrent index, and the pointer to the array variable goes to the top of the STACK
    27A0
    PUSH AFF5
    Save the number of dimensions for the array in Register A to the STACK
    27A1
    Now we need to compare the subscript limit in DE with the subscript for the array in HL, so we call the COMPARE DE:HL routine at RST 10H.

    The RST 10H routine parses the characters starting at HL+1 for the first non-SPACE,non-09H,non-0BH character it finds. On exit, Register A will hold that character, and the C FLAG is set if its alphabetic, and NC FLAG if its alphanumeric. All strings must have a 00H at the end.
    27A2-27A4
    If the current inex is too big, then we need to throw a ?BS ERROR via a JUMP to 273DH
    27A5-27A7
    CURTOL = CURTOL * the current maximum subscript
    27A8
    ADD HL,DE19
    Add the index to CURTOL
    27A9
    POP AFF1
    Get the number of dimensions for the array from the STACK and put it in Register A
    27AA
    DEC A3D
    We checked one, so cross one off the list and see if there are anymore dimensions to be evaluated
    27AB
    LD B,H44
    Load Register B with the MSB of the subscript pointer in Register H
    27AC
    LD C,L4D
    Load Register C with the LSB of the subscript pointer in Register L. Now BC = CURTOL for the start of the next loop.
    27AD-27AE
    Loop back to 279AH until all of the subscripts have been evaluated
    27AF-27B1
    LD A,(40AFH)LD A,(VALTYP)3A AF 40
    Get the number type flag for the current array; which also doubles for how big the values are
    NOTE: 40AFH holds Current number type flag
    27B2
    27B3
    LD B,H
    LD C,L44
    We are going to need to multiply by THREE, so we need to save the original value into BC as well.
    27B4
    ADD HL,HL29
    Multiply the subscript pointer in HL by two
    27B5-27B6
    SUB 04HD6 04
    Check the value of the number type flag in Register A because we would be done if we have an integer or a string.
    27B7-27B8
    Jump forward to 27BDH if the current number type is an integer or string
    27B9
    ADD HL,HL29
    It isn’t an integer or a string so once again multiply the subscript pointer in HL by two (so now it is multiplied by 4)
    27BA-27BB
    Jump forward to 27C2H if the current number type is single precision as we then have enough bytes.
    27BC
    ADD HL,HL29
    It must be double precision, so once again multiply the subscript pointer in HL by two (so now it is multiplied by 8)
    27BD
     ↳ DMLVAL
    OR AB7
    Set the flags
    27BE-27C0
    Jump forward to 27C2H if the current number type isn’t a string
    27C1
    ADD HL,BC09
    The current number type is a string so add the value of the original subscript pointer in BC to the subscript pointer in HL
    27C2
     ↳ DONMUL
    POP BCC1
    Get the value of the array variables pointer from the STACK and put it in BC
    27C3
    ADD HL,BC09
    Add the value of the array variables pointer in BC to the subscript pointer in HL to get the place where the size value needs to be stored
    27C4
    EX DE,HLEB
    Load DE with the variable pointer in HL
    27C5-27C7
     ↳ FINNNOW
    LD HL,(40F3H)LD HL,(TEMP2)2A F3 40
    Get the value of the current BASIC program pointer and put it in HL.
    Note: 40F3H-40F4H is a temporary storage location
    27C8
    RETC9
    RETurn to CALLer

    27C9-27D3 – LEVEL II BASIC MEM ROUTINE – “MEM”

    This is the RETURN AMOUNT OF FREE MEMORY routine at 27C9H which computes the amount of memory remaining between the end of the variable list and the end of the STACK and puts the result in ACCumulator as a SINGLE PRECISION number.
    27C9
     ↳ MEM
    XOR AAF
    Zero Register A and the status flags
    27CA
    PUSH HLE5
    Save the value of the current BASIC program pointer in HL to the STACK
    27CB-27CD
    LD (40AFH),ALD (VALTYP),A32 AF 40
    Zero the number type flag.
    NOTE: 40AFH holds Current number type flag
    27CE-27D0
    Determine how much space there is via a GOSUB to the FRE routine at 27D4H
    27D1
    POP HLE1
    Get the value of the current BASIC program pointer from the STACK and put it in HL
    27D2
    We need the next character in the BASIC program so call the EXAMINE NEXT SYMBOL routine at RST 10H.

    The RST 10H routine parses the characters starting at HL+1 for the first non-SPACE,non-09H,non-0BH character it finds. On exit, Register A will hold that character, and the C FLAG is set if its alphabetic, and NC FLAG if its alphanumeric. All strings must have a 00H at the end.
    27D3
    RETC9
    Return to BASIC

    27D4-27F4 – LEVEL II BASIC FRE ROUTINE – “FRE”

    27D4-27D6
     ↳ FRE
    LD HL,(40FDH)LD HL,(STREND)2A FD 40
    Load HL with the start of free memory pointer (which is also the end of the variable and text space).
    NOTE: 40FDH-40FEH holds Free memory pointer
    27D7
    EX DE,HLEB
    Load DE with the value of the free memory pointer in HL for subtraction
    27D8-27DA
    LD HL,0000H21 00 00
    Zero HL
    27DB
    ADD HL,SP39
    Add the value in HL (which is zero) to the current value of the STACK pointer so that the STACK pointer is now in HL
    27DC
    We need to check the value of the current number type flag, so we call the TEST DATA MODE routine at RST 20H.
    NOTE: The RST 20H routine determines the type of the current value in ACCumulator and returns a combination of STATUS flags and unique numeric values in the A Register according to the data mode flag (40AFH). The results are returned as follows:
    • Integer = NZ/C/M/E and A is -1
    • String = Z/C/P/E and A is 0
    • Single Precision = NZ/C/P/O and A is 1
    • and Double Precision is NZ/NC/P/E and A is 5.
    27DD-27DE
    If that test shows we do NOT have a STRING (meaning this was really a MEM call, jump to forward to 27ECH
    27DF-27E1
    Free up the argument and set up to give some free string space
    27E2-27E1
    Do garbage collection to free up space
    27E5-27E7
    LD HL,(40A0H)LD HL,(STKTOP)2A A0 40
    Load HL with the start of string space pointer / bottom of free space.
    NOTE: 40A0H-40A1H holds the start of string space pointer
    27E8
    EX DE,HLEB
    Load DE with the start of string space pointer in HL
    27E9-27EB
    LD HL,(40D6H)LD HL,(FRETOP)2A D6 40
    Load HL with the next available location in string space pointer / top of free space.
    NOTE: 40D6H-40D7H holds the next available location in string space pointer
    The next routine subtracts DE from HL and then floats the result leaving it in FAC.
    27EC
     ↳ GIVDBL
    LD A,L7D
    Prepare to do HL = HL – DE. First, load Register A with the LSB of the next available location in string space pointer in Register L
    27ED
    SUB E93
    Subtract the LSB of the start of string space pointer in Register E from the LSB of the next available location in string space pointer in Register A
    27EE
    LD L,A6F
    Load Register L with the LSB of the amount of string space remaining in Register A
    27EF
    LD A,H7C
    Load Register A with the MSB of the next available location in string space pointer in Register H
    27F0
    SBC A,D9A
    Subtract the MSB of the string space pointer in Register D from the MSB of the next available location of string space pointer in Register A
    27F1
    LD H,A67
    Load Register H with the MSB of the amount of string space remaining in Register A
    27F2-27F4
    Jump to 0C66H to convert the difference between HL and DE to single precision and then RETurn out of the routine

    27F5-27FD – LEVEL II BASIC POS( ROUTINE – “POS”

    27F5-27F7
     ↳ POS
    LD A,(40A6H)LD A,(TTYPOS)3A A6 40
    Load Register A with the current cursor line position.
    Note: 40A6H holds the current cursor line position
    27F8
     ↳ SNGFLT
    LD L,A6F
    Load Register L with the value of the current cursor line position in Register A.
    27F9
    XOR AAF
    Zero Register A
    27FA
     ↳ GIVINT
    LD H,A67
    Load Register H with zero, so now HL is 00 + cursor position
    27FB-27FD
    Jump to 0A9AH to make A an unsigned integer

    27FE-2818 – LEVEL II BASIC USR(x) ROUTINE – “USRFN”

    27FE-2780
     ↳ USRFN
    CALL 41A9HCALL USROUTCD A9 41
    GOSUB to DOS to see if DOS wants to deal with this
    2801
    We need the next character so call the EXAMINE NEXT SYMBOL routine at RST 10H.

    The RST 10H routine parses the characters starting at HL+1 for the first non-SPACE,non-09H,non-0BH character it finds. On exit, Register A will hold that character, and the C FLAG is set if its alphabetic, and NC FLAG if its alphanumeric. All strings must have a 00H at the end.
    2802-2804
    GOSUB to 252CH to evaluate the expression at the location of the current BASIC program pointer in HL and return with the result in ACCumulator
    2805
    PUSH HLE5
    Save the value of the current BASIC program pointer in HL (=the address of the next element in the code string) to the STACK
    2806-2808
    LD HL,0890HLD HL,POPHRT21 90 08
    Load HL with the return address of 0890H which will clear the STACK before returning to BASIC
    2809
    PUSH HLE5
    Save the value of the return address in HL to the STACK
    280A-280C
    LD A,(40AFH)LD A,(VALTYP)3A AF 40
    Load Register A with the value of the current number type flag for the argument provided.
    Note: 40AFH holds Current number type flag
    280D
    PUSH AFF5
    Save the value of the current number type flag in Register A.
    (02=INT, 03=STR, 04=SNG, 08=DBL)
    280E-280F
    CP 03HFE 03
    Check to see if the current value is a string. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
    2810-2812
    If the current result is a string then GOSUB to 29DAH to get the free the space and get the string address into HL
    2813
    POP AFF1
    Restore the number type flag into Register A
    2814
    EX DE,HLEB
    Load DE with the (possible) value of the pointer to the string (in HL)
    2815-2817
    LD HL,(408EH)2A 8E 40
    Load HL with the starting address of the machine language subroutine. In TRSDOS, 408EH is a variable called MAXFIL which holds the value the user entered when answering the prompted “FILES?” question. This would definitely NOT be the right address under DOS.
    2818
    JP (HL)E9
    Jump to (HL) to run the routine

    2819-2827 – CONVERSION ROUTINE– “DOCNVF”

    Usually called by LET to convert the result of arithmetic routines to the proper destination type.
    2819
     ↳ DOCNVF
    PUSH HLE5
    Save the pointer to the current character in the BASIC program being evaluated to the STACK
    281A-281B
    AND 07HE6 07
    Mask the value of the current number type flag in Register A to force the formula type to conform to the variable type that it is assigned to
    281C-281E
    LD HL,18A1HLD HL,FRCTBL21 A1 18
    Load HL with the address of the arithmetic conversion routines
    281F
    LD C,A4F
    Load Register C with the value of the number type flag in Register A.
    (02=INT, 03=STR, 04=SNG, 08=DBL)
    2820-2821
    LD B,00H06 00
    Zero Register B. Now BC holds 00 + type and will be the two byte offset into the table
    2822
    ADD HL,BC09
    Add the offset (of BC) to the base arithmetic conversion routines, to find the right jump point
    2823-2825
    GOSUB to 2586H to convert the current result in REG l to its proper number type
    2826
    POP HLE1
    Restore the pointer to the current character in the BASIC program being evaluated to HL
    2827
    RETC9
    RETurn to CALLer

    2828-2835 – Routine to see if we are in DIRECT MODE and ERROR OUT if so– “ERRDIR”

    Usually called from the INPUT routine. On entry HL has the current line number in binary.
    2828
     ↳ ERRDIR
    PUSH HLE5
    Save whatever was in HL to the STACK
    2829-282B
    LD HL,(40A2H)LD HL,(CURLIN)2A A2 40
    Load HL with the value of the current BASIC line number (which is stored at 40A2H-40A3H).
    282C
    INC HL23
    Bump the value of the current BASIC line number in HL to enable us to test for a direct statement. Direct is 65535 so bumping by 1 will give us a ZERo
    282D
    LD A,H7C
    Load Register A with the MSB of the current BASIC line number in Register H
    282E
    OR LB5
    Combine the LSB of the current BASIC line number in Register L with the MSB of the current BASIC line number in Register A. If H and L are both ZERO then the Z FLAG will be set.
    282F
    POP HLE1
    Restore whatever was in HL on entry back into HL
    2830
    RET NZC0
    Return if there is a line number (i.e., this isn’t the command mode) and otherwise fall through to the ?ID ERROR routine

    2831 – ID ERROR entry point.

    2831-2832
    LD E,16H1E 16
    Load Register E with the ?ID ERROR code
    2833-2835
    Display an ?ID ERROR if this is the command mode

    2836-2856 – STRING ROUTINE – STR$ logic– “STR$”

    2836-2838
     ↳ STR$
    GOSUB to 0FBDH to convert the current result in ACCumulator to an ASCII string
    2839-283B
     ↳ STR$1
    Scan it and turn it into a string (make a temporary string work area entry)
    283C-283E
    Load HL with the string’s VARPTR and free up the temp
    283F-2841
    LD BC,2A2BHLD BC,FINBCK01 2B 2A
    Load BC with a return address of 2A2BH (which cleans the STACK and then jumps to 2884H)
    2842
    PUSH BCC5
    Save the value of the return address in BC to the STACK
    The next routine, STRCPY, creates a copy of the string pointed to by Register Pair HL. On exit, DE points to DSCTMP which has the string information.
    2843
     ↳ STRCPY
    LD A,(HL)7E
    Load Register A with the string’s length at the location of the string’s VARPTR in HL
    2844
    INC HL23
    Bump the value of the string’s VARPTR in HL
    2845
    PUSH HLE5
    Save the value of the string’s VARPTR in HL to the STACK
    2846-2848
    GOSUB to 28BFH to test the remaining string area to make sure that the new string will fit
    2849
    POP HLE1
    Reload HL with the string’s VARPTR. This is the destination to where the string should be copied.
    284A
    LD C,(HL)4E
    Load Register C with the LSB of the string’s address at the location of the string’s VARPTR in HL
    284B
    INC HL23
    Bump the value of the string’s VARPTR in HL
    284C
    LD B,(HL)46
    Load Register B with the MSB of the string’s address at the location of the string’s VARPTR in HL
    284D-284F
    GOSUB to 285AH to save the string’s length and the string’s address at 40D3H, so as to set up DSCTMP
    2850
    PUSH HLE5
    Save the pointer to STRAD2 (which is 40D3H) to the STACK
    2851
    LD L,A6F
    Load Register L with the string’s length (from Register A)
    2852-2854
    GOSUB to 29CEH to move L characters from the temp area (of BC) to the string data area (in DE)
    2855
    POP DED1
    Restore the pointer to DSCTMP (40D3H) into Register Pair DE
    2856
    RETC9
    RETurn to CALLer

    2857-2864 – STRING ROUTINE– “STRINI”

    2857-2859
     ↳ STRINI
    GOSUB to 28BFH to make sure that there is enough string space remaining for the string length of Register A characters. Get the address of the next string area in DE. Then save A and DE at 40D3H-40D5H
    285A
     ↳ STRAD2
    LD HL,40D3HLD HL,DSCTMP21 D3 40
    Load HL with the address of the temporary string parameter storage area.
    Note: 40D3H-40D5H holds Used for temporary string VARPTR’s
    285D
     ↳ STRAD1
    PUSH HLE5
    Save the address of the temporary string parameter area in HL to the STACK
    285E
    LD (HL),A77
    Save the string’s length in Register A at the location of the temporary string parameter storage pointer in HL
    285F
     ↳ PUTDEI
    INC HL23
    The next instructions are to set up DE to be the pointer to free space. First, bump the value of the temporary string parameter storage pointer in HL
    2860
    LD (HL),E73
    Save the LSB of the string’s address in Register E at the location of the temporary string parameter storage pointer in HL
    2861
    INC HL23
    Bump the value of the temporary string parameter storage pointer in HL
    2862
    LD (HL),D72
    Save the MSB of the string’s address in Register D at the location of the temporary string parameter storage pointer in HL
    2863
    POP HLE1
    Get the address of the temporary string parameter storage area from the STACK and put it in HL
    2864
    RETC9
    RETurn to CALLer

    2865-28A5 – STRING ROUTINE– “STRLIT”

    STRLT2 takes the string literal whose first character is pointed by HL+1 and builds a descriptor for it. Leading quotes should be skipped before the CALL to this routine.

    The descriptor is initially built in DSCTMP, but PUTNEW transfers it into a temporary RAM area and leaves a pointer at the temporary in FACLO.

    All characters other than zero (that terminate the string) should be set up in Registers B and D. If the terminator is a quote, the quote is skipped over.

    On EXIT, the character after the string literal is pointed to by Register Pair HL and is in Register A. No flags are set.

    2865
     ↳ STRLIT
    DEC HL2B
    Decrement the value of the current BASIC program pointer in HL
    2866-2867
     ↳ STRLTI
    LD B,22H06 22
    Load Register B with a (which is really the end of the quote search character)
    2868
     ↳ STRLT3
    LD D,B50
    Load Register D with a (which is really the ending search character)
    2869
     ↳ STRLT2
    PUSH HLE5
    Save the address of the current BASIC program pointer in HL to the STACK. This is ALSO the pointer to the start of the literal string being worked on.
    286A-286B
    LD C,0FFH0E FF
    Load Register C with a -1
    286C
     ↳ STRGET
    INC HL23
    Bump the value of the current BASIC program pointer in HL to skip over that initial
    286D
    LD A,(HL)7E
    Load Register A with the character at the location of the current BASIC program pointer in HL
    286E
    INC C0C
    Bump the counter in Register C
    286F
    OR AB7
    Check to see if the character at the location of the current BASIC program pointer in Register A is an end of the BASIC line character
    2870-2871
    Jump to 2878H if the character at the location of the current BASIC program pointer in Register A is an end of the BASIC line character
    2872
    CP DBA
    Check to see if the character at the location of the current BASIC program pointer in Register A is the same as the terminating character in Register D. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
    2873-2874
    Jump to 2878H if the character at the location of the current BASIC program pointer in Register A is the same as the terminating character in Register D
    2875
    CP BB8
    Check to see if the character at the location of the current BASIC program pointer in Register A is the same at the terminating character in Register B. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
    2876-2877
    Loop back to 286CH if the character at the location of the current BASIC program pointer in Register A isn’t the same as the terminating character in Register B or D
    2878-2879
     ↳ STRFIN
    CP 22HFE 22
    Check to see if the character at the location of the current BASIC program pointer in Register A is a quote. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
    287A-287C
    If it was a quote, then GOSUB to 1D78H to bump the value of the current BASIC program pointer in HL until it points to the next character (i.e., skip the quote)
    287D
    EX (SP),HLE3
    Exchange the value of the current BASIC program pointer in HL with the string’s address to the STACK
    287E
    INC HL23
    Bump the string’s address in HL until it points to the first character of the string
    287F
    EX DE,HLEB
    Load DE with the temporary pointer string’s address in HL
    2880
    LD A,C79
    Load Register A with the string’s length from Register C
    2881-2883
    GOSUB to 285AH to save the string’s length and the string’s address into 40D3H (i.e., DSCTMP)
    2884-2886
     ↳ PUTNEW
    LD DE,40D3HLD DE,DSCTMP11 D3 40
    Load DE with the address of the string parameter storage area.
    Note: 40D3H-40D5H holds Used for temporary string VARPTR’s
    2887-2888
    LD A,D5H3E D5
    This seems to be garbage, but 2888H is a JUMP point in DOS Basic to process a new string in the DEF FN routine. When JUMPed to 2888H, a PUSH DE is processed
    2888
     ↳ PUTTMP
    PUSH DED5
    Save a pointer to the stat of the string to the STACK
    2889-288B
    LD HL,(40B3H)LD HL,(TEMPPT)2A B3 40
    Load HL with the first avaialble free location in the temporary string work area in HL. This will serve as the string’s VARPTR in ACCumulator.
    Note: 40B3H-40B4H holds the next available location in the temporary string work area pointer
    288C-288E
    LD (4121H),HLLD (FACLO),HL22 21 41
    Save the value of the next available location in the temporary string work area in HL. This is where the result string descriptor will be
    288F-2890
    LD A,03H3E 03
    Load Register A with the string number type flag
    2891-2893
    LD (40AFH),ALD (VALTYP),A32 AF 40
    Save the value in Register A as the current number type flag.
    Note: 40AFH holds current number type flag
    2894-2896
    Move the value into the temporary string work area in HL
    2897-2899
    LD DE,40D6HLD DE,FRETOP11 D6 40
    Depending on how we got here, DE will be different. If the jump was into PUTTMP, then DE will NOT equal FRETOP.
    289A
    We need to do some checking, as FRETOP is just beyond the temporary string storage areas, so if TEMPPT points to it, then there are no free temporary storage areas left! To do this we check to see if the updated temporary string work area location in HL isn’t greater than the ending address of the temporary string work area in DE, so we call the COMPARE DE:HL routine at RST 10H.

    The RST 10H routine parses the characters starting at HL+1 for the first non-SPACE,non-09H,non-0BH character it finds. On exit, Register A will hold that character, and the C FLAG is set if its alphabetic, and NC FLAG if its alphanumeric. All strings must have a 00H at the end.
    289B-289D
    LD (40B3H),HLLD (TEMPPT),HL22 B3 40
    Save the new temporary string pointer in HL as the next available location in the temporary string work area.
    Note: 40B3H-40B4H holds the next available location in the temporary string work area pointer
    289E
    POP HLE1
    Get the value of the current BASIC program pointer from the STACK and put it in HL
    289F
    LD A,(HL)7E
    Load Register A with the character at the location of the current BASIC program pointer in HL
    28A0
    RET NZC0
    Return if the updated temporary string work area location wasn’t beyond the end of the temporary string work area (meaning it overflowed, because if it overflowed .)

    28A1 – ST ERROR entry point.

    28A1-28A2
    LD E,1EH1E 1E
    Load Register E with a ?ST ERROR code
    28A3-28A5
    Display a ?ST ERROR message if the temporary string work area has overflowed

    28A6-28BE – DISPLAY MESSAGE ROUTINE– “STROUI”

    According to the original ROM source, this routine will print the string pointed to by Register Pair HL. The string MUST be terminated by a 00H. If the string exists below DSCTMP, then it is copied into string space first.
    28A6
     ↳ STROUI

    INC HL23
    Bump the value of the current BASIC program pointer in HL
    EXAMPLE: Suppose that we have the following symbolic setup:
    TITL DEFM ‘INSIDE LEVEL II’
    DEFB 0
    Then, the instructions:
    LD HL,TITL
    CALL 28A7H
    CALL STROUT

    will cause “INSIDE LEVEL II” to be displayed at the current cursor position and the cursor position to be updated.

  • NOTE: If the subroutine at 28A7H is used by an assembly language program that is itself entered by a USR call, the return from the assembly language program may encounter the embarrassment of a TM error, with control passing to the Level II monitor. This occurs because the subroutine at 28A7H leaves a 3 in location 40AFH, while the USR structure requires a 2 in 40AFH upon returning. The malady is cured by storing a 2 in 40AFH before returning, or by jumping to 0A9AH instead of executing the simple RET. The problem would not occur in the first place if the assembly language program returns the value of an integer variable to the BASIC program, and it might not occur if some other ROM routine is called after the subroutine at 28A7H and before returning – if the other subroutine produces an integer output. DISK SYSTEM CAUTION: See the DISK SYSTEM CAUTION of Section 8.1 regarding the exits to DISK BASIC from the subroutine at 28A7H.
  • 28A7-28A9H
    “STROUT”
    Go build a temporary string work area entry for the message at FACLOthe location of the current BASIC program pointer in HL
    If the routine entry is at STRPRT, then it just prints the string whose descriptor is held in FACLO
    28AA-28AC
     ↳ STRPRT
    GOSUB to 29DAH to build a temporary string work area entry for the message pointed to by FACLO
    28AD-28AF
    Go get the string’s length in Register D and the string’s address in BC
    28B0
    INC D14
    Bump the value of the string’s length in Register D in preparation for the following loop which starts with a DEC D
    28B1
     ↳ STRPR2
    DEC D15
    Top of a loop. Decrement the value of the string’s length in Register D
    28B2
    RET ZC8
    Return if all of the characters in the string have been sent to the current output device.
    28B3
    LD A,(BC)0A
    Load Register A with the character at the location of the string pointer in BC
    28B4-28B6
    Go send the character in Register A to the current output device
    28B7-28B8
    CP 0DHFE 0D
    Check to see if the character in Register A is a CARRIAGE RETURN. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
    28B9-28BB
    Jump to 2103H if the character in Register A is a carriage return
    28BC
    INC BC03
    Bump the value of the string pointer in BC
    28BD-28BE
    Loop until all of the characters in the string have been sent to the current output device

    28BF-28D9 – STRING ROUTINE– “GETSPA”

    This routine will get space for a character string, and it might force garbage collection as well. The number of characters is in Register A. On exit, DE will point to the string, but if it could not allocate space, then an ?OS ERROR is thrown instead.
    28BF
     ↳ GETSPA
    OR AB7
    Make sure A is not zero. A ZERO FLAG will signal that garbage collection has happened
    28C0-28C1
    LD C,0F1H0E F1
    Z-80 Trick. If passing through, the C just changes and the POP AF which follows is ignored.
    28C1
     ↳ TRYGI2
    POP AFF1
    Get the string’s length from the STACK and put it in Register A
    28C2
    PUSH AFF5
    Save the length of the string in Register A to the STACK
    28C3-28C5
    LD HL,(40A0H)LD HL,(STKTOP)2A A0 40
    Load HL with the poinmter to the bottom of the string space. 40A0H-40A1H holds the start of string space pointer
    28C6
    EX DE,HLEB
    Move the bottom of the string space pointer into DE. We don’t care what happens to HL
    28C7-28C9
    LD HL,(40D6H)LD HL,(FRETOP)2A D6 40
    Load HL with the pointer to the TOP of free space.
    Note: 40D6H-40D7H holds the next available location in string space pointer
    28CA
    CPL2F
    Complement the string’s length in Register A so that it is negative
    28CB
    LD C,A4F
    The next two instructions put the negative of the number of characters into Register Pair BC. First, load Register C with the negative string’s length in Register A
    28CC-28CD
    LD B,0FFH06 FF
    Load Register B with a -1 so that BC will be the negative length of the string
    28CE
    ADD HL,BC09
    Add the negative string’s length in BC to the top of free space pointer in HL
    28CF
    INC HL23
    Bump the value of the adjusted next available location in string space pointer in HL
    28D0
    We need to make sure there is enough room for the string, so we need to compare these by checking to see if the adjusted next available location in string space pointer in HL is less than the start of string space pointer in DE, so we call the COMPARE DE:HL routine at RST 10H.

    The RST 10H routine parses the characters starting at HL+1 for the first non-SPACE,non-09H,non-0BH character it finds. On exit, Register A will hold that character, and the C FLAG is set if its alphabetic, and NC FLAG if its alphanumeric. All strings must have a 00H at the end.
    28D1-28D2
    If the CARRY FLAG is set then we do not have enough room for the string, so lets JUMP forward to 28DAH to do some garbae collection.
    28D3-28D5
    LD (40D6H),HLLD (FRETOP),HL22 D6 40
    Save the value in HL as new bottom of MEMORY
    28D6
    INC HL23
    Bump the value of HL to point to the string
    28D7
    EX DE,HLEB
    Load DE with the pointer to the string
    28D8
     ↳ PPSWRT
    POP AFF1
    Get the string’s length from the STACK and put it in Register A
    28D9
    RETC9
    RETurn to CALLer

    28DA-298E – STRING ROUTINE – “GARBAG”

    28DA
     ↳ GARBAG
    POP AFF1
    Get the garbage collection code which was PUSHed
    28DB-28DC
    LD E,1AH1E 1A
    Load Register E with an ?OS ERROR code
    28DD-28DF
    If the Z FLAG is set, then we already tried garbage collection and still have no RAM left for the string, so display a ?OS ERROR if there isn’t enough string space available for the string and we had already reorganized string space
    28E0
    CP ABF
    Otherwise, set the flags to say that we have already done the garbage collection. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
    28E1
    PUSH AFF5
    Save the garbage collection flag to the STACK
    28E2-28E4
    LD BC,28C1HLD BC,TRYGI201 C1 28
    Load BC with a return address of 28C1H (which would retry allocation)
    28E5
    PUSH BCC5
    Save that return address to the STACK
    28E6-28E8
     ↳ GARBA2
    LD HL,(40B1H)LD HL,(MEMSIZ)2A B1 40
    Load HL with the top of memory pointer.
    Note: 40B1H-40B2H holds MEMORY SIZE? pointer
    28E9-28EB
     ↳ FNDVAR
    LD (40D6H),HLLD (FRETOP),HL22 D6 40
    Save the top of BASIC memory pointer in HL as the next available location in string space pointer.
    Note: 40D6H-40D7H holds the next available location in string space pointer
    28EC-28EE
    LD HL,0000H21 00 00
    Zero HL
    28EF
    PUSH HLE5
    Save the value in HL to the STACK to indicate that we didn’t find a variable on this pass
    28F0-28F2
    LD HL,(40A0H)LD HL,(STKTOP)2A A0 40
    Load HL with the start of string space pointer to force DVARS to ignore strings in the program text (literals and data).
    NOTE: 40A0H-40A1H holds the start of string space pointer
    28F3
    PUSH HLE5
    Save high address (start of string space pointer in HL) to the STACK
    28F4-28F6
    LD HL,40B5HLD HL,TEMPST21 B5 40
    Load HL with the start of the temporary string work area pointer.
    Note: 40B5H-40D2H holds Temporary string work area
    28F7
    “TVAR”
    EX DE,HLEB
    Load DE with the start of the temporary string work area pointer in HL
    28F8-28FA
    LD HL,(40B3H)LD HL,(TEMPPT)2A B3 40
    Load HL with the next available location in the temporary string work area pointer.
    NOTE: 40B3H-40B4H holds the next available location in the temporary string work area pointer
    28FB
    EX DE,HLEB
    Exchange the start of the temporary string work area pointer in DE with the next available location in the temporary string work area pointer in HL
    28FC
    We need to see if 40B3H is pointing to the first entry (40B5H) – if the start of the temporary string work area pointer in HL is the same as the next available location in the temporary string work area pointer, so we call the COMPARE DE:HL routine at RST 10H.

    The RST 10H routine parses the characters starting at HL+1 for the first non-SPACE,non-09H,non-0BH character it finds. On exit, Register A will hold that character, and the C FLAG is set if its alphabetic, and NC FLAG if its alphanumeric. All strings must have a 00H at the end.
    28FD-28FF
    LD BC,28F7HLD BC,TVAR01 F7 28
    Load BC with a return address of 28F7H
    2900-2902
    Jump to 294AH to do the temporary variable garbage collection if the temporary string work area isn’t empty
    2903
     ↳ SVARS
    LD HL,(40F9H)LD HL,(VARTAB)2A F9 40
    Load HL with the start of the simple variables pointer.
    NOTE: 40F9H-40FAH holds the starting address of the simple variable storage area
    2906
     ↳ SVAR
    EX DE,HLEB
    Load DE with the simple variables pointer in HL
    2907-2909
    LD HL,(40FBH)LD HL,(ARYTAB)2A FB 40
    Load HL with the start of the array variables pointer (which is also the end of the simple variables). 40FBH-40FCH holds the starting address of the BASIC array variable storage area
    290A
    EX DE,HLEB
    Swap DE and HL so that DE holds the end and HL holds the start.
    290B
    Now we need to check to see if the simple variables pointer in HL is the same as the array variables pointer in DE, so we call the COMPARE DE:HL routine at RST 10H.

    The RST 10H routine parses the characters starting at HL+1 for the first non-SPACE,non-09H,non-0BH character it finds. On exit, Register A will hold that character, and the C FLAG is set if its alphabetic, and NC FLAG if its alphanumeric. All strings must have a 00H at the end.
    290C-290D
    If the Z FLAG is set then we are at the end of the simple variable. If so, we then need to do the string type variables so we jump forward to 2921H.
    290E
    LD A,(HL)7E
    Load Register A with second character of the variable name
    290F
    INC HL23
    Bump the value of the simple variables pointer in HL
    2910
    INC HL23
    Bump the simple variables pointer in HL
    2911
    INC HL23
    Bump the value of the simple variables pointer in HL. HL should now point to the value of the variable.
    2912-2913
    CP 03HFE 03
    Check to see if the variable at the location of the simple variables pointer is a string. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
    2914-2915
    Jump to 291AH if the variable at the location of the simple variables pointer in HL isn’t a string
    2916-2918
    GOSUB to 294BH to do collect the string
    2919
    XOR AAF
    Zero Register A to indicate that we should not be skipping anything else.
    291A
     ↳ SKPVAR
    LD E,A5F
    Zero Register E
    291B-291C
    LD D,00H16 00
    Zero Register D. Now DE should be the number of characters to skip.
    291D
    ADD HL,DE19
    Add the number of characters to skip (held in DE) to the simple variables pointer in HL
    291E-291F
    Loop back to 2906H until all of the simple variables have been checked
    2920
     ↳ ARYVA2
    POP BCC1
    Clean up the STACK
    2921
     ↳ ARYVAR
    EX DE,HLEB
    Load DE with the value of the array variables pointer (ARTVAR) in HL
    2922-2924
    LD HL,(40FDH)LD HL,(STREND)2A FD 40
    Load HL with the end of the arrays / start of free memory pointer.
    Note: 40FDH-40FEH holds Free memory pointer
    2925
    EX DE,HLEB
    Exchange the value of the array variables pointer in DE with the value of the free memory pointer in HL
    2926
    We need to see if we are donee with arrays, so we check to see if the array variables pointer in HL is the same as the free memory pointer in DE, so we call the COMPARE DE:HL routine at RST 10H.

    The RST 10H routine parses the characters starting at HL+1 for the first non-SPACE,non-09H,non-0BH character it finds. On exit, Register A will hold that character, and the C FLAG is set if its alphabetic, and NC FLAG if its alphanumeric. All strings must have a 00H at the end.
    2927-2929
    Jump if the array variables pointer in Register HL is the same as the start of the free memory pointer in DE
    292A
    LD A,(HL)7E
    Load Register A with the number type flag at the location of the array variables pointer in HL
    292B
    INC HL23
    Bump the value of the array variables pointer in HL
    292C-292E
    Get the length of the array into Register Pair BC via a CALL to 09C2H (which loads a SINGLE PRECISION value pointed to by HL into Register Pairs BC and DE)
    292F
    PUSH HLE5
    Save the pointer to the DIMS to the STACK
    2930
    ADD HL,BC09
    Add the value of the offset to the next array in BC to the value of the array variables pointer in HL
    2931-2932
    CP 03HFE 03
    Check to see if the array being examined is a string. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
    2933-2934
    If the array being examined isn’t a string then skip it via a JUMP to 2920H
    2935-2937
    LD (40D8H),HLLD (TEMP3),HL22 D8 40
    Save the address of the end of the array being examined.
    Note: 40D8H-40D9H holds Temporary storage location
    2938
    POP HLE1
    Get the value of the array variables pointer from the STACK and put it in HL
    2939
    LD C,(HL)4E
    Load Register C with the number of subscripts for the array at the location of the array variables pointer in HL
    293A-293B
    LD B,00H06 00
    Zero Register B so that BC holds the number of dimensions
    293C
    ADD HL,BC09
    Add the number of subscripts in the array in BC to the value of the array variables pointer in HL
    293D
    ADD HL,BC09
    Add the number of subscripts in the array in BC to the value of the array variables pointer in HL. Now we should be past the DIMs because we added twice the DIMs and they are 2 bytes each.
    293E
    INC HL23
    Bump the value of the array variables pointer in HL one more time to account for #DIMs.
    293F
     ↳ ARYSTR
    EX DE,HLEB
    Load DE with the value of the current position in the array variables pointer in HL
    2940-2942
    LD HL,(40D8H)LD HL,(TEMP3)2A D8 40
    Load HL with the address of the end of this array.
    Note: 40D8H-40D9H holds Temporary storage location
    2943
    EX DE,HLEB
    Swap DE and HL so that HL now points to the current position
    2944
    We need to test for the end of the array space so we need to check to see if the array variables pointer in HL is the same as the address of the next array in DE, so we call the COMPARE DE:HL routine at RST 10H.

    The RST 10H routine parses the characters starting at HL+1 for the first non-SPACE,non-09H,non-0BH character it finds. On exit, Register A will hold that character, and the C FLAG is set if its alphabetic, and NC FLAG if its alphanumeric. All strings must have a 00H at the end.
    2945-2946
    If the Z FLAG is set then we are at the end of an array so JUMP to 2921H to try the next array
    2947-2948
    LD BC,293FHLD BC,ARYSTR01 3F 29
    Load BC with a return address of 293FH
    294A
     ↳ DVAR2
    PUSH BCC5
    Save the value in BC to the STACK
    294B
     ↳ DVAR and DVARS
    XOR AAF
    Zero Register A so we can test for a null string
    294C
    OR (HL)B6
    Load Register A with the length of the string at the location of the array variables pointer in HL
    294D
    INC HL23
    Bump the value of the array variables pointer in HL
    294E
    LD E,(HL)5E
    Load Register E with the LSB of the string’s address at the location of the array variables pointer in HL
    294F
    INC HL23
    Bump the value of the array variables pointer in HL
    2950
    LD D,(HL)56
    Load Register D with the MSB of the string’s address at the location of the array variables pointer in HL. DE should now point to the value of the array.
    2951
    INC HL23
    Bump the value of the array variables pointer in HL
    2952
    RET ZC8
    Return if the string’s length in Register A is equal to zero
    2953
    2954
    LD B,H
    LD C,L44
    Let BC = HL
    2955-2957
    LD HL,(40D6H)LD HL,(FRETOP)2A D6 40
    Load HL with the location of the the top of string free space.
    NOTE: 40D6H-40D7H holds the next available location in string space pointer
    2958
    We need to see if this string’s pointer is LESS than the top of free string space by checking to see if the string’s address in DE is in string space, so we call the COMPARE DE:HL routine at RST 10H.

    The RST 10H routine parses the characters starting at HL+1 for the first non-SPACE,non-09H,non-0BH character it finds. On exit, Register A will hold that character, and the C FLAG is set if its alphabetic, and NC FLAG if its alphanumeric. All strings must have a 00H at the end.
    2959
    295A
    LD H,B
    LD L,C60
    Let HL = BC
    295B
    RET CD8
    If this string’s pointer is NOT less than the top of string free space, then there is no need to continue working on it, so RETurn
    295C
    POP HLE1
    Get the return address from the STACK and put it in HL
    295D
    EX (SP),HLE3
    Swap (SP) and HL so that the return address is back on the STACK and HL holds the maximum number seen
    295E
    Now we need to check to see if the string’s address in DE is below the start of string space pointer in HL, so we call the COMPARE DE:HL routine at RST 10H.

    The RST 10H routine parses the characters starting at HL+1 for the first non-SPACE,non-09H,non-0BH character it finds. On exit, Register A will hold that character, and the C FLAG is set if its alphabetic, and NC FLAG if its alphanumeric. All strings must have a 00H at the end.
    295F
    EX (SP),HLE3
    Swap (SP) and HL so that the return address is back in HL and the STACK holds the maximum number seen
    2960
    PUSH HLE5
    Save the return address in HL to the STACK
    2961
    2962
    LD H,B
    LD L,C60
    Let HL = BC
    2963
    RET NCD0
    Return if the string’s address in DE is below the string space pointer
    2964
    POP BCC1
    Get the return address from the STACK and put it in BC
    2965
    POP AFF1
    Clean up the STACK (remove the MAX SEEN)
    2966
    POP AFF1
    Clean up the STACK (remove the VARIABLE POINTER)
    2967
    PUSH HLE5
    Save the value of the array variables pointer in HL to the STACK
    2968
    PUSH DED5
    Save the new MAX pointer in DE to the STACK
    2969
    PUSH BCC5
    Save the value of the return address in BC to the STACK
    296A
    RETC9
    RETurn to CALLer
    If we are here, we have made one complete pass through the string variables.
    296B
     ↳ GRBPAS
    POP DED1
    Load DE with the address of the last string put into the temporary string work area (aka the MAX pointer)
    296C
    POP HLE1
    Get the variable pointer from the STACK and put it in HL
    296D
    LD A,L7D
    Load Register A with the LSB of the variable pointer in Register L
    296E
    OR HB4
    Combine the MSB of the temporary string work area pointer in Register H with the LSB of the temporary string work area pointer in Register A
    296F
    RET ZC8
    If HL=0 then we are at the end of the garbage collection, so return
    2970
    DEC HL2B
    Decrement the value of the temporary string work area pointer in HL, currently just past the string descriptor
    2971
    LD B,(HL)46
    Load Register B with the MSB of the string’s address at the location of the temporary string work area pointer in HL
    2972
    DEC HL2B
    Decrement the value of the temporary string work area pointer in HL
    2973
    LD C,(HL)4E
    Load Register C with the LSB of the string’s address at the location of the temporary string work area pointer in HL. BC will now point to the string data.
    2974
    PUSH HLE5
    Save the value of the temporary string work area pointer in HL to the STACK. This will be needed to update the pointer after the string is moved.
    2975
    DEC HL2B
    Decrement the value of the temporary string work area pointer in HL
    2976
    LD L,(HL)6E
    Load Register L with the string’s length at the location of the temporary string work area pointer in HL
    2977-2978
    LD H,00H26 00
    Zero Register H so that HL is now the string’s character count
    2979
    ADD HL,BC09
    Add the length of the string in HL to the string’s address in BC. HL now points just beyond the string.
    297A
    LD D,B50
    Load Register D with the MSB of the string’s address in Register B
    297B
    LD E,C59
    Load Register E with the LSB of the string’s address in Register C. DE now is the original pointer to the string.
    297C
    DEC HL2B
    Decrement the value of the string’s ending address in HL to avoid moving one beyond the string
    297D
    LD B,H44
    Load Register B with the MSB of the string’s ending address in Register H
    297E
    LD C,L4D
    Load Register C with the LSB of the string’s ending address in Register L. BC now points to the top of the string
    297F-2981
    LD HL,(40D6H)LD HL,(FRETOP)2A D6 40
    Load HL with the top of free space.
    NOTE: 40D6H-40D7H holds the next available location in string space pointer
    2982-2984
    Move the string from the temporary storage location to string space
    2985
    POP HLE1
    Get back the pointer to the description of the variable from the STACK and put it in HL
    2986
    LD (HL),C71
    Save the LSB of the string’s permanent address (held in Register C) to (HL)
    2987
    INC HL23
    Bump the value of the temporary string work area pointer in HL
    2988
    LD (HL),B70
    Save the MSB of the string’s permanent address (held in Register C) to (HL)
    2989
    LD L,C69
    Load Register L with the LSB of the string’s address in Register C
    298A
    LD H,B60
    Load Register H with the MSB of the string’s address in Register B. Register Pair HL will now be the new pointer to the string.
    298B
    DEC HL2B
    Decrement the string’s address in HL to adjust FRETOP
    298C-298E
    Jump to 28E9H to try to find the high again.

    298F-29C5 – STRING ADDITION ROUTINE – Concatenate two strings – “CAT”

    This routine concatenates two strings. The first is pointed to by FACLO and HL points to the character after the “+” sign in on the command line.
    298F
     ↳ CAT
    PUSH BCC5
    Save the precedence/operator value in BC to the STACK
    2990
    PUSH HLE5
    Save the value of the current BASIC program pointer in HL to the STACK
    2991-2993
    LD HL,(4121H)LD HL,(FACLO)2A 21 41
    Load HL with the first string’s VARPTR (from ACCumulator)
    2994
    EX (SP),HLE3
    Exchange the value of the first string’s VARPTR in HL with the value of the current BASIC program to the STACK
    2995-2997
    GOSUB to 249FH to evaluate the expression at the location of the current BASIC program pointer in HL
    2998
    EX (SP),HLE3
    Exchange the value of the current BASIC program pointer in HL with the value of the first string’s VARPTR to the STACK
    2999-299B
    Go make sure the current result in ACCumulator is a string
    299C
    LD A,(HL)7E
    Load Register A with the first string’s length at the location of the first string’s VARPTR in HL
    299D
    PUSH HLE5
    Save the value of the first string’s descriptor (VARPTR) in HL to the STACK
    299E-29A0
    LD HL,(4121H)LD HL,(FACLO)2A 21 41
    Load HL with the second string’s VARPTR in ACCumulator
    29A1
    PUSH HLE5
    Save the second string’s VARPTR in HL to the STACK
    29A2
    ADD A,(HL)86
    Add the length of the second string at the location of the second string’s VARPTR in HL to the length of the first string in Register A
    29A3-29A4
    LD E,1CH1E 1C
    Load Register E with a ?LS ERROR code
    in case the two string lengths are not less than 256.
    29A5-29A7
    Display a ?LS ERROR message if the combined lengths of the strings is greater than 255
    29A8-29AA
    Go make sure that there is enough string space for the new string
    29AB
    POP DED1
    Get the second string’s VARPTR from the STACK and put it in DE
    29AC-29AE
    Go update the temporary string work area
    29AF
    EX (SP),HLE3
    Exchange the second string’s VARPTR in HL with the first string’s VARPTR to the STACK
    29B0-29B2
    Go update the temporary string work area
    29B3
    PUSH HLE5
    Save the value of the first string’s VARPTR in HL to the STACK
    29B4-29B6
     ↳ INCSTR
    LD HL,(40D4H)LD HL,(DSCTMP+1)2A D4 40
    Load HL with the pointer to the first string’s address
    29B7
    EX DE,HLEB
    Load DE with the first string’s address in HL
    29B8-29BA
    Go move the first string to its temporary storage location
    29BB-29BD
    Go move the second string to its temporary storage location
    29BE-29C0
    LD HL,2349HLD HL,TSTOP21 49 23
    Load HL with the return address
    29C1
    EX (SP),HLE3
    Exchange the value of the return address in HL with the value of the current BASIC program pointer to the STACK
    29C2
    PUSH HLE5
    Save the value of the current BASIC program pointer in HL to the STACK
    29C3-29C5
    Jump to 2884H to RETurn to TSTOP

    29C6-29D6 – STRING ROUTINE – This will move strings using the STACK – “MOVINS”

    On entry, the STACK should have the count/source address and DE should have the destination address
    29C6
     ↳ MOVINS
    POP HLE1
    Load HL with the value of the return address to the STACK
    29C7
    EX (SP),HLE3
    Swap (SP) and HL so that the return address is now at the top of the STACK and the string’s descriptor/VARPTR is in Register Pair HL.

    29C8 – STRING MOVE ROUTINE
    On entry HL points to the string control block for the string to be moved, and DE contains the destination address. All registers are used. The string length and address are not moved. String control blocks have the format: X=String Length; ADDR = String Address.

    29C8
    LD A,(HL)7E
    Load Register A with the string’s length at the location of the string’s VARPTR in HL
    29C9
    INC HL23
    Bump the value of the string’s VARPTR in HL
    29CA
    LD C,(HL)4E
    Load Register C with the LSB of the string’s address at the location of the string’s VARPTR in HL
    29CB
    INC HL23
    Bump the value of the string’s VARPTR in HL
    29CC
    LD B,(HL)46
    Load Register B with the MSB of the string’s address at the location of the string’s VARPTR in HL. BC now points to the string data.
    29CD
    LD L,A6F
    Load Register L with the string’s length in Register A
    29CE
     ↳ MOVSTR
    INC L2C
    Increment the value of the string’s length in Register L in preparation for the next instruction which is a loop.
    29CF
     ↳ MOVLP
    DEC L2D
    Decrement the value of the string’s length in Register L
    29D0
    RET ZC8
    If L hits zero then we have moved all the characters, so RETurn
    29D1
    LD A,(BC)0A
    If we are here then we still have characters to move. First, load Register A with the character at the location of the string pointer in BC
    29D2
    LD (DE),A12
    Save the character in Register A at the location of the string storage pointer in DE
    29D3
    INC BC03
    Bump the value of the string pointer in BC
    29D4
    INC DE13
    Bump the value of the string storage pointer in DE
    29D5-29D6
    Loop until the string has been completely moved

    29D7-29F4 – STRING ROUTINE – “FRESTR”

    According to the original ROM source code, FRETMP is passed a pointer to a string descriptor in Register Pair DE and is returned in Register Pair HL. All the other registers are modified. A check to is made to see if the string descriptor in Register Pair DE points to is the last temporary descriptor allocated by PUTNEW. If so, the temporary is freed up by the updating of TEMPPT. If a temporary is freed up, a further check is made to see if the string data that that string temporary pointed to is the the lowest part of string space in use. If so, FRETMP is updated to reflect the fact that that space is no longer in use.

    This routine is a contination of VAL, FRE, and PRINT processing. A jump to here would include the need to get a string’s VARPTR and put it in HL.
    29D7-29D9
     ↳ FRESTR
    GOSUB to 0AF4H to make sure that the current result in REG l is a string
    29DA-29DC
     ↳ FREFAC
    LD HL,(4121H)LD HL,(FACLO)2A 21 41
    Load HL with the string’s VARPTR in ACCumulator
    29DD
     ↳ FRETM2
    EX DE,HLEB
    Load DE with the value of the string’s VARPTR in HL
    29DE-29E0
     ↳ FRETMP
    Check to see if the string is the last entry in the temporary string work area
    29E1
    EX DE,HLEB
    Load HL with the value of the string’s VARPTR in DE
    29E2
    RET NZC0
    Return if the string isn’t the last entry in the temporary string work area
    29E3
    PUSH DED5
    Save the value of the string’s VARPTR in DE to the STACK
    29E4
    LD D,B50
    Load Register D with the MSB of the string’s address in Register B
    29E5
    LD E,C59
    Load Register E with the LSB of the string’s address in Register C. DE now points to the string.
    29E6
    DEC DE1B
    Decrement the value of the string’s address in DE
    29E7
    LD C,(HL)4E
    Load Register C with the string’s length at the location of the string’s VARPTR in HL
    29E8-29EA
    LD HL,(40D6H)LD HL,(FRETOP)2A D6 40
    Load HL with the next available location in string space pointer for the purpose of testing to see if this is the FIRST one in the string space.
    Note: 40D6H-40D7H holds the next available location in string space pointer
    29EB
    We need to see if the current string is the last one defined in the string area by seeing if the string’s address in DE is the same as the next available location in string space pointer in HL, so we call the COMPARE DE:HL routine at RST 10H.

    The RST 10H routine parses the characters starting at HL+1 for the first non-SPACE,non-09H,non-0BH character it finds. On exit, Register A will hold that character, and the C FLAG is set if its alphabetic, and NC FLAG if its alphanumeric. All strings must have a 00H at the end.
    29EC-29ED
    Jump forward to 29F3H if the string’s address in DE isn’t the same as the next available location in string space pointer in HL
    29EE
    LD B,A47
    If is the last one defined then we need to update the current string pointer so first we load Register B with the value in Register A
    29EF
    ADD HL,BC09
    Add the length of the string in BC to the next available location in string space pointer in HL
    29F0-29F2
    LD (40D6H),HLLD (FRETOP),HL22 D6 40
    Save the adjusted next available location in string space pointer in HL.
    Note: 40D6H-40D7H holds the next available location in string space pointer
    29F3
     ↳ NOTLST
    POP HLE1
    Get the string’s VARPTR from the STACK and put it in HL
    29F4
    RETC9
    RETurn to CALLer

    29F5-2A02 – STRING ROUTINE – – “FRETMS”
    Test to see if the string in DE is the last string used in the temporary string work area.

    29F5-29F7
     ↳ FRETMS
    LD HL,(40B3H)LD HL,(TEMPPT)2A B3 40
    Load HL with the temporary string work area pointer.
    Note: 40B3H-40B4H holds the next available location in the temporary string work area pointer
    29F8
    DEC HL2B
    Decrement the value of the temporary string work area pointer in HL which backs up two words
    29F9
    LD B,(HL)46
    Load Register B with the MSB of the string’s address at the location of the temporary string work area pointer in HL
    29FA
    DEC HL2B
    Decrement the value of the temporary string work area pointer in HL
    29FB
    LD C,(HL)4E
    Load Register C with the LSB of the string’s address at the location of the temporary string work area pointer in HL
    29FC
    DEC HL2B
    Decrement the value of the temporary string work area pointer in HL
    29FD
    We want to see if Register Pairr DE points to the last by checking to see if the string’s VARPTR in DE matches the temporary string work area pointer in HL, so we call the COMPARE DE:HL routine at RST 18H.
    NOTE:
    • The RST 18H routine The result of the comparison is returned in the status Register as: CARRY SET=HL<DE; NO CARRY=HL>DE; NZ=Unequal; Z=Equal.
    29FE
    RET NZC0
    If the Z FLAG is set then we are done freeing space, so RETURN
    29FF-2A01
    LD (40B3H),HLLD (TEMPPT),HL22 B3 40
    Save the value of the temporary string work area pointer in HL.
    Note: 40B3H-40B4H holds the next available location in the temporary string work area pointer
    2A02
    RETC9
    RETurn to CALLer

    2A03-2A0E – LEVEL II BASIC LEN ROUTINE– “LEN”

    2A03-2A05
     ↳ LEN
    LD BC,27F8HLD BC,SNGFLT01 F8 27
    Load BC with the return address of 27F8H
    2A06
    PUSH BCC5
    Save the return address of 27F8H (in BC) to the STACK
    2A07-2A09
     ↳ LEN1
    GOSUB to 29D7H to free up the temporary variable pointed to by FACLO
    2A0A
    XOR AAF
    Zero Register A so as to force a numeric flag
    2A0B
    LD D,A57
    Zero Register D so that DE can be used when E is set.
    2A0C
    LD A,(HL)7E
    Load Register A with the string’s length at the location of the string’s VARPTR in HL
    2A0D
    OR AB7
    Set the flags according to the string’s length in Register A
    2A0E
    RETC9
    RETurn to CALLer

    2A0F-2A1E – LEVEL II BASIC ASC ROUTINE – “ASC”

    2A0F-2A11
     ↳ ASC
    LD BC,27F8HLD BC,SNGFLT01 F8 27
    Load BC with the return address of 27F8H
    2A12
    PUSH BCC5
    Save the return address of 27F8H (in BC) to the STACK
    2A13-2A15
     ↳ ASC2
    GOSUB to 2A07H (which itself is a GOSUB to 29D7H) to get string’s VARPTR into HL and the string’s length into Register A
    2A16-2A18
    If the Z FLAG is set, then this was a null string (bad argument), so display a ?FC ERROR
    2A19
    INC HL23
    Bump the value of the string’s VARPTR in HL
    2A1A
    LD E,(HL)5E
    Load Register E with the LSB of the address of the string’s data at the location of the string’s VARPTR in HL
    2A1B
    INC HL23
    Bump the value of the string’s VARPTR in HL
    2A1C
    LD D,(HL)56
    Load Register D with the MSB of the address of the string’s data at the location of the string’s VARPTR in HL
    2A1D
    LD A,(DE)1A
    Load Register A with the first character at the location of the string pointer in DE
    2A1E
    RETC9
    RETurn to CALLer

    2A1F-2A2E – LEVEL II BASIC CHR$ ROUTINE – “CHR$”

    2A1F-2A20
     ↳ CHR$
    LD A,01H3E 01
    Load Register A with the length of the string to be created
    2A21-2A23
    GOSUB to 2857H to save the string’s length in Register A and value and set up the string’s address
    2A24-2A26
    GOSUB to 2B1FH to evaluate the expression at the location of the current BASIC program pointer in HL and return with the integer result in DE
    2A27-2A29
     ↳ SETSTR
    LD HL,(40D4H)LD HL,(DSCTMP+1)2A D4 40
    Load HL with the temporary string’s address
    2A2A
    LD (HL),E73
    Save the character in Register E at the location of the string pointer in HL
    2A2B
     ↳ FINBCK
    POP BCC1
    Clean up the STACK so that the RETURN address is another one that is next in the STACK.
    2A2C-2A2E
    Jump to 2884H

    2A2F-2A60 – LEVEL II BASIC STRING$ ROUTINE – “STRNG$”

    2A2F
    We have the STRING$ command, but now we need the next character so we call a RST 10H to bump the value of the current BASIC program pointer until it points to the next character, call the EXAMINE NEXT SYMBOL routine at RST 10H.

    The RST 10H routine parses the characters starting at HL+1 for the first non-SPACE,non-09H,non-0BH character it finds. On exit, Register A will hold that character, and the C FLAG is set if its alphabetic, and NC FLAG if its alphanumeric. All strings must have a 00H at the end.
    2A30-2A31
    RST 08H ⇒ 28SYNCHK “(“CF 28
    Since the character at the location of the current BASIC program pointer in HL must be a (, call the COMPARE SYMBOL routine at RST 08H.

    NOTE: The RST 08H routine compares 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 the next execution address (i.e, the RST 08H 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 and control returns to the Input Phase).
    2A32-2A34
    This will get the string length required (which we will call “N”) via a GOSUB to 2B1CH to evaluate the expression at the location of the current BASIC program pointer in HL and return with the integer result in DE
    2A34
    DEC HL2B
    Backspace the code string. This is a Z-80 trick because this code was part of the above call instruction
    2A35
    PUSH DED5
    Save the string’s length (“N”) (currently in DE) to the STACK
    2A36-2A37
    RST 08 ⇒ 2CSYNCHK “,”CF 2C
    Now we have STRING$(nnn so the next character needs to be a ,. To test for the character at the location of the current BASIC program pointer in HL being a ,, call the COMPARE SYMBOL routine which compares 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 and control returns to the Input Phase)
    2A38-2A3A
    Now we have STRING$(xxx, and an expression so GOSUB to 2337H to evaluate the expression at the location of the current BASIC program pointer in HL and return with the result in ACCumulator
    2A3B-2A3C
    RST 08H ⇒ 29SYNCHK “)”CF 29
    Now we have STRING$(nnn,X. Since the character at the location of the current BASIC program pointer in HL must be a ), call the COMPARE SYMBOL routine at RST 08H.

    NOTE: The RST 08H routine compares 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 the next execution address (i.e, the RST 08H 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 and control returns to the Input Phase).
    2A3D
    EX (SP),HLE3
    We are now done with getting STRING$(nnn,X). Next we must exchange the value of the current BASIC program pointer in HL with the string’s length (“N”) in the STACK
    2A3E
    PUSH HLE5
    Save the string’s length (“N”) in HL to the STACK so that we can test it to make sure it is an integer
    2A3F
    We need to check the value of the current data type flag, so we call the TEST DATA MODE routine at RST 20H.
    NOTE: The RST 20H routine determines the type of the current value in ACCumulator and returns a combination of STATUS flags and unique numeric values in the A Register according to the data mode flag (40AFH). The results are returned as follows:
    • Integer = NZ/C/M/E and A is -1
    • String = Z/C/P/E and A is 0
    • Single Precision = NZ/C/P/O and A is 1
    • and Double Precision is NZ/NC/P/E and A is 5.
    2A40-2A41
    If that test shows “N” is a a STRING, jump to down to 2A47H
    2A42-2A44
    We now know that “N” is at least a number, so we GOSUB to 2B1FH to convert the current result in ACCumulator to an integer and return with the 8-bit result in Register A
    2A45-2A46
    Skip the next instruction (which would load the string address and 1st character) by jumping to 2A4AH
    2A47-2A49
     ↳ STRSTR
    Go get the first character in the string and return with it in Register A. This is the character that will be repeated
    2A4A
     ↳ CALSPA
    POP DED1
    Get the “N” from the STACK and put it in DE (well, actually, Register E)
    2A4B
    PUSH AFF5
    Save the character for the string (held in Register A) to the STACK
    2A4C
     ↳ SPACE2
    PUSH AFF5
    and then save it to the STACK again
    2A4D
    LD A,E7B
    Load Register A with “N” (held in Register E)
    2A4E-2A4F
    GOSUB to 2857H to allocate N bytes in the temporary string work area
    2A51
    LD E,A5F
    Load Register E with “N” (held in Register A)
    2A52
    POP AFF1
    Get the character for the string (“X”) from the STACK and put it in Register A
    2A53
    INC E1C
    To set the status flags we need to increase and then decrease E. First, bump the value of the string’s length in Register E
    2A54
    DEC E1D
    . and then decrement the string’s length in Register E
    2A55-2A56
    If “N” was zero (so that the string is now complete), jump back to 2A2BH
    2A57-2A59
    LD HL,(40D4H)LD HL,(DSCTMP+1)2A D4 40
    If we are here, we have not finished building the STRING$ string so now we load HL with the string’s address and get ready to loop
    2A5A
     ↳ SPLP$
    LD (HL),A77
    Save the character in Register A (“X”) at the location of the string pointer in HL
    2A5B
    INC HL23
    Bump the value of the string pointer in HL
    2A5C
    DEC E1D
    Decrement the string’s length in Register E
    2A5D-2A5E
    Loop back to 2A5AH to keep filling (HL) until the string of X’s has been completed
    2A5F-2A60
    Jump back to 2A2BH to put the temp description to finish

    2A61-2A90 – LEVEL II BASIC LEFT$( ROUTINE – “LEFT$”

    On entry, HL=address of LEFT$$, the STACK = string address, STACK+1 = n, and DE = code string address.
    2A61-2A63
     ↳ LEFT$
    Go check the syntax. The character at the location of the current BASIC program pointer in HL must be a )
    2A64
    XOR AAF
    Zero Register A because the string pointer never changes
    2A65
     ↳ LEFT3
    EX (SP),HLE3
    Exchange the value of the current BASIC program pointer in HL with the string’s VARPTR to the STACK
    2A66
    LD C,A4F
    Zero Register C
    2A67-2A68
    LD A,0E5H3E E5
    Z-80 Trick. By adding a 3E at 2A67, it masks out 2A68H if passing through by making the Z-80 think the instruction is LD A,0E5H
    2A68
     ↳ LEFTUS
    PUSH HLE5
    Save the value of the string’s VARPTR in HL to the STACK. This is actually a dummy push to offset for the extra POP command in PUTNEW
    2A69
     ↳ LEFT2
    PUSH HLE5
    Save the value of the string’s VARPTR in HL to the STACK
    2A6A
    LD A,(HL)7E
    Load Register A with the string’s length at the location of the string’s VARPTR in HL
    2A6B
    CP BB8
    Check to see if the new string’s length in Register B is greater than the string’s length in Register A. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
    2A6C-2A6D
    Jump to 2A70H if the new string’s length in Register B is greater than the string’s length in Register A
    2A6E
    LD A,B78
    Load Register A with the new string’s TRUNCATED length in Register B
    2A6F-2A71
    LD DE,000EH11 0E 00
    Z-80 Trick. This is a LD DE,000EH which is irrelevant and only executed if continuing through. If, however, one was to jump to 2A70H instead, a proper opcode would occur
    2A70-2A7l
     ↳ ALLSTR
    LD C,00H0E 00
    Since Register C tracks the offset, Zero Register C
    2A72
    PUSH BCC5
    Save the offset in BC to the STACK
    2A73-2A75
    Go see if there is enough string space for the new string
    2A76
    POP BCC1
    Get the offset from the STACK and put it in BC
    2A77
    POP HLE1
    Get the string’s VARPTR from the STACK and put it in HL
    2A78
    PUSH HLE5
    Save the string’s VARPTR in HL to the STACK
    2A79
    INC HL23
    Bump HL to now point to the address of the string
    2A7A
    LD B,(HL)46
    Load Register B with the LSB of the string’s address at the location of the string’s VARPTR in HL
    2A7B
    INC HL23
    Bump the value of the string’s VARPTR in HL
    2A7C
    LD H,(HL)66
    Load Register H with the MSB of the string’s address at the location of the string’s VARPTR in HL
    2A7D
    LD L,B68
    Load Register L with the LSB of the string’s address in Register B
    2A7E-2A7F
    LD B,00H06 00
    Zero Register B so that BC can be used
    2A80
    ADD HL,BC09
    Add the string’s length in BC to the string’s address in HL
    2A81
    LD B,H44
    Load Register B with the MSB of the string’s ending address in Register H
    2A82
    LD C,L4D
    Load Register C with the LSB of the string’s ending address in Register L
    2A83-2A85
    Go save the string’s length (held in A) and the string’s starting address (held in DE)
    2A86
    LD L,A6F
    Load Register L with the string’s length (i.e., the number of characters to move) held in Register A
    2A87-2A89
    Go move L characers frm BC to DE
    2A8A
    POP DED1
    Clean up the STACK
    2A8B-2A8D
    Go update the temporary string work area
    2A8E-2A90
    Jump to 2884H to put the temp variable in the temp list

    2A91-2A99 – LEVEL II BASIC RIGHT$ ROUTINE – “RIGHT$”

    2A91-2A93
    Go check the syntax. The character at the location of the current BASIC program pointer in HL must be a )
    2A94
    POP DED1
    Get the string’s VARPTR from the STACK and put it in DE
    2A95
    PUSH DED5
    Save the string’s VARPTR in DE to the STACK
    2A96
    LD A,(DE)1A
    Load Register A with the string’s length (held at the location of the string’s VARPTR in DE)
    2A97
    SUB B90
    Subtract the new string’s length in Register B from the string’s length in Register A to isolate the number of bytes
    2A98-2A99
    Jump to the LEFT$( code

    2A9A-2AC4 – LEVEL II BASIC MID$ ROUTINE – “MID$”

    The original ROM source code clarifies that if the number provided is greater than the actual length of the string, a NULL value is returned. If the second number (the number of characters) exceeds the end of the string, the maximum amount of available characters are returned.
    2A9A
     ↳ MID$
    EX DE,HLEB
    Load HL with the value of the current BASIC program pointer (held in DE)
    2A9B
    LD A,(HL)7E
    Load Register A with the terminal character, currently held at the location of the current BASIC program pointer in HL
    2A9C-2A9E
    GOSUB to 2AE2H to get the offset in Register B and the string’s VARPTR in DE
    2A9F
    INC B04
    We need to set the status flags to correspond to the offset position value so we first bump the value of the string’s position in Register B
    2AA0
    DEC B05
    … and then we decrement the value of the string’s offset position in Register B
    2AA1-2AAJ
    If the starting position (held in B) is 0, display ?FC ERROR
    2AA4
    PUSH BCC5
    Save the value of the offset position (held in Register B) to the STACK
    2AA5-2AA6
    LD E,0FFH1E FF
    Load Register E with the default string’s length of 256 in case no number of bytes are given
    2AA7-2AA8
    CP 29HCP “)”FE 29
    More syntax checking. Here we need to test for a ) at the location of the current BASIC program pointer. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
    2AA9-2AAA
    Jump to 2AB0H if the character at the location of the current BASIC program pointer in Register A is a )
    2AAB-2AAC
    RST 08H ⇒ 2CSYNCHK “,”CF 2C
    If it wasn’t a ), it had best be a , so we need to test the character at the location of the current BASIC program pointer in HL by calling the COMPARE SYMBOL routine at RST 08H.

    NOTE: The RST 08H routine compares 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 the next execution address (i.e, the RST 08H 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 and control returns to the Input Phase).
    2AAD-2AAF
    Go evaluate the expression at the location of the current BASIC program pointer in HL and return with the integer result in DE. Now the byte count is in DE as an integer
    2AB0-2AB1
    RST 08H ⇒ 29SYNCHK “)”CD 29
    Since the character at the location of the current BASIC program pointer in HL must be a ), call the COMPARE SYMBOL routine at RST 08H.

    NOTE: The RST 08H routine compares 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 the next execution address (i.e, the RST 08H 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 and control returns to the Input Phase).
    2AB2
    POP AFF1
    Get the offset from the STACK and put it in Register A
    2AB3
    EX (SP),HLE3
    Exchange the value of the current BASIC program pointer in HL with the value of the string’s VARPTR to the STACK
    2AB4-2AB6
    LD BC,2A69HLD BC,LEFT201 69 2A
    Load BC with 2A69H as the return address (which is in the LEFT$ routine)
    2AB7
    PUSH BCC5
    Save the return address in BC to the STACK
    2AB8
    DEC A3D
    Decrement the value of the requested offset in Register A so that we have a starting position minus 1
    2AB9
    CP (HL)BE
    Compare the string’s length at the location of the string’s VARPTR in HL with the value of the offset in Register A. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
    2ABA-2ABB
    LD B,00H06 00
    Zero Register B
    2ABC
    RET NCD0
    If the offset pointer ispast the end of the string we are going to return a null
    2ABD
    LD C,A4F
    Load Register C with the offset in Register A
    2ABE
    LD A,(HL)7E
    Load Register A with the string’s length at the location of the string’s VARPTR in HL
    2ABF
    SUB C91
    Subtract the index (the second argument) in Register C from the string’s length in Register A
    2AC0
    CP EBB
    Compare the new string’s length in Register E with the adjusted string’s length in Register A to see if we are going to truncate. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
    2AC1
    LD B,A47
    Load Register B with the calculated string’s length in Register A
    2AC2
    RET CD8
    If we are not going to truncate, then just use the partial string we already have and Return to 2A69H
    2AC3
    LD B,E43
    Load Register B with the new string’s truncated length in Register E
    2AC4
    RETC9
    Return to 2A69H aka LEFT2

    2AC5-2ADE – LEVEL II BASIC VAL ROUTINE – “VAL”

    2AC5-2AC7
     ↳ VAL
    Go get the string’s length in Register A and the string’s VARPTR in HL
    2AC8-2ACA
    Jump to 27F8H if the string’s length in Register A is equal to zero
    2ACB
    LD E,A5F
    Load Register E with the string’s length at the location of the string’s VARPTR in HL.
    The original ROM source explains that we need to do some fancy footwork here to handle the case where the two strings are stored next to each other.
    2ACC
    INC HL23
    Bump the value of the string’s VARPTR in HL
    2ACD
    LD A,(HL)7E
    Load Register A with the LSB of the string’s address at the location of the string’s VARPTR in HL
    2ACE
    INC HL23
    Bump the value of the string’s VARPTR in HL
    2ACF
    LD H,(HL)66
    Load Register H with the MSB of the string’s address at the location of the string’s VARPTR in HL
    2AD0
    LD L,A6F
    Load Register L with the LSB of the string’s address in Register A
    2AD1
    PUSH HLE5
    Save the value of the string’s address in HL to the STACK
    2AD2
    ADD HL,DE19
    Add the string’s length in DE to the string’s address in HL
    2AD3
    LD B,(HL)46
    Load Register B with the last character of the string at the location of the string pointer in HL
    2AD4
    LD (HL),D72
    Save the zero in Register D at the location of the string pointer in HL
    2AD5
    EX (SP),HLE3
    Exchange the string’s ending address in HL with the string’s address to the STACK
    2AD6
    PUSH BCC5
    Save the last character of the string in Register B to the STACK
    2AD7
    LD A,(HL)7E
    Load Register A with the first character of the argument
    2AD8-2ADA
    Call the ASCII TO DOUBLE routine at 0E65H (which converts the ASCII string pointed to by HL to its double precision equivalent; with output left in ACCumulator)
    2ADB
    POP BCC1
    Get the modified character of the next string into Register B
    2ADC
    POP HLE1
    Get the pointer to the modified character back into HL
    2ADD
    LD (HL),B70
    Restore the character.
    2ADE
    RETC9
    RETurn to CALLer

    2ADF-2A6 – STRING ROUTINE – “PREAM”

    This is called by LEFT$, MID$, and RIGHT$ to test for the ending “)” character. On entry, the STACK has the string address, byte count, and return address. On exit the STACK has the string address, DE and B each have the byte count.
    2ADF
     ↳ PREAM
    EX DE,HLEB
    Load HL with the value of the current BASIC program pointer in DE
    2AE0-2AE1
    RST 08H ⇒ 29SYNCHK “)”CF 29
    Since the character at the location of the current BASIC program pointer in HL must be a ), call the COMPARE SYMBOL routine at RST 08H.

    NOTE: The RST 08H routine compares 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 the next execution address (i.e, the RST 08H 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 and control returns to the Input Phase).
    2AE2
     ↳ PREAM2
    POP BCC1
    Get the return address from the STACK and put it in BC
    2AE3
    POP DED1
    Get the number of bytes to isolate from the string (from the STACK) and put it in DE
    2AE4
    PUSH BCC5
    Save the return address in BC to the STACK
    2AE5
    LD B,E43
    Load Register B with the number of bytes in Register E
    2AE6
    RETC9
    RETurn to CALLer

    2AE7H-2AEE – Process a LEFT-HAND-SIDE MID$– “ISMID$”

    2AE7-2AE8
     ↳ ISMID$
    CP 7AHCP MIDTK-$ENDFE 7A
    This routine is designed to handle a left-size MID$ call. So check to see if the character at the location of the current BASIC program pointer in Register A is trying to process a left hand side MID$. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
    2AE9-2AEB
    Display a ?SN ERROR message if that is not what is going on.
    2AEC-2AEE
    JP 41D9HJP DLHSMDC3 D9 41
    JUMP to DOS to see if DOS wants to deal with this.

    2AEF-2AF7 – LEVEL II BASIC INP ROUTINE– “FNINP”

    2AEF-2AF1
     ↳ FNINP

    Go evaluate the expression at the location of the current BASIC program pointer in HL and return with the port number in Register A
    2AF2-2AF4
    LD (4094H),ALD (STAINP+1),A32 94 40
    Save the value of the port number (from Register A) into 4094H, which is in the middle of a routine.
    2AEF-2AF1
    CALL 4093HCALL STAINPCD 1F 2B
    Perform in INP on the channel held in Register A
    2AF8-2AFA
    Evaluate the results and return them

    2AF8-2B00 – LEVEL II BASIC OUT ROUTINE– “FNOUT”

    2AFB-2AFD
     ↳ FNOUT

    Get the I/O Port Ready
    2AFB-2AFD
    JP 4096HJP OUTWRDCD 0E 2B
    Do the OUT and RETurn

    2B01-2B0D – EVALUATE EXPRESSION ROUTINE
    “GETINT”

    This evaluates an expression and leaves the result in DE as an integer.

    2B01
     ↳ GETINT
    We need the next character in the BASIC program so call the EXAMINE NEXT SYMBOL routine at RST 10H.

    The RST 10H routine parses the characters starting at HL+1 for the first non-SPACE,non-09H,non-0BH character it finds. On exit, Register A will hold that character, and the C FLAG is set if its alphabetic, and NC FLAG if its alphanumeric. All strings must have a 00H at the end.
    2B02-2B04
     ↳ GETIN2
    Go evaluate the expression at the location of the current BASIC program pointer in HL and return with the result in ACCumulator

    2B05 – This routine takes the value from the ACC, converts it to an integer value and places the result in the DE Register Pair. The Z flag will be set if the result in DE is smaller than or equal to 255 (FFH). (DE = INT (ACC)).

    2B05
     ↳ INTFR2
    PUSH HLE5
    Save the value of the current BASIC program pointer in HL to the STACK
    2B06-2B08
    Call the CONVERT TO INTEGER routine at 0A7FH (where the contents of ACCumulator are converted from single or double precision to integer and deposited into HL)
    2B09
    EX DE,HLEB
    Load DE with the integer result in HL
    2B0A
    POP HLE1
    Get the value of the current BASIC program pointer from the STACK and put it in HL
    2B0B
    LD A,D7A
    Load Register A with the MSB of the integer result in Register D
    2B0C
    OR AB7
    Test the value of the MSB in Register A
    2B0D
    RETC9
    RETurn to CALLer

    2B0E-2B16 – EVALUATE EXPRESSION ROUTINE – OUT continues here – “SETIO”

    2B0E-2B10
     ↳ SETIO
    GOSUB to 2B1CH to evaluate the expression at the location of the current BASIC program pointer in HL and return with the 8-bit value in Register A
    2B11-2B13
    LD (4094H),ALD (STAINP+1),A32 94 40
    Save the 8-bit value in Register A in the DOS address of 4094H to set up for WAIT
    2B14-2B16
    LD (4097H),ALD (OUTWRD+1),A32 97 40
    Save the 8-bit value in Register A in the DOS address of 4097H to set up for OUT

    2B17-2B1A – CHECK SYNTAX ROUTINE – This checks to see if the next character is a and contnues on to 2B1CH if it is, and errors out if it isn’t.

    2B17-2B18
    RST 08H ⇒ 2ESYNCHK “,”CF 2E
    Since the character at the location of the current BASIC program pointer in HL must be a “,”, call the COMPARE SYMBOL routine at RST 08H.

    NOTE: The RST 08H routine compares 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 the next execution address (i.e, the RST 08H 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 and control returns to the Input Phase).
    2B19-2B1A
    Jump forward to 2B1CH

    2B1B-2B28 – EVALUATE EXPRESSION ROUTINE – This is called by PRINT TAB – “GTBYTC”.

    2B1B
     ↳ GTBYTC
    We need the next character in the BASIC program so call the EXAMINE NEXT SYMBOL routine at RST 10H.

    The RST 10H routine parses the characters starting at HL+1 for the first non-SPACE,non-09H,non-0BH character it finds. On exit, Register A will hold that character, and the C FLAG is set if its alphabetic, and NC FLAG if its alphanumeric. All strings must have a 00H at the end.

    2B1C – Common Conversion Routine – “GETBYT”

    • This routine converts a numeric ASCII string pointed to by the HL into a hexadecimal value and places the result in the A register. If the result is larger than 255 (FFH) then an FC ERROR (Illegal function call) will be generated. After execution the HL will point to the delimiter. If the delimiter is a zero byte or a colon (3AH) then the Z flag will be set. Any other delimiter will cause the Z flag to be reset.
    2B1C-2B1E
     ↳ GETBYT
    GOSUB to 2337H to evaluate the formula/expression at the location of the current BASIC program pointer in HL and return with the result in REG l
    2B1F-2B21
     ↳ CONINT
    GOSUB to 2B05H to convert the result in ACCumulator to an integer and return with the integer result in DE. Flags are set based on Register D.
    2B22-2B24
    If the result is greater than 255, display a ?FC ERROR message
    2B25
    DEC HL2B
    Decrement the value of the current BASIC program pointer in HL
    2B26
    We need the next character in the BASIC program so call the EXAMINE NEXT SYMBOL routine at RST 10H.

    The RST 10H routine parses the characters starting at HL+1 for the first non-SPACE,non-09H,non-0BH character it finds. On exit, Register A will hold that character, and the C FLAG is set if its alphabetic, and NC FLAG if its alphanumeric. All strings must have a 00H at the end.
    2B27
    LD A,E7B
    Load Register A with the 8-bit result in Register E so that both A and E have the result.
    2B28
    RETC9
    RETurn to CALLer

    2B29-2B2D – LEVEL II BASIC LLIST ROUTINE – “LLIST”

    This routine sets the output device flag to PRINTER and then flows through to the LIST command.
    2B29-2B2A
     ↳ LLIST
    LD A,01H3E 01
    Load Register A with the printer output device code
    2B2B-2B2D
    LD (409CH),ALD (PRTFLG),A32 9C 40
    Save the value in Register A as the current output device flag.
    Note: 409CH holds the current output device flag: -1=cassette, 0=video and 1=printer

    2B2E-2B74 – LEVEL II BASIC LIST ROUTINE – “LIST”

    On entry the STACK has the return address, then the first basic line number to be listed, then the last basic line number to be listed.
    2B2E
     ↳ LIST
    POP BCC1
    Get rid of the the return address on the STACK
    2B2F-2B31
    Go evaluate the range of line numbers given at the location of the current BASIC program pointer in HL
    2B32
    PUSH BCC5
    Save the address of the first BASIC line (held in BC) to the STACK
    2B33-2B35
     ↳ LIST4
    LD HL,FFFFH21 FF FF
    Load HL with a -1. This is because the below loop starts with a INC HL, so as to turn the first line number into 0
    2B36-2B38
    LD (40A2H),HLLD (CURLIN),HL22 A2 40
    Save the value in HL as the current BASIC line number (which is stored at 40A2H-40A3H).
    2B39
    POP HLE1
    Get the address of the first BASIC line to be listed (from the STACK) and put it in HL
    2B3A
    POP DED1
    Get the value of the last BASIC line number to be listed (from the STACK) and put it in DE
    2B3B
    LD C,(HL)4E
    Load Register C with the LSB of the next BASIC line pointer at the location of the memory pointer in HL
    2B3C
    INC HL23
    Bump the value of the memory pointer in HL
    2B3D
    LD B,(HL)46
    Load Register B with the MSB of the next BASIC line pointer at the location of the memory pointer in HL
    2B3E
    INC HL23
    Bump the value of the memory pointer in HL
    2B3F
    LD A,B78
    Load Register A with the MSB of the next BASIC line pointer in Register B
    2B40
    OR CB1
    Combine the LSB of the next BASIC line pointer in Register C with the MSB of the next BASIC line pointer in Register A. This will let us test for the end of the BASIC program
    2B41-2B43
    If we are at the elast line, then STOP and JUMP to 1A19H to the READY PROMPT.
    2B44-2B46
    CALL 41DFHCALL EXCHDSCD DF 41
    GOSUB to DOS to see if DOS wants to do anything here.
    2B47-2B49
    Go scan the keyboard to see if the BREAK key or the shift@ key was pressed
    2B4A
    PUSH BCC5
    Save the address of the next BASIC line in BC to the STACK
    2B4B
    LD C,(HL)4E
    We now want to push the line number, but we have to load BC with it first. Load Register C with the LSB of the BASIC line number at the location of the memory pointer in HL
    2B4C
    INC HL23
    Bump the value of the memory pointer in HL
    2B4D
    LD B,(HL)46
    Load Register B with the MSB of the BASIC line number at the location of the memory pointer in HL
    2B4E
    INC HL23
    Bump the value of the memory pointer in HL
    2B4F
    PUSH BCC5
    Save the BASIC line number in BC to the STACK
    2B50
    EX (SP),HLE3
    Swap (SP) and HL so that the line number is now in HL
    2B51
    EX DE,HLEB
    Swap DE and HL so that the last BASIC line number is now in HL
    2B52
    We need to see if we are outside the last number in the specified range so compare the BASIC line number in DE with the last BASIC line number in HL, so we call the COMPARE DE:HL routine at RST 10H.

    The RST 10H routine parses the characters starting at HL+1 for the first non-SPACE,non-09H,non-0BH character it finds. On exit, Register A will hold that character, and the C FLAG is set if its alphabetic, and NC FLAG if its alphanumeric. All strings must have a 00H at the end.
    2B53
    POP BCC1
    Get the pointer to the location on the BASIC program line being processed and put it in BC
    2B54-2B56
    If the BASIC line number in DE is greater than the last BASIC line number in HL then we have gone past the end, so we are done processing!
    2B57
    EX (SP),HLE3
    Swap (SP) and HL so that the last BASIC line number is now on the STACK
    2B58
    PUSH HLE5
    Save the address of the next BASIC line in HL to the STACK
    2B59
    PUSH BCC5
    Save the pointer to the location on the BASIC program line being processed to the STACK
    2B5A
    EX DE,HLEB
    Load HL with the BASIC line number (from DE)
    2B5B-2B5D
    LD (40ECH),HLLD (DOT),HL22 EC 40
    Save the BASIC line number in HL into DOT for use later in EDIT or LIST.
    Note: 40ECH-40EDH holds EDIT line number
    2B5E-2B60
    Call the HL TO ASCII routine at 0FAFH (which converts the value in the HL (assumed to be an integer) to ASCII and display it at the current cursor position on the video screen) to display the current BASIC line number
    2B61-2B62
    LD A,20H3E 20
    Load Register A with a space
    2B63
    POP HLE1
    Get the value of the memory pointer from the STACK and put it in HL
    2B64-2B66
    Go send the space in Register A to the current output device
    2B67-2B69
    GOSUB to 2B7EH move the BASIC line at the location of the memory pointer in HL into the input buffer and untokenize the BASIC line
    2B6A-2B6C
    LD HL,(40A7H)LD HL,(BUFPNT)2A A7 40
    Load HL with the starting address of the input buffer.
    Note: 40A7H-40A8H holds the input Buffer pointer
    2B6D-2B6F
    Since we need to send the BASIC line in the input buffer to the current output device we call the PRINT MESSAGE routine at 2B75H which writes string pointed to by HL to the current output device
    2B70-2B72
    Go send a carriage return to the current output device
    2B73-2B74
    Loop back to 2B33H until the listing is complete

    2B75-2B7D – DISPLAY MESSAGE ROUTINE – “LISPRT”

    This is the PRINT MESSAGE routine which writes string pointed to by HL to the current output device. String must be terminated by a byte of zeros. This call is different from 28A7H because it does not use the literal string pool area, but it does use the same display routine and it takes the same DOS Exit at 41C1H. Uses all registers. This routine can be called without loading the BASIC utility, if a C9H (RET) is stored in 41ClH.

    This routine outputs a string to device indicated by device type flag stored at 409CH. String must end with zero byte. On entry, HL registers must point to address of start of string. Calls routine at 032AH.

    2B75“LISPRT”

    LD A,(HL)7E
    Load Register A with the character at the location of the memory pointer in HL
    2B76
    OR AB7
    Check to see if the character in Register A is an end of the string character (00H)
    2B77
    RET ZC8
    Return if the character in Register A is an end of the string character
    2B78-2B7A
    Go send the character in Register A to the current output device
    2B7B
    INC HL23
    Bump the value of the memory pointer in HL
    2B7C-2B7D
    Loop back to 2B75H until all of the characters have been sent to the current output device

    2B7E-2BC5 – UNTOKENIZE ROUTINE – “BUFLIN”

    This routine is called by LIST and EDIT. It moves the line pointed to by HL to the input buffer area and then expands each token into the appropriate key word.
    2B7E
     ↳ BUFLIN

    PUSH HLE5
    Save the BASIC line pointer in HL to the STACK
    2B7F-2B81
    LD HL,(40A7H)LD HL,(BUFPNT)2A A7 40
    Load HL with the starting address of the input buffer.
    Note: 40A7H-40A8H holds the input Buffer pointer
    2B82
    2B83
    LD B,H
    LD C,L44
    LET Register Pair BC = Register Pair HL
    2B84
    POP HLE1
    Get the value of the BASIC line pointer from the STACK and put it in HL
    2B85-2B86
    LD D,FFHLD D,BUFLEN16 FF
    Load Register D with the maximum length of an untokenized line
    2B87-2B88
    Jump forward to 2B8CH into the middle of the move/expand code
    2B89
     ↳ PLOOP
    INC BC03
    Top of a loop. Bump the value of the input buffer pointer in BC
    2B8A
    DEC D15
    Decrement the character count in Register D
    2B8B
    RET ZC8
    Return if 256 characters have been moved into the input buffer
    2B8C
     ↳ PLOOP2
    LD A,(HL)7E
    Load Register A with the character at the location of the BASIC line pointer in HL
    2B8D
    OR AB7
    Set the status flags to enable us to check to see if the character in Register A is a reserved word (in which case the P FLAG will be set) or an end of the BASIC line character (in which case the Z FLAG will be set)
    2B8E
    INC HL23
    Bump the value of the BASIC line pointer in HL to the next character in the code string
    2B8F
    LD (BC),A02
    Save the character at the location of the input buffer pointer (held in Register A)to the memory location held by BC. If the character was a 00H terminator, then the terminator will also be copied.
    2B90
    RET ZC8
    Return if the character in Register A is an end of the BASIC line character
    2B91-2B93
    If the character in A is just a regular character (i.e., not a token), then JUMP back to 2B89H
    2B94-2B95
    CP 0FBHCP SNGQTKFE FB
    Check to see if the character in Register A is a token. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
    2B96-2B97
    Jump forward to 2BA0H if the character in Register A isn’t a token
    This is where the infamous ROM bug which can crash Level II sits. It assumes that a has room to move backwards 4 characters, which it might not!
    2B98-2B9B
    DEC BC
    DEC BC
    DEC BC
    DEC BC0B
    First, backspace 4 characters to compensat for “:REM” which is otherwise hidden from the user’s view. Decrement the value of the input buffer pointer in BC
    2B9C-2B9F
    INC D
    INC D
    INC D
    INC D14
    Then, bump the value of the character counter in Register D 4 times
    A REM isn’t the only TOKEN with a hidden add-on. ELSE also has a hidden colon in front of it. So let’s now deal with that.
    2BA0-2BA1
     ↳ NRQTTK
    CP 95HCP $ELSEFE 95
    Check to see if the character in Register A is an ELSE token. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
    2BA2-2BA4
    If it was an ELSE we need to backspace the expanded buffer pointer to NOT print the hidden “:”. To do this, go back to 0B24H to decrement the value of the input buffer pointer if the character in Register A is an ELSE token
    2BA4
    DEC BC0B
    This is NOT executed in the regular process of the ROM. This is a mid-instruction jump point from DOS BASIC if the DOS routine which analyzes the INPUT command determines that the routine which called the DOS VECTOR was > the location in ROM for the LIST command
    2BA5-2BA6
    SUB 7FHD6 7F
    Next, we need to get rid of the SIGN BIT and add one, so subtract 7F to get the number of the entry we are looking for in token list
    2BA7
    PUSH HLE5
    Save the value of the BASIC line pointer in HL to the STACK. Register L holds the reserved word number at this point.
    2BA8
    LD E,A5F
    Load Register E with the character in Register A
    2BA9-2BAB
    LD HL,1650HLD HL,RESLST21 50 16
    Load HL with the starting address of the reserved words list
    2BAC
     ↳ LOPRES
    LD A,(HL)7E
    Load Register A with the character at the location of the reserved words list pointer in HL
    2BAD
    OR AB7
    Test the value of the character in Register A. The P FLAG will be set on the first character of each TOKEN because it has the high bit set.
    2BAE
    INC HL23
    Bump the value of the reserved words list pointer in HL
    2BAF-2BB1
    If the character at the location of the reserved words pointer in Register A doesn’t have bit 7 set then Jump back to 2BACH.
    2BB2
    DEC E1D
    Decrement the counter
    2BB3-2BB4
    Jump back to 2BACH if this isn’t the reserved word for the token
    2BB5-2BB6
    AND 7FHE6 7F
    Reset bit 7 of the character in Register A by ANDing it against 0111 1111. This is to eliminate the MSB for “EDIT” and for disk I/O
    2BB7
     ↳ MORPUR
    LD (BC),A02
    Save the character in Register A at the location of the input buffer pointer in BC
    2BB8
    INC BC03
    Bump the value of the input buffer pointer in BC
    2BB9
    DEC D15
    Decrement the value of the character counter in Register D
    2BBA-2BBC
    If the Z FLAG has been set, then the character counter for the buffer has been exhausted and the buffer is now full, so JUMP back to 28D8H
    2BBD
    LD A,(HL)7E
    Load Register A with the character at the location of the reserved words pointer in HL
    2BBE
    INC HL23
    Bump the reserved words pointer in HL
    2BBF
    OR AB7
    Test the value of the character in Register A
    2BC0-2BC2
    Keep getting characters in this reserved word until we hit the next reserved word
    2BC3
    POP HLE1
    Get the value of the BASIC line pointer from the STACK and put it in HL
    2BC4-2BC5
    Jump back to 2B8CH to continue processing the BASIC line being interpreted

    – “DELETE”

    2BC6-2BC8
     ↳ DELETE
    GOSUB to 1B10H to evaluate the line numbers at the location of the current BASIC program pointer in HL
    2BC9
    POP DED1
    Get the value of the last BASIC line number to be deleted (in binary) from the STACK and put it in DE
    2BCA
    PUSH BCC5
    Save the address of the first BASIC line to be deleted in BC to the STACK
    2BCB
    PUSH BCC5
    Save the address of the first BASIC line to be deleted in BC to the STACK AGAIN!
    2BCC-2BCE
    GOSUB to 1B2CH to the SEARCH FOR LINE NUMBER routine which looks for the line number specified in DE so as to get the address of the last line to be deleted.Returns C/Z with the line found in BC, NC/Z with line number is too large and HL/BC having the next available location, or NC/NZ with line number not found, and BC has the first available one after that
    2BCF-2BD0
    Since the first line number provided MUST be found, if FNDLIN returns with the NC FLAG set (i.e., not found) we must JUMP to 2BD6H to show a ?FC ERROR
    2BD1
    2BD2
    LD D,H
    LD E,L54
    Let Register Pair DE = Register Pair HL
    2BD3
    EX (SP),HLE3
    Exchange the last BASIC line’s address in HL with the first BASIC line’s address to the STACK
    2BD4
    PUSH HLE5
    Save the pointer to the first line in range to the STACK
    2BD5
    We need to check to see if the first BASIC line’s address in HL is greater than or equal to the last BASIC line’s address in DE, so we call the COMPARE DE:HL routine at RST 10H.

    The RST 10H routine parses the characters starting at HL+1 for the first non-SPACE,non-09H,non-0BH character it finds. On exit, Register A will hold that character, and the C FLAG is set if its alphabetic, and NC FLAG if its alphanumeric. All strings must have a 00H at the end.
    2BD6-2BD8
     ↳ FCERRG
    Display a ?FC ERROR message if the first BASIC lines address in HL is greater than or equal to the last BASIC line’s address in DE
    2BD9-2BDB
    LD HL,1929HLD HL,REDDY21 29 19
    Load HL with the starting address of the BASIC READY message
    2BDC-2BDE
    Call the WRITE MESSAGE routine at 28A7H to print the message pointed to by HL.
    2BDF
    POP BCC1
    Get the first BASIC line’s address from the STACK and put it in BC
    2BE0-2BE2
    LD HL,1AE8HLD HL,FINI21 E8 1A
    Load HL with the return address
    2BE3
    EX (SP),HLE3
    Swap (SP) and HL so that HL now points to the next BASIC line’s address …
    2BE4
     ↳ DEL
    EX DE,HLEB
    and then put it into DE
    2BE5-2BE7
    LD HL,(40F9H)LD HL,(VARTAB)2A F9 40
    Load HL with the end of the BASIC program pointer.
    • Note: 40F9H-40FAH holds the starting address of the simple variable storage area.
    2BE8
     ↳ MLOOP
    LD A,(DE)1A
    Load Register A with the character at the location of the memory pointer in DE
    2BE9
    LD (BC),A02
    Save the character in Register A at the location of the memory pointer in BC
    2BEA
    INC BC03
    Bump the value of the memory pointer in BC
    2BEB
    INC DE13
    Bump the value of the memory pointer in DE
    2BEC
    Now we need to check to see if the memory pointer in DE equals the end of the BASIC program pointer in HL, so we call the COMPARE DE:HL routine at RST 10H.

    The RST 10H routine parses the characters starting at HL+1 for the first non-SPACE,non-09H,non-0BH character it finds. On exit, Register A will hold that character, and the C FLAG is set if its alphabetic, and NC FLAG if its alphanumeric. All strings must have a 00H at the end.
    2BED-2BEE
    Loop back to 2BE8H until the memory pointer in DE equals the end of the BASIC program pointer in HL
    2BEF
    LD H,B60
    Load Register H with the MSB of the memory pointer in Register B
    2BF0
    LD L,C69
    Load Register L with the LSB of the memory pointer in Register C
    2BF1-2BF3
    LD (40F9H),HLLD (VARTAB),HL22 F9 40
    Save the value in HL as the new end of the BASIC program pointer.
    • Note: 40F9H-40FAH holds the starting address of the simple variable storage area.
    2BF4
    RETC9
    RETurn to CALLer

    2BF5-2C1E – LEVEL II BASIC CSAVE ROUTINE – “CSAVE”

    • The original ROM source code says that the CSAVE command dump’s BASIC’s core. Three D3H’s are written, followed by a 1 character filename. At the end 3 zeros in a row are written.
    2BF5-2BF7
     ↳ CSAVE
    Calls the WRITE LEADER routine at 0284H (which writes a Level II leader on the cassette unit set in Register A)
    2BF8
    2BFAH Go evaluate the rest of the CSAVE expression at the location of the current BASIC program pointer in HL and return with the result in REG l
    2BFB
    PUSH HLE5
    Save the value of the current BASIC program pointer in HL to the STACK so we can get it back at the end of the routine
    2BFC-2BFE
    Go get the starting address of the filename into DE
    2BFF-2C00
    LD A,D3H3E D3
    Load Register A with the filename header byte (=D3H which is a “S” with the sign bit on)
    2C01-2C03
    the WRITE ONE BYTE TO CASSETTE routine at 0264H (which writes the byte in the A Register to the cassette drive selected in the A register), which in this case the filename header byte
    2C04-2C06
    Go write the filename header byte in Register A twice more
    2C07
    LD A,(DE)1A
    Load Register A with the first character of the filename at the location of the filename pointer in DE
    2C08-2C0A
    the WRITE ONE BYTE TO CASSETTE routine at 0264H (which writes the byte in the A Register to the cassette drive selected in the A register), which in this case is the filename
    2C0B-2C0D
    LD HL,(40A4H)LD HL,(TXTTAB)2A A4 40
    Load HL with the start of the BASIC program pointer.
    • Note: 40A4H-40A5H holds the starting address of BASIC program text also known as the PROGRAM STATEMENT TABLE (PST).
    2C0E
    EX DE,HLEB
    Load DE with the start of the BASIC program pointer in HL
    2C0F-2C11
    LD HL,(40F9H)LD HL,(VARTAB)2A F9 40
    Load HL with the end of the BASIC program pointer.
    • Note: 40F9H-40FAH holds the starting address of the simple variable storage area.
    2C12
     ↳ LOPSCO
    LD A,(DE)1A
    Top of a loop. We are going to loop from DE (start of program) to HL (end of program) now. Load Register A with the character at the location of the memory pointer in DE
    2C13
    INC DE13
    Bump the value of the memory pointer in DE
    2C14-2C16
    the WRITE ONE BYTE TO CASSETTE routine at 0264H (which writes the byte in the A Register to the cassette drive selected in the A register)
    2C17
    Now we need to check to see if the memory pointer in DE is equal to the end of the BASIC program pointer in HL, so we call the COMPARE DE:HL routine at RST 10H.

    The RST 10H routine parses the characters starting at HL+1 for the first non-SPACE,non-09H,non-0BH character it finds. On exit, Register A will hold that character, and the C FLAG is set if its alphabetic, and NC FLAG if its alphanumeric. All strings must have a 00H at the end.
    2C18-2C19
    Loop back to 2C12H until the memory pointer in DE is equal to the end of the BASIC program pointer in HL
    2C1A-2C1C
    All done! GOSUB 01F8H to turn the cassette recorder off
    2C1D
    POP HLE1
    Get the value of the current BASIC program pointer from the STACK and put it in HL
    2C1E
    RETC9
    RETurn to CALLer

    2C1F-2CA4 – LEVEL II BASIC CLOAD ROUTINE – ROM v1.0 – “CLOAD”

    2C1F-2C21
     ↳ CLOAD
    Go turn on the cassette recorder
    2C22
    LD A,(HL)7E
    Load Register A with the character at the location of the current BASIC program pointer in HL
    2C23-2C24
    SUB 0B2HSUB $PRINTD6 B2
    Check to see if the character at the location of the current BASIC program pointer in Register A is a ?, meaning that CLOAD? was requested.
    2C25-2C26
    Jump to the CLOAD? routine at 2C29H if the character at the location of the current BASIC program pointer in Register A is a ?
    2C27
    XOR AAF
    OK – So this is now a straight CLOAD. First, zero Register A
    2C28
    LD BC,232F01 2F 23
    Z-80 Trick! The next instruction would set the flag for a CLOAD? which we don’t want if we are passing through because we need A to be 0, so 2C28H starts with a 01H which would be a meaningless LOAD statement and assumes that the following instruction at 2C29H is what to load it with, effectively skipping 2C29H. BUT, if you jump to 2C29H you get the actual XOR command and keep going
    2C29
     ↳ CLOADP
    CPL2F
    Load Register A with a -1 for CLOAD?. It will still be a 0 if this is CLOAD
    2C2A
    INC HL23
    Bump the value of the current BASIC program pointer in HL until it points to the next character after the ? in CLOAD?
    2C2B
    PUSH AFF5
    Save the CLOAD/CLOAD? flag in Register A to the STACK
    2C2C
    DEC HL2B
    Decrement the value of the current BASIC program pointer in HL so we can see if we are at the end
    2C2D
    We need the next character in the BASIC program so call the EXAMINE NEXT SYMBOL routine at RST 10H.

    The RST 10H routine parses the characters starting at HL+1 for the first non-SPACE,non-09H,non-0BH character it finds. On exit, Register A will hold that character, and the C FLAG is set if its alphabetic, and NC FLAG if its alphanumeric. All strings must have a 00H at the end.
    2C2E-2C2F
    LD A,00H3E 00
    Zero Register A to allow for any filename
    2C30-2C31
    Jump if the character at the location of the current BASIC program pointer in HL is an end of the BASIC statement character
    2C32-2C34
    To get the filename we need to GOSUB to 2337H to evaluate the expression at the location of the current BASIC program pointer in HL and return with the result in ACCumulator
    2C35-2C37
    Make sure the length is good, and save the pointer to the filename to Register Pair DE
    2C38
    LD A,(DE)1A
    Load Register A with the first character of the filename at the location of the filename pointer in DE
    2C39
     ↳ CLNONM
    LD L,A6F
    Load Register L with the filename in Register A
    2C3A
    POP AFF1
    Get the value of the CLOAD/CLOAD? flag from the STACK and put it in Register A
    2C3B
    OR AB7
    Test the value of the CLOAD/CLOAD? flag in Register A (since CPL doesn’t set any flags)
    2C3C
    LD H,A67
    Load Register H with the value of the CLOAD/CLOAD? flag in Register A
    2C3D-2C3F
    LD (4121H),HLLD (FACLO),HL22 21 41
    Save the value of the CLOAD/CLOAD? flag and the filename in HL in ACCumulator
    2C40-2C42
    Call the NEW routine at 1B4D if it is a CLOAD
    2C43-2C45
    LD HL,(4121H)LD HL,(FACLO)2A 21 41
    Load HL with the CLOAD/CLOAD? flag and the filename in ACCumulator

    *2C1F-2CA4 – LEVEL II BASIC CLOAD ROUTINE – ROM v1.3

    *2C1F
    SUB 0B2H
    Test for CLOAD?
    *2C21
    Jump to 2C25H if it is CLOAD?
    *2C23
    XOR A
    So we know that we have a CLOAD and not a CLOAD?, so clear Register A and continue
    *2C24
    01
    Z-80 Trick! The next instruction would set the flag for a CLOAD? which we don’t want if we are passing through because we need A to be 0, so 2C28H starts with a 01H which would be a meaningless LOAD statement and assumes that the following instruction at 2C29H is what to load it with, effectively skipping 2C29H. BUT, if you jump to 2C29H you get the actual XOR command and keep going
    CPL
    Since A is Zero going into this command, once this complement code is exected, A=-1 if CLOAD?, 0000 if CLOAD
    *2C26
    INC HL
    Increment HL to the filname of the CLOAD/CLOAD? flag
    *2C27
    PUSH AF
    Save the CLOAD/CLOAD? flag in Register A to the STACK
    *2C28
    LD A,(HL)
    Set the next element from the code string, which should be the filename
    *2C29
    OR A
    Set status flags
    *2C2A
    If it is the EOL, jump to 2C33H
    *2C2C
    Call 2337H to get the filename
    *2C2F
    Call 2A13H to get the address of the filename into DE
    *2C32
    LD A,(DE)
    Get the filename
    *2C33
    LD L,A
    Move the filename into Register L
    *2C34
    POP AF
    Restore the CLOAD/CLOAD? flag
    *2C35
    OR A
    Set the status Register according to that flag
    *2C36
    LD H,A
    H will now hold CLOAD/CLOAD? flag, and L will hold the filename
    *2C37
    LD (4121H),HLLD (FACLO),HL
    Put the flag and filename into ACCumulator
    *2C3A
    If the flag is a CLOAD, call the NEW routine at 1B4DH
    *2C3D
    LD HL,0000H
    Cause the drive to be selected
    *2C40
    Call 2093H to get the leader and sync byte from the cassette
    *2C43
    LD HL,(4121H)LD HL,(FACLO)
    Restore the CLOAD/CLOAD? flag and filename

    Common code between ROM v1.0 and v1.2 continues here.

    2C46
    EX DE,HLEB
    Load D with the CLOAD/CLOAD? flag and load Register E with the filename
    2C47-2C48
     ↳ LOPCLK
    LD B,03H06 03
    Load Register B with the number of header bytes
    2C49-2C4B
     ↳ LOPCL2
    Calls the READ ONE BYTE FROM CASSETTE routine at 0235H (which reads one byte from the cassette drive specified in Register A, and returns the byte in Register A)
    2C4C-2C4D
    SUB 0D3HD6 D3
    Check to see if the character in Register A is a filename header byte
    2C4E-2C4F
    Loop if the character in Register A isn’t a filename header byte
    2C50-2C51
    Loop back to 2C49H until three filename header bytes have been read
    2C52-2C54
    Now that the header is out of the way, let’s start working on the filename. GOSUB to 0235H to the READ ONE BYTE FROM CASSETTE (which reads one byte from the cassette drive specified in Register A, and returns the byte in Register A)
    2C55
    INC E1C
    We need to test to see if a filename was even given so we have to increase and decrease E to set flags . Bump the value of the filename in Register E
    2C56
    DEC E1D
    Decrement the value of the filename in Register E
    2C57-2C58
    Jump to 2C5CH (to pretend the filename matched) if no filename was specified
    2C59
    CP EBB
    If we are here, then the user has supplied a filename which is held in Register E AND we have the first byte from the tape in Register A, so we need to compare the filename specified in Register E with the character in Register A. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
    2C5A-2C5B
    Jump to 2C93H (to skip to the end of that file) if the filename specified in Register E doesn’t match the byte read from tape in Register A
    2C5C-2C5E
     ↳ NONAMC
    LD HL,(40A4H)LD HL,(TXTTAB)2A A4 40
    If we are here, the filename on tape matches the filename given so lets start loading. Load HL with the start of the BASIC program pointer.
    • Note: 40A4H-40A5H holds the starting address of BASIC program text also known as the PROGRAM STATEMENT TABLE (PST).

    This loop is going to read a byte, compare it to the next byte in the program memory, jump away if it doesn’t match AND CLOAD? was chosen, write (or overwrite) that byte to memory, check for a zero, and loop back if no zero was found.

    2C5F-2C60
     ↳ DOCRS
    LD B,03H06 03
    Load Register B with the number of zeros to look for to stop the load (which is 3)
    2C61-2C63
     ↳ DOCSMR
    Calls the READ ONE BYTE FROM CASSETTE routine at 0235H (which reads one byte from the cassette drive specified in Register A, and returns the byte in Register A)
    2C64
    LD E,A5F
    Preserve the character that was just read from tape into Register E
    2C65
    SUB (HL)96
    Compare the character we just read from the tape (held in Register A) with the character at the location of the memory pointer in HL by subtracting them
    2C66
    AND DA2
    Combine the subtracted result in Register A with the value of the CLOAD/CLOAD? flag in Register D. Why is this tricky? Because D is always 0 for a CLOAD, so when you AND against 0, you always get 0. If this was CLOAD?, nothing would happen as a result of this.
    2C67-2C68
    Jump to 2C8AH if CLOAD? was selected but the bytes don’t match
    2C69
    LD (HL),E73
    At this point either CLOAD? was selected and the bytes match, or CLOAD was selected. Either way, save the character we read from the tape (held in Register E) to the location of the memory pointer in HL
    2C6A-2C6C
    Make sure there is more room, and toss a ?OM ERROR if there isn’t.
    2C6D
    LD A,(HL)7E
    Load Register A with the character at the location of the memory pointer in HL
    2C6E
    OR AB7
    Check to see if the byte just read in Register A is equal to zero
    2C6F
    INC HL23
    Bump the value of the memory pointer in HL
    2C70-2C71
    Loop if the byte in Register A isn’t equal to zero (meaning that it isn’t end of program or end of statement)
    2C72-2C74
    Call the BLINK ASTERISK routine at 022CH which alternatively displays and clears an asterisk in the upper right hand corner of the video display
    2C75-2C76
    Do that loop until three zeros in a row have been read from the cassette recorder
    2C77-2C79
    LD (40F9H),HLLD (VARTAB),HL22 F9 40
    By this point, HL will have been incremented all the way through the program. Save the value of the memory pointer in HL as the new end of the BASIC program pointer.
    • Note: 40F9H-40FAH holds the starting address of the simple variable storage area.
    2C7A-2C7C
     ↳ OKCASS
    LD HL,1929HLD HL,REDDY21 29 19
    Load HL with the starting address of the BASIC READY message
    2C75-2C76
    Do that loop until three zeros in a row have been read from the cassette recorder
    2C80-2C82
    Go turn off the cassette recorder
    2C83-2C85
    LD HL,(40A4H)LD HL,(TXTTAB)2A A4 40
    Load HL with the start of the BASIC program pointer.
    • Note: 40A4H-40A5H holds the starting address of BASIC program text also known as the PROGRAM STATEMENT TABLE (PST).
    2C86
    PUSH HLE5
    Save the start of the BASIC program pointer in HL to the STACK. FINI will need this value there.
    2C87-2C89
    Jump to 1AE8H to reinitialize the BASIC interpreter and continue
    2C8A-2C8C
     ↳ NOGOOD
    LD HL,2CA5HLD HL,NOOKCS21 A5 2C
    Load HL with the starting address of the BAD message
    2C8D-2C8F
    CALL 28A7HCALL STROUTCD A7 28
    Call the WRITE MESSAGE routine at 28A7H to print the message pointed to by HL.
    NOTE:
    • The routine at 28A7 displays the message pointed to by HL on current system output device (usually video).
    • The string to be displayed must be terminated by a byte of machine zeros or a carriage return code 0D.
    • If terminated with a carriage return, control is returned to the caller after taking the DOS exit at 41D0H (JP 5B99H).
    2C90-2C92
    JUMP to STPRDY to pop NEWSTT from the STACK and then fall into the READY routine
    2C93-2C95
     ↳ SKPFIL
    LD (3C3EH),A32 3E 3C
    Go display the filename on the video display
    2C96-2C97
     ↳ ZERSRF
    LD B,03H06 03
    Load Register B with the number of zeros to be found to stop the search
    2C98-2C9A
     ↳ GETCHZ
    Calls the READ ONE BYTE FROM CASSETTE routine at 0235H (which reads one byte from the cassette drive specified in Register A, and returns the byte in Register A)
    2C9B
    OR AB7
    Check to see if the character in Register A is equal to zero
    2C9C-2C9D
    Loop if the character in Register A isn’t equal to zero
    2C9E-2C9F
    Loop until three zeros in a row have been read from the cassette recorder
    2CA0-2CA2
    Calls the READ CASSETTE LEADER routine at 0296 (which reads from the cassette recorder selected in Register A until the end-of-leader marker of A5H is found; and flashes the cursor while doing this)
    2CA3-2CA4
    Jump back to 2C47H

    2CA5-2CA9 – MESSAGE STORAGE LOCATION – “NOOKCS”

    2CA5-2CA9
     ↳ NOOKCS
    “BAD” + 0DH + 00H42
    The BAD message is stored here

    2CAA-2CB0 – LEVEL II BASIC PEEK ROUTINE – “PEEK”

    The original ROM source code says that PEEK only accepts positive numbers up to 32767 and POKE will only take an address up to 32767. Negative numbers can be used to refer to locations higher than 32767, the correspondence is given by subtracting 65536 from locations higher than 32767 or by specifying a positive number up to 65535
  • On entry, ACCumulator to have the peek location, and on exit ACCumulator to have the peeked value.
  • 2CAA-2CAC
     ↳ PEEK
    Call the CONVERT TO INTEGER routine at 0A7FH (where the contents of ACCumulator are converted from single or double precision to integer and deposited into HL)
    2CAD
    LD A,(HL)7E
    Load Register A with the value at the location of the memory pointer in HL
    2CAE-2CB0
    Go save the 8-bit value in Register A as the current result in ACCumulator

    2CB1-2CBC – LEVEL II BASIC POKE ROUTINE – “POKE”

    2CB1-2CB3
     ↳ POKE
    Go evaluate the expression at the location of the current BASIC program pointer in HL and return with the integer result in DE
    2CB4
    PUSH DED5
    Save the address the user wants to POKE to (held in DE) to the STACK
    2CB5-2CB6
    RST 08H ⇒ 2ESYNCHK “,”CF 2E
    Since the character at the location of the current BASIC program pointer in HL must be a ,, call the COMPARE SYMBOL routine at RST 08H.

    NOTE: The RST 08H routine compares 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 the next execution address (i.e, the RST 08H 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 and control returns to the Input Phase).
    2CB7-2CB9
    GOSUB to 2B1CH to evaluate the expression at the location of the current BASIC program pointer in HL and return with the 8-bit value in Register A
    2CBA
    POP DED1
    Get the address the user wants to POKE to from the STACK and put it in DE
    2CBB
    LD (DE),A12
    Save the value the user wanted to poke (held in Register A) in the location that the user wants to POKE to (held in DE)
    2CBC
    RETC9
    RETurn to CALLer

    2CBD-2E52 – LEVEL II BASIC USING ROUTINE – “PRINUS”

    The original ROM source code says that we wind up here after the “USING” clause in a PRINT statement is recognized. The idea is to scan the using string until the value list is exhausted, finding string and numeric fields to print values out of the list in, and just outputing any characters that aren’t part of a print field
    2CBD-2CBF
     ↳ PRINUS
    Go evaluate the string expression at the location of the current BASIC program pointer in HL
    2CC0-2CC2
    Go make sure the expression that was just evaluated was a string
    2CC3-2CC4
    RST 08H ⇒ 3BSYNCHK “;”CF 3B
    Since the character at the location of the current BASIC program pointer in HL must be a “;”, call the COMPARE SYMBOL routine at RST 08H.

    NOTE: The RST 08H routine compares 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 the next execution address (i.e, the RST 08H 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 and control returns to the Input Phase).
    2CC5
    EX DE,HLEB
    Swap DE and HL so that DE now holds the current BASIC program pointer
    2CC6-2CC8
    LD HL,(4121H)LD HL,(FACLO)2A 21 41
    Load HL with the USING string’s VARPTR
    2CC9-2CCA
    Jump down to 2CD3H to continue
    2CCB-2CCD
     ↳ REUSST
    LD A,(40DEH)LD A,(FLGINP)3A DE 40
    Load Register A with the value of the READ/INPUT flag, which is being used here to track if we printed out a value on the prior scan.
    2CCE
    OR AB7
    Check to see if that flag indivates that we did, or did not, print out a value last time.
    2CCF-2CD0
    If we did not print out a value last time, we have an error, so JUMP down to 2CDDH
    2CD1
    POP DED1
    Restore the pointer to the “USING” string decription from the STACK into DE
    2CD2
    EX DE,HLEB
    Swap DE and HL so that HL will hold the pointer to the “USING” string descriptor and DE will hold the pointer to the position on the BASIC line being evaluated.
    2CD3
     ↳ INIUS
    PUSH HLE5
    Save the pointer to the “USING” string descriptor (i.e., the USING string’s VARPTR) in HL to the STACK
    2CD4
    XOR AAF
    Zero Register A and all the flags.
    2CD5-2CD7
    LD (40DEH),ALD (FLGINP),A32 DE 40
    Clear the flag we are using to see if we printed the values or not.
    2CD8
    CP DBA
    Turn the Z FLAG off so as to indicate the value list has not ended yet. This is accomplished by checking to see if the value in D is equal to zero by checking it against A which was XOR’d to 0 above. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
    2CD9
    PUSH AFF5
    Save the flag indicating if the value list has ended or not to the STACK
    2CDA
    PUSH DED5
    Save the pointer into the value list to the STACK
    2CDB
    LD B,(HL)46
    Load Register B with the USING string’s length
    2CDC
    OR BB0
    Check to see if the USING string’s length in Register B is equal to zero
    2CDD-2CDF
     ↳ FCERR3
    If the USING string is NULL then display a ?FC ERROR
    2CE0
    INC HL23
    Bump the pointer to the USING string’s data in HL by 1
    2CE1
    LD C,(HL)4E
    Load Register C with the LSB of the USING string’s address at the location of the USING string’s VARPTR in HL
    2CE2
    INC HL23
    Bump the value of the USING string’s VARPTR in HL
    2CE3
    LD H,(HL)66
    Load Register H with the MSB of the USING string’s address at the location of the USING string’s VARPTR in HL
    2CE4
    LD L,C69
    Load Register L with the LSB of the USING string’s address in Register C
    2CE5-2CE6
    Jump down to 2D03H to loop to scan the USING string

    2CE7
     ↳ BGSTRF
    LD E,B58
    Load Register E with the USING string’s length
    2CE8
    PUSH HLE5
    Save the pointer to the USING string pointer in HL to the top of the STACK
    2CE9-2CEA
    LD C,02H0E 02
    Since the \\ string field length is two plus number of enclosed spaces, add two
    2CEB
     ↳ LPSTRF
    LD A,(HL)7E
    Load Register A with the character at the location of the USING string pointer in HL
    2CEC
    INC HL23
    Bump the value of the USING string data pointer in HL
    2CED-2CEE
    CP 25HCP CSTRNGFE 25
    Check to see if the character in Register A is a %, which acts as a field terminator. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
    2CEF-2CF1
    If it is a “%” then JUMP to 2E17H to evaluate a string and print
    2CF2-2CF3
    CP 20HFE 20
    Check to see if the character in Register A is a ” “, which acts as a field extender. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
    2CF4-2CF5
    If the character is not a field extender, then it isn’t a string field, so JUMP down a few opcodes to 2CF9H
    2CF6
    INC C0C
    Increment the field width (tracked in in Register C)
    2CF7-2CF8
    Decrement the USING string’s length in Register B and loop back to keep scanning for the field terminator or more characters

    If we are here, then a string field was not found. The “USING” string character count and the pointer into its data MUST be restored and the “\” printed.
    2CF9
     ↳ NOSTRF
    POP HLE1
    Restore the pointer to the “USING” string’s data into Register Pair HL
    2CFA
    LD B,E43
    Load Register B with the USING string’s length
    2CFB-2CFC
    LD A,25HLD A,CSTRNG3E 25
    Restore the character into Register Adiv>
    At this point we need to print the character held in Register A since it wasn’t part of any field
    2CFD-2CFF
     ↳ NEWUCH
    If a + came before the character, make sure to print it
    2D00-2D02
    Once that has been printed, now we print the character in Register A since we know it isn’t part of a field
    2D03
     ↳ PRCCHR
    XOR AAF
    We need to set Register Pair DE to 0 so that if we jump away, some of the flags are already ZERO, thus preventing us from printing a second “+”. To do this, first zero Register A and clear the flags
    2D04
    LD E,A5F
    Zero Register E
    2D05
    LD D,A57
    Zero Register D
    2D06-2D08
     ↳ PLSFIN
    Go print a leading + if necessary (i.e., to allow for multiple plusses)
    2D09
    LD D,A57
    Set the “plus flag” in Register D based on Register A. Note, since this is a loop, A could (and is) set to different values below.
    2D0A
    LD A,(HL)7E
    Load Register A with the next field description character in the USING string
    2D0B
    INC HL23
    Bump the value of the USING string pointer in HL
    2D0C-2D0D
    CP 21HCP “!”FE 21
    Check to see if the character in Register A is a ! (which represents a single string character). If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
    2D0E-2D10
    Jump if the character in Register A is a !
    2D11-2D12
    CP 23HCP “#”FE 23
    Check to see if the character in Register A is a # (which represents the start of a numeric field). If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
    2D13-2D14
    Jump if the character in Register A is a #
    2D15
    DEC B05
    Since every other possibility is actually a two character field, decrement the value of the string’s length in Register B onem ore time
    2D16-2D18
    If the USING list is exhausted (because we have a Z from that DEC), JUMP to REUSIN to reuse the USING string.
    Now we parse all the 2 character USING fields.
    2D19-2D1A
    CP 2BHCP “+”FE 2B
    Check to see if the character in Register A is a + (i.e., a leading PLUS). If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
    2D1B-2D1C
    LD A,08H3E 08
    Set Register A to feed Register D (at the top of the loop) with an 08H to force a leading + in case a numeric field starts
    2D1D-2D1E
    Jump if the character in Register A was a +
    2D1F
    DEC HL2B
    Decrement the value of the USING string pointer so we can re-get the character.
    2D20
    LD A,(HL)7E
    Load Register A with the (current) character at the location of the USING string pointer in HL
    2D21
    INC HL23
    Bump the value of the USING string pointer in HL
    2D22-2D23
    CP 2EHCP “.”FE 2E
    Check to see if the character in Register A is a . (i.e., a numeric field with trailing digits). If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
    2D24-2D25
    Jump if the character in Register A is a . to scan with Register E holding the number of digits before the “.” as 0
    2D26-2D27
    CP 25HCP CSTRNGFE 25
    Check to see if the character in Register A is a % (i.e., a really big string field). If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
    2D28-2D29
    Jump to see if it is really a string field if the character in Register A is a %
    2D2A
    CP (HL)BE
    Check to see if the next character matches the current character in the the USING string. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
    2D2B-2D2C
    If the NZ flag is set, then we can’t have a $$ or a **, so all remaining possibilities are exhausted, so JUMP to NEWUCH
    2D2D-2D2E
    CP 24HCP “$”FE 24
    Check to see if the double character is a $. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
    2D2F-2D30
    Jump to set up the flag bit if the match is $$
    2D31-2D32
    CP 2AHCP “*”FE 2A
    Check to see if the double character is a **. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
    2D33-2D34
    If the NZ FLAG is set, then the character is simply not part of a field since all the possibilties have been tested. If so, JUMP
    2D35
    LD A,B78
    Prepare to test to see if the “USING” string is long enough for a **$ by first loading Register A with the USING string’s length
    2D36-2D37
    CP 02HFE 02
    Check to see if the USING string’s length in Register A is at least two. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
    2D38
    INC HL23
    Bump the value of the USING string pointer in HL
    2D39-2D3A
    Jump to 2D3EH if the USING string’s length in Register A isn’t at least two
    2D3B
    LD A,(HL)7E
    Load Register A with the character at the location of the USING string pointer in HL
    2D3C-2D3D
    CP 24HCP “$”FE 24
    Check to see if the character in Register A is a $. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
    2D3E-2D3F
    NOTSPC
    LD A,20H3E 20
    Set the * bit in Register A
    2D40-2D41
    If we did not ultimately get a **$ then JUMP (noting we do NOT set the dollar sign flag)
    2D42
    DEC B05
    Decrement the value of the USING string’s length to take the $ into account
    2D43
    INC E1C
    Bump the field width tracker to account for the floating dollar sign
    2D44-2D45
    CP 0AFHFE AF
    Z-80 Trick to skip over a XOR A if passing through by processing it as a CP AFH. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
    2D45
     ↳ DOLRNM
    XOR AAF
    This is $ processing for PRINT USING. Clear Register A.
    2D46-2D47
    ADD A,10HC6 10
    Mask Register A to set the bit for a floating dollar sign flag.
    2D48
    INC HL23
    Bump the value of the USING string pointer in HL to go past the special characters
    2D49
     ↳ SPCNUM
    INC E1C
    Since two characters specify the field size, start off with E=1
    2D4A
    ADD A,D82
    Combine the bits in Register D into the flag tracker
    2D4B
    LD D,A57
    Preserve the modified flag tracker into Register D.
    2D4C
     ↳ NUMNUM
    INC E1C
    Bump the number of characters to the left of the decimal point in Register E
    2D4D-2D4E
    LD C,00H0E 00
    Set the number of digits to the right of the decimal point (tracked in Register C) to 0
    2D4F
    DEC B05
    Check to see if there are any more characters by decrementing the value of the string’s length in Register B
    2D50-2D51
    If the Z FLAG is set because we ran out of the characters to scan, then JUMP to ENDNUS because we are done scanning this particular numeric field.
    2D52
    LD A,(HL)7E
    Load Register A with the next character at the location of the USING string pointer in HL
    2D53
    INC HL23
    Bump the value of the USING string pointer in HL
    2D54-2D55
    CP 2EHCP “.”FE 2E
    Check to see if the character in Register A is a . (i.e., a trailing digit). If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
    2D56-2D57
    If yes, then need to use a special scan loop to scan after the decimal point, so JUMP to AFTDOT
    2D58-2D59
    CP 23HCP “#”FE 23
    Check to see if the character in Register A is a # (i.e., a leading digit). If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
    2D5A-2D
    If yes, increment the count and keep scanning via a JUMP to NUMNUM
    2D5C-2D5D
    CP 2CHCP “,”FE 2C
    Check to see if the character in Register A is a ,. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
    2D5E-2D5F
    If there is no comma, then JUMP to FINNUM because there are no more leading digits and we need to check for “^^^”
    2D60
    LD A,D7A
    If we are here, then a comma was requested. Turn on the COMMA bit
    2D61-2D62
    OR 40HF6 40
    Mask the flag in Register A for ,
    2D63
    LD D,A57
    Load Register D with the value of the flag in Register A
    2D64-2D65
    Jump to 2D4CH to keep scanning

    2D66 – Part of the PRINT USING Routine – “DOTNUM”

    Jumped here when a “.” is seen in the USING string. THis means that we are starting a numeric field ONLY if it is followed by a “#”
    2D66
     ↳ DOTNUM
    LD A,(HL)7E
    Load Register A with the next character of the USING string
    2D67-2D68
    CP 23HFE 23
    Check to see if the character in Register A is a # (i.e., a numeric field following a “.”). If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
    2D69-2D6A
    LD A,2EHLD A,”.”3E 2E
    Load Register A with a decimal point
    2D6B-2D6C
    If it isn’t a “.” then JUMP AWAY to NEWUCH with A holding a “.” so that a “.” will get printed
    2D6D-2D6E
    LD C,01H0E 01
    If it was a “.” then we have a numeric field to process. First, set C with the number of characters to the right of the decimal point
    2D6F
    INC HL23
    Bump the value of the USING string pointer in HL
    2D70
     ↳ AFTDOT
    INC C0C
    Bump the number of digits to the right of the decimal point (tracked in Register C)
    2D71
    DEC B05
    Decrement the value of the USING STRING’s length to test to see if there are more characters
    2D72-2D73
    If the USING string length is now ZERO, JUMP to ENDNUS to stop scanning
    2D74
    LD A,(HL)7E
    Load Register A with the character at the location of the USING string pointer in HL
    2D75
    INC HL23
    Bump the value of the USING string pointer in HL
    2D76-2D77
    CP 23HFE 23
    Check to see if the character in Register A is a #; meaning that there are more digits after the decimal point. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
    2D78-2D79
    If there are more digits, JUMP to AFTDOT to increment the count and keep scanning

    2D7A – Part of the PRINT USING Routine – “FINNUM”

    Now we move on to check the “^^^^” that indicates scientific notation
    2D7A
     ↳ FINNUM
    PUSH DED5
    Save the value of the flag (tracked in D) and the number of leading digits (tracked in E) to the STACK
    2D7B-2D7D
    LD DE,2D97HLD DE,NOTSCI11 97 2D
    Load DE with the return address in case this is not a scientific notation
    2D7E
    PUSH DED5
    Save the value of the return address in DE to the STACK
    2D7F
    2D80
    LD D,H
    LD E,L54
    Let DE = HL in case we need to rememer HL
    2D81-2D82
    CP 5BHFE 5B
    Check to see if the character in Register A is an up arrow. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
    2D83
    RET NZC0
    Return if the character in Register A isn’t an up arrow
    2D84
    CP (HL)BE
    Check to see if the character at the location of the USING string pointer in HL is an up arrow. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
    2D85
    RET NZC0
    Return to 2D97 if the character at the location of the USING string pointer in HL isn’t an up arrow (meaning we do not have a ^^ format)
    2D86
    INC HL23
    Bump the value of the USING string pointer in HL
    2D87
    CP (HL)BE
    Check to see if there is a third up arrow at the location of the USING string pointer in HL. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
    2D88
    RET NZC0
    Return to 2D97 if the character at the location of the USING string pointer in HL isn’t an up arrow (meaning we do not have a ^^^ format)
    2D89
    INC HL23
    Bump the value of the USING string pointer in HL
    2D8A
    CP (HL)BE
    Check to see if the character at the location of the USING string pointer in HL is a fourth up arrow. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
    2D8B
    RET NZC0
    Return to 2D97 if the character at the location of the USING string pointer in HL isn’t an up arrow (meaning we do not have a ^^^^ format)
    2D8C
    INC HL23
    Bump the value of the USING string pointer in HL. If we are here we have a #.^^^^ format
    2D8D
    LD A,B78
    Now we need to check if there were enough characters for a ^^^^. First load Register A with the value of the USING string’s length in Register B
    2D8E-2D8F
    SUB 04HD6 04
    Check to see if there are at least 4 characters left in the USING string
    2D90
    RET CD8
    Return to 2D97 if there aren’t at least four characters left in the USING string
    2D91
    POP DED1
    If there are at least 4 characters left, then clean up the STACK by removing the NOTSCI return address
    2D92
    POP DED1
    Get the flag and the count of the characters to the left of the decimal point from the STACK and put it in DE
    2D93
    LD B,A47
    Load Register B with the new USING string’s length in Register A
    2D94
    INC D14
    Set the exponential notation flag (tracked in Register D)
    2D95
    INC HL23
    Bump the value of the USING string pointer in HL
    2D96
    JP Z,0D1EBHCA EB D1
    Z-80 Trick! If passing through this won’t do anything because the Z FLAG won’t be set AND the EX DE,HL won’t be executed because it doesn’t see that instruction.
    2D97“NOTSCI”
    EX DE,HLEB
    (Ignored if passing through) Restore the old HL into HL
    2D98
    POP DED1
    (Ignored if passing through) Restore the flags into Register D and the number of leading digits into Register E
    2D99
     ↳ ENDNUS
    LD A,D7A
    We need to test to see if the ‘leading plus’ flag is on, so we load Register A with the value of the edit flag in Register D
    2D9A
    DEC HL2B
    Decrement the value of the USING string pointer in HL
    2D9B
    INC E1C
    Bump the number of characters to the left of the decimal point in Register E to take into account the leading plus
    2D9C-2D9D
    AND 08HE6 08
    Mask Register A to NOT check for a trailing sign
    2D9E-2D9F
    If that AND leaves us with a NZ, then we are all done with the field, so JUMP to ENDNUM
    2DA0
    DEC E1D
    Otherwise, since we don’t have a leading plus, we don’t increment the number of digits before the decimal point … so decrement the number of characters to the left of the decimal point in Register E
    2DA1
    LD A,B78
    Check to see if there are more characters by first loading Register A with the USING string’s length from Register B
    2DA2
    OR AB7
    Check to see if this is the end of the USING string
    2DA3-2DA4
    If we are out of characters, then we are all done, so JUMP to ENDNUM
    2DA5
    LD A,(HL)7E
    If there ARE more characters, then fill Register A with the character at the location of the USING string pointer in HL
    2DA6-2DA7
    SUB 2DHSUB “-“D6 2D
    Check to see if the character in Register A is a (i.e., a trailing minus)
    2DA8-2DA9
    If it is, then JUMP to SGNTRL to set the trailing sign flag
    2DAA-2DAB
    CP 0FEHCP “+” – “-“FE FE
    Check to see if the character in Register A is a + (i.e., a trailing plus). If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
    2DAC-2DAD
    If its NOT, then we are done scanning, so JUMP to ENDNUM
    2DAE-2DAF
    LD A,08H3E 08
    If we are here then we did have a trailing “+” so first set the flag for a POSITIVE “+”
    2DB0-2DB1
     ↳ SGNTRL
    ADD A,04HC6 04
    Then set the flag for a trailing sign
    2DB2
    ADD A,D82
    Combine the value of the flag in Register D with the value of the flag in Register A
    2DB3
    LD D,A57
    Load Register D with the current flags
    2DB4
    DEC B05
    Decrement the value of the USING string’s length in Register B by 1 to account for the trailing sign

    2DB5 – Part of the PRINT USING Routine – “ENDNUM”

    Jump point for when we figure out that we are at the end of a string of digits within a USING string
    2DB5
     ↳ ENDNUM
    POP HLE1
    Get the value of the current BASIC program pointer from the STACK and put it in HL
    2DB6
    POP AFF1
    Load Register A with the flag that tells us whether there are more values to process in the value list.
    2DB7-2DB8
    If there are no more values in the value list to process, then JUMP to FLDFIN because we are done with the PRINT
    2DB9
    PUSH BCC5
    Save the number of characters remaining to be processed in the USING string (held in B) and the trailing digits (held in C) to the STACK
    2DBA
    PUSH DED5
    Save the flags (held in D) and the number of leading digits (held in E) to the STACK
    2DBB-2DBD
    Read a value from the value list by CALLING the routine to evaluate the expression at the location of the current BASIC program pointer and return with the result in ACCumulator
    2DBE
    POP DED1
    Restore the flags (held in D) and the number of leading digits (held in E) from the STACK
    2DBF
    POP BCC1
    Restore the number of characters remaining to be processed in the USING string (held in B) and the trailing digits (held in C) from the STACK
    2DC0
    PUSH BCC5
    Save the number of characters remaining to be processed in the USING string (held in B) and the trailing digits (held in C) to the STACK
    2DC1
    PUSH HLE5
    Save the value of the current BASIC program pointer in HL to the STACK
    2DC2
    LD B,E43
    Set Register B to hold the number of leading digits (i.e., the number of characters to the left of the decimal point)
    2DC3
    LD A,B78
    We need to test to make sure the total number if digits does not exceed 24, so first load Register A with the number of characters to the left of the decimal point in Register B
    2DC4
    ADD A,C81
    Then add the number of characters to the right of the decimal point in Register C to the number of characters to the left of the decimal point in Register A
    2DC5-2DC6
    CP 19HFE 19
    Check to see if the total number of characters in Register A is greater than 24. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
    2DC7-2DC9
    Display a FC ERROR message if the total number of digits is greater than 24
    2DCA
    LD A,D7A
    Load Register A with the flags (held in Register D)
    2DCB-2DCC
    OR 80HF6 80
    Turn on the “USING” bit in the flags
    2DCD-2DCF
    Prepare to print by calling the FLOATING TO ASCII routine at 0FBEH (whcih converts a single or double precision number in ACCumulator to its ASCII equivalent which will be stored at the buffer pointed to by HL using the format codes in the A, B, and C registers
    2DD0-2DD2
    Call the WRITE MESSAGE routine at 28A7H to print the message pointed to by HL.
    NOTE:
    • The routine at 28A7 displays the message pointed to by HL on current system output device (usually video).
    • The string to be displayed must be terminated by a byte of machine zeros or a carriage return code 0D.
    • If terminated with a carriage return, control is returned to the caller after taking the DOS exit at 41D0H (JP 5B99H).
    2DD3
     ↳ FNSTRF
    POP HLE1
    Top of a loop. Get the value of the current BASIC program pointer from the STACK and put it in HL
    2DD4
    DEC HL2B
    Decrement the value of the current BASIC program pointer in HL so we can test to see what the terminator was
    2DD5
    We need the next character in the BASIC program so call the EXAMINE NEXT SYMBOL routine at RST 10H.

    The RST 10H routine parses the characters starting at HL+1 for the first non-SPACE,non-09H,non-0BH character it finds. On exit, Register A will hold that character, and the C FLAG is set if its alphabetic, and NC FLAG if its alphanumeric. All strings must have a 00H at the end.
    2DD6
    SCF37
    Set the Carry flag to indicate that a CRLF is desired
    2DD7-2DD8
    If the character at the location of the current BASIC program pointer in Register A is an end of the BASIC statement character, then we need to print a CRLF, so JUMP to CRDNUS
    2DD9-2DDB
    LD (40DEH),ALD (FLGINP),A32 DE 40
    Set the flag that the value HAS been printed!
    2DDC-2DDD
    CP 3BHCP “;”FE 3B
    Check to see if the character at the location of the current BASIC program pointer in Register A is a semicolon. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
    2DDE-2DDF
    If so, then we have a legal delimiter, so JUMP to SEMUSN
    2DE0-2DE1
    CP 2CHCP “,”FE 2C
    Check to see if the character at the location of the current BASIC program pointer in Register A is a comma. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
    2DE2-2DE4
    If not a comma, then we have no more valid delimiters (it wasnt a “;” or a “,”) so go to the Level II BASIC error routine and display an SN ERROR message if the character at the location of the current BASIC program pointer in Register A isn’t a comma
    2DE5
     ↳ SEMUSN
    We need the next character in the BASIC program so call the EXAMINE NEXT SYMBOL routine at RST 10H.

    The RST 10H routine parses the characters starting at HL+1 for the first non-SPACE,non-09H,non-0BH character it finds. On exit, Register A will hold that character, and the C FLAG is set if its alphabetic, and NC FLAG if its alphanumeric. All strings must have a 00H at the end.
    2DE6
     ↳ CRDNUS
    POP BCC1
    Restore the number of characters remaining to be procesed in the USING string into Register B
    2DE7
    EX DE,HLEB
    Swap DE and HL so that DE will point to the location of the current BASIC program pointer. We don’t care about HL.
    2DE8
    POP HLE1
    Restore the position in the USING string from the STACK and put it in HL
    2DE9
    PUSH HLE5
    Save the position in the USING string (held in HL) to the STACK
    2DEA
    PUSH AFF5
    Save the flag that indicates whether or not the value list has terminated to the STACK
    2DEB
    PUSH DED5
    Save the value of the current BASIC program pointer (held in DE) to the STACK
    The original ROM source code indicates that since FRMEVL may have forced some garbage collection, we cannot rely on the pointer of characters remaining to be scanned. Instead, we have to use the number of characters scanned prior to calling FRMEVL as an offset to the “USING” string’s data after FRMEVL.
    2DEC
    LD A,(HL)7E
    Load Register A with the USING string’s length at the location of the USING string’s VARPTR in HL
    2DED
    SUB B90
    Subtract the number of characers which were already scanned
    2DEE
    INC HL23
    Bump the pointer to the “USING” strings string data
    2DEF
    LD C,(HL)4E
    Load Register C with the LSB of the USING string’s address at the location of the USING string’s VARPTR in HL
    2DF0
    INC HL23
    Bump the value of the USING string’s VARPTR in HL
    2DF1
    LD H,(HL)66
    Load Register H with the MSB of the USING string’s address at the location of the USING string’s VARPTR in HL
    2DF2
    LD L,C69
    Load Register L with the LSB of the USING string’s address in Register C
    2DF3-2DF4
    LD D,00H16 00
    Zero Register D so that Register Pair DE can be a 16 bit offset of whatever is held in A.
    2DF5
    LD E,A5F
    Load Register E with the USING string’s offset in Register A
    2DF6
    ADD HL,DE19
    Add the USING string’s offset in DE to the USING string’s address in HL to get us the new pointer into the USING string’s string data into HL
    2DF7
    LD A,B78
    Load Register A with the number of characters left to scan
    2DF8
    OR AB7
    Check to see if this is the end of the USING string
    2DF9-2DFB
    If there are still more string characters to scan, JUMP to PRCCHR to do so
    2DFC-2DFD
    Jump to 2E04H if this is the actual end of the entire USING string

    2DFE-2E00 – Part of the PRINT USING Routine – “REUSIN”

    We will wind up here when we are done processing a numeric field
    2DFE-2E00
     ↳ REUSIN
    GOSUB to 2E49H print a + if necessary
    2E01-2E03
    Go send the FINAL character (held in Register A) to the current output device
    2E04
     ↳ FINUSI
    POP HLE1
    Get the value of the current BASIC program pointer from the STACK and put it in HL
    2E05
    POP AFF1
    Restore the flag which indicates whether or not the value list has ended into Register A
    2E06-2E08
    If the value list has NOT ended, JUMP back to REUSST to reuse the USING string
    2E09-2E0B
     ↳ FLDFIN
    If we are here, then we didn’t have a , or ; after the PRINT USING, so we GOSUB to 20FEH to send a carriage return to the current output device if necessary
    2E0C
    EX (SP),HLE3
    Swap (SP) with HL so that HL will now point to the “USING” string’s descriptor and (SP) will hold the value of the current BASIC program pointer
    2E0D-2E0F
    Free the RAM holding the USING string
    2E10
    POP HLE1
    Get the value of the current BASIC program pointer from the STACK and put it in HL
    2E11-2E13
    Return to 2169H

    2E14-2E15 – Part of the PRINT USING Routine – “SMSTRF”

    We will wind up here when the “!” indicating a single character string field has been scanned
    2E14-2E15
     ↳ SMSTRF
    LD C,01H0E 01
    Set the field width to 1
    2E16-2E17
    LD A,0F1H3E F1
    Z-80 Trick. By putting a 3E in front of the F1 (which is POP AF, to clear the STACK) that POP AF gets skipped if flowing down in the code
    2E17
     ↳ ISSTRF
    POP AFF1
    (Skipped if passing down) Clear the STACK *dumping the HL that was being saved in case it turned out that this wasn’t actually a string)
    2E18
    DEC B05
    Decrement the USING string character count (tracked in Register B)
    2E19-2E1B
    If there was a “+” before the field, then print it
    2E1C
    POP HLE1
    Get the value of the current BASIC program pointer from the STACK and put it in HL
    2E1D
    POP AFF1
    Get the flag which indicates whether there are more values in the value list into Register A
    2E1E-2E1F
    If there are no more values in the value list, then we are done so JUMP back to 2E09H
    2E20
    PUSH BCC5
    Save the number of characters still to be scanned from the USING string (tracked in B) to the STACK
    2E21-2E23
    Read a value by GOSUBing to FRMEVL which will evaluate the expression at the location of the current BASIC program pointer in HL and return with the result in ACCumulator
    2E24-2E26
    Go make sure the current result in ACCumulator is a string
    2E27
    POP BCC1
    Restore the field width (a/k/a the number of characters to be printed) into Register C
    2E28
    PUSH BCC5
    Save the USING string’s length and the number of characters to be printed in BC to the STACK
    2E29
    PUSH HLE5
    Save the value of the current BASIC program pointer in HL to the STACK
    2E2A-2E2C
    LD HL,(4121H)LD HL,(FACLO)2A 21 41
    Load HL with the string’s VARPTR in ACCumulator
    2E2D
    LD B,C41
    Load Register B with field width (a/k/a the number of characters to be printed)
    2E2E-2E2F
    LD C,00H0E 00
    Zero Register C so that we can use the LEFT$ routine
    2E30
    PUSH BCC5
    Save the length of the string to be printed in Register B to the STACK (as we will need that for space padding)
    2E31-2E33
    Truncate the string to B characters via a call to the LEFT$ routine
    2E34-2E36
    Print the string to the current output device
    2E37-2E39
    LD HL,(4121H)LD HL,(FACLO)2A 21 41
    Load HL with the string’s VARPTR in ACCumulator so we can see if we need to pad the string
    2E3A
    POP AFF1
    Get the field width (a/k/a the length of the string to be printed) from the STACK and put it in Register A
    2E3B
    SUB (HL)96
    Determine the amount of padding needed into Register A by subtracting the string’s length at the location of the string’s VARPTR in HL from the length of the string to be printed in Register A
    2E3C
    LD B,A47
    Save the amount of padding needed into Register B
    2E3D-2E3E
    LD A,20H3E 20
    Load Register A with a SPACE
    2E3F
    INC B04
    Bump the number of spaces in Register B because the loop startes with a DEC B

    This loop will print all the spaces needed and then jump to 2DD3H.

    2E40
     ↳ UPRTSP
    DEC B05
    Top of a loop. Decrement the number of spaces in Register B
    2E41-2E43
    If all of the spaces have been printed, Jump back to 2DD3H to see if the value list ended and to resume scanning
    2E44-2E46
    Go send a space to the current output device
    2E47-2E48
    LOOP back to 2E40H to print all the spaces

    2E49 – Part of the PRINT USING Routine – “PLSPRT”

    When a “+” is detected in the “USING” string and a numeric field follows, a bit in Register D should be set, otherwise + should be printed. Since deciding whether a numeric field follows is very difficult, the bit is always set in Register D. At the point it is decided a character is not part of a numeric field, this routine is called to see if the bit in Register D is set, which means a plus preceded the character and should be printed
    2E49
     ↳ PLSPRT
    PUSH AFF5
    Save the current character (held in Register A) to the STACK
    2E4A
    LD A,D7A
    We need to test the PLUS BIT in D, so first load Register A with the value in Register D
    2E4B
    OR AB7
    Check to see if Register A is equal to zero as that would be the ONLY bit which could be turned on at this particular point in the routine.
    2E4C-2E4D
    LD A,2BHLD A,”+”3E 2B
    Prepare to print the + by loading Register A with a +
    2E4E-2E50
    If the bit was set (i.e., A was non-zero), then send a + to the current output device
    2E51
    POP AFF1
    Get the current character from the STACK and put it in Register A
    2E52
    RETC9
    RETurn to CALLer

    2E53-2FFA – LEVEL II BASIC EDIT ROUTINE – “ERREDT”

    According to the original ROM source, the EDIT command takes a single line number as its argument. If that line doesn’t exist, and error is thrown. If the line does exist, the line number is then typed, and the system waits for the user to enter any of the valid commands.

  • Register C holds the number of characters in the line, Register B holds the current character position (with 0 being the first character) and Register Pair HL points to the current character
  • 2E53-2E55
     ↳ ERREDT
    LD (409AH),ALD (ERRFLG),A32 9A 40
    Reset the EDIT flag.
    Note: 409AH holds the ERROR/RESUME flag
    2E56-2E58
    LD HL,(40EAH)LD HL,(ERRLIN)2A EA 40
    Load HL with the line number to be edited.
    Note: 40EAH-40EBH holds the line number with error
    2E59
    OR HB4
    OR Register A with the MSB of the error line number in Register H
    2E5A
    AND LA5
    Combine the LSB of the error line number in Register L with the MSB of the line number in Register A. It will be FFH if this was a direct command rather than being part of a program
    2E5B
    INC A3C
    Bump the combined value of the error line number in Register A. If this was a direct call from the command line, this will turn A from FFH into 00H
    2E5C
    EX DE,HLEB
    Swap DE and HL so that DE now holds the line number to edit.
    2E5D
    RET ZC8
    If there was no line number, return if Level II BASIC
    2E5E-2E5F
    otherwise, continue via a JUMP to 2E64H
    Now that the above code is out of the way (it was the code which would enter EDIT if there was an error in a line number), let us actually process the EDIT command
    2E60-2E62
     ↳ EDIT
    Get the first line number by calling 1E4F – returns in in DE
    2E63
    RET NZC0
    If the zero flag got set, there was no line number, so return
    2E64
     ↳ EREDIT
    POP HLE1
    Clean up the STACK (i.e., discard the NEWSTT return address)
    2E65
     ↳ EEDITS
    EX DE,HLEB
    Load HL with the line number to be edited in DE
    2E66-2E68
    LD (40ECH),HLLD (DOT),HL22 EC 40
    Save the value of the line number to be edited (in HL) to the memory location that cares about such things.
    Note: 40ECH-40EDH holds EDIT/LIST line number
    2E69
    EX DE,HLEB
    Load HL with the line number to be edited
    2E6A-2E6C
    Find that line number via a GOSUB to the SEARCH FOR LINE NUMBER routine at 1B2CH which looks for the line number specified in DE. Returns C/Z with the line found in BC, NC/Z with line number is too large and HL/BC having the next available location, or NC/NZ with line number not found, and BC has the first available one after that
    2E6D-2E6F
    If the BASIC line number doesn’t exist, display a ?UL ERROR
    2E70
    2E71
    LD H,B
    LD L,C60
    At this point, the line number has been found. Let HL=BC so that HL also points to the location in RAM of the line number being edited
    2E72
    2E73
    INC HL
    INC HL23
    Bump the value of the memory pointer in HL twice to now point to the first byte of the line.
    2E74
    LD C,(HL)4E
    Load Register C with first byte of the line number being edited
    2E75
    INC HL23
    Bump the value of the memory pointer in HL to point to the second byte of the line being edited
    2E76
    LD B,(HL)46
    Load Register B with second byte of the line number being edited
    2E77
    INC HL23
    Bump the value of the memory pointer in HL to now point to the first byte of the actual line
    2E78
    PUSH BCC5
    Save the line number to the STACK
    2E79-2E7B
    GOSUB to 2B7EH move the BASIC line at the location of the memory pointer in HL into a memory buffer and untokenize the BASIC line
    2E7C
     ↳ LLED
    POP HLE1
    Get the value of the line number from the STACK and put it in HL
    2E7D
     ↳ INLED
    PUSH HLE5
    Save the value of the line number in HL to the STACK
    2E7E-2E80
    Convert the line number to ASCII and print it out by calling the HL TO ASCII routine at 0FAFH (which converts the value in the HL (assumed to be an integer) to ASCII and display it at the current cursor position on the video screen)
    2E81-2E82
    LD A,20H3E 20
    Load Register A with a space
    2E83-2E85
    Go display the space in Register A
    2E86-2E88
    LD HL,(40A7H)LD HL,(BUFPNT)2A A7 40
    Load HL with the starting address of the expanded version of the current line from the input buffer.
    Note: 40A7H-40A8H holds the input Buffer pointer
    2E89-2E8A
    LD A,0EH3E 0E
    Load Register A with the “turn on the cursor” character
    2E8B-2E8D
    Go turn on the cursor
    2E8E
    PUSH HLE5
    Save the value of the input buffer pointer (in HL) to the STACK
    2E8F-2E90
    LD C,FFH0E FF
    Load Register C with the number of characters examined so far with FFH because the next line is going to INC it by 1 to make it 0
    2E91
     ↳ LENLP
    INC C0C
    Bump the number of characters examined so far in Register C
    2E92
    LD A,(HL)7E
    Load Register A with the character at the location of the input buffer pointer in HL
    2E93
    OR AB7
    Check to see if the character in Register A is an end of the BASIC line character
    2E94
    INC HL23
    Bump the value of the input buffer pointer in HL
    2E95-2E96
    Loop back to 2E91H until the end of the BASIC line has been found
    2E97
    POP HLE1
    At this point, C will be the maximum number of characters in the line at issue. Put the start of the expanded buffer into HL
    2E98
    LD B,A47
    Set the current position in the BASIC line being edited (tracked by Register B) to ZERO
    2E99-2E9A
     ↳ DISPED
    LD D,00H16 00
    Assume the repetition count for the upcoming command (tracked by Register D) is zero
    2E9B-2E9D
     ↳ DISPI
    Go scan the keyboard to wait for the user command
    2D9E-2E9F
     ↳ DISP
    SUB 30H20 15
    We need to test to see if the character was alphabetic or alphanumeric so we subtract 30H from it
    2EA0-2EA1
    Jump down to 2EB0H if the character in Register A is alphabetic
    2EA2-2EA3
    CP 0AHFE 0A
    Check to see if the character is Register A is numeric. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
    2EA4-2EA5
    Jump to 2EB0H if the character in Register A isn’t numeric
    2EA6
    LD E,A5F
    Load Register E with the binary value of the character in Register A
    2EA7
    LD A,D7A
    Put the repetition value into Register A
    2EA8
    RLCA07
    Multiply the value in Register A by two (so now A has multiplied by 2)
    2EA9
    RLCA07
    Multiply the value in Register A by two (so now A has multiplied by 4)
    2EAA
    ADD A,D82
    Add the value in Register D to the value in Register A (so now A has multiplied by 5)
    2EAB
    RLCA07
    Multiply the value in Register A by two (so now A has multiplied by 10). Now the “ones place” is empty.
    2EAC
    ADD A,E83
    Add the value in Register E to the value in Register A in the “ones place”
    2EAD
    LD D,A57
    Load Register D with the value in Register A
    2EAE-2EAF
    Loop until a nonnumeric character is pressed

    2EB0H – LEVEL II BASIC EDIT ROUTINE – “NOTDGI”

    While getting user command input within an edit, we wind up here if the user enters a non-numeric character (i.e., the actual command, and not just the repetition number which precedes it)
    2EB0
     ↳ NOTDGI
    PUSH HLE5
    Save the value of the input buffer pointer in HL to the STACK
    2EB1-2EB3
    LD HL,2E99HLD HL,DISPED21 99 2E
    Load HL with the return address of 2E99H
    2EB4
    EX (SP),HLE3
    Exchange the value of the return address in HL with the value of the input buffer pointer to the STACK
    2EB5
    DEC D15
    We need to test if the command was preceded by a number so we need to set the flags by first decrementing the numeric value in Register D
    2EB6
    INC D14
    … and then incrementing the numeric value in Register D to set the flags
    2EB7-2EB9
    If we had a received a repetition count already, then JUMP to 2EBBH
    2EBA
    INC D14
    Otherwise, set the repetition count (held in Register D) to be one
    2EBB-2EBC
     ↳ NTZERD
    CP 0D8HFE D8
    Check to see if the character in Register A is a BACKSPACE character. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
    2EBD-2EBF
    If the character in Register A is a BACKSPACE character, JUMP to DELED
    2EC0-2EC1
    CP 0DDHFE DD
    Check to see if the character in Register A is a CARRIAGE RETURN. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
    2EC2-2EC4
    If the character in Register A is a CARRIAGE RETURN, JUMP to CRED
    2EC5-2EC6
    CP 0F0HFE F0
    Check to see if the character in Register A is a SPACE. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
    2EC7-2EC8
    If the character in Register A is a SPACE, JUMP to SPED
    That’s it for non-alphabetic instructions, so we need to need to convert a lower case command to upper case
    2EC9-2ECA
    CP 31HFE 31
    Check to see if the character in Register A is lowercase. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
    2ECB-2ECC
    Jump if the character in Register A isn’t lowercase
    2ECD-2ECE
    SUB 20HD6 20
    Convert the lowercase character in Register A to uppercase
    2ECF-2ED0
     ↳ NOTLW4
    CP 21HFE 21
    Check to see if the character in Register A is a Q (i.e., QUIT the edit). If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
    2ED1-2ED3
    Jump if the character in Register A is a Q (i.e., QUIT)
    2ED4-2ED5
    CP 1CHFE 1C
    Check to see if the character in Register A is an L. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
    2ED6-2ED7
    Jump if the character in Register A is an L (i.e., BRANCH)
    2ED9-2EDA
    CP 23HFE 23
    Check to see if the character in Register A is an S. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
    2EDB-2EDC
    Jump if the character in Register A is an S (i.e., SEARCH)
    2EDD-2EDE
    CP 19HFE 19
    Check to see if the character in Register A is an I. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
    2EDF-2EE1
    Jump if the character in Register A is an I (i.e., INSERT)
    2EE2-2EE3
    CP 14HFE 14
    Check to see if the character in Register A is a D. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
    2EE4-2EE6
    Jump if the character in Register A is a D (i.e., DELETE)
    2EE7-2EE8
    CP 13HFE 13
    Check to see if the character in Register A is a C. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
    2EE9-2EEB
    Jump if the character in Register A is a C (i.e., CHANGE)
    2EEC-2EED
    CP 15HFE 15
    Check to see if the character in Register A is an E. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
    2EEE-2EF0
    Jump if the character in Register A is an E (i.e., END)
    2EF1-2EF2
    CP 28HFE 28
    Check to see if the character in Register A is an X. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
    2EF3-2EF5
    Jump if the character in Register A is an X (i.e., EXTEND)
    2EF6-2EF7
    CP 1BHFE 1B
    Check to see if the character in Register A is a K. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
    2EF8-2EF9
    Jump if the character in Register A is a K (i.e., KILL)
    2EFA-2EFB
    CP 18HFE 18
    Check to see if the character in Register A is an H. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
    2EFC-2EFE
    Jump if the character in Register A is an H (i.e., HACK off the rest of the line and then enter INSERT mode)
    2EFF-2F00
    CP 11HFE 11
    Check to see if the character in Register A is an A (i.e., AGAIN). If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
    2F01
    RET NZC0
    Return if the character in Register A isn’t an A

    2F02 – EDIT Command – Cancel and Restore Logic.

    2F02
    POP BCC1
    Clean up the STACK (i.e., remove the DISPI return address)
    2F03
    POP DED1
    Get the BASIC line number from the STACK and put it in DE
    2F04-2F06
    Go print a carriage return on the video display if necessary
    2F07-2F09
    Jump back to 2E65H to re-enter the EDIT routine

    2F0A – This routine prints a string of text to the display, printer or tape – “SPED”

    This routine it uses 032AH to do this. HL must point to the first character of the string. (409CH must be set before calling this routine, see 32AH). String must be delimited with a zero byte.
    Note: 409CH holds the current output device flag: -1=cassette, 0=video and 1=printer
    2F0A
     ↳ SPED
    LD A,(HL)7E
    Load Register A with the character at the location of the input buffer pointer in HL
    2F0B
    OR AB7
    Check to see if the character in Register A is an end of the BASIC line character
    2F0C
    RET ZC8
    Return if the character in Register A is an end of the BASIC line character
    2F0D
    INC B04
    Bump the character position in Register B
    2F0E-2F10
    Go display the character in Register A
    2F11
    INC HL23
    Bump the value of the pointer in HL
    2F12
    DEC D15
    Decrement the number of times to perform the operation in Register D
    2F13-2F14
    Loop until done
    2F15
    RETC9
    RETurn to CALLer

    2F16 – EDIT Command – KILL Logic – “KED”.

    2F16
     ↳ KED
    PUSH HLE5
    Save the current character position in the buffer in HL to the STACK
    2F17-2F19
    LD HL,2F5FHLD HL,TYPSLH21 5F 2F
    Load HL with the return address of 2F5FH (which will print the final !
    2F1A
    EX (SP),HLE3
    Exchange the value of the return address in HL with the value of the input buffer pointer to the STACK
    2F1B
    SCF37
    Set the KILL/SEARCH flag for KILL since CARRY flag signals KILL
    2F1C
     ↳ SED
    PUSH AFF5
    Save the KILL/SEARCH flag to the STACK
    2F1D-2F1F
    Go scan the keyboard for the character the user wants to SEARCH for
    2F20
    LD E,A5F
    Save the character the user wants to SEARCH for into Register E
    2F21
    POP AFF1
    Get the KILL/SEARCH flag from the STACK
    2F22
    PUSH AFF5
    Save the KILL/SEARCH flag to the STACK
    2F23-2F25
    If KILL (because the CARRY flag was set) then GOSUB to 2F5FH to print a !
    2F26
     ↳ SRCALP
    LD A,(HL)7E
    Load Register A with the character at the location of the input buffer pointer in HL
    2F27
    OR AB7
    Check to see if the character in Register A is an end of the BASIC line character
    2F28-2F2A
    Jump down to 2F3EH if the character in Register A is an end of the BASIC line character
    2F2B-2F2D
    Go display the character in Register A
    2F2E
    POP AFF1
    Get the KILL/SEARCH flag from the STACK
    2F2F
    PUSH AFF5
    Save the KILL/SEARCH flag to the STACK
    2F30-2F32
    If the CARRY flag is set, that means we are in KILL mode so GOSUB to 2FA1H to delete the character from the input buffer
    2F33-2F34
    Jump to 2F37H if KILL. Note, we do not move the HL pointer in this case because DELCHR already moved it.
    2F35
    INC HL23
    If we are here, it must be SEARCH! So bump to the next character
    2F36
    INC B04
    Bump the value of the character position in Register B
    2F37
     ↳ NOTSRC
    LD A,(HL)7E
    Regardless of whether we are SEARCH or KILL, load Register A with the character at the location of the current input buffer pointer in HL
    2F38
    CP EBB
    Check to see if the character in Register A is the same as the character to be located (i.e., the one specified by the user) in Register E. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
    2F39-2F3A
    Loop back to 2F26H until the character to be located is found
    2F3B
    DEC D15
    Decrement the number of times to perform the operation in Register D (as initially specified by the user by entering a number before the command)
    2F3C-2F3D
    Loop until done
    2F3E
     ↳ POPART
    POP AFF1
    Get the KILL/SEARCH flag from the STACK
    2F3F
    RETC9
    RETurn to CALLer

    2F40 – EDIT Command – LIST Logic – “LED”.

    2F40-2F42
     ↳ LED
    Since we need to display the line being edited we call the PRINT MESSAGE routine at 2B75H which writes string pointed to by HL to the current output device
    2F43-2F45
    Go display a carriage return if necessary
    2F46
    POP BCC1
    Clear off the RETURN address to DISPED
    2F47-2F49
    Jump to 2E7CH (to display the current line number and await the next EDIT command)

    2F4A – EDIT Command – DELETE Logic – “DED”

    2F4A
     ↳ DED
    LD A,(HL)7E
    Load Register A with the character at the location of the input buffer pointer in HL
    2F4B
    OR AB7
    Check to see if the character in Register A is an end of the BASIC line character
    2F5C
    RET Z15
    Return if the character in Register A is an end of the BASIC line character
    2F4D-2F4E
    LD A,21HLD A,”!”3E 21
    Load Register A with an !
    2F4F-2F51
    Go display the ! in Register A
    2F52
     ↳ DELLP
    LD A,(HL)7E
    Load Register A with the character at the location of the input buffer pointer in HL
    2F53
    OR AB7
    Check to see if the character in Register A is an end of the BASIC line character
    2F54-2F5B
    Jump to 2F5FH if the character in Register A is an end of the BASIC line character
    2F56-2F58
    Go display the character in Register A
    2F59-2F5B
    Go delete the character from the input buffer
    2F5C
    DEC D15
    Decrement the number of times to perform the operation in Register D (as initially specified by the user by entering a number before the command)
    2F5D-2F5E
    Loop until done
    2F5F-2F60
     ↳ TYPSLH
    LD A,21HLD A,”!”3E 21
    Load Register A with an !
    2F61-2F63
    Go display the ! in Register A
    2F64
    RETC9
    RETurn to CALLer

    2F65 – EDIT Command – CHANGE Logic – “CED”.

    2F65
     ↳ CED
    LD A,(HL)7E
    Load Register A with the character at the location of the input buffer pointer in HL
    2F66
    OR AB7
    Check to see if the character in Register A is an end of the BASIC line character
    2F67
    RET ZC8
    Return if the character in Register A is an end of the BASIC line character
    2F68-2F6A
    Go get the character to put in the input buffer from the keyboard
    2F6B
    LD (HL),A77
    Save the character in Register A at the memory location of the input buffer pointer in HL
    2F6C-2F6E
    Go display the character in Register A
    2F6F
    INC HL23
    Bump the value of the input buffer pointer in HL
    2F70
    INC B04
    Bump the character position in Register B
    2F71
    DEC D15
    Decrement the number of times to perform the operation in Register D (as initially specified by the user by entering a number before the command)
    2F72-2F73
    Loop until done
    2F74
    RETC9
    RETurn to CALLer

    2F75 – EDIT Command – HACK/INSERT Logic – “HED”

    2F75-2F76
     ↳ HED
    LD (HL),00H36 00
    Set the line end to be the current position.
    2F77
    LD C,B48
    Load Register C with the character position in Register B which will now be the line length
    2F78-2F79
     ↳ XED
    LD D,0FFH16 FF
    Prepare for the next CALL to find the end of the line by loading Register D with the number of times to perform the operation
    2F7A-2F7C
    GOSUB to 2F0AH to display the Register BASIC line if necessary
    2F7D-2F7F
     ↳ IED
    Go get the character to be inserted from the keyboard
    2F80
    OR AB7
    Check to see if a key was pressed
    2F81-2F83
    Loop back to 2F7DH until a key is pressed
    2F84-2F85
    CP 08HFE 08
    Check to see if the character in Register A is a backspace character. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
    2F86-2F87
    Jump to 2F92H if the character in Register A is a backspace character
    2F88-2F89
    CP 0DHFE 0D
    Check to see if the character in Register A is a carriage return. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
    2F8A-2F8C
    Jump to 2FE0H if the character in Register A is a carriage return
    2F8D-2F8E
    CP 1BHFE 1B
    Check to see if the character in Register A is a shift up arrow (also known as an ESCape). If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
    2F8F
    RET ZC8
    Return if the character in Register A is shift up arrow
    2F90-2F91
    Jump to 2FB0H to add the new character to the current line

    2F92 – EDIT Command – BACKSPACE CURSOR Logic – “TYPARW”.

    2F92-2F93
     ↳ TYPARW
    LD A,08H3E 08
    Load Register A with a backspace the cursor character
    2F94
     ↳ TYPAR1
    DEC B05
    Decrement the character position in Register B
    2F95
    INC B04
    Bump the character position in Register B
    2F96-2F97
    If this is the first character of the BASIC line Jump forward to 2FB7H
    2F98-2F9A
    Go backspace the cursor on the video display
    2F9B
    DEC HL2B
    Decrement the value of the input buffer pointer in HL
    2F9C
    DEC B05
    Decrement the character position in Register B
    2F9D-2F9F
    LD DE,2F7DHLD DE,IED11 7D 2F
    Load DE with a return address of 2F7DH
    2FA0
    PUSH DED5
    Save the value of the return address in DE to the STACK

    2FA1 – LEVEL II BASIC EDIT ROUTINE – “DELCHR”

    • This subroutine will delete the character pointed to by Register Pair HL and will correct Register C
    2FA1
     ↳ DELCHR
    PUSH HLE5
    Save the value of the input buffer pointer in HL to the STACK
    2FA2
    DEC C0D
    Decrement the character position in Register C
    2FA3
     ↳ CMPRSS
    LD A,(HL)7E
    Load Register A with the character at the location of the input buffer pointer in HL
    2FA4
    OR AB7
    Check to see if the character in Register A is an end of the BASIC line character
    2FA5
    SCF37
    Set the Carry flag to signal that DELCHR was called
    2FA6-2FA8
    If the character in Register A is an end of the BASIC line character then we are done compressing so Jump to 0890H
    2FA9
    INC HL23
    Bump the value of the input buffer pointer in HL
    2FAA
    LD A,(HL)7E
    Load Register A with the character at the location of the input buffer pointer in HL
    2FAB
    DEC HL2B
    Decrement the value of the input buffer pointer in HL
    2FAC
    LD (HL),A77
    Save the character in Register A at the location of the current input buffer pointer in HL
    2FAD
    INC HL23
    Bump the value of the input buffer pointer in HL
    2FAE-2FAF
    Loop back to 2FA3H to keep crunching the line

    2FB0 – EDIT Command – ADD A CHARACTER Logic – “NTARRW”.

    2FB0
     ↳ NTARRW
    PUSH AFF5
    Save the character to be inserted in Register A to the STACK
    2FB1
    LD A,C79
    Load Register A with the number of characters in the input buffer (i.e., the length of the line) in Register C
    2FB2-2FB3
    CP FFHCP BUFLENFE FF
    We need to make sure we aren’t trying to make the line too long, so check for the maximum BASIC line length. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
    2FB4-2FB5
    Jump forward to 2FB9H if the maximum BASIC line length hasn’t been reached
    2FB6
    POP AFF1
    Get the character to be inserted from the STACK and put it in Register A
    2FB7-2FB8
     ↳ DINGI
    The character needs to be ESCape, so jump back to 2F7DH
    2FB9
     ↳ OKINS
    SUB B90
    Subtract the character position in Register B from the number of characters in the input buffer in Register A. This should give the current byte position
    2FBA
    INC C0C
    Bump the number of characters in the input buffer in Register C
    2FBB
    INC B04
    Bump the character position in Register B
    2FBC
    PUSH BCC5
    Save the character position and the number of characters in the input buffer in BC to the STACK
    2FBD
    EX DE,HLEB
    Load DE with the input buffer pointer in HL
    2FBE
    LD L,A6F
    Load Register L with the number of bytes to move
    2FBF-2FC0
    LD H,00H26 00
    Zero Register H so that the number of bytes to move can be done in a 16 bit Register Pair.
    2FC1
    ADD HL,DE19
    Add the value of the input buffer pointer in DE to the character count in HL
    2FC2
    LD B,H44
    Load Register B with the MSB of the end of the BASIC line pointer in Register H
    2FC3
    LD C,L4D
    Load Register C with the LSB of the end of the BASIC line pointer in Register L
    2FC4
    INC HL23
    Bump the value of the end of the BASIC line pointer in HL
    2FC5-2FC7
    Go move the line up out character
    2FC8
    POP BCC1
    Get the character position and the number of characters in the input buffer from the STACK and put it in BC
    2FC9
    POP AFF1
    Get the character to be inserted from the STACK and put it in Register A
    2FCA
    LD (HL),A77
    Save the character in Register A at the location of the current input buffer pointer in HL
    2FCB-2FCD
    Go display the character in Register A
    2FCE
    INC HL23
    Bump the value of the input buffer pointer in HL
    2FCF-2FD1
    Jump back to 2F7DH to get more characters

    2FD2 – EDIT Command – BACKSPACE Logic – “DELED”.

    2FD2
     ↳ DELED
    LD A,B78
    Top of a loop. Test to see if we are moving back past the first character by first loading Register A with the number of times to backspace in Register B
    2FD3
    OR AB7
    Check to see if this is the start of the BASIC line
    2FD4
    RET ZC8
    Return if this is the start of the BASIC line
    2FD5
    DEC B05
    Decrement the character position in Register B
    2FD6
    DEC HL2B
    Decrement the value of the buffer pointer in HL
    2FD7-2FD8
    LD A,08H3E 08
    Load Register A with a backspace the cursor character
    2FD9-2FDB
    Backspace the cursor on the video display
    2FDC
    DEC D15
    Decrement the number of times to perform the operation in Register D
    2FDD-2FDE
    Loop until done
    2FDF
    RETC9
    RETurn to CALLer
    2FE0-2FE2
     ↳ CRED
    Since we need to display the rest of the BASIC line, we call the PRINT MESSAGE routine at 2B75H which writes string pointed to by HL to the current output device
    2FE3-2FE5
     ↳ EED
    Go display a carriage return if necessary
    2FE6
    POP BCC1
    Clean up the STACK (to remove the DISPED return address)
    2FE7
    POP DED1
    Get the BASIC line number (in binary) from the STACK and put it in DE
    2FE8
    LD A,D7A
    Load Register A with the MSB of the BASIC line number in Register D
    2FE9
    AND EA3
    Combine the LSB of the BASIC line number in Register E with the MSB of the BASIC line number in Register A
    2FEA
    INC A3C
    Bump the combined BASIC line number in Register A
    2FEB-2FED
     ↳ EDITRT
    LD HL,(40A7H)LD HL,(BUFPNT)2A A7 40
    Load HL with the starting address of the input buffer.
    Note: 40A7H-40A8H holds the input Buffer pointer
    2FEE
    DEC HL2B
    Decrement the value of the input buffer pointer in HL
    2FEF
    RET ZC8
    Return if this is the Level II BASIC command mode
    2FF0
    SCF37
    Set the Carry flag to to fool the INSERT code; this flags the line number has having been seen
    2FF1
    INC HL23
    Bump the value of the input buffer pointer in HL
    2FF2
    PUSH AFF5
    Save the command mode flag in AF to the STACK
    2FF3-2FF5
    Jump to entry point in the main Level II processing code

    2FF6 – EDIT Command – QUIT Logic – “QED”.

    2FF6
     ↳ QED
    POP BCC1
    Get rid of the DISPED return address
    2FF7
    POP DED1
    Get the line number off of the stack
    2FF8-2FFA
    Jump to the Level II BASIC READY routine
    2FFB-2FFF
    NOP00
    THE END OF THE LEVEL II BASIC ROMS
    2FFB-2FFF
    NOP00
    Nothing here
    *2FFB-2FFC
    SBC A,0C3H
    In ROM v1.2 this is just garbage
    2FF8-2FFA
    Jump to the Level II BASIC READY routine