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
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.
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
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
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
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)
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.
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.
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
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.
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
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
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.
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.
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.
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)
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.
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.
. 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.
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.
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.
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:
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.
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.
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
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 #
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
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.
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.
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.
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
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
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
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
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.
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
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
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.
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
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
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
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
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).
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.
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
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:
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.
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
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)
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.
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.
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.
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
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
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.
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.
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
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
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
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
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)
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:
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.
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)
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
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.
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
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.
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.
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)
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
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)
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.
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.
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.
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
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
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.
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
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.
Call the CONVERT TO SINGLE PRECISION routine at 0AB1H (which converts the contents of ACCumulator from integer or double precision into single precision)
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
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
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
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:
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.
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.
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.
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.
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.
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)
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)
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
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.
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.
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
(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
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)
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.
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)
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)
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.
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.
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.
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.
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.
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.
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
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
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.
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).
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)
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
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.
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.
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.
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.
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.
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.
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.
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
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”
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.
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.
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.
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:
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”
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.
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.
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.
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
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.
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
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.
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.
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
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
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
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
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.
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.
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
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
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:
If an entry is found, dimflg being on indicates a “doubly dimensioned” variable
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.
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
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.
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.
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
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!
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
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
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.
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.
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
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
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.
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
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
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
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.
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:
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
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.
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
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.
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
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
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
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
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
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)
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
Get an index
Put number+1 down at the VARPTR
Increase the VARPTR
Decmrent the number of DIMs
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
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
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
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.
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
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
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.
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
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
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:
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
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.
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.
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
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
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
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.
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.
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.
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
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
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 .)
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.
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.
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
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.
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
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.
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.
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.
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.
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.
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.
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
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.
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
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
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
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
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.
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
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.
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
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.
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).
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)
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
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
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:
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
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.
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
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
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.
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).
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
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
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
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.
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.
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
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”
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).
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.
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.
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
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
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
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
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
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
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
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
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.
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.
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
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
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.
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.
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.
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
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
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.
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
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.
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
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
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
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
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.
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)
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.
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
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
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
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)
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.
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
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).
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
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
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
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.
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.
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
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
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.
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.
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
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.
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.
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.
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.
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.
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.
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.
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
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.
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.
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.
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.
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.
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
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
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.
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.
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
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
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.
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.
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
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
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
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
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
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 +
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
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
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
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
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)
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.
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
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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
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
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.
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
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.
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.
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
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.
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
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
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