Page Customization
2003 – UE ERROR entry point – “GOERR”
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.
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.
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).
Note: 40E4H-40E5H holds AUTO increment
Note: 40E4H-40E5H holds AUTO increment
Note: 40E2H-40E3H holds Current BASIC line number
2039-2066 – LEVEL II BASIC IF ROUTINE – “IF”
. If they match, the Z FLAG is set, and otherwise the NZ 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 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.
2056H – LEVEL II BASIC ELSE ROUTINE – “FALSIF”
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.
2067-206E – LEVEL II BASIC LPRINT ROUTINE – FOR v1.0 ONLY – “LPRINT”
206F-2177 – LEVEL II BASIC PRINT@ ROUTINE – FOR v1.0 ONLY – “PRINT”
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).
NOTE: The RST 20H routine determines the type of the current value in ACCumulator and returns a combination of STATUS flags and unique numeric values in the A Register according to the data mode flag (40AFH). The results are returned as follows:
- Integer = NZ/C/M/E and A is -1
- String = Z/C/P/E and A is 0
- Single Precision = NZ/C/P/O and A is 1
- and Double Precision is NZ/NC/P/E and A is 5.
- Note: 409CH holds the current output device type number (-1=cassette, 0=video; or 1=printer)
Note: 409BH holds the printer carriage position
20DDH – LEVEL II BASIC PRINT@ ROUTINE – Jumped here if we are sure we are using the display – “ISTTY”
Note: 409DH holds the size of line on the video display
Note: 40A6H holds the current cursor line position
Note: 40A6H holds the current cursor line position
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.
2108 – This is the jump point for a continuation of the PRINT# code – “COMPRT” .
- Note: 409CH holds the current output device type number (-1=cassette, 0=video; or 1=printer)
- M will be set if the value in A is negative.
- P will be set if the value in A is positive or zero.
Note: 409BH holds the printer carriage position
Note: 409EH holds the size of line on the printer
Note: 40A6H holds the current cursor line position
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.
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).
- 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.
- Note: 409CH holds the current output device type number (-1=cassette, 0=video; or 1=printer)
Note: 409BH holds the printer carriage position
2153H – Displaying to Screen – “TTYIST”
Note: 40A6H holds the current cursor line position
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.
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” .
- Note: 409CH holds the current output device type number (-1=cassette, 0=video; or 1=printer)
- Note: 409CH holds the current output device type number (-1=cassette, 0=video; or 1=printer)
2178-217E – MESSAGE STORAGE LOCATION FOR REDO MESSAGE
– “TRYAGN”
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.
Note: 40DEH holds READ flag
Note: 40A9H holds Cassette input flag
Note: 40E6H-40E7H is a common temporary storage location
219A – INPUT logic – “INPUT”
Note: 40A9H holds cassette input flag
Note: 40A7H-40A8H holds the input Buffer pointer
Note: 40A7H-40A8H holds the input Buffer pointer
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).
21EF – READ logic – “READ”
Note: 40FFH-4100H holds READ pointer
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).
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).
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.
Note: 40DEH holds READ flag
Note: 40A9H holds Cassette input flag
NOTE: The RST 20H routine determines the type of the current value in ACCumulator and returns a combination of STATUS flags and unique numeric values in the A Register according to the data mode flag (40AFH). The results are returned as follows:
- Integer = NZ/C/M/E and A is -1
- String = Z/C/P/E and A is 0
- Single Precision = NZ/C/P/O and A is 1
- and Double Precision is NZ/NC/P/E and A is 5.
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.
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.
- NOTE: 0E65H converts the ASCII string pointed to by HL to its double precision equivalent; with output left in ACCumulator).
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.
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.
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.
Note: 40A9H holds Cassette input flag
*226A-226E – For ROM v1.2 – Replaced with NOPS
Note: 40DEH holds READ flag
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).
2286-2295 – MESSAGE STORAGE LOCATION – “EXIGNT”
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.
Note: 40DAH-40DBH holds DATA line number
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.
22B6-2336 – LEVEL II BASIC NEXT ROUTINE – “NEXT”
The original ROM source notes that a FOR entry on the STACK has the following format:
- LOW ADDRESS
- Token ($FOR in high byte) – 1 Byte
- Pointer to the loop variable – 2 Bytes
- A Byte reflecting the sign of the increment – 1 Byte
- Step value – 4 bytes
- Upper limit of FOR loop – 4 bytes
- Line number of the FOR statement – 2 bytes
- Text pointer to the FOR statement – 2 bytes
- HIGH ADDRESS
NOTE: The routine at 0A0CH algebraically compares the single precision value in BC/DE to the single precision value ACCumulator.
The results are stored in A as follows:
- A=0 if ACCumulator = BCDE
- A=1 if ACCumulator>BCDE; and
- A=FFH if ACCumulator<BCDE.
22EAH – Part of the NEXT code, where we process the variable as an integer – “INTNXT”
Note: 40AFH holds Current number type flag
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”
2313H – Part of the NEXT code, jumped if we haven’t hit the TO counter yet – “LOOPDN”
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.
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.
- The RETURN location on completion (RETAOP)
- The floating point temporary result
- The address of the operator routine
- The precedence of the operator
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).
Note: 40F3H-40F4H is a temporary storage location
Note: 40F3H-40F4H is a temporary storage location
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.
E Token
0 +
1 –
2 *
3 /
4 @@
5 AND
6 OR
Note: 40AFH holds Current number type flag
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
Note: 40AFH holds Current number type flag
Note: 411DH-4124H holds REG l
Note: 40D8H-40D9H holds Temporary storage location
23D4-23D6 – Part of the Evaluation Routine – “EPSTK”
Per the original ROM source, for exponentiation, we want to force the current value in the ACCumulator to be single precision. When application time comes, we force the right hand operand to single precision as well.
23D4-23D6 – 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.
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.
NOTE: The RST 20H routine determines the type of the current value in ACCumulator and returns a combination of STATUS flags and unique numeric values in the A Register according to the data mode flag (40AFH). The results are returned as follows:
- Integer = NZ/C/M/E and A is -1
- String = Z/C/P/E and A is 0
- Single Precision = NZ/C/P/O and A is 1
- and Double Precision is NZ/NC/P/E and A is 5.
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
Note: 40B0H holds Temporary storage location
Note: 40AFH holds Current number type flag
At this point, the number in the STACK MUST be an integer.
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.
Note: 411DH-4124H holds the ACCumulator
LD A,(DORES) 3A B0 40
Note: 40B0H holds Temporary storage location
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.
Note: 40AFH holds Current number type flag
2472H – Part of the Evaluation Routine – “STKSNG”
According to the original ROM source code, at this point the STACK holds a single precision number, we know that the ACCumulator holds either an integer or a single precision number, so we need to convert it.
247CH – Part of the Evaluation Routine – “FACSNG”
According to the original ROM source code, at this point the ACCuumulator holds a single precision number and the STACK holds an integer.
2490 – Integer divide – “INTDIV”
(ACC=DE / HL) Result will be in single-precision (NTF=4) and will be in the ACC.
Divides DE by HL. Both values are converted to single precision before the division is started. The quotient is left in REG l; the mode flag is updated. The orginal contents of the DE and HL Register sets are lost
The original ROM source code points that we can’t just live in integer world here, because we want 1/3 to be .3333 and not 0! So all arguments must be single precision even if they are integer
Integer Division: Divides DE by HL. Both values are converted to single precision before the division is started. The quotient is left in the ACCumulator; the mode flag is updated. The orginal contents of the DE and HL Register sets are lost
Single Precision Divide Divides the single precision value in (BC/DE) by the single precision value in the ACCumulator. The quotient is left in the ACCumulator.
249F – Evaluate a Variable, Constant, or Function Call – “EVAL”
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.
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.
Notes:
- C3H is a ERR token.
- A CP will return Z if there is a match against Register A, and NZ if not a match against Register A.
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.
Note: 409AH holds the RESUME flag
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.
Note: 40EAH-40EBH holds the line number with error
24E7-24FE VARPTR logic – “NTERL”
CP 0C0H CP $VARPTR FE C0Check to see if the character at the location of the current BASIC program pointer in Register A is a VARPTR token
24E9-24EAJump back to 24FFH if the character at the location of the current BASIC program pointer in Register A isn’t a VARPTR token
24EBWe need the next character in the BASIC program so call the EXAMINE NEXT SYMBOL routine at RST 10H.
The RST 10H routine parses the characters starting at HL+1 for the first non-SPACE,non-09H,non-0BH character it finds. On exit, Register A will hold that character, and the C FLAG is set if its alphabetic, and NC FLAG if its alphanumeric. All strings must have a 00H at the end.
24EC-24EDSince the character at the location of the current BASIC program pointer in HL must be a ( , call the COMPARE SYMBOL routine at RST 08H.
NOTE: The RST 08H routine compares the symbol in the input string pointed to by HL Register to the value in the location following the RST 08 call.- If there is a match, control is returned to the next execution address (i.e, the RST 08H instruction + 2) with the next symbol in the A Register and HL incremented by one.
- If the two characters do not match, a syntax error message is given and control returns to the Input Phase).
24EE-24F0CALL 260DH CALL PTRGETCD 0D 26Call the FIND ADDRESS OF VARIABLE routine at 260DH which searches the Variable List Table for a variable name which matches the name in the string pointed to in HL, and return the address of that variable in DE (and if there is no variable, it creates it, zeroes it, and returns THAT location)
24F1-24F2 VARRETSince 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)
24F3PUSH HL E5Save the value of the current BASIC program pointer in HL to the STACK
24F4EX DE,HL EBSwap DE and HL so that HL now holds the value to return
24F5LD A,H 7CLoad Register A with MSB of the variable’s address in Register H to make sure that it isn’t undefined.
24F6OR L B5Combine the LSB of the variable’s address in Register L with the MSB of the variable’s address in Register A. This type of pattern is used to check for something being zero
24F7-24F9JP Z,1E4AH JP Z,FCERRCA 4A 1EDisplay a ?FC ERROR if the variable’s address in HL is equal to zero, meaning that the variable is undefined
24FA-24FCCALL 0A9AH CALL MAKINTCD 9A 0ASave the variable’s address in HL as an integer into ACCumulator
24FDPOP HL E1Get the value of the current BASIC program pointer from the STACK and put it in HL
24FERET C9Return to the execution driver
24FF – Other Function Routine – Jumped here if it wasn’t VARPTR to see what else it might have been – “NTVARP”
CP 0C1H CP USRTK FE C1Check to see if the character at the location of the current BASIC program pointer in Register A is a USR token. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
2501-2503JP Z,27FEH JP Z,USRFNCA FE 27Jump to 27FEH if the character at the location of the current BASIC program pointer in Register A is a USR token
2504-2505CP 0C5H CP INSRTK FE C5Check to see if the character at the location of the current BASIC program pointer in Register A is a INSTR token. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
2501-2503JP Z,419DH JP Z,INSTRCA FE 27If 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-250ACP 0C8H CP $MEM FE C8Check to see if the character at the location of the current BASIC program pointer in Register A is a MEM token. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
250B-250DJP Z,27C9H JP Z,MEMCA C9 27If 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-250FCP 0C7H CP $TIME FE C7Check to see if the character at the location of the current BASIC program pointer in Register A is a TIME$ token. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
250B-250DJP Z,417DH JP Z,TIMECA C9 27If 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-2514CP 0C6H CP $POINT FE C6Check to see if the character at the location of the current BASIC program pointer in Register A is a POINT token. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
2515-2517JP Z,0132H JP Z,POINTCA 32 01Jump to 0132H if the character at the location of the current BASIC program pointer in Register A is a POINT token
2518-2519CP 0C9H CP $INKEY FE C9Check to see if the character at the location of the current BASIC program pointer in Register A is an INKEY$ token. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
251A-251CJP Z,019DH JP Z,INKEYCA 9D 01Jump to 019DH if the character at the location of the current BASIC program pointer in Register A is an INKEY$ token
251D-251ECP 0C4H CP $STRING FE C4Check to see if the character at the location of the current BASIC program pointer in Register A is a STRING$ token. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
241F-2421Jump to 2A2FH if the character at the location of the current BASIC program pointer in Register A is a STRING$ token
2522-2523CP 0BEH CP FNTK FE BECheck 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-2421JP Z,4155H JP Z,FNDOER 7AIf 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-2528SUB 0D7H SUB ONEFUN D6 D7Check 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
JP NC,254EH JP NC,ISFUND2 4E 25Jump to 254EH if the character at the location of the current BASIC program pointer in Register A is a SGN to MID$ token. The original ROM source notes that there is no need to check for an upper bound because functions are the highest allowed characters
252CH – Other Function Routine – If we pass through to here, the only other possibility is that it is a function in parenthesis – “PARCHK”
252C-252E PARCHKCALL 2335H CALL FRMPRNCD 35 23GOSUB to 2335H to recursively evaluate the expression at the location of the current BASIC program pointer in HL
252F-2530Since 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).
2531RET C9Return out of this routine
2532 – Binary Minus Routine – “DOMIN”
2532 DOMINLD D,7DH 16 7DLoad Register D with a precedence value below “^” but above everything else since its a uniary minus.
2534-2536CALL 233AH CALL LPOPERCD 3A 23GOSUB to 233AH to evaluate the variable at the location of the current BASIC program pointer in HL
2537-2539LD HL,(40F3H) LD HL,(TEMP2) 2A F3 40Load HL with the value of the current BASIC program pointer.
Note: 40F3H-40F4H is a temporary storage location
253APUSH HL E5Save the value of the current BASIC program pointer in HL to the STACK so we know where to continue
253E LABBCKPOP HL E1According 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$(
253FRET C9Return 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.
CALL 260DH CALL PTRGETCD 0D 26Get 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 RETVARPUSH HL E5Save the value of the current BASIC program pointer in HL to the STACK
2544EX DE,HL EBSwap 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-2547LD (4121H),HL LD (FACLO),HL 22 21 41In case it is a string, we will store the pointer to the descriptor in FACLO.
2548We need to check the value of the current number type flag, so we call the TEST DATA MODE routine at RST 20H.
NOTE: The RST 20H routine determines the type of the current value in ACCumulator and returns a combination of STATUS flags and unique numeric values in the A Register according to the data mode flag (40AFH). The results are returned as follows:- Integer = NZ/C/M/E and A is -1
- String = Z/C/P/E and A is 0
- Single Precision = NZ/C/P/O and A is 1
- and Double Precision is NZ/NC/P/E and A is 5.
2549-254BCALL NZ,09F7H CALL NZ,VMOVFMC4 F7 09If 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
254CPOP HL E1Restore the value of the current BASIC program pointer to Register Pair HL
254DRET C9Return to the caller
254E – This routine processes an expression for SNG( to MID$( – “ISFUN”
254E-254F ISFUNLD B,00H 06 00Load Register B with zero
2550RLCA 07Set A to be 2 * (token – D7H)
2551LD C,A 4FSave the new token
2552PUSH BC C5Save 0/2*(token-D7) on STACK
2553Get 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.
2554LD A,C 79Prepare to look for the function number
2555 NUMGFNCP 41H CP NUMGFN FE 41Test 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.
2557If the CARRY FLAG is set, then the function is past that last number, so JUMP to 256FH if the token is SGN( to CHR$( . If not, it is a LEFT$ – MID$
2559CALL 2335H CALL FRMPRNCD 35 23Otherwise, 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.
255CWe need TWO arguments, so there needs to be a “,”. With this we use RST 08H to test for a ,
255ECALL 0AF4H CALL CHKSTRCD F4 0AGOSUB to 0AF4H to ensure the current variable is a string, otherwise it is an error
2561EX DE,HL EBSwap 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)
2562LD HL,(4121H) LD HL,(FACLO) 2A 21 41Load HL with the string descriptor address held at the memory location pointed to by ACCumulator
2565EX (SP),HL E3Put the pointer to the string descriptor onto the STACK and put the function number into Register Pair HL
2566PUSH HL E5Save function number (i.e., 00 / 2*(token-D7H)) to the STACK
2567EX DE,HL EBSwap DE and HL so that HL will now point to the position in the current BASIC program being evaluated.
2568CALL 2B1CH CALL GETBYTCD 1C 2BEvaluate n portion of the string function. Register E will contain the value of the formula.
256BEX DE,HL EBSwap 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.
256CEX (SP),HL E3Swap (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
CALL 252CH CALL PARCHKCD 2C 25Next 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
2572EX (SP),HL E3Swap (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.
2573LD A,L 7DLoad Register A with the function number [i.e., 2 * (token – D7H)]
2574-2575 BOTCONCP 0CH CP (SQRTK-ONEFUN)*2 FE 0CCheck 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 TOPCONCP 1BH CP (ATNTK-ONEFUN)*2+1 FE 1BCheck 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.
257APUSH HL E5Save the function number (i.e., 0 + 2*(token – D7H)) to the stop of the STACK
257B-257DCALL C,0AB1H CALL C,FRCSNGDC B1 0AIf 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)
LD DE,253EH LD DE,LABBCK 11 3E 25Load DE with a return address of 253EH for once the function is executed
2582PUSH DE D5Save the value of the return address in DE to the STACK so it will act as the return adddress
LD BC,1608H LD BC,FUNDSP 01 08 16Load BC with the function dispatch/jump table address
ADD HL,BC 09Add the jump table pointer in BC (i.e., the offset) with the value of the operator token in HL
2587LD C,(HL) 4ELoad Register C with the LSB of the jump address at the location of the jump table pointer in HL
2588INC HL 23Bump the value of the jump table pointer in HL
2589LD H,(HL) 66Load Register H with the MSB of the jump address at the location of the jump table pointer in HL
258ALD L,C 69Load Register L with the LSB of the jump address in Register C
258BJP (HL) E9Perform the function.
258C – Part of the Formula Evaluation Code – “STRCMP”
According to the original ROM source, this routine will compare two strings, one with the description in Register Pair DE and the other in FACLO/FACLO+1. On exit:
- A = 0 if the strings are equal
- A = 377 if BCDE > FACLO
- A = 1 if BCDE < FACLO
This routine will do a relational comparison of two strings.
It will load A with the length of the first string and BC with the string’s address. Then it will load D with the length of the second string and HL with the string’s address.
258C-258E STRCMPCALL 29D7H CALL FRESTRCD D7 29First 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
258FLD A,(HL) 7ELoad Register A with the LSB of the length of the string in the FACLO
2590INC HL 23Bump the value of the string’s VARPTR in HL so that HL points to the LSB of the string address
2591LD C,(HL) 4ELoad Register C with the LSB of the string in the FACLO
2592INC HL 23Bump the value of the string’s VARPTR in HL so that HL points to the MSB of the string address
2593LD B,(HL) 46Load Register B with the MSB of the string in the FACLO. Register Pair BC now points to the FACLO string.
2594POP DE D1Put the STACK string pointer into Register Pair DE
2595PUSH BC C5Save the pointer to the FACLO string data
2596PUSH AF F5Save the FACLO string’s length in Register A to the STACK
2597-2599CALL 29DEH CALL FRETMPCD DE 29Free up the STACK string and RETURN with the pointer to the STACK string descriptor in Register Pair HL.
259APOP DE D1Get the length of the FACLO string from the STACK and put it in Register D
259BLD E,(HL) 5ELoad Register E with the STACK / BCDE string’s length
259CINC HL 23Bump the pointer to the STACK / BCDE string’s entry in HL
259DLD C,(HL) 4ELoad Register C with the LSB of the STACK / BCDE string’s address
259EINC HL 23Bump the pointer to the STACK / BCDE string’s entry in HL
259FLD B,(HL) 46Load Register B with the MSB of the STACK / BCDE string’s address
25A0POP HL E1Get the second character pointer from the STACK and put it in HL
25A1 CSLOOPLD A,E 7BLoad Register A with the length of the STACK / BCDE string in Register E
25A2OR D B2Combine the FACLO string’s length in Register D with the STACK / BCDE string’s length in Register A
25A3RET Z C8If 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
25A5-25A6SUB 01H D6 01Check 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.
25A7RET C D8If the CARRY FLAG is set, then the FACLO string has run out of characters, so RETurn
XOR A AFIf 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
25A9CP E BBCheck 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.
25AAINC A 3CBump the value in Register A for a return code of A = 1
25ABRET NC D0Return if there aren’t any more characters in the STACK / BCDE string to be compared
DEC D 15If we are STILL here, then neither string has ended. First, decrement the value of the FACLO string’s length in Register D
25ADDEC E 1DDecrement the value of the STACK / BCDE string’s length in Register E
25AELD A,(BC) 0ALoad Register A with the character at the location of the STACK / BCDE string pointer in BC
25AFCP (HL) BECompare 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.
25B0INC HL 23Bump the value of the first string pointer in HL
25B1INC BC 03Bump the value of the second string pointer in BC
25B4CCF 3FIf we are here, then the NZ FLAG was set and the strings are NOT equal. Since they are not equal, reverse the CARRY flag
25B8 DOCMPINC A 3CBump the value of the current precedence value in Register A
25B9ADC A,A 8FAdjust 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
25BAPOP BC C1Get the last operator value from the STACK and put it in BC
25BBAND B A0Combine the precedence value in Register B with the precedence value in Register A to see if any of the bits match.
25BC-25BDADD A,FFH C6 FFAdjust the value in Register A. This will give a 0 if both are equal and a CARRY if they are unequal
25BESBC A,A 9FCheck to see if the precedence values in registers A and B match. This will set A=0 if equal, and, depending on the routine which called this, either an A+1 or a A=377 if unequal
25BF-25C1CALL 098DH CALL CONIACD 8D 09Convert Register A to a signed integer via a CALL to 098DH. This will set the current value to 00 if A is positive, and to FF if A is negative.
If the values match, set the current result in zero. If they do not match, set the current result to -1
25C2-25C3JR 25D6H JR RETAPG18 12At 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”
LD D,5AH 16 5ANOT has a precedence value of 90, so we need a dummy entry of 90 on the STACK
25C6-25C8CALL 233AH CALL LPOPERCD 3A 23Go evaluate the expression with a dummy entry of 90 on the STACK
25C9-25CBCALL 0A7FH CALL FRCINTCD 7F 0AWe 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)
25CCLD A,L 7DThe next bunch of instructions are to complement Register Pair HL. First, load Register A with the LSB of the integer value
25CDCPL 2FCompliment the LSB of the integer value in Register A
25CELD L,A 6FLoad Register L with the adjusted LSB of the integer value in Register A
25CFLD A,H 7CLoad Register A with the MSB of the integer value in Register H
25D0CPL 2FCompliment the MSB of the integer value in Register A
25D1LD H,A 67Load Register H with the adjusted MSB of the integer value in Register A
25D2-25D4LD (4121H),HL LD (FACLO),HL 22 21 41Save the complimented integer value in HL as the current result in ACCumulator
25D5POP BC C1Clean up the STACK
JP 2346H JP RETAOPC3 46 23Jump 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
LD A,(40AFH) LD A,(VALTYP) 3A AF 40Load Register A with the current value of the number type flag.
Note: 40AFH holds Current number type flag
25DC-25DDCP 08H FE 08Check 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.
If that test shows that we have a DOUBLE PRECISION number, jump forward to 25E5H
25E0-25E1SUB 03H D6 03If the number is not double precision, subtract 3
25E2OR A B7Set the status flags of the adjusted number type flag in Register A
25E3SCF 37Set the Carry flag
25E4RET C9RETurn to CALLer
SUB 03H D6 03We are dealing with a double precision number so adjust the value of the current number type flag in Register A
25E7OR A B7Test the value of the current number type flag in Register A, which will exit without the CARRY flag set
25E8RET C9RETurn to CALLer
25E9 – AND and OR Routines – “DANDOR”
According to the original ROM source, this routine applies the AND and OR operators and should be used to implement all logical operators
Whenever an operator is applied, its precedence is in Register B
This fact is used to distinguish between AND and OR
The right hand argument is coerced to integer, just as the left hand one was when it was pushed on the STACK
25E9 DANDORPUSH BC C5B has he precedence value, so save BC to the STACK. The precedence value for OR is 70.
25EA-25ECCALL 0A7FH CALL FRCINTCD 7F 0AWe 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)
25EDPOP AF F1Get the precedence value from the STACK and put it in Register A so that we can detemined between span class=”code”>AND and OR
25EEPOP DE D1Get the left hand argument from the STACK and put it in DE
25F2PUSH BC C5Save the value of the return address in BC to the STACK
25F3-25F4CP 46H FE 46Check to see if the operator value in Register A is an OR token. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
25F5-25F6If 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.
25F7LD A,E 7BLoad Register A with the LSB of the first value in Register E
25F8OR L B5Combine the LSB of the first value in Register A with the LSB of the second value in Register L
25F9LD L,A 6FLoad Register L with the ORed value in Register A
25FALD A,H 7CLoad Register A with the MSB of the second value in Register H
25FBOR D B2Combine the MSB of the first value in Register D with the MSB of the second value in Register A
25FCRET C9Return to 27FAH (=convert the result to integer and return that integer calue to 2346H)
25FD – AND logic – “NOTOR”
25FEAND L A5Combine the LSB of the first value in Register A with the LSB of the second value in Register L
25FFLD L,A 6FLoad Register L with the ANDed value in Register A
2600LD A,H 7CLoad Register A with the MSB of the second value in Register H
2601AND D A2Combine the MSB of the first value in Register D with the MSB of the second value in Register A
2602RET C9Return to 27FAH (=Make the result an integer and return to 2346H)
2603 – Dimension and Variable Searching Routine – “DIMCON”
2603 DIMCONDEC HL 2BDecrement the value of the BASIC program pointer in HL so that we can see what the prior character was
2604We 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.
2605RET Z C8If 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 DIMLD BC,2603H D BC,DIMCON 01 03 26Load BC with a return address of 2603H
260BPUSH BC C5Save the return address of 2603H (in BC) to the STACK
260C-260DOR AFH F6 AFThis 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 PTRGETXOR A AFIf JUMPed here, then A is set to ZERO. As a reminder, if passed through from the above routine, A will be NOT ZERO.
260E-2610LD (40AEH),A LD (DIMFLG),A 32 AE 40Save the value in Register A as the current variable location/creation flag.
Note: 40AEH holds LOCATE/CREATE variable flag
2611LD B,(HL) 46Load Register B with the first character of the variable name
2612-2614 PTRGT2CALL 1E3DH CALL ISLETCD 3D 1EGOSUB to 1E3DH to make sure the first character of the variable name is a letter
2615-2617JP C,1997H JP C,SNERRDA 97 19Display a ?SN ERROR if the first character of the variable name isn’t a letter
2618XOR A AFZero Register A
2619LD C,A 4FSet up to assume that there is no second character by zeroing Register C
261AWe 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 2622H if the character at the location of the current BASIC program pointer in Register A is numeric
261D-261FCALL 1E3DH CALL ISLETCD 3D 1EGOSUB to 1E3DH to check to see if the character at the location of the current BASIC program pointer is a letter. This will set the CARRY FLAG.
Jump to 262BH if the character at the location of the current BASIC program pointer in Register A isn’t a letter
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.
Loop back one OPCODE to keep eating characters until a non-numeric character is found
2626-2628CALL 1E3DH CALL ISLETCD 3D 1EGo check to see if the character at the location of the current BASIC program pointer in HL is alphabetic
Jump back to 2623H if the character at the location of the current BASIC program pointer in HL is alphabetic
LD DE,2652H LD DE,HAVTYP 11 52 26Load DE with a return address of 2652H. Done to save time/RAM from using JUMPs instead.
262EPUSH DE D5Save the value of the return address in DE to the STACK
262F-2630LD D,02H 16 02Load Register D with an integer number type flag
2631-2632CP 25H FE 25Check 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.
2633RET Z C8Return if the character at the location of the current BASIC program pointer in Register A is a %
INC D 14Bump Register D so that it will be equal to a string number type flag (02=INT, 03=STR, 04=SNG, 08=DBL)
2635-2636CP 24H FE 24Check 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.
2637RET Z C8Return if the character at the location of current BASIC program pointer in Register A is a $
INC D 14Bump Register D so that it will be equal to a single precision number type flag (02=INT, 03=STR, 04=SNG, 08=DBL)
2639-263ACP 21H FE 21Check 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.
263BRET Z C8Return if the character at the location of the current BASIC program pointer in Register A is a !
LD D,08H 16 08Load 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-263FCP 23H FE 23Check 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.
2640RET Z C8Return if the character at the location of the current BASIC program pointer in Register A is a #
2642-2643SUB 41H D6 41Adjust 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-2645AND 7FH E6 7FGet rid of the user-defined function bit in Register B by ANDing it against 0111 1111
2646LD E,A 5FNext 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-2648LD D,00H 16 00Load Register D with zero
2649PUSH HL E5Save the value of the current BASIC program pointer in HL to the STACK
264A-264CLD HL,4101H LD HL,DEFTBL 21 01 41Load HL with the starting address of the variable declaration table.
NOTE: 4101H-411AH holds Variable Declaration Table
264DADD HL,DE 19Add the offset to the top of the table
264ELD D,(HL) 56Load Register D with the number type value from the variable declaration table pointer in HL
264FPOP HL E1Get the value of the current BASIC program pointer from the STACK and put it in HL
2650DEC HL 2BDecrement the value of the current BASIC program pointer in HL as there was no marking character
2651RET C9Return with data type in D
2653-2655LD (40AFH),A LD (VALTYP),A 32 AF 40Save the number type flag for the current variable name from Register A.
NOTE: 40AFH holds Current number type flag
2656We 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-2659LD A,(40DCH) LD A,(SUBFLG) 3A DC 40Load Register A with the FOR flag. Why the FOR flag? It doubles as a “should we allow arrays here” flag!
265AOR A B7Test the value of the FOR flag in Register A
265ELD A,(HL) 7ERe-fetch the next element of the code string by loading Register A with the character at the location of the current BASIC program pointer in HL
265F-2660SUB 28H D6 28Next, test for an array by checking to see if the character at the location of the current BASIC program pointer in Register A is a (
2661-2663JP Z,26E9H JP Z,ISARYCA E9 26If the Z FLAG is set then we have an array (meaning, it is a subscripted variable), so JUMP to 26E9H
2665-2667LD (40DCH),A LD (SUBFLG),A 32 DC 40Set the “permit arrays” array flag to ‘no subscript’.
Note: 40DCH holds FOR flag
2668PUSH HL E5Save the value of the current BASIC program pointer in HL to the STACK
2669PUSH DE D5Save the number type flag for the variable in DE to the STACK
266A-266CLD HL,(40F9H) LD HL,(VARTAB) 2A F9 40Load HL with the value of the simple variables pointer, which will be t he place to start the search.
- Note: 40F9H-40FAH holds the starting address of the simple variable storage area.
EX DE,HL EBSwap DE and HL so that DE will not point to the place to start the search. We don’t care what happens to HL
266E-2670LD HL,(40FBH) LD HL,(ARYTAB) 2A FB 40Load HL with the pointer to the end of simple variables. 40FBH-40FCH holds the starting address of the BASIC array variable storage area
2671Now 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.
2672POP HL E1Get the number type flag for the variable from STACK and put it in HL
2673-2674If 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
2675LD A,(DE) 1ALoad Register A with the number type flag for the variable at the location of the simple variables pointer in DE
2676LD L,A 6FPreserve Register A into Register L so we know how many entries to skip.
2677CP H BCCompare 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.
2678INC DE 13Bump the value of the current simple variables pointer in DE to the 2nd character name for this entry
2679-267AIf 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
267BLD A,(DE) 1ASince 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
267CCP C B9Compare the character at the location of the simple variables pointer in Register A with the first character of the variable name in Register C. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
267D-2637Jump to 2686H if the first characters of the variable names don’t match
267FINC DE 13Bump the value of the current simple variables pointer in DE
2680LD A,(DE) 1ALoad Register A with the second character of the variable name at the location of the simple variables pointer in DE
2681CP B B8Compare the character at the location of the simple variables pointer in Register A with the first character of the variable name in Register B. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
2682-2684JP Z,26CCH JP Z,FINPTRCA CC 26Jump 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-2686LD A,13H 3E 13Z-80 Trick to skip the next INC DE if continuing through
2687INC DE 13Bump the value of the simple variables pointer in DE part 2
2688PUSH HL E5Save the number type flag for the variable in HL to the STACK so that it can be re-loaded at 2672H
2689-268ALD H,00H 26 00Load Register H with zero so that Register Pair HL is the number of bytes to skip, but in 16 bits.
268BADD HL,DE 19Add the value of the simple variables pointer in DE to the value of the number type flag in HL
268FPOP HL E1Get the value of the current BASIC program pointer from the STACK and put it in HL
2690EX (SP),HL E3Exchange (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
2691PUSH AF F5Save length of the variable in Register A to the STACK
2692PUSH DE D5Save the current variable table position from DE to the STACK
2693-2695LD DE,24F1H LD DE,VARRET 11 F1 24Load DE with a VARPTR locator return address of 24F1H
2696Now we need to check to see if this was a VARPTR or not, so we compare the return address in DE with the return address in HL by calling the COMPARE DE:HL routine at RST 10H.
The RST 10H routine parses the characters starting at HL+1 for the first non-SPACE,non-09H,non-0BH character it finds. On exit, Register A will hold that character, and the C FLAG is set if its alphabetic, and NC FLAG if its alphanumeric. All strings must have a 00H at the end.
2697-2698If the Z FLAG is set, then this was a VARPTR call, so JUMP forward to 26CFH.
2699-269BLD DE,2543H LD DE,RETVAR 11 43 25Next we need to see if EVAL called this routine. Load DE with a return address of the find address of variables routine at 2543H
269CWe 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.
269DPOP DE D1Restore the current variable table position from the STACK and put it in DE
269E-269FIf 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.
26A0POP AF F1Clear the STACK and put the value of the number type flag for the variable from the STACK and put it in Register A
26A1EX (SP),HL E3Swap (SP) and HL so that the value of the current BASIC program pointer is now in Register Pair HL
26A2PUSH HL E5Save the value of the current BASIC program pointer in HL to the STACK
26A3PUSH BC C5Save the variable’s address in BC to the STACK as we are about to use both Register B and Register C
26A4LD C,A 4FLoad Register C with the value of the number type flag for the variable in Register A
26A5-26A6LD B,00H 06 00Load Register B with zero so that the number type flag for the variable can be represented in 16 bits
26A7PUSH BC C5Save the variable’s number type flag in BC to the STACK
26A8INC BC 03Bump the value of the variable’s number type flag in BC
26A9INC BC 03Bump the value of the variable’s number type flag in BC
26AAINC BC 03Bump the value of the variable’s number type flag in BC. Now the variable’s length includes room for the addresses as well.
26AB-26ADLD HL,(40FDH) LD HL,(STREND) 2A FD 40Load HL with the value of the free memory pointer.
Note: 40FDH-40FEH holds Free memory pointer
26AEPUSH HL E5Save the value of the free memory pointer in HL to the STACK
26AFADD HL,BC 09Add the value of the variable’s number type flag in BC to the value of the free memory pointer in HL
26B0POP BC C1Restore the high address from the STACK and put it in BC
26B1PUSH HL E5Save the value of the high address pointer in HL to the STACK
26B2-26B4CALL 1955H CALL BLTUCD 55 19Block transfer the variable information and make sure we do not overflow the STACK space via a GOSUB to BLTU.
26B5POP HL E1Get the value of the new free memory pointer (i.e., STREND) from the STACK and put it in HL
26B6-26B8LD (40FDH),HL LD (STREND),HL 22 FD 40Save the value of the new free memory pointer in HL to lock in that variable space.
NOTE: 40FDH-40FEH holds Free memory pointer
26B9LD H,B 60Load Register H with the MSB of the new array variables pointer in Register B
26BALD L,C 69Load 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-26BDLD (40FBH),HL LD (ARYTAB),HL 22 FB 40Save the value of the new array variables pointer in HL. 40FBH-40FCH holds the starting address of the BASIC array variable storage area
DEC HL 2BAt this point, HL is retuned pointing to the end of the variable, so we need to zero backwards to DE which points to the start of the variable table. First, decrement the value of the array variables pointer in HL
26BF-26C0LD (HL),00H 36 00Zero the location of the memory pointer in HL
26C1Now 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.
26C4POP DE D1Get the value of the variable’s number type flag from the STACK and put it in DE
26C5LD (HL),E 73Save the value of the number type flag in Register E at the location of the memory pointer in HL
26C6INC HL 23Bump the value of the memory pointer in HL
26C7POP DE D1Get the 2nd character of the variable’s name from the STACK and put it in DE
26C8LD (HL),E 73Save the first character of the variable’s name in Register E at the location of the memory pointer in HL
26C9INC HL 23Bump the value of the memory pointer in HL
26CALD (HL),D 72Save the first character of the variable’s name in Register D at the location of the memory pointer in HL
26CBEX DE,HL EBLoad DE with the value of the variable pointer in from HL
26CDPOP HL E1Restore the value of the current BASIC program pointer from the STACK into Register Pair HL
26CERET C9RETurn to CALLer
LD D,A 57On entry, the Z FLAG was set, meaning that A=0. Zero out Register D with the value of Register AA
26D0LD E,A 5FZero out Register E
26D1POP AF F1Clean up the STACK (which was the PUSHed DE)
26D2POP AF F1Clean up the STACK (which was the length)
26D3EX (SP),HL E3Swap (SP) and HL so that the return return is now at the top of the STACK and the pointer in current BASIC program pointer is restored to HL
26D4RET C9Return to the VARPTR routine
26D5 – This routine is ZERO out all variable types and skip any RETurn – “FINZER”
LD (4124H),A LD (FAC),A 32 24 41Zero ACCumulator so that all single-precision and double-precision variables become zero
26D8POP BC C1Clean up the STACK (i.e., remove the length of the variable)
26D9LD H,A 67Zero Register H to clear out integers as well
26DALD L,A 6FZero Register L to clear out integers as well
26DB-26DDLD (4121H),HL LD (FACLO),HL 22 21 41Zero the string pointer location in ACCumulator
26DEWe need to check the value of the current number type flag, so we call the TEST DATA MODE routine at RST 20H.
NOTE: The RST 20H routine determines the type of the current value in ACCumulator and returns a combination of STATUS flags and unique numeric values in the A Register according to the data mode flag (40AFH). The results are returned as follows:- Integer = NZ/C/M/E and A is -1
- String = Z/C/P/E and A is 0
- Single Precision = NZ/C/P/O and A is 1
- and Double Precision is NZ/NC/P/E and A is 5.
26DF-26E0If 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-26E3LD HL,1928H LD HL,REDDY-1 21 28 19If 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-26E6LD (4121H),HL LD (FACLO),HL 22 21 41Save the value in HL as the current string pointer, which is now null.
POP HL E1Get the value of the current BASIC program pointer from the STACK and put it in HL
26E8RET C9RETurn (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.
26EA-26ECLD HL,(40AEH) LD HL,(DIMFLG) 2A AE 40Load 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
26EDEX (SP),HL E3Swap (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
26EELD D,A 57Zero Register D (which will hold the number of dimension)
26F0PUSH BC C5Save the variable’s name in BC to the STACK
26F1-26F3CALL 1E45H CALL INTIDXCD 45 1EGo 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
26F4POP BC C1Get the variable’s name from the STACK (1st and 2nd character) and put it in BC
26F5POP AF F1Get the variable’s number of dimension so far from the STACK and put it in Register A
26F6EX DE,HL EBSwap 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
26F7EX (SP),HL E3Swap (SP) and HL so that HL will now hold DIMFLG and VALTYP and the array subscript will be at the stop of the STACK
26F8PUSH HL E5Save the DIMGFLG and VALTYP (in HL) to the STACK
26F9EX DE,HL EBSwap 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.
26FAINC A 3CBump the number of dimensions evaluated in Register A
26FBLD D,A 57Load Register D with the number of dimensions evaluated in Register A
26FCLD A,(HL) 7ELoad Register A with the character at the location of the current BASIC program pointer in HL
26FD-26FECP 2CH FE 2CCheck to see if the character at the location of the current BASIC program pointer in Register A is a , . If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
26FF-2700If the character at the location of the current BASIC program pointer in Register A is a , , then we have more dimensions to process, so JUMP back to INDLOP to process again
2701-2702Since 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 SUBSOKLD (40F3H),HL LD (TEMP2),HL 22 F3 40Save the value of the current BASIC program pointer in HL into the TEMP2 storage area.
2706POP HL E1Get the DIMFLG and VALTYP from the STACK and put it in HL.
2707-2709LD (40AEH),HL LD (DIMFLG),HL 22 AE 40Save the value of the DIMFLG and VALTYP into the DIMFLG location in RAM.
NOTE: 40AEH holds LOCATE/CREATE variable flag
270APUSH DE D5Save 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-270DLD HL,(40FBH) LD HL,(ARYTAB) 2A FB 40We 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-270FLD A,19H 3E 19Z-80 Trick to skip the next command of ADD HL,DE if falling through
ADD HL,DE 19Advance past the current array as we know it isn’t the correct one. Note: 40FBH-40FCH holds the array variables pointer
2710EX DE,HL EBSwap DE and HL so that DE holds the current search point. We don’t care about HL.
2711-2713LD HL,(40FDH) LD HL,(STREND) 2A FD 40Load HL with the place to STOP the search (i.e., the value of the free memory pointer).
Note: 40FDH-40FEH holds Free memory pointer
2714EX DE,HL EBSwap DE and HL so that DE now holds the place to stop the search and HL holds the current search point.
2715Now 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-2718LD A,(40AFH) LD A,(VALTYP) 3A AF 40Load Register A with the value of the current number type flag.
Note: 40AFH holds Current number type flag
2719-271AIf 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
271BCP (HL) BECompare 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.
271CINC HL 23Bump the value of the array variables pointer in HL
271D-271EJump forward (but still in this loop) to 2727H if the number type flags don’t match
271FLD A,(HL) 7ELoad Register A with the first character of the variable name at the location of the array variables pointer in HL
2720CP C B9Check 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.
2721INC HL 23Bump the value of the array variables pointer in HL
2722-2723Jump forward (but still in this loop) to 2728H if the first characters of the variable names don’t match
2724LD A,(HL) 7ELoad Register A with the second character of the variable name at the location of the array variables pointer in HL
2725CP B B8Compare 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-2727LD A,23H 3E 23This part of a Z-80 Trick. Will load A with 23H if passing through, and not do the following INC HL.
INC HL 23Bump the value of the array variables pointer in HL. HL should now point to the LENGTH entry of the array being looked at
2729LD E,(HL) 5ELoad Register E with the LSB of the LENGTH of the array being looked at
272AINC HL 23Bump the value of the array variables pointer in HL
272BLD D,(HL) 56Load Register D with the MSB of the LENGTH of the array being looked at
272CINC HL 23Bump the value of the array variables pointer in HL
272D-272EIf 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-2731LD A,(40AEH) LD A,(DIMFLG) 3A AE 40Load 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
2732OR A B7Since 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-2734LD E,12H 1E 12Prepare for an error if this routine was NOT called by “DIM” by loading Register E with the ?DD ERROR code
2735-2737JP NZ,19A2H JP NZ,ERRORC2 A2 19If 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.
2738POP AF F1Get the number of dimension evaluated from the STACK and put it in Register A
2739SUB (HL) 96To 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 DIM med)
273A-273CJP Z,2795H JP Z,GETDEFCA 95 27If they match then we are done so JUMP down to 2795H to read the indices
273D – ?BS ERROR entry point – “BSER”
273F-2741JP 19A2H JP ERRORC3 A2 19Display 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.
LD (HL),A 77Save the variable type for the array in Register A at the location of the array variables pointer in HL
2743INC HL 23Bump 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)
2744LD E,A 5FLoad Register E with the variable type flag for the current variable
2745-2746LD D,00H 16 00Zero Register D so that Register Pair DE can be the size of one value of the type VALTYP
2747POP AF F1Get the number of dimensions evaluated from the STACK and put it in Register A
2748LD (HL),C 71Save the second character of the variable’s name in Register C at the location of the array variables pointer in HL
2749INC HL 23Bump 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)
274ALD (HL),B 70Save the first character of the variable’s name in Register B at the location of the array variables pointer in HL
274BINC HL 23Bump the value of the array variables pointer in HL to the LSB of the offset to the next entry
274CLD C,A 4FIn preparation for the next CALL, load Register C with the number of two byte entries needed to store the size of each dimension
274D-274FCALL 1963H CALL GETSTKCD 63 19Figure the amount of memory space left between HL and the free memory and get the space needed as set in Register C
2750INC HL 23Next 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
2751INC HL 23Bump the value of the array variables pointer in HL. These 2 INC’s skip over the offset entry
2752-2754LD (40D8H),HL LD (TEMP3),HL 22 D8 40Next 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
2755LD (HL),C 71Save the number of dimension at the location of the array variables pointer in HL
2756INC HL 23Bump the value of the array variables pointer in HL to point to the first subscript entry in the array table
2757-2759LD A,(40AEH) LD A,(DIMFLG) 3A AE 40Load 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
275ARLA 17Set the CARRY flag accordingly
275BLD A,C 79Load Register A with the number of dimension evaluated in Register C
LD BC,000BH 01 0B 00Top 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
If the NC flag is set, then we did not arrive here from DIM, so JUMP forward to 2763H if the array is being created because it certainly wasn’t found
2761POP BC C1Get a subscript/index from the STACK and put it in BC
2762INC BC 03Bump the value of the subscript in BC by one for the ZERO entry.
2763 NOTDIMLD (HL),C 71Top of a loop. Save the LSB of the subscript’s value in Register C at the location of the array variables pointer in HL
2764INC HL 23Bump the value of the array variables pointer in HL
2765LD (HL),B 70Save the MSB of the subscript’s value in Register B at the location of the array variables pointer in HL
2766INC HL 23Bump the value of the array variables pointer in HL
2767PUSH AF F5Save the number of dimensions evaluated in Register A (and the CARRY aflag results from DIMFLG) to the STACK
2768-276ACALL 0BAAH CALL UMULTCD AA 0BGo multiply the size of the subscript by the value of the number type flag to determine the amount of memory necessary for the subscript
276BPOP AF F1Get the number of domensions that the CARRY FLAG (DIMFLG) from the STACK and put it in Register A
276CDEC A 3DDecrement the counter of the number of dimensions to check by one
276D-276EJump back to 275CH if there are anymore subscripts to be evaluated
276FPUSH AF F5If 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
2770LD B,D 42Load Register B with the MSB of the array’s length in Register D
2771LD C,E 4BLoad Register C with the LSB of the array’s length in Register E. Now BC = size of the array in bytes
2772EX DE,HL EBSwap DE and HL so that DE now has the start of the values and HL has the end of the values
2773ADD HL,DE 19Add the length of the array in HL to the value of the array variable pointer in DE
JR C,273DH JR C,BSER38 C7If that addition triggered the CARRY FLAG then we are out of RAM so JUMP back to 273DH and throw a ?BS ERROR
2776-2778CALL 196CH
CALL REASONCD 6C 19We now know there is room in RAM, so GOSUB to “REASON” to make sure there is room for the values
2779-277BLD (40FDH),HL LD (STREND),HL 22 FD 40Update the end of storage pointer with the end of the array (held in HL).
Note: 40FDH-40FEH holds free memory pointer
DEC HL 2BNow we need to zero the new array. First, decrement the value of the array pointer in HL
277D-277ELD (HL),00H 36 00Zero the location of the array pointer in HL
277FNow we need to compare the array pointer in HL with the array variables pointer in DE, so we call the COMPARE DE:HL routine at RST 10H.
The RST 10H routine parses the characters starting at HL+1 for the first non-SPACE,non-09H,non-0BH character it finds. On exit, Register A will hold that character, and the C FLAG is set if its alphabetic, and NC FLAG if its alphanumeric. All strings must have a 00H at the end.
2780-2781If the NZ FLAG is set, then we have more entries to ZERO, so loop until the array has been cleared
2782INC BC 03Load 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
2783LD D,A 57Zero Register D
2784-2786LD HL,(40D8H) HL,(TEMP3) 2A D8 40Load HL with the array variables pointer (=the number of indices).
Note: 40D8H-40D9H holds Temporary storage location
2787LD E,(HL) 5ELoad Register E with the number of dimension for the array at the location of the array variables pointer in HL
2788EX DE,HL EBSwap DE and HL so that HL now holds the number of dimensions and DE holds the value of the array variables pointer
2789ADD HL,HL 29Multiply the number of subscripts for the array in HL by two
278AADD HL,BC 09Add 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
278BEX DE,HL EBSwap 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
278CDEC HL 2BWe 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
278DDEC HL 2BDecrement the value of the array variables pointer in HL
278ELD (HL),E 73Save the LSB of the size of the array in Register E at the location of the array variables pointer in HL
278FINC HL 23Bump the value of the array variables pointer in HL
2790LD (HL),D 72Save the MSB of size of the array array in Register D at the location of the array variables pointer in HL
2791INC HL 23Bump the value of the array variables pointer in HL
2792POP AF F1Get the value of the DIMFLG (i.e., the CARRY BIT) and a 0 into Register A
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).
2796LD C,A 4FZero Register C. Now BC = 0 = CURTOL
2797LD A,(HL) 7ELoad Register A with the number of dimensions for the array at the location of the array variables pointer in HL
2798INC HL 23Bump the value of the array variables pointer in HL to one entry past the number of dimensions
2799LD D,0E1H 16 E1Z-80 Trick to hide the next instruction (POP HL) if proceeding downward
279BLD E,(HL) 5ENext, 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
279CINC HL 23Bump the value of the array variables pointer in HL
279DLD D,(HL) 56Load Register D with the MSB of the subscript limit at the location of the array variables pointer in HL
279EINC HL 23Bump the value of the array variables pointer in HL
279FEX (SP),HL E3Swap 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
27A0PUSH AF F5Save the number of dimensions for the array in Register A to the STACK
27A1Now 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.
JP NC,273DH JP NC,BSERD2 3D 27If the current inex is too big, then we need to throw a ?BS ERROR via a JUMP to 273DH
27A8ADD HL,DE 19Add the index to CURTOL
27A9POP AF F1Get the number of dimensions for the array from the STACK and put it in Register A
27AADEC A 3DWe checked one, so cross one off the list and see if there are anymore dimensions to be evaluated
27ABLD B,H 44Load Register B with the MSB of the subscript pointer in Register H
27ACLD C,L 4DLoad Register C with the LSB of the subscript pointer in Register L. Now BC = CURTOL for the start of the next loop.
27AD-27AELoop back to 279AH until all of the subscripts have been evaluated
27AF-27B1LD A,(40AFH) LD A,(VALTYP) 3A AF 40Get the number type flag for the current array; which also doubles for how big the values are
NOTE: 40AFH holds Current number type flag
27B2
27B3LD B,H
LD C,L 44We are going to need to multiply by THREE, so we need to save the original value into BC as well.
27B4ADD HL,HL 29Multiply the subscript pointer in HL by two
27B5-27B6SUB 04H D6 04Check the value of the number type flag in Register A because we would be done if we have an integer or a string.
Jump forward to 27BDH if the current number type is an integer or string
27B9ADD HL,HL 29It isn’t an integer or a string so once again multiply the subscript pointer in HL by two (so now it is multiplied by 4)
27BA-27BBJump forward to 27C2H if the current number type is single precision as we then have enough bytes.
27BCADD HL,HL 29It must be double precision, so once again multiply the subscript pointer in HL by two (so now it is multiplied by 8)
27BE-27C0JP PO,27C2H JP PO,DONMULE2 C2 27Jump forward to 27C2H if the current number type isn’t a string
27C1ADD HL,BC 09The current number type is a string so add the value of the original subscript pointer in BC to the subscript pointer in HL
27C3ADD HL,BC 09Add 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
27C4EX DE,HL EBLoad DE with the variable pointer in HL
LD HL,(40F3H) LD HL,(TEMP2) 2A F3 40Get the value of the current BASIC program pointer and put it in HL.
Note: 40F3H-40F4H is a temporary storage location
27C8RET C9RETurn 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.
27CAPUSH HL E5Save the value of the current BASIC program pointer in HL to the STACK
27CB-27CDLD (40AFH),A LD (VALTYP),A 32 AF 40Zero the number type flag.
NOTE: 40AFH holds Current number type flag
27CE-27D0CALL 27D4H CALL FRECD D4 27Determine how much space there is via a GOSUB to the FRE routine at 27D4H
27D1POP HL E1Get the value of the current BASIC program pointer from the STACK and put it in HL
27D2We 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.
27D3RET C9Return to BASIC
27D4-27F4 – LEVEL II BASIC FRE ROUTINE – “FRE”
LD HL,(40FDH) LD HL,(STREND) 2A FD 40Load 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
27D7EX DE,HL EBLoad DE with the value of the free memory pointer in HL for subtraction
27D8-27DALD HL,0000H 21 00 00Zero HL
27DBADD HL,SP 39Add the value in HL (which is zero) to the current value of the STACK pointer so that the STACK pointer is now in HL
27DCWe need to check the value of the current number type flag, so we call the TEST DATA MODE routine at RST 20H.
NOTE: The RST 20H routine determines the type of the current value in ACCumulator and returns a combination of STATUS flags and unique numeric values in the A Register according to the data mode flag (40AFH). The results are returned as follows:- Integer = NZ/C/M/E and A is -1
- String = Z/C/P/E and A is 0
- Single Precision = NZ/C/P/O and A is 1
- and Double Precision is NZ/NC/P/E and A is 5.
27DD-27DEIf that test shows we do NOT have a STRING (meaning this was really a MEM call, jump to forward to 27ECH
27DF-27E1CALL 29DAH CALL FREFACCD DA 29Free up the argument and set up to give some free string space
27E5-27E7LD HL,(40A0H) LD HL,(STKTOP) 2A A0 40Load HL with the start of string space pointer / bottom of free space.
NOTE: 40A0H-40A1H holds the start of string space pointer
27E8EX DE,HL EBLoad DE with the start of string space pointer in HL
27E9-27EBLD HL,(40D6H) LD HL,(FRETOP) 2A D6 40Load 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 GIVDBLLD A,L 7DPrepare to do HL = HL – DE. First, load Register A with the LSB of the next available location in string space pointer in Register L
27EDSUB E 93Subtract 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
27EELD L,A 6FLoad Register L with the LSB of the amount of string space remaining in Register A
27EFLD A,H 7CLoad Register A with the MSB of the next available location in string space pointer in Register H
27F0SBC A,D 9ASubtract 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
27F1LD H,A 67Load Register H with the MSB of the amount of string space remaining in Register A
27F2-27F4JP 0C66H JP INEG2C3 66 0CJump to 0C66H to convert the difference between HL and DE to single precision and then RETurn out of the routine
27F5-27FD – LEVEL II BASIC POS( ROUTINE – “POS”
27F5-27F7 POSLD A,(40A6H) LD A,(TTYPOS) 3A A6 40Load Register A with the current cursor line position.
Note: 40A6H holds the current cursor line position
LD L,A 6FLoad Register L with the value of the current cursor line position in Register A.
27F9XOR A AFZero Register A
27FA GIVINTLD H,A 67Load Register H with zero, so now HL is 00 + cursor position
27FE-2818 – LEVEL II BASIC USR(x) ROUTINE – “USRFN”
27FE-2780 USRFNCALL 41A9H CALL USROUT CD A9 41GOSUB to DOS to see if DOS wants to deal with this
2801We need the next character so call the EXAMINE NEXT SYMBOL routine at RST 10H.
The RST 10H routine parses the characters starting at HL+1 for the first non-SPACE,non-09H,non-0BH character it finds. On exit, Register A will hold that character, and the C FLAG is set if its alphabetic, and NC FLAG if its alphanumeric. All strings must have a 00H at the end.
2802-2804CALL 252CH CALL PARCHKCD 2C 25GOSUB to 252CH to evaluate the expression at the location of the current BASIC program pointer in HL and return with the result in ACCumulator
2805PUSH HL E5Save the value of the current BASIC program pointer in HL (=the address of the next element in the code string) to the STACK
2806-2808LD HL,0890H LD HL,POPHRT 21 90 08Load HL with the return address of 0890H which will clear the STACK before returning to BASIC
2809PUSH HL E5Save the value of the return address in HL to the STACK
280A-280CLD A,(40AFH) LD A,(VALTYP) 3A AF 40Load Register A with the value of the current number type flag for the argument provided.
Note: 40AFH holds Current number type flag
280DPUSH AF F5Save the value of the current number type flag in Register A.
(02=INT, 03=STR, 04=SNG, 08=DBL)
280E-280FCP 03H FE 03Check to see if the current value is a string. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
2810-2812CALL Z,29DAH CALL Z,FREFACCC DA 29If the current result is a string then GOSUB to 29DAH to get the free the space and get the string address into HL
2813POP AF F1Restore the number type flag into Register A
2814EX DE,HL EBLoad DE with the (possible) value of the pointer to the string (in HL)
2815-2817LD HL,(408EH) 2A 8E 40Load 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.
2818JP (HL)E9Jump 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.
PUSH HL E5Save the pointer to the current character in the BASIC program being evaluated to the STACK
281A-281BAND 07H E6 07Mask 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-281ELD HL,18A1H LD HL,FRCTBL 21 A1 18Load HL with the address of the arithmetic conversion routines
281FLD C,A 4FLoad Register C with the value of the number type flag in Register A.
(02=INT, 03=STR, 04=SNG, 08=DBL)
2820-2821LD B,00H 06 00Zero Register B. Now BC holds 00 + type and will be the two byte offset into the table
2822ADD HL,BC 09Add the offset (of BC) to the base arithmetic conversion routines, to find the right jump point
2823-2825CALL 2586H CALL DISPATCD 86 25GOSUB to 2586H to convert the current result in REG l to its proper number type
2826POP HL E1Restore the pointer to the current character in the BASIC program being evaluated to HL
2827RET C9RETurn 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.
2829-282BLD HL,(40A2H) LD HL,(CURLIN) 2A A2 40Load HL with the value of the current BASIC line number (which is stored at 40A2H-40A3H).
282CINC HL 23Bump 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
282DLD A,H 7CLoad Register A with the MSB of the current BASIC line number in Register H
282EOR L B5Combine 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.
282FPOP HL E1Restore whatever was in HL on entry back into HL
2830RET NZ C0Return if there is a line number (i.e., this isn’t the command mode) and otherwise fall through to the ?ID ERROR routine
2831 – ID ERROR entry point.
2831-2832LD E,16H 1E 16Load Register E with the ?ID ERROR code
2836-2856 – STRING ROUTINE – STR$ logic – “STR$”
2836-2838 STR$CALL 0FBDH CALL FOUTCD BD 0FGOSUB to 0FBDH to convert the current result in ACCumulator to an ASCII string
2839-283B STR$1CALL 2865H CALL STRLITCD 65 28Scan it and turn it into a string (make a temporary string work area entry)
LD BC,2A2BH LD BC,FINBCK 01 2B 2ALoad BC with a return address of 2A2BH (which cleans the STACK and then jumps to 2884H)
2842PUSH BC C5Save the value of the return address in BC to the STACK
The next routine, STRCPY, creates a copy of the string pointed to by Register Pair HL. On exit, DE points to DSCTMP which has the string information.
2843 STRCPYLD A,(HL) 7ELoad Register A with the string’s length at the location of the string’s VARPTR in HL
2844INC HL 23Bump the value of the string’s VARPTR in HL
2845PUSH HL E5Save the value of the string’s VARPTR in HL to the STACK
2846-2848CALL 28BFH CALL GETSPACD BF 28GOSUB to 28BFH to test the remaining string area to make sure that the new string will fit
2849POP HL E1Reload HL with the string’s VARPTR. This is the destination to where the string should be copied.
284ALD C,(HL) 4ELoad Register C with the LSB of the string’s address at the location of the string’s VARPTR in HL
284BINC HL 23Bump the value of the string’s VARPTR in HL
284CLD B,(HL) 46Load Register B with the MSB of the string’s address at the location of the string’s VARPTR in HL
284D-284FCALL 285AH CALL STRAD2CD 5A 28GOSUB to 285AH to save the string’s length and the string’s address at 40D3H, so as to set up DSCTMP
2850PUSH HL E5Save the pointer to STRAD2 (which is 40D3H) to the STACK
2851LD L,A 6FLoad Register L with the string’s length (from Register A)
2852-2854CALL 29CEH CALL MOVSTRCD CE 29GOSUB to 29CEH to move L characters from the temp area (of BC) to the string data area (in DE)
2855POP DE D1Restore the pointer to DSCTMP (40D3H) into Register Pair DE
2856RET C9RETurn to CALLer
2857-2864 – STRING ROUTINE – “STRINI”
CALL 28BFH CALL GETSPACD BF 28GOSUB 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
LD HL,40D3H LD HL,DSCTMP 21 D3 40Load HL with the address of the temporary string parameter storage area.
Note: 40D3H-40D5H holds Used for temporary string VARPTR’s
285D STRAD1PUSH HL E5Save the address of the temporary string parameter area in HL to the STACK
285ELD (HL),A 77Save the string’s length in Register A at the location of the temporary string parameter storage pointer in HL
285F PUTDEIINC HL 23The 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
2860LD (HL),E 73Save the LSB of the string’s address in Register E at the location of the temporary string parameter storage pointer in HL
2861INC HL 23Bump the value of the temporary string parameter storage pointer in HL
2862LD (HL),D 72Save the MSB of the string’s address in Register D at the location of the temporary string parameter storage pointer in HL
2863POP HL E1Get the address of the temporary string parameter storage area from the STACK and put it in HL
2864RET C9RETurn 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.
LD B,22H 06 22Load Register B with a “ (which is really the end of the quote search character)
PUSH HL E5Save 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-286BLD C,0FFH 0E FFLoad Register C with a -1
INC HL 23Bump the value of the current BASIC program pointer in HL to skip over that initial “
286DLD A,(HL) 7ELoad Register A with the character at the location of the current BASIC program pointer in HL
286EINC C 0CBump the counter in Register C
286FOR A B7Check to see if the character at the location of the current BASIC program pointer in Register A is an end of the BASIC line character
2870-2871Jump 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
2872CP D BACheck to see if the character at the location of the current BASIC program pointer in Register A is the same as the terminating character in Register D. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
2873-2874Jump 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
2875CP B B8Check to see if the character at the location of the current BASIC program pointer in Register A is the same at the terminating character in Register B. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
2876-2877Loop 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
CP 22H FE 22Check to see if the character at the location of the current BASIC program pointer in Register A is a quote. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
287A-287CCALL Z,1D78H CALL Z,CHRGTRCC 78 1DIf 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)
287DEX (SP),HL E3Exchange the value of the current BASIC program pointer in HL with the string’s address to the STACK
287EINC HL 23Bump the string’s address in HL until it points to the first character of the string
287FEX DE,HL EBLoad DE with the temporary pointer string’s address in HL
2880LD A,C 79Load Register A with the string’s length from Register C
2881-2883CALL 285AH CALL STRAD2CD 5A 28GOSUB to 285AH to save the string’s length and the string’s address into 40D3H (i.e., DSCTMP)
LD DE,40D3H LD DE,DSCTMP 11 D3 40Load DE with the address of the string parameter storage area.
Note: 40D3H-40D5H holds Used for temporary string VARPTR’s
LD A,D5H 3E D5This 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 PUTTMPPUSH DE D5Save a pointer to the stat of the string to the STACK
2889-288BLD HL,(40B3H) LD HL,(TEMPPT) 2A B3 40Load 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-288ELD (4121H),HL LD (FACLO),HL 22 21 41Save 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-2890LD A,03H 3E 03Load Register A with the string number type flag
2891-2893LD (40AFH),A LD (VALTYP),A 32 AF 40Save the value in Register A as the current number type flag.
Note: 40AFH holds current number type flag
2897-2899LD DE,40D6H LD DE,FRETOP 11 D6 40Depending on how we got here, DE will be different. If the jump was into PUTTMP, then DE will NOT equal FRETOP.
289AWe 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-289DLD (40B3H),HL LD (TEMPPT),HL 22 B3 40Save 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
289EPOP HL E1Get the value of the current BASIC program pointer from the STACK and put it in HL
289FLD A,(HL) 7ELoad Register A with the character at the location of the current BASIC program pointer in HL
28A0RET NZ C0Return if the updated temporary string work area location wasn’t beyond the end of the temporary string work area (meaning it overflowed, because if it overflowed .)
28A1 – ST ERROR entry point.
28A1-28A2LD E,1EH 1E 1ELoad Register E with a ?ST ERROR code
28A3-28A5JP 19A2H JP ERRORC3 A2 19Display 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 STROUIINC HL 23Bump 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.
CALL 2865H CALL STRLITCD 65 28Go build a temporary string work area entry for the message at FACLOthe location of the current BASIC program pointer in HL
If the routine entry is at STRPRT, then it just prints the string whose descriptor is held in FACLO
28AA-28AC STRPRTCALL 29DAH CALL FREFACCD DA 29GOSUB to 29DAH to build a temporary string work area entry for the message pointed to by FACLO
28AD-28AFCALL 09C4H CALL GETBCDCD C4 09Go get the string’s length in Register D and the string’s address in BC
28B0INC D 14Bump the value of the string’s length in Register D in preparation for the following loop which starts with a DEC D
28B1 STRPR2DEC D 15Top of a loop. Decrement the value of the string’s length in Register D
28B2RET Z C8Return if all of the characters in the string have been sent to the current output device.
28B4-28B6CALL 032AH CALL OUTDOCD 2A 03Go send the character in Register A to the current output device
28B7-28B8CP 0DH FE 0DCheck to see if the character in Register A is a CARRIAGE RETURN . If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
28B9-28BBCALL Z,2103H CALL Z,CRFINCC 03 21Jump to 2103H if the character in Register A is a carriage return
28BCINC BC 03Bump the value of the string pointer in BC
28BD-28BEJR 28B1H JR STRPR218 F2Loop 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.
OR A B7Make sure A is not zero. A ZERO FLAG will signal that garbage collection has happened
28C0-28C1LD C,0F1H 0E F1Z-80 Trick. If passing through, the C just changes and the POP AF which follows is ignored.
28C1 TRYGI2POP AF F1Get the string’s length from the STACK and put it in Register A
28C2PUSH AF F5Save the length of the string in Register A to the STACK
28C3-28C5LD HL,(40A0H) LD HL,(STKTOP) 2A A0 40Load HL with the poinmter to the bottom of the string space. 40A0H-40A1H holds the start of string space pointer
28C6EX DE,HL EBMove the bottom of the string space pointer into DE. We don’t care what happens to HL
28C7-28C9LD HL,(40D6H) LD HL,(FRETOP) 2A D6 40Load HL with the pointer to the TOP of free space.
Note: 40D6H-40D7H holds the next available location in string space pointer
28CACPL 2FComplement the string’s length in Register A so that it is negative
28CBLD C,A 4FThe 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-28CDLD B,0FFH 06 FFLoad Register B with a -1 so that BC will be the negative length of the string
28CEADD HL,BC 09Add the negative string’s length in BC to the top of free space pointer in HL
28CFINC HL 23Bump the value of the adjusted next available location in string space pointer in HL
28D0We 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 CARRY FLAG is set then we do not have enough room for the string, so lets JUMP forward to 28DAH to do some garbae collection.
28D3-28D5LD (40D6H),HL LD (FRETOP),HL 22 D6 40Save the value in HL as new bottom of MEMORY
28D6INC HL 23Bump the value of HL to point to the string
28D7EX DE,HL EBLoad DE with the pointer to the string
28D9RET C9RETurn to CALLer
28DA-298E – STRING ROUTINE – “GARBAG”
28DB-28DCLD E,1AH 1E 1ALoad Register E with an ?OS ERROR code
28DD-28DFJP Z,19A2H JP Z,ERRORCA A2 19If 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
28E0CP A BFOtherwise, 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.
28E1PUSH AF F5Save the garbage collection flag to the STACK
LD BC,28C1H LD BC,TRYGI2 01 C1 28Load BC with a return address of 28C1H (which would retry allocation)
28E5PUSH BC C5Save that return address to the STACK
LD HL,(40B1H) LD HL,(MEMSIZ) 2A B1 40Load HL with the top of memory pointer.
Note: 40B1H-40B2H holds MEMORY SIZE? pointer
LD (40D6H),HL LD (FRETOP),HL 22 D6 40Save 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-28EELD HL,0000H 21 00 00Zero HL
28EFPUSH HL E5Save the value in HL to the STACK to indicate that we didn’t find a variable on this pass
28F0-28F2LD HL,(40A0H) LD HL,(STKTOP) 2A A0 40Load 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
28F3PUSH HL E5Save high address (start of string space pointer in HL) to the STACK
28F4-28F6LD HL,40B5H LD HL,TEMPST 21 B5 40Load HL with the start of the temporary string work area pointer.
Note: 40B5H-40D2H holds Temporary string work area
28F7
“TVAR”EX DE,HL EBLoad DE with the start of the temporary string work area pointer in HL
28F8-28FALD HL,(40B3H) LD HL,(TEMPPT) 2A B3 40Load 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
28FBEX DE,HL EBExchange 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
28FCWe need to see if 40B3H is pointing to the first entry (40B5H) – if the start of the temporary string work area pointer in HL is the same as the next available location in the temporary string work area pointer, so we call the COMPARE DE:HL routine at RST 10H.
The RST 10H routine parses the characters starting at HL+1 for the first non-SPACE,non-09H,non-0BH character it finds. On exit, Register A will hold that character, and the C FLAG is set if its alphabetic, and NC FLAG if its alphanumeric. All strings must have a 00H at the end.
28FD-28FFLD BC,28F7H LD BC,TVAR 01 F7 28Load BC with a return address of 28F7H
2900-2902JP NZ,294AH JP NZ,DVAR2C2 4A 29Jump to 294AH to do the temporary variable garbage collection if the temporary string work area isn’t empty
2903 SVARSLD HL,(40F9H) LD HL,(VARTAB) 2A F9 40Load HL with the start of the simple variables pointer.
NOTE: 40F9H-40FAH holds the starting address of the simple variable storage area
2907-2909LD HL,(40FBH) LD HL,(ARYTAB) 2A FB 40Load 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
290AEX DE,HL EBSwap DE and HL so that DE holds the end and HL holds the start.
290BNow we need to check to see if the simple variables pointer in HL is the same as the array variables pointer in DE, so we call the COMPARE DE:HL routine at RST 10H.
The RST 10H routine parses the characters starting at HL+1 for the first non-SPACE,non-09H,non-0BH character it finds. On exit, Register A will hold that character, and the C FLAG is set if its alphabetic, and NC FLAG if its alphanumeric. All strings must have a 00H at the end.
290C-290DIf 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.
290ELD A,(HL) 7ELoad Register A with second character of the variable name
290FINC HL 23Bump the value of the simple variables pointer in HL
2910INC HL 23Bump the simple variables pointer in HL
2911INC HL 23Bump the value of the simple variables pointer in HL. HL should now point to the value of the variable.
2912-2913CP 03H FE 03Check to see if the variable at the location of the simple variables pointer is a string. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
2914-2915Jump to 291AH if the variable at the location of the simple variables pointer in HL isn’t a string
2919XOR A AFZero Register A to indicate that we should not be skipping anything else.
291A SKPVARLD E,A 5FZero Register E
291B-291CLD D,00H 16 00Zero Register D. Now DE should be the number of characters to skip.
291DADD HL,DE 19Add the number of characters to skip (held in DE) to the simple variables pointer in HL
291E-291FJR 2906H JR SVAR18 E6Loop back to 2906H until all of the simple variables have been checked
2922-2924LD HL,(40FDH) LD HL,(STREND) 2A FD 40Load HL with the end of the arrays / start of free memory pointer.
Note: 40FDH-40FEH holds Free memory pointer
2925EX DE,HL EBExchange the value of the array variables pointer in DE with the value of the free memory pointer in HL
2926We need to see if we are donee with arrays, so we check to see if the array variables pointer in HL is the same as the free memory pointer in DE, so we call the COMPARE DE:HL routine at RST 10H.
The RST 10H routine parses the characters starting at HL+1 for the first non-SPACE,non-09H,non-0BH character it finds. On exit, Register A will hold that character, and the C FLAG is set if its alphabetic, and NC FLAG if its alphanumeric. All strings must have a 00H at the end.
2927-2929JP Z,296BH JP Z,GRBPASCA 6B 29Jump if the array variables pointer in Register HL is the same as the start of the free memory pointer in DE
292ALD A,(HL) 7ELoad Register A with the number type flag at the location of the array variables pointer in HL
292BINC HL 23Bump the value of the array variables pointer in HL
292C-292ECALL 09C2H CALL MOVRMCD C2 09Get 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)
292FPUSH HL E5Save the pointer to the DIMS to the STACK
2930ADD HL,BC 09Add the value of the offset to the next array in BC to the value of the array variables pointer in HL
2931-2932CP 03H FE 03Check to see if the array being examined is a string. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
2933-2934If the array being examined isn’t a string then skip it via a JUMP to 2920H
2935-2937LD (40D8H),HL LD (TEMP3),HL 22 D8 40Save the address of the end of the array being examined.
Note: 40D8H-40D9H holds Temporary storage location
2938POP HL E1Get the value of the array variables pointer from the STACK and put it in HL
2939LD C,(HL) 4ELoad Register C with the number of subscripts for the array at the location of the array variables pointer in HL
293A-293BLD B,00H 06 00Zero Register B so that BC holds the number of dimensions
293CADD HL,BC 09Add the number of subscripts in the array in BC to the value of the array variables pointer in HL
293DADD HL,BC 09Add 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.
293EINC HL 23Bump the value of the array variables pointer in HL one more time to account for #DIMs.
293F ARYSTREX DE,HL EBLoad DE with the value of the current position in the array variables pointer in HL
2940-2942LD HL,(40D8H) LD HL,(TEMP3) 2A D8 40Load HL with the address of the end of this array.
Note: 40D8H-40D9H holds Temporary storage location
2943EX DE,HL EBSwap DE and HL so that HL now points to the current position
2944We need to test for the end of the array space so we need to check to see if the array variables pointer in HL is the same as the address of the next array in DE, so we call the COMPARE DE:HL routine at RST 10H.
The RST 10H routine parses the characters starting at HL+1 for the first non-SPACE,non-09H,non-0BH character it finds. On exit, Register A will hold that character, and the C FLAG is set if its alphabetic, and NC FLAG if its alphanumeric. All strings must have a 00H at the end.
2945-2946If the Z FLAG is set then we are at the end of an array so JUMP to 2921H to try the next array
294COR (HL) B6Load Register A with the length of the string at the location of the array variables pointer in HL
294DINC HL 23Bump the value of the array variables pointer in HL
294ELD E,(HL) 5ELoad Register E with the LSB of the string’s address at the location of the array variables pointer in HL
294FINC HL 23Bump the value of the array variables pointer in HL
2950LD D,(HL) 56Load 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.
2951INC HL 23Bump the value of the array variables pointer in HL
2952RET Z C8Return if the string’s length in Register A is equal to zero
2955-2957LD HL,(40D6H) LD HL,(FRETOP) 2A D6 40Load HL with the location of the the top of string free space.
NOTE: 40D6H-40D7H holds the next available location in string space pointer
2958We 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
295ALD H,B
LD L,C 60Let HL = BC
295BRET C D8If 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
295DEX (SP),HL E3Swap (SP) and HL so that the return address is back on the STACK and HL holds the maximum number seen
295ENow 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.
295FEX (SP),HL E3Swap (SP) and HL so that the return address is back in HL and the STACK holds the maximum number seen
2960PUSH HL E5Save the return address in HL to the STACK
2961
2962LD H,B
LD L,C 60Let HL = BC
2963RET NC D0Return if the string’s address in DE is below the string space pointer
2965POP AF F1Clean up the STACK (remove the MAX SEEN)
2966POP AF F1Clean up the STACK (remove the VARIABLE POINTER)
2967PUSH HL E5Save the value of the array variables pointer in HL to the STACK
2968PUSH DE D5Save the new MAX pointer in DE to the STACK
2969PUSH BC C5Save the value of the return address in BC to the STACK
296ARET C9RETurn to CALLer
If we are here, we have made one complete pass through the string variables.
296B GRBPASPOP DE D1Load DE with the address of the last string put into the temporary string work area (aka the MAX pointer)
296CPOP HL E1Get the variable pointer from the STACK and put it in HL
296DLD A,L 7DLoad Register A with the LSB of the variable pointer in Register L
296EOR H B4Combine 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
296FRET Z C8If HL=0 then we are at the end of the garbage collection, so return
DEC HL 2BDecrement the value of the temporary string work area pointer in HL, currently just past the string descriptor
2971LD B,(HL) 46Load Register B with the MSB of the string’s address at the location of the temporary string work area pointer in HL
2972DEC HL 2BDecrement the value of the temporary string work area pointer in HL
2973LD C,(HL) 4ELoad 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.
2974PUSH HL E5Save 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.
2975DEC HL 2BDecrement the value of the temporary string work area pointer in HL
2976LD L,(HL) 6ELoad Register L with the string’s length at the location of the temporary string work area pointer in HL
2977-2978LD H,00H 26 00Zero Register H so that HL is now the string’s character count
2979ADD HL,BC 09Add the length of the string in HL to the string’s address in BC. HL now points just beyond the string.
297ALD D,B 50Load Register D with the MSB of the string’s address in Register B
297BLD E,C 59Load Register E with the LSB of the string’s address in Register C. DE now is the original pointer to the string.
297CDEC HL 2BDecrement the value of the string’s ending address in HL to avoid moving one beyond the string
297DLD B,H 44Load Register B with the MSB of the string’s ending address in Register H
297ELD C,L 4DLoad Register C with the LSB of the string’s ending address in Register L. BC now points to the top of the string
297F-2981LD HL,(40D6H) LD HL,(FRETOP) 2A D6 40Load HL with the top of free space.
NOTE: 40D6H-40D7H holds the next available location in string space pointer
2982-2984CALL 1958H CALL BLTUCCD 58 19Move the string from the temporary storage location to string space
2985POP HL E1Get back the pointer to the description of the variable from the STACK and put it in HL
2986LD (HL),C 71Save the LSB of the string’s permanent address (held in Register C) to (HL)
2987INC HL 23Bump the value of the temporary string work area pointer in HL
2988LD (HL),B 70Save the MSB of the string’s permanent address (held in Register C) to (HL)
2989LD L,C 69Load Register L with the LSB of the string’s address in Register C
298ALD H,B 60Load Register H with the MSB of the string’s address in Register B. Register Pair HL will now be the new pointer to the string.
298BDEC HL 2BDecrement the string’s address in HL to adjust FRETOP
298F-29C5 – STRING ADDITION ROUTINE – Concatenate two strings – “CAT”
This routine concatenates two strings. The first is pointed to by FACLO and HL points to the character after the “+” sign in on the command line.
2990PUSH HL E5Save the value of the current BASIC program pointer in HL to the STACK
2991-2993LD HL,(4121H) LD HL,(FACLO) 2A 21 41Load HL with the first string’s VARPTR (from ACCumulator)
2994EX (SP),HL E3Exchange the value of the first string’s VARPTR in HL with the value of the current BASIC program to the STACK
2995-2997CALL 249FH CALL EVALCD 9F 24GOSUB to 249FH to evaluate the expression at the location of the current BASIC program pointer in HL
2998EX (SP),HL E3Exchange the value of the current BASIC program pointer in HL with the value of the first string’s VARPTR to the STACK
299CLD A,(HL) 7ELoad Register A with the first string’s length at the location of the first string’s VARPTR in HL
299DPUSH HL E5Save the value of the first string’s descriptor (VARPTR) in HL to the STACK
299E-29A0LD HL,(4121H) LD HL,(FACLO) 2A 21 41Load HL with the second string’s VARPTR in ACCumulator
29A1PUSH HL E5Save the second string’s VARPTR in HL to the STACK
29A2ADD A,(HL) 86Add the length of the second string at the location of the second string’s VARPTR in HL to the length of the first string in Register A
29A3-29A4LD E,1CH 1E 1CLoad Register E with a ?LS ERROR codein case the two string lengths are not less than 256.
29A5-29A7JP C,19A2H JP C,ERRORDA A2 19Display a ?LS ERROR message if the combined lengths of the strings is greater than 255
29A8-29AACALL 2857H CALL STRINICD 57 28Go make sure that there is enough string space for the new string
29ABPOP DE D1Get the second string’s VARPTR from the STACK and put it in DE
29AFEX (SP),HL E3Exchange the second string’s VARPTR in HL with the first string’s VARPTR to the STACK
29B3PUSH HL E5Save the value of the first string’s VARPTR in HL to the STACK
29B4-29B6 INCSTRLD HL,(40D4H) LD HL,(DSCTMP+1) 2A D4 40Load HL with the pointer to the first string’s address
29B7EX DE,HL EBLoad DE with the first string’s address in HL
29BE-29C0LD HL,2349H LD HL,TSTOP 21 49 23Load HL with the return address
29C1EX (SP),HL E3Exchange the value of the return address in HL with the value of the current BASIC program pointer to the STACK
29C2PUSH HL E5Save the value of the current BASIC program pointer in HL to the STACK
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
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.
29C8LD A,(HL) 7ELoad Register A with the string’s length at the location of the string’s VARPTR in HL
29C9INC HL 23Bump the value of the string’s VARPTR in HL
29CALD C,(HL) 4ELoad Register C with the LSB of the string’s address at the location of the string’s VARPTR in HL
29CBINC HL 23Bump the value of the string’s VARPTR in HL
29CCLD B,(HL) 46Load 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.
29CDLD L,A 6FLoad Register L with the string’s length in Register A
INC L 2CIncrement the value of the string’s length in Register L in preparation for the next instruction which is a loop.
29D0RET Z C8If L hits zero then we have moved all the characters, so RETurn
LD A,(BC) 0AIf 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
29D2LD (DE),A 12Save the character in Register A at the location of the string storage pointer in DE
29D3INC BC 03Bump the value of the string pointer in BC
29D4INC DE 13Bump the value of the string storage pointer in DE
29D7-29F4 – STRING ROUTINE – “FRESTR”
According to the original ROM source code, FRETMP is passed a pointer to a string descriptor in Register Pair DE and is returned in Register Pair HL. All the other registers are modified. A check to is made to see if the string descriptor in Register Pair DE points to is the last temporary descriptor allocated by PUTNEW. If so, the temporary is freed up by the updating of TEMPPT. If a temporary is freed up, a further check is made to see if the string data that that string temporary pointed to is the the lowest part of string space in use. If so, FRETMP is updated to reflect the fact that that space is no longer in use.
This routine is a contination of VAL , FRE , and PRINT processing. A jump to here would include the need to get a string’s VARPTR and put it in HL.
CALL 0AF4H CALL CHKSTRCD F4 0AGOSUB to 0AF4H to make sure that the current result in REG l is a string
CALL 29F5H CALL FRETMSCD F5 29Check to see if the string is the last entry in the temporary string work area
29E1EX DE,HL EBLoad HL with the value of the string’s VARPTR in DE
29E2RET NZ C0Return if the string isn’t the last entry in the temporary string work area
29E4LD D,B 50Load Register D with the MSB of the string’s address in Register B
29E5LD E,C 59Load Register E with the LSB of the string’s address in Register C. DE now points to the string.
29E6DEC DE 1BDecrement the value of the string’s address in DE
29E7LD C,(HL) 4ELoad Register C with the string’s length at the location of the string’s VARPTR in HL
29E8-29EALD HL,(40D6H) LD HL,(FRETOP) 2A D6 40Load 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
29EBWe need to see if the current string is the last one defined in the string area by seeing if the string’s address in DE is the same as the next available location in string space pointer in HL, so we call the COMPARE DE:HL routine at RST 10H.
The RST 10H routine parses the characters starting at HL+1 for the first non-SPACE,non-09H,non-0BH character it finds. On exit, Register A will hold that character, and the C FLAG is set if its alphabetic, and NC FLAG if its alphanumeric. All strings must have a 00H at the end.
29EC-29EDJump forward to 29F3H if the string’s address in DE isn’t the same as the next available location in string space pointer in HL
29EELD B,A 47If is the last one defined then we need to update the current string pointer so first we load Register B with the value in Register A
29EFADD HL,BC 09Add the length of the string in BC to the next available location in string space pointer in HL
29F0-29F2LD (40D6H),HL LD (FRETOP),HL 22 D6 40Save the adjusted next available location in string space pointer in HL.
Note: 40D6H-40D7H holds the next available location in string space pointer
29F4RET C9RETurn to CALLer
29F5-2A02 – STRING ROUTINE – – “FRETMS”
Test to see if the string in DE is the last string used in the temporary string work area.
LD HL,(40B3H) LD HL,(TEMPPT) 2A B3 40Load HL with the temporary string work area pointer.
Note: 40B3H-40B4H holds the next available location in the temporary string work area pointer
29F8DEC HL 2BDecrement the value of the temporary string work area pointer in HL which backs up two words
29F9LD B,(HL) 46Load Register B with the MSB of the string’s address at the location of the temporary string work area pointer in HL
29FADEC HL 2BDecrement the value of the temporary string work area pointer in HL
29FBLD C,(HL) 4ELoad Register C with the LSB of the string’s address at the location of the temporary string work area pointer in HL
29FCDEC HL 2BDecrement the value of the temporary string work area pointer in HL
29FDWe 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.
29FERET NZ C0If the Z FLAG is set then we are done freeing space, so RETURN
LD (40B3H),HL LD (TEMPPT),HL 22 B3 40Save 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
2A02RET C9RETurn to CALLer
2A03-2A0E – LEVEL II BASIC LEN ROUTINE – “LEN”
2A03-2A05 LENLD BC,27F8H LD BC,SNGFLT 01 F8 27Load BC with the return address of 27F8H
2A06PUSH BC C5Save the return address of 27F8H (in BC) to the STACK
CALL 29D7H CALL FRESTRCD D7 29GOSUB to 29D7H to free up the temporary variable pointed to by FACLO
2A0AXOR A AFZero Register A so as to force a numeric flag
2A0BLD D,A 57Zero Register D so that DE can be used when E is set.
2A0CLD A,(HL) 7ELoad Register A with the string’s length at the location of the string’s VARPTR in HL
2A0DOR A B7Set the flags according to the string’s length in Register A
2A0ERET C9RETurn to CALLer
2A0F-2A1E – LEVEL II BASIC ASC ROUTINE – “ASC”
2A0F-2A11 ASCLD BC,27F8H LD BC,SNGFLT 01 F8 27Load BC with the return address of 27F8H
2A12PUSH BC C5Save the return address of 27F8H (in BC) to the STACK
CALL 2A07H CALL LEN1CD 07 2AGOSUB to 2A07H (which itself is a GOSUB to 29D7H) to get string’s VARPTR into HL and the string’s length into Register A
2A16-2A18JP Z,1E4AH JP Z,FCERRCA 4A 1EIf the Z FLAG is set, then this was a null string (bad argument), so display a ?FC ERROR
2A19INC HL 23Bump the value of the string’s VARPTR in HL
2A1ALD E,(HL) 5ELoad Register E with the LSB of the address of the string’s data at the location of the string’s VARPTR in HL
2A1BINC HL 23Bump the value of the string’s VARPTR in HL
2A1CLD D,(HL) 56Load Register D with the MSB of the address of the string’s data at the location of the string’s VARPTR in HL
2A1DLD A,(DE) 1ALoad Register A with the first character at the location of the string pointer in DE
2A1ERET C9RETurn to CALLer
2A1F-2A2E – LEVEL II BASIC CHR$ ROUTINE – “CHR$”
2A1F-2A20 CHR$LD A,01H 3E 01Load Register A with the length of the string to be created
2A21-2A23CALL 2857H CALL STRINICD 57 28GOSUB to 2857H to save the string’s length in Register A and value and set up the string’s address
2A24-2A26CALL 2B1FH CALL CONINTCD 1F 2BGOSUB to 2B1FH to evaluate the expression at the location of the current BASIC program pointer in HL and return with the integer result in DE
2A27-2A29 SETSTRLD HL,(40D4H) LD HL,(DSCTMP+1) 2A D4 40Load HL with the temporary string’s address
2A2ALD (HL),E 73Save the character in Register E at the location of the string pointer in HL
POP BC C1Clean up the STACK so that the RETURN address is another one that is next in the STACK.
2A2F-2A60 – LEVEL II BASIC STRING$ ROUTINE – “STRNG$”
We have the STRING$ command, but now we need the next character so we call a RST 10H to bump the value of the current BASIC program pointer until it points to the next character, call the EXAMINE NEXT SYMBOL routine at RST 10H.
The RST 10H routine parses the characters starting at HL+1 for the first non-SPACE,non-09H,non-0BH character it finds. On exit, Register A will hold that character, and the C FLAG is set if its alphabetic, and NC FLAG if its alphanumeric. All strings must have a 00H at the end.
2A30-2A31Since the character at the location of the current BASIC program pointer in HL must be a ( , call the COMPARE SYMBOL routine at RST 08H.
NOTE: The RST 08H routine compares the symbol in the input string pointed to by HL Register to the value in the location following the RST 08 call.- If there is a match, control is returned to the next execution address (i.e, the RST 08H instruction + 2) with the next symbol in the A Register and HL incremented by one.
- If the two characters do not match, a syntax error message is given and control returns to the Input Phase).
2A32-2A34CALL 2B1CH CALL GETBYTCD 1C 2BThis 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
2A34DEC HL 2BBackspace the code string. This is a Z-80 trick because this code was part of the above call instruction
2A35PUSH DE D5Save the string’s length (“N”) (currently in DE) to the STACK
2A36-2A37RST 08 ⇒ 2C SYNCHK “,” CF 2CNow we have STRING$(nnn so the next character needs to be a , . To test for the character at the location of the current BASIC program pointer in HL being a , , call the COMPARE SYMBOL routine which compares the symbol in the input string pointed to by HL Register to the value in the location following the RST 08 call. If there is a match, control is returned to address of the RST 08 instruction + 2 with the next symbol in the A Register and HL incremented by one. If the two characters do not match, a syntax error message is given and control returns to the Input Phase)
2A38-2A3ACALL 2337H CALL FRMEVLCD 37 23Now we have STRING$(xxx, and an expression so GOSUB to 2337H to evaluate the expression at the location of the current BASIC program pointer in HL and return with the result in ACCumulator
2A3B-2A3CNow 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).
2A3DEX (SP),HL E3We 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
2A3EPUSH HL E5Save the string’s length (“N”) in HL to the STACK so that we can test it to make sure it is an integer
2A3FWe need to check the value of the current data type flag, so we call the TEST DATA MODE routine at RST 20H.
NOTE: The RST 20H routine determines the type of the current value in ACCumulator and returns a combination of STATUS flags and unique numeric values in the A Register according to the data mode flag (40AFH). The results are returned as follows:- Integer = NZ/C/M/E and A is -1
- String = Z/C/P/E and A is 0
- Single Precision = NZ/C/P/O and A is 1
- and Double Precision is NZ/NC/P/E and A is 5.
2A42-2A44CALL 2B1FH CALL CONINTCD 1F 2BWe now know that “N” is at least a number, so we GOSUB to 2B1FH to convert the current result in ACCumulator to an integer and return with the 8-bit result in Register A
2A45-2A46JR 2A4AH JR CALSPA18 03Skip the next instruction (which would load the string address and 1st character) by jumping to 2A4AH
CALL 2A13H CALL ASC2CD 13 2AGo get the first character in the string and return with it in Register A. This is the character that will be repeated
2A4BPUSH AF F5Save the character for the string (held in Register A) to the STACK
2A4C SPACE2PUSH AF F5and then save it to the STACK again
2A4DLD A,E 7BLoad Register A with “N” (held in Register E)
2A4E-2A4FCALL 2857H CALL STRINICD 57 28GOSUB to 2857H to allocate N bytes in the temporary string work area
2A51LD E,A 5FLoad Register E with “N” (held in Register A)
2A52POP AF F1Get the character for the string (“X”) from the STACK and put it in Register A
2A53INC E 1CTo set the status flags we need to increase and then decrease E. First, bump the value of the string’s length in Register E
2A54DEC E 1D. and then decrement the string’s length in Register E
2A55-2A56If “N” was zero (so that the string is now complete), jump back to 2A2BH
2A57-2A59LD HL,(40D4H) LD HL,(DSCTMP+1) 2A D4 40If we are here, we have not finished building the STRING$ string so now we load HL with the string’s address and get ready to loop
LD (HL),A 77Save the character in Register A (“X”) at the location of the string pointer in HL
2A5BINC HL 23Bump the value of the string pointer in HL
2A5CDEC E 1DDecrement the string’s length in Register E
2A5D-2A5EJR NZ,2A5AH20 FBLoop back to 2A5AH to keep filling (HL) until the string of X’s has been completed
2A61-2A90 – LEVEL II BASIC LEFT$( ROUTINE – “LEFT$”
On entry, HL=address of LEFT$$, the STACK = string address, STACK+1 = n, and DE = code string address.
2A61-2A63 LEFT$CALL 2ADFH CALL PREAMCD DF 2AGo check the syntax. The character at the location of the current BASIC program pointer in HL must be a )
2A64XOR A AFZero Register A because the string pointer never changes
EX (SP),HL E3Exchange the value of the current BASIC program pointer in HL with the string’s VARPTR to the STACK
2A66LD C,A 4FZero Register C
2A67-2A68LD A,0E5H 3E E5Z-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
PUSH HL E5Save 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 LEFT2PUSH HL E5Save the value of the string’s VARPTR in HL to the STACK
2A6ALD A,(HL) 7ELoad Register A with the string’s length at the location of the string’s VARPTR in HL
2A6BCP B B8Check 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
2A6ELD A,B 78Load Register A with the new string’s TRUNCATED length in Register B
2A6F-2A71LD DE,000EH 11 0E 00Z-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
2A72PUSH BC C5Save the offset in BC to the STACK
2A76POP BC C1Get the offset from the STACK and put it in BC
2A77POP HL E1Get the string’s VARPTR from the STACK and put it in HL
2A78PUSH HL E5Save the string’s VARPTR in HL to the STACK
2A79INC HL 23Bump HL to now point to the address of the string
2A7ALD B,(HL) 46Load Register B with the LSB of the string’s address at the location of the string’s VARPTR in HL
2A7BINC HL 23Bump the value of the string’s VARPTR in HL
2A7CLD H,(HL) 66Load Register H with the MSB of the string’s address at the location of the string’s VARPTR in HL
2A7DLD L,B 68Load Register L with the LSB of the string’s address in Register B
2A7E-2A7FLD B,00H 06 00Zero Register B so that BC can be used
2A80ADD HL,BC 09Add the string’s length in BC to the string’s address in HL
2A81LD B,H 44Load Register B with the MSB of the string’s ending address in Register H
2A82LD C,L 4DLoad Register C with the LSB of the string’s ending address in Register L
2A83-2A85CALL 285AH CALL STRAD2CD 5A 28Go save the string’s length (held in A) and the string’s starting address (held in DE)
2A86LD L,A 6FLoad Register L with the string’s length (i.e., the number of characters to move) held in Register A
2A8APOP DE D1Clean up the STACK
2A91-2A99 – LEVEL II BASIC RIGHT$ ROUTINE – “RIGHT$”
2A91-2A93CALL 2ADFH CALL PREAMCD DF 2AGo check the syntax. The character at the location of the current BASIC program pointer in HL must be a )
2A94POP DE D1Get the string’s VARPTR from the STACK and put it in DE
2A95PUSH DE D5Save the string’s VARPTR in DE to the STACK
2A96LD A,(DE) 1ALoad Register A with the string’s length (held at the location of the string’s VARPTR in DE)
2A97SUB B 90Subtract the new string’s length in Register B from the string’s length in Register A to isolate the number of bytes
2A9A-2AC4 – LEVEL II BASIC MID$ ROUTINE – “MID$”
The original ROM source code clarifies that if the number provided is greater than the actual length of the string, a NULL value is returned. If the second number (the number of characters) exceeds the end of the string, the maximum amount of available characters are returned.
2A9A MID$EX DE,HL EBLoad HL with the value of the current BASIC program pointer (held in DE)
2A9BLD A,(HL) 7ELoad Register A with the terminal character, currently held at the location of the current BASIC program pointer in HL
2A9C-2A9ECALL 2AE2H CALL PREAM2CD E2 2AGOSUB to 2AE2H to get the offset in Register B and the string’s VARPTR in DE
2A9FINC B 04We need to set the status flags to correspond to the offset position value so we first bump the value of the string’s position in Register B
2AA0DEC B 05… and then we decrement the value of the string’s offset position in Register B
2AA4PUSH BC C5Save the value of the offset position (held in Register B) to the STACK
2AA5-2AA6LD E,0FFH 1E FFLoad Register E with the default string’s length of 256 in case no number of bytes are given
2AA7-2AA8CP 29H CP “)” FE 29More syntax checking. Here we need to test for a ) at the location of the current BASIC program pointer. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
2AA9-2AAAJR Z,2AB0H JR Z,MID228 05Jump to 2AB0H if the character at the location of the current BASIC program pointer in Register A is a )
2AAB-2AACIf it wasn’t a ) , it had best be a , so we need to test the character at the location of the current BASIC program pointer in HL by calling the COMPARE SYMBOL routine at RST 08H.
NOTE: The RST 08H routine compares the symbol in the input string pointed to by HL Register to the value in the location following the RST 08 call.- If there is a match, control is returned to the next execution address (i.e, the RST 08H instruction + 2) with the next symbol in the A Register and HL incremented by one.
- If the two characters do not match, a syntax error message is given and control returns to the Input Phase).
2AAD-2AAFCALL 2B1CH CALL GETBYTCD 1C 2BGo evaluate the expression at the location of the current BASIC program pointer in HL and return with the integer result in DE. Now the byte count is in DE as an integer
2AB0-2AB1Since 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).
2AB2POP AF F1Get the offset from the STACK and put it in Register A
2AB3EX (SP),HL E3Exchange the value of the current BASIC program pointer in HL with the value of the string’s VARPTR to the STACK
LD BC,2A69H LD BC,LEFT2 01 69 2ALoad BC with 2A69H as the return address (which is in the LEFT$ routine)
2AB7PUSH BC C5Save the return address in BC to the STACK
2AB8DEC A 3DDecrement the value of the requested offset in Register A so that we have a starting position minus 1
2AB9CP (HL) BECompare 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-2ABBLD B,00H 06 00Zero Register B
2ABCRET NC D0If the offset pointer ispast the end of the string we are going to return a null
2ABELD A,(HL) 7ELoad Register A with the string’s length at the location of the string’s VARPTR in HL
2ABFSUB C 91Subtract the index (the second argument) in Register C from the string’s length in Register A
2AC0CP E BBCompare 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.
2AC1LD B,A 47Load Register B with the calculated string’s length in Register A
2AC2RET C D8If we are not going to truncate, then just use the partial string we already have and Return to 2A69H
2AC4RET C9Return to 2A69H aka LEFT2
2AC5-2ADE – LEVEL II BASIC VAL ROUTINE – “VAL”
2AC5-2AC7 VALCALL 2A07H CALL LEN1CD 07 2AGo get the string’s length in Register A and the string’s VARPTR in HL
2AC8-2ACAJP Z,27F8H JP Z,SNGFLTCA F8 27Jump to 27F8H if the string’s length in Register A is equal to zero
2ACBLD E,A 5FLoad Register E with the string’s length at the location of the string’s VARPTR in HL.
The original ROM source explains that we need to do some fancy footwork here to handle the case where the two strings are stored next to each other.
2ACCINC HL 23Bump the value of the string’s VARPTR in HL
2ACDLD A,(HL) 7ELoad Register A with the LSB of the string’s address at the location of the string’s VARPTR in HL
2ACEINC HL 23Bump the value of the string’s VARPTR in HL
2ACFLD H,(HL) 66Load Register H with the MSB of the string’s address at the location of the string’s VARPTR in HL
2AD0LD L,A 6FLoad Register L with the LSB of the string’s address in Register A
2AD1PUSH HL E5Save the value of the string’s address in HL to the STACK
2AD2ADD HL,DE 19Add the string’s length in DE to the string’s address in HL
2AD3LD B,(HL) 46Load Register B with the last character of the string at the location of the string pointer in HL
2AD4LD (HL),D 72Save the zero in Register D at the location of the string pointer in HL
2AD5EX (SP),HL E3Exchange the string’s ending address in HL with the string’s address to the STACK
2AD6PUSH BC C5Save the last character of the string in Register B to the STACK
2AD7LD A,(HL) 7ELoad Register A with the first character of the argument
2AD8-2ADACALL 0E65H CALL FINDBLCD 65 0ECall 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)
2ADBPOP BC C1Get the modified character of the next string into Register B
2ADCPOP HL E1Get the pointer to the modified character back into HL
2ADDLD (HL),B 70Restore the character.
2ADERET C9RETurn 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.
2AE0-2AE1Since 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).
2AE3POP DE D1Get the number of bytes to isolate from the string (from the STACK) and put it in DE
2AE4PUSH BC C5Save the return address in BC to the STACK
2AE5LD B,E 43Load Register B with the number of bytes in Register E
2AE6RET C9RETurn to CALLer
2AE7H-2AEE – Process a LEFT-HAND-SIDE MID$ – “ISMID$”
CP 7AH CP MIDTK-$END FE 7AThis routine is designed to handle a left-size MID$ call. So check to see if the character at the location of the current BASIC program pointer in Register A is trying to process a left hand side MID$. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
2AE9-2AEBJP NZ,1997H JP NZ,SNERRC2 97 19Display a ?SN ERROR message if that is not what is going on.
2AEC-2AEEJP 41D9H JP DLHSMDC3 D9 41JUMP to DOS to see if DOS wants to deal with this.
2AEF-2AF7 – LEVEL II BASIC INP ROUTINE – “FNINP”
2AEF-2AF1 FNINPCALL 2B1FH CALL CONINTCD 1F 2BGo evaluate the expression at the location of the current BASIC program pointer in HL and return with the port number in Register A
2AF2-2AF4LD (4094H),A LD (STAINP+1),A 32 94 40Save the value of the port number (from Register A) into 4094H, which is in the middle of a routine.
2AF5-2AF1CALL 4093H CALL STAINP CD 1F 2BPerform in INP on the channel held in Register A
2AF8-2B00 – LEVEL II BASIC OUT ROUTINE – “FNOUT”
2AFB-2AFDJP 4096H JP OUTWRDCD 0E 2BDo the OUT and RETurn
2B01-2B0D – EVALUATE EXPRESSION ROUTINE
“GETINT”
This evaluates an expression and leaves the result in DE as an integer.
2B01 GETINTWe 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.
CALL 2337H CALL FRMEVLCD 37 23Go 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)).
2B06-2B08CALL 0A7FH CALL FRCINTCD 7F 0ACall 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)
2B09EX DE,HL EBLoad DE with the integer result in HL
2B0APOP HL E1Get the value of the current BASIC program pointer from the STACK and put it in HL
2B0BLD A,D 7ALoad Register A with the MSB of the integer result in Register D
2B0COR A B7Test the value of the MSB in Register A
2B0DRET C9RETurn to CALLer
2B0E-2B16 – EVALUATE EXPRESSION ROUTINE – OUT continues here – “SETIO”
CALL 2B1CH CALL GETBYTCD 1C 2BGOSUB to 2B1CH to evaluate the expression at the location of the current BASIC program pointer in HL and return with the 8-bit value in Register A
2B11-2B13LD (4094H),A LD (STAINP+1),A 32 94 40Save the 8-bit value in Register A in the DOS address of 4094H to set up for WAIT
2B14-2B16LD (4097H),A LD (OUTWRD+1),A 32 97 40Save the 8-bit value in Register A in the DOS address of 4097H to set up for OUT
2B17-2B1A – CHECK SYNTAX ROUTINE – This checks to see if the next character is a “ and contnues on to 2B1CH if it is, and errors out if it isn’t.
2B17-2B18Since 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).
2B1B-2B28 – EVALUATE EXPRESSION ROUTINE – This is called by PRINT TAB – “GTBYTC” .
2B1B GTBYTCWe need the next character in the BASIC program so call the EXAMINE NEXT SYMBOL routine at RST 10H.
The RST 10H routine parses the characters starting at HL+1 for the first non-SPACE,non-09H,non-0BH character it finds. On exit, Register A will hold that character, and the C FLAG is set if its alphabetic, and NC FLAG if its alphanumeric. All strings must have a 00H at the end.
2B1C – Common Conversion Routine – “GETBYT”
This routine converts a numeric ASCII string pointed to by the HL into a hexadecimal value and places the result in the A register. If the result is larger than 255 (FFH) then an FC ERROR (Illegal function call) will be generated. After execution the HL will point to the delimiter. If the delimiter is a zero byte or a colon (3AH) then the Z flag will be set. Any other delimiter will cause the Z flag to be reset.
2B1C-2B1E GETBYTCALL 2337H CALL FRMEVLCD 37 23GOSUB to 2337H to evaluate the formula/expression at the location of the current BASIC program pointer in HL and return with the result in REG l
2B1F-2B21 CONINTCALL 2B05H CALL INTFR2CD 05 2BGOSUB to 2B05H to convert the result in ACCumulator to an integer and return with the integer result in DE. Flags are set based on Register D.
2B22-2B24JP NZ,1E4AH JP NZ,FCERRC2 4A 1EIf the result is greater than 255, display a ?FC ERROR message
2B25DEC HL 2BDecrement the value of the current BASIC program pointer in HL
2B26We 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.
2B27LD A,E 7BLoad Register A with the 8-bit result in Register E so that both A and E have the result.
2B28RET C9RETurn 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 LLISTLD A,01H 3E 01Load Register A with the printer output device code
2B2B-2B2DLD (409CH),A LD (PRTFLG),A 32 9C 40Save the value in Register A as the current output device flag.
Note: 409CH holds the current output device flag: -1=cassette, 0=video and 1=printer
2B2E-2B74 – LEVEL II BASIC LIST ROUTINE – “LIST”
On entry the STACK has the return address, then the first basic line number to be listed, then the last basic line number to be listed.
2B2E LISTPOP BC C1Get rid of the the return address on the STACK
2B2F-2B31CALL 1B10H CALL SCNLINCD 10 1BGo evaluate the range of line numbers given at the location of the current BASIC program pointer in HL
2B32PUSH BC C5Save the address of the first BASIC line (held in BC) to the STACK
LD HL,FFFFH 21 FF FFLoad 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-2B38LD (40A2H),HL LD (CURLIN),HL 22 A2 40Save the value in HL as the current BASIC line number (which is stored at 40A2H-40A3H).
2B39POP HL E1Get the address of the first BASIC line to be listed (from the STACK) and put it in HL
2B3APOP DE D1Get the value of the last BASIC line number to be listed (from the STACK) and put it in DE
2B3BLD C,(HL) 4ELoad Register C with the LSB of the next BASIC line pointer at the location of the memory pointer in HL
2B3CINC HL 23Bump the value of the memory pointer in HL
2B3DLD B,(HL) 46Load Register B with the MSB of the next BASIC line pointer at the location of the memory pointer in HL
2B3EINC HL 23Bump the value of the memory pointer in HL
2B3FLD A,B 78Load Register A with the MSB of the next BASIC line pointer in Register B
2B40OR C B1Combine the LSB of the next BASIC line pointer in Register C with the MSB of the next BASIC line pointer in Register A. This will let us test for the end of the BASIC program
2B41-2B43JP Z,1A19H JP Z,READYCA 19 1AIf we are at the elast line, then STOP and JUMP to 1A19H to the READY PROMPT.
2B44-2B46CALL 41DFH CALL EXCHDSCD DF 41GOSUB to DOS to see if DOS wants to do anything here.
2B47-2B49CALL 1D9BH CALL ISCNTCCD 9B 1DGo scan the keyboard to see if the BREAK key or the shift – @ key was pressed
2B4APUSH BC C5Save the address of the next BASIC line in BC to the STACK
2B4BLD C,(HL) 4EWe 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
2B4CINC HL 23Bump the value of the memory pointer in HL
2B4DLD B,(HL) 46Load Register B with the MSB of the BASIC line number at the location of the memory pointer in HL
2B4EINC HL 23Bump the value of the memory pointer in HL
2B4FPUSH BC C5Save the BASIC line number in BC to the STACK
2B50EX (SP),HL E3Swap (SP) and HL so that the line number is now in HL
2B51EX DE,HL EBSwap DE and HL so that the last BASIC line number is now in HL
2B52We 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.
2B53POP BC C1Get the pointer to the location on the BASIC program line being processed and put it in BC
2B54-2B56JP C,1A18H JP C,STPRDYDA 18 1AIf the BASIC line number in DE is greater than the last BASIC line number in HL then we have gone past the end, so we are done processing!
2B57EX (SP),HL E3Swap (SP) and HL so that the last BASIC line number is now on the STACK
2B58PUSH HL E5Save the address of the next BASIC line in HL to the STACK
2B59PUSH BC C5Save the pointer to the location on the BASIC program line being processed to the STACK
2B5AEX DE,HL EBLoad HL with the BASIC line number (from DE)
2B5B-2B5DLD (40ECH),HL LD (DOT),HL 22 EC 40Save the BASIC line number in HL into DOT for use later in EDIT or LIST.
Note: 40ECH-40EDH holds EDIT line number
2B5E-2B60CALL 0FAFH CALL LINPRTCD AF 0FCall 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-2B62LD A,20H 3E 20Load Register A with a space
2B63POP HL E1Get the value of the memory pointer from the STACK and put it in HL
2B67-2B69CALL 2B7EH CALL BUFLINCD 7E 2BGOSUB to 2B7EH move the BASIC line at the location of the memory pointer in HL into the input buffer and untokenize the BASIC line
2B6A-2B6CLD HL,(40A7H) LD HL,(BUFPNT) 2A A7 40Load HL with the starting address of the input buffer.
Note: 40A7H-40A8H holds the input Buffer pointer
2B6D-2B6FCALL 2B75H CALL LISPRTCD 75 2BSince 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
2B75-2B7D – DISPLAY MESSAGE ROUTINE – “LISPRT”
This is the PRINT MESSAGE routine which writes string pointed to by HL to the current output device. String must be terminated by a byte of zeros. This call is different from 28A7H because it does not use the literal string pool area, but it does use the same display routine and it takes the same DOS Exit at 41C1H. Uses all registers. This routine can be called without loading the BASIC utility, if a C9H (RET) is stored in 41C1H.
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.
LD A,(HL) 7ELoad Register A with the character at the location of the memory pointer in HL
2B76OR A B7Check to see if the character in Register A is an end of the string character (00H)
2B77RET Z C8Return if the character in Register A is an end of the string character
CALL 032AH CALL OUTDOCD 2A 03Go send the character in Register A to the current output device
2B7BINC HL 23Bump the value of the memory pointer in HL
2B7C-2B7DJR 2B75H JR LISPRT18 F7Loop 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.
2B7F-2B81LD HL,(40A7H) LD HL,(BUFPNT) 2A A7 40Load HL with the starting address of the input buffer.
Note: 40A7H-40A8H holds the input Buffer pointer
2B82
2B83LD B,H
LD C,L 44LET Register Pair BC = Register Pair HL
2B84POP HL E1Get the value of the BASIC line pointer from the STACK and put it in HL
2B85-2B86LD D,FFH LD D,BUFLEN 16 FFLoad Register D with the maximum length of an untokenized line
2B8ADEC D 15Decrement the character count in Register D
2B8BRET Z C8Return if 256 characters have been moved into the input buffer
LD A,(HL) 7ELoad Register A with the character at the location of the BASIC line pointer in HL
2B8DOR A B7Set 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)
2B8EINC HL 23Bump the value of the BASIC line pointer in HL to the next character in the code string
2B8FLD (BC),A 02Save 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.
2B90RET Z C8Return if the character in Register A is an end of the BASIC line character
JP P,2B89H JP P,PLOOPF2 89 2BIf the character in A is just a regular character (i.e., not a token), then JUMP back to 2B89H
2B94-2B95CP 0FBH CP SNGQTK FE FBCheck to see if the character in Register A is a ‘ token. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
2B96-2B97Jump 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-2B9BDEC BC
DEC BC
DEC BC
DEC BC 0BFirst, 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-2B9FINC D
INC D
INC D
INC D 14Then, 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.
CP 95H CP $ELSE FE 95Check to see if the character in Register A is an ELSE token. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
2BA2-2BA4CALL Z,0B24H CALL Z,DCXVBRTCC 24 0BIf 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
DEC BC 0BThis 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-2BA6SUB 7FH D6 7FNext, 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
2BA7PUSH HL E5Save the value of the BASIC line pointer in HL to the STACK. Register L holds the reserved word number at this point.
2BA8LD E,A 5FLoad Register E with the character in Register A
2BA9-2BABLD HL,1650H LD HL,RESLST 21 50 16Load HL with the starting address of the reserved words list
LD A,(HL) 7ELoad Register A with the character at the location of the reserved words list pointer in HL
2BADOR A B7Test 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.
2BAEINC HL 23Bump the value of the reserved words list pointer in HL
2BAF-2BB1JP P,2BACH JP P,LOPRESF2 AC 2BIf the character at the location of the reserved words pointer in Register A doesn’t have bit 7 set then Jump back to 2BACH.
2BB2DEC E 1DDecrement the counter
2BB3-2BB4Jump back to 2BACH if this isn’t the reserved word for the token
2BB5-2BB6AND 7FH E6 7FReset bit 7 of the character in Register A by ANDing it against 0111 1111. This is to eliminate the MSB for “EDIT” and for disk I/O
LD (BC),A 02Save the character in Register A at the location of the input buffer pointer in BC
2BB8INC BC 03Bump the value of the input buffer pointer in BC
2BB9DEC D 15Decrement the value of the character counter in Register D
2BBA-2BBCJP Z,28D8H JP Z,PPSWRTCA D8 28If the Z FLAG has been set, then the character counter for the buffer has been exhausted and the buffer is now full, so JUMP back to 28D8H
2BBDLD A,(HL) 7ELoad Register A with the character at the location of the reserved words pointer in HL
2BBEINC HL 23Bump the reserved words pointer in HL
2BBFOR A B7Test the value of the character in Register A
2BC0-2BC2JP P,2BB7H JP P,MORPURF2 B7 2BKeep getting characters in this reserved word until we hit the next reserved word
2BC3POP HL E1Get the value of the BASIC line pointer from the STACK and put it in HL
2BC4-2BC5JR 2B8CH JR PLOOP218 C6Jump back to 2B8CH to continue processing the BASIC line being interpreted
2BC6-2BF4 – LEVEL II BASIC DELETE ROUTINE – “DELETE”
2BC6-2BC8 DELETECALL 1B10H CALL SCNLINCD 10 1BGOSUB to 1B10H to evaluate the line numbers at the location of the current BASIC program pointer in HL
2BC9POP DE D1Get the value of the last BASIC line number to be deleted (in binary) from the STACK and put it in DE
2BCAPUSH BC C5Save the address of the first BASIC line to be deleted in BC to the STACK
2BCBPUSH BC C5Save the address of the first BASIC line to be deleted in BC to the STACK AGAIN!
2BCC-2BCECALL 1B2CH CALL FNDLINCD 2C 1BGOSUB 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
Since the first line number provided MUST be found, if FNDLIN returns with the NC FLAG set (i.e., not found) we must JUMP to 2BD6H to show a ?FC ERROR
2BD1
2BD2LD D,H
LD E,L 54Let Register Pair DE = Register Pair HL
2BD3EX (SP),HL E3Exchange the last BASIC line’s address in HL with the first BASIC line’s address to the STACK
2BD4PUSH HL E5Save the pointer to the first line in range to the STACK
2BD5We 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.
JP NC,1E4AH JP NC,FCERRD2 4A 1EDisplay a ?FC ERROR message if the first BASIC lines address in HL is greater than or equal to the last BASIC line’s address in DE
2BD9-2BDBLD HL,1929H LD HL,REDDY 21 29 19Load HL with the starting address of the BASIC READY message
2BDC-2BDECALL 28A7H CALL STROUTCD A7 28Call the WRITE MESSAGE routine at 28A7H to print the message pointed to by HL.
2BDFPOP BC C1Get the first BASIC line’s address from the STACK and put it in BC
2BE0-2BE2LD HL,1AE8H LD HL,FINI 21 E8 1ALoad HL with the return address
2BE3EX (SP),HL E3Swap (SP) and HL so that HL now points to the next BASIC line’s address …
2BE5-2BE7LD HL,(40F9H) LD HL,(VARTAB) 2A F9 40Load HL with the end of the BASIC program pointer.
- Note: 40F9H-40FAH holds the starting address of the simple variable storage area.
LD A,(DE) 1ALoad Register A with the character at the location of the memory pointer in DE
2BE9LD (BC),A 02Save the character in Register A at the location of the memory pointer in BC
2BEAINC BC 03Bump the value of the memory pointer in BC
2BEBINC DE 13Bump the value of the memory pointer in DE
2BECNow we need to check to see if the memory pointer in DE equals the end of the BASIC program pointer in HL, so we call the COMPARE DE:HL routine at RST 10H.
The RST 10H routine parses the characters starting at HL+1 for the first non-SPACE,non-09H,non-0BH character it finds. On exit, Register A will hold that character, and the C FLAG is set if its alphabetic, and NC FLAG if its alphanumeric. All strings must have a 00H at the end.
2BED-2BEELoop back to 2BE8H until the memory pointer in DE equals the end of the BASIC program pointer in HL
2BEFLD H,B 60Load Register H with the MSB of the memory pointer in Register B
2BF0LD L,C 69Load Register L with the LSB of the memory pointer in Register C
2BF1-2BF3LD (40F9H),HL LD (VARTAB),HL 22 F9 40Save 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.
2BF4RET C9RETurn to CALLer
2BF5-2C1E – LEVEL II BASIC CSAVE ROUTINE – “CSAVE”
The original ROM source code says that the CSAVE command dump’s BASIC’s core. Three D3H’s are written, followed by a 1 character filename. At the end 3 zeros in a row are written.
2BF5-2BF7 CSAVECALL 0284H CALL CWRTONCD 84 02Calls the WRITE LEADER routine at 0284H (which writes a Level II leader on the cassette unit set in Register A)
2BF8CALL 2337H CALL FRMEVLCD 37 232BFAH Go evaluate the rest of the CSAVE expression at the location of the current BASIC program pointer in HL and return with the result in REG l
2BFBPUSH HL E5Save the value of the current BASIC program pointer in HL to the STACK so we can get it back at the end of the routine
2BFF-2C00LD A,D3H 3E D3Load Register A with the filename header byte (=D3H which is a “S” with the sign bit on)
2C01-2C03CALL 0264H CALL CASOUTCD 64 02the 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
2C07LD A,(DE) 1ALoad Register A with the first character of the filename at the location of the filename pointer in DE
2C08-2C0ACALL 0264H CALL CASOUTCD 64 02the 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-2C0DLD HL,(40A4H) LD HL,(TXTTAB) 2A A4 40Load 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).
2C0EEX DE,HL EBLoad DE with the start of the BASIC program pointer in HL
2C0F-2C11LD HL,(40F9H) LD HL,(VARTAB) 2A F9 40Load HL with the end of the BASIC program pointer.
- Note: 40F9H-40FAH holds the starting address of the simple variable storage area.
LD A,(DE) 1ATop 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
2C13INC DE 13Bump the value of the memory pointer in DE
2C14-2C16CALL 0264H CALL CASOUTCD 64 02the 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)
2C17Now we need to check to see if the memory pointer in DE is equal to the end of the BASIC program pointer in HL, so we call the COMPARE DE:HL routine at RST 10H.
The RST 10H routine parses the characters starting at HL+1 for the first non-SPACE,non-09H,non-0BH character it finds. On exit, Register A will hold that character, and the C FLAG is set if its alphabetic, and NC FLAG if its alphanumeric. All strings must have a 00H at the end.
2C18-2C19Loop back to 2C12H until the memory pointer in DE is equal to the end of the BASIC program pointer in HL
2C1DPOP HL E1Get the value of the current BASIC program pointer from the STACK and put it in HL
2C1ERET C9RETurn to CALLer
2C1F-2CA4 – LEVEL II BASIC CLOAD ROUTINE – ROM v1.0 – “CLOAD”
2C22LD A,(HL) 7ELoad Register A with the character at the location of the current BASIC program pointer in HL
2C23-2C24SUB 0B2H SUB $PRINT D6 B2Check to see if the character at the location of the current BASIC program pointer in Register A is a ? , meaning that CLOAD? was requested.
Jump to the CLOAD? routine at 2C29H if the character at the location of the current BASIC program pointer in Register A is a ?
2C27XOR A AFOK – So this is now a straight CLOAD . First, zero Register A
2C28LD BC,232F 01 2F 23Z-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
2C2AINC HL 23Bump the value of the current BASIC program pointer in HL until it points to the next character after the ? in CLOAD?
2C2BPUSH AF F5Save the CLOAD / CLOAD? flag in Register A to the STACK
2C2CDEC HL 2BDecrement the value of the current BASIC program pointer in HL so we can see if we are at the end
2C2DWe need the next character in the BASIC program so call the EXAMINE NEXT SYMBOL routine at RST 10H.
The RST 10H routine parses the characters starting at HL+1 for the first non-SPACE,non-09H,non-0BH character it finds. On exit, Register A will hold that character, and the C FLAG is set if its alphabetic, and NC FLAG if its alphanumeric. All strings must have a 00H at the end.
2C2E-2C2FLD A,00H 3E 00Zero Register A to allow for any filename
2C30-2C31Jump if the character at the location of the current BASIC program pointer in HL is an end of the BASIC statement character
2C32-2C34CALL 2337H CALL FRMEVLCD 37 23To get the filename we need to GOSUB to 2337H to evaluate the expression at the location of the current BASIC program pointer in HL and return with the result in ACCumulator
2C35-2C37CALL 2A13H CALL ASC2CD 13 2AMake sure the length is good, and save the pointer to the filename to Register Pair DE
2C38LD A,(DE) 1ALoad Register A with the first character of the filename at the location of the filename pointer in DE
2C3APOP AF F1Get the value of the CLOAD / CLOAD? flag from the STACK and put it in Register A
2C3BOR A B7Test the value of the CLOAD / CLOAD? flag in Register A (since CPL doesn’t set any flags)
2C3CLD H,A 67Load Register H with the value of the CLOAD / CLOAD? flag in Register A
2C3D-2C3FLD (4121H),HL LD (FACLO),HL 22 21 41Save the value of the CLOAD / CLOAD? flag and the filename in HL in ACCumulator
2C43-2C45LD HL,(4121H) LD HL,(FACLO) 2A 21 41Load HL with the CLOAD / CLOAD? flag and the filename in ACCumulator
*2C1F-2CA4 – LEVEL II BASIC CLOAD ROUTINE – ROM v1.3
*2C1FSUB 0B2HTest for CLOAD?
*2C23XOR ASo we know that we have a CLOAD and not a CLOAD?, so clear Register A and continue
*2C2401Z-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
CPLSince A is Zero going into this command, once this complement code is exected, A=-1 if CLOAD?, 0000 if CLOAD
*2C26INC HLIncrement HL to the filname of the CLOAD / CLOAD? flag
*2C27PUSH AFSave the CLOAD / CLOAD? flag in Register A to the STACK
*2C28LD A,(HL)Set the next element from the code string, which should be the filename
*2C29OR ASet status flags
*2C32LD A,(DE)Get the filename
*2C33LD L,AMove the filename into Register L
*2C34POP AFRestore the CLOAD / CLOAD? flag
*2C35OR ASet the status Register according to that flag
*2C36LD H,AH will now hold CLOAD / CLOAD? flag, and L will hold the filename
*2C37LD (4121H),HL LD (FACLO),HLPut the flag and filename into ACCumulator
*2C3DLD HL,0000HCause the drive to be selected
*2C43LD HL,(4121H) LD HL,(FACLO)Restore the CLOAD / CLOAD? flag and filename
Common code between ROM v1.0 and v1.2 continues here.
2C46EX DE,HL EBLoad D with the CLOAD/CLOAD? flag and load Register E with the filename
CALL 0235H CALL CASINCD 35 02Calls 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-2C4DSUB 0D3H D6 D3Check to see if the character in Register A is a filename header byte
2C4E-2C4FLoop if the character in Register A isn’t a filename header byte
2C50-2C51Loop back to 2C49H until three filename header bytes have been read
2C52-2C54CALL 0235H CALL CASINCD 35 02Now 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)
2C55INC E 1CWe 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
2C56DEC E 1DDecrement the value of the filename in Register E
2C57-2C58Jump to 2C5CH (to pretend the filename matched) if no filename was specified
2C59CP E BBIf we are here, then the user has supplied a filename which is held in Register E AND we have the first byte from the tape in Register A, so we need to compare the filename specified in Register E with the character in Register A. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
2C5A-2C5BJump 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
LD HL,(40A4H) LD HL,(TXTTAB) 2A A4 40If 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.
LD B,03H 06 03Load Register B with the number of zeros to look for to stop the load (which is 3)
CALL 0235H CALL CASINCD 35 02Calls 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)
2C64LD E,A 5FPreserve the character that was just read from tape into Register E
2C65SUB (HL) 96Compare 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
2C66AND D A2Combine the subtracted result in Register A with the value of the CLOAD / CLOAD? flag in Register D. Why is this tricky? Because D is always 0 for a CLOAD, so when you AND against 0, you always get 0. If this was CLOAD?, nothing would happen as a result of this.
2C67-2C68Jump to 2C8AH if CLOAD? was selected but the bytes don’t match
2C69LD (HL),E 73At this point either CLOAD? was selected and the bytes match, or CLOAD was selected. Either way, save the character we read from the tape (held in Register E) to the location of the memory pointer in HL
2C6A-2C6CCALL 196CH
CALL REASONCD 6C 19Make sure there is more room, and toss a ?OM ERROR if there isn’t.
2C6DLD A,(HL) 7ELoad Register A with the character at the location of the memory pointer in HL
2C6EOR A B7Check to see if the byte just read in Register A is equal to zero
2C6FINC HL 23Bump the value of the memory pointer in HL
2C70-2C71Loop if the byte in Register A isn’t equal to zero (meaning that it isn’t end of program or end of statement)
2C72-2C74CALL 022CH CALL BCASINCD 2C 02Call the BLINK ASTERISK routine at 022CH which alternatively displays and clears an asterisk in the upper right hand corner of the video display
2C75-2C76Do that loop until three zeros in a row have been read from the cassette recorder
2C77-2C79LD (40F9H),HL LD (VARTAB),HL 22 F9 40By 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 OKCASSLD HL,1929H LD HL,REDDY 21 29 19Load HL with the starting address of the BASIC READY message
2C75-2C76Do that loop until three zeros in a row have been read from the cassette recorder
2C83-2C85LD HL,(40A4H) LD HL,(TXTTAB) 2A A4 40Load 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).
2C86PUSH HL E5Save the start of the BASIC program pointer in HL to the STACK. FINI will need this value there.
LD HL,2CA5H LD HL,NOOKCS 21 A5 2CLoad HL with the starting address of the BAD message
2C8D-2C8FCALL 28A7H CALL STROUTCD A7 28Call the WRITE MESSAGE routine at 28A7H to print the message pointed to by HL.
NOTE:
- The routine at 28A7 displays the message pointed to by HL on current system output device (usually video).
- The string to be displayed must be terminated by a byte of machine zeros or a carriage return code 0D.
- If terminated with a carriage return, control is returned to the caller after taking the DOS exit at 41D0H (JP 5B99H).
2C90-2C92JP 1A18 JP STPRDYC3 18 1AJUMP to STPRDY to pop NEWSTT from the STACK and then fall into the READY routine
LD B,03H 06 03Load Register B with the number of zeros to be found to stop the search
CALL 0235H CALL CASINCD 35 02Calls 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)
2C9BOR A B7Check to see if the character in Register A is equal to zero
2C9E-2C9FLoop until three zeros in a row have been read from the cassette recorder
2CA0-2CA2CALL 0296H CALL CSRDON + 3CD 96 02Calls 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)
2CA5-2CA9 – MESSAGE STORAGE LOCATION – “NOOKCS”
2CA5-2CA9 NOOKCS“BAD” + 0DH + 00H 42The BAD message is stored here
2CAA-2CB0 – LEVEL II BASIC PEEK ROUTINE – “PEEK”
The original ROM source code says that PEEK only accepts positive numbers up to 32767 and POKE will only take an address up to 32767. Negative numbers can be used to refer to locations higher than 32767, the correspondence is given by subtracting 65536 from locations higher than 32767 or by specifying a positive number up to 65535
On entry, ACCumulator to have the peek location, and on exit ACCumulator to have the peeked value.
2CAA-2CAC PEEKCALL 0A7FH CALL FRCINTCD 7F 0ACall 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)
2CADLD A,(HL) 7ELoad Register A with the value at the location of the memory pointer in HL
2CAE-2CB0JP 27F8H JP SNGFLTC3 F8 27Go save the 8-bit value in Register A as the current result in ACCumulator
2CB1-2CBC – LEVEL II BASIC POKE ROUTINE – “POKE”
2CB1-2CB3 POKECALL 2B02H CALL GETIN2CD 02 2BGo evaluate the expression at the location of the current BASIC program pointer in HL and return with the integer result in DE
2CB4PUSH DE D5Save the address the user wants to POKE to (held in DE) to the STACK
2CB5-2CB6Since the character at the location of the current BASIC program pointer in HL must be a , , call the COMPARE SYMBOL routine at RST 08H.
NOTE: The RST 08H routine compares the symbol in the input string pointed to by HL Register to the value in the location following the RST 08 call.- If there is a match, control is returned to the next execution address (i.e, the RST 08H instruction + 2) with the next symbol in the A Register and HL incremented by one.
- If the two characters do not match, a syntax error message is given and control returns to the Input Phase).
2CB7-2CB9CALL 2B1CH CALL GETBYTCD 1C 2BGOSUB 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
2CBAPOP DE D1Get the address the user wants to POKE to from the STACK and put it in DE
2CBBLD (DE),A 12Save the value the user wanted to poke (held in Register A) in the location that the user wants to POKE to (held in DE)
2CBCRET C9RETurn 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
Vernon Hester has reported an error in the PRINT USING routine. A PRINT USING statement with a negative sign at the end of the field prints a negative sign after negative numbers and prints a space for positive numbers. However, if the field specifiers in the string also has two asterisks at the beginning of the field, the ROM prints an asterisk instead of a space after a positive number.
Example: PRINT USING “**####-“;1234 will display **1234* instead of **1234 SPACE
CALL 2338H CALL FRMCHKCD 38 23Go evaluate the string expression at the location of the current BASIC program pointer in HL
2CC0-2CC2CALL 0AF4H CALL CHKSTRCD F4 0AGo make sure the expression that was just evaluated was a string
2CC3-2CC4Since 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).
2CC5EX DE,HL EBSwap DE and HL so that DE now holds the current BASIC program pointer
2CC6-2CC8LD HL,(4121H) LD HL,(FACLO) 2A 21 41Load HL with the USING string’s VARPTR
LD A,(40DEH) LD A,(FLGINP) 3A DE 40Load Register A with the value of the READ/INPUT flag, which is being used here to track if we printed out a value on the prior scan.
2CCEOR A B7Check to see if that flag indivates that we did, or did not, print out a value last time.
2CCF-2CD0If we did not print out a value last time, we have an error, so JUMP down to 2CDDH
2CD1POP DE D1Restore the pointer to the “USING” string decription from the STACK into DE
2CD2EX DE,HL EBSwap 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.
PUSH HL E5Save the pointer to the “USING” string descriptor (i.e., the USING string’s VARPTR) in HL to the STACK
2CD4XOR A AFZero Register A and all the flags.
2CD5-2CD7LD (40DEH),A LD (FLGINP),A 32 DE 40Clear the flag we are using to see if we printed the values or not.
2CD8CP D BATurn 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.
2CD9PUSH AF F5Save the flag indicating if the value list has ended or not to the STACK
2CDAPUSH DE D5Save the pointer into the value list to the STACK
2CDBLD B,(HL) 46Load Register B with the USING string’s length
2CDCOR B B0Check to see if the USING string’s length in Register B is equal to zero
2CE0INC HL 23Bump the pointer to the USING string’s data in HL by 1
2CE1LD C,(HL) 4ELoad Register C with the LSB of the USING string’s address at the location of the USING string’s VARPTR in HL
2CE2INC HL 23Bump the value of the USING string’s VARPTR in HL
2CE3LD H,(HL) 66Load Register H with the MSB of the USING string’s address at the location of the USING string’s VARPTR in HL
2CE4LD L,C 69Load Register L with the LSB of the USING string’s address in Register C
2CE8PUSH HL E5Save the pointer to the USING string pointer in HL to the top of the STACK
2CE9-2CEALD C,02H 0E 02Since the \\ string field length is two plus number of enclosed spaces, add two
LD A,(HL) 7ELoad Register A with the character at the location of the USING string pointer in HL
2CECINC HL 23Bump the value of the USING string data pointer in HL
2CED-2CEECP 25H CP CSTRNG FE 25Check to see if the character in Register A is a %, which acts as a field terminator. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
2CEF-2CF1JP Z,2E17H JP Z,ISSTRFCA 17 2EIf it is a “%” then JUMP to 2E17H to evaluate a string and print
2CF2-2CF3CP 20H FE 20Check to see if the character in Register A is a ” “, which acts as a field extender. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
2CF4-2CF5If the character is not a field extender, then it isn’t a string field, so JUMP down a few opcodes to 2CF9H
2CF6INC C 0CIncrement the field width (tracked in in Register C)
2CF7-2CF8Decrement 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 NOSTRFPOP HL E1Restore the pointer to the “USING” string’s data into Register Pair HL
2CFALD B,E 43Load Register B with the USING string’s length
2CFB-2CFCLD A,25H LD A,CSTRNG 3E 25Restore 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
CALL 2E49H CALL PLSPRTCD 49 2EIf a + came before the character, make sure to print it
2D00-2D02CALL 032AH CALL OUTDOCD 2A 03Once that has been printed, now we print the character in Register A since we know it isn’t part of a field
XOR A AFWe 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
2D04LD E,A 5FZero Register E
2D05LD D,A 57Zero Register D
CALL 2E49H CALL PLSPRTCD 49 2EGo print a leading + if necessary (i.e., to allow for multiple plusses)
2D09LD D,A 57Set 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.
2D0ALD A,(HL) 7ELoad Register A with the next field description character in the USING string
2D0BINC HL 23Bump the value of the USING string pointer in HL
2D0C-2D0DCP 21H CP “!” FE 21Check 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.
2D11-2D12CP 23H CP “#” FE 23Check 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.
2D15DEC B 05Since every other possibility is actually a two character field, decrement the value of the string’s length in Register B onem ore time
2D16-2D18JP Z,2DFEH JP Z,REUSINCA FE 2DIf 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-2D1ACP 2BH CP “+” FE 2BCheck 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-2D1CLD A,08H 3E 08Set 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
2D1FDEC HL 2BDecrement the value of the USING string pointer so we can re-get the character.
2D20LD A,(HL) 7ELoad Register A with the (current) character at the location of the USING string pointer in HL
2D21INC HL 23Bump the value of the USING string pointer in HL
2D22-2D23CP 2EH CP “.” FE 2ECheck to see if the character in Register A is a . (i.e., a numeric field with trailing digits). If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
2D24-2D25Jump if the character in Register A is a . to scan with Register E holding the number of digits before the “.” as 0
2D26-2D27CP 25H CP CSTRNG FE 25Check to see if the character in Register A is a % (i.e., a really big string field). If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
2D28-2D29Jump to see if it is really a string field if the character in Register A is a %
2D2ACP (HL) BECheck to see if the next character matches the current character in the the USING string. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
2D2B-2D2CIf the NZ flag is set, then we can’t have a $$ or a ** , so all remaining possibilities are exhausted, so JUMP to NEWUCH
2D2D-2D2ECP 24H CP “$” FE 24Check 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.
2D31-2D32CP 2AH CP “*” FE 2ACheck to see if the double character is a ** . If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
2D33-2D34If 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
2D35LD A,B 78Prepare 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-2D37CP 02H FE 02Check 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.
2D38INC HL 23Bump the value of the USING string pointer in HL
2D39-2D3AJump to 2D3EH if the USING string’s length in Register A isn’t at least two
2D3BLD A,(HL) 7ELoad Register A with the character at the location of the USING string pointer in HL
2D3C-2D3DCP 24H CP “$” FE 24Check 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.
2D40-2D41If we did not ultimately get a **$ then JUMP (noting we do NOT set the dollar sign flag)
2D42DEC B 05Decrement the value of the USING string’s length to take the $ into account
2D43INC E 1CBump the field width tracker to account for the floating dollar sign
2D44-2D45CP 0AFH FE AFZ-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.
2D46-2D47ADD A,10H C6 10Mask Register A to set the bit for a floating dollar sign flag.
2D48INC HL 23Bump the value of the USING string pointer in HL to go past the special characters
2D4AADD A,D 82Combine the bits in Register D into the flag tracker
2D4BLD D,A 57Preserve the modified flag tracker into Register D.
2D4D-2D4ELD C,00H 0E 00Set the number of digits to the right of the decimal point (tracked in Register C) to 0
2D4FDEC B 05Check to see if there are any more characters by decrementing the value of the string’s length in Register B
2D50-2D51If 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.
2D52LD A,(HL) 7ELoad Register A with the next character at the location of the USING string pointer in HL
2D53INC HL 23Bump the value of the USING string pointer in HL
2D54-2D55CP 2EH CP “.” FE 2ECheck to see if the character in Register A is a . (i.e., a trailing digit). If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
2D56-2D57If yes, then need to use a special scan loop to scan after the decimal point, so JUMP to AFTDOT
2D58-2D59CP 23H CP “#” FE 23Check to see if the character in Register A is a # (i.e., a leading digit). If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
2D5A-2DIf yes, increment the count and keep scanning via a JUMP to NUMNUM
2D5C-2D5DCP 2CH CP “,” FE 2CCheck to see if the character in Register A is a , . If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
2D5E-2D5FIf there is no comma, then JUMP to FINNUM because there are no more leading digits and we need to check for “^^^”
2D60LD A,D 7AIf we are here, then a comma was requested. Turn on the COMMA bit
2D61-2D62OR 40H F6 40Mask the flag in Register A for ,
2D63LD D,A 57Load Register D with the value of the flag in Register A
2D66 – Part of the PRINT USING Routine – “DOTNUM”
Jumped here when a “.” is seen in the USING string. THis means that we are starting a numeric field ONLY if it is followed by a “#”
2D66 DOTNUMLD A,(HL) 7ELoad Register A with the next character of the USING string
2D67-2D68CP 23H FE 23Check to see if the character in Register A is a # (i.e., a numeric field following a “.”). If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
2D69-2D6ALD A,2EH LD A,”.” 3E 2ELoad Register A with a decimal point
2D6B-2D6CIf it isn’t a “.” then JUMP AWAY to NEWUCH with A holding a “.” so that a “.” will get printed
2D6D-2D6ELD C,01H 0E 01If it was a “.” then we have a numeric field to process. First, set C with the number of characters to the right of the decimal point
2D6FINC HL 23Bump the value of the USING string pointer in HL
INC C 0CBump the number of digits to the right of the decimal point (tracked in Register C)
2D71DEC B 05Decrement the value of the USING STRING’s length to test to see if there are more characters
2D72-2D73If the USING string length is now ZERO, JUMP to ENDNUS to stop scanning
2D74LD A,(HL) 7ELoad Register A with the character at the location of the USING string pointer in HL
2D75INC HL 23Bump the value of the USING string pointer in HL
2D76-2D77CP 23H FE 23Check to see if the character in Register A is a # ; meaning that there are more digits after the decimal point. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
2D78-2D79If 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
PUSH DE D5Save the value of the flag (tracked in D) and the number of leading digits (tracked in E) to the STACK
2D7B-2D7DLD DE,2D97H LD DE,NOTSCI 11 97 2DLoad DE with the return address in case this is not a scientific notation
2D7EPUSH DE D5Save the value of the return address in DE to the STACK
2D7F
2D80LD D,H
LD E,L 54Let DE = HL in case we need to rememer HL
2D81-2D82CP 5BH FE 5BCheck 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.
2D83RET NZ C0Return if the character in Register A isn’t an up arrow
CP (HL) BECheck 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.
2D85RET NZ C0Return 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)
2D87CP (HL) BECheck 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.
2D88RET NZ C0Return 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)
2D8ACP (HL) BECheck 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.
2D8BRET NZ C0Return 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)
INC HL 23Bump the value of the USING string pointer in HL. If we are here we have a #.^^^^ format
2D8DLD A,B 78Now 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-2D8FSUB 04H D6 04Check to see if there are at least 4 characters left in the USING string
2D90RET C D8Return to 2D97 if there aren’t at least four characters left in the USING string
POP DE D1If there are at least 4 characters left, then clean up the STACK by removing the NOTSCI return address
2D92POP DE D1Get the flag and the count of the characters to the left of the decimal point from the STACK and put it in DE
2D93LD B,A 47Load Register B with the new USING string’s length in Register A
2D94INC D 14Set the exponential notation flag (tracked in Register D)
2D95INC HL 23Bump the value of the USING string pointer in HL
2D96JP Z,0D1EBH CA EB D1Z-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,HL EB(Ignored if passing through) Restore the old HL into HL
2D98POP DE D1(Ignored if passing through) Restore the flags into Register D and the number of leading digits into Register E
LD A,D 7AWe 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
2D9ADEC HL 2BDecrement the value of the USING string pointer in HL
2D9BINC E 1CBump the number of characters to the left of the decimal point in Register E to take into account the leading plus
2D9C-2D9DAND 08H E6 08Mask Register A to NOT check for a trailing sign
2D9E-2D9FIf that AND leaves us with a NZ, then we are all done with the field, so JUMP to ENDNUM
2DA0DEC E 1DOtherwise, 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
2DA1LD A,B 78Check to see if there are more characters by first loading Register A with the USING string’s length from Register B
2DA2OR A B7Check to see if this is the end of the USING string
2DA3-2DA4If we are out of characters, then we are all done, so JUMP to ENDNUM
2DA5LD A,(HL) 7EIf there ARE more characters, then fill Register A with the character at the location of the USING string pointer in HL
2DA6-2DA7SUB 2DH SUB “-“ D6 2DCheck to see if the character in Register A is a – (i.e., a trailing minus)
2DAA-2DABCP 0FEH CP “+” – “-“ FE FECheck 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.
2DAE-2DAFLD A,08H 3E 08If we are here then we did have a trailing “+” so first set the flag for a POSITIVE “+”
2DB2ADD A,D 82Combine the value of the flag in Register D with the value of the flag in Register A
2DB3LD D,A 57Load Register D with the current flags
2DB4DEC B 05Decrement the value of the USING string’s length in Register B by 1 to account for the trailing sign
2DB5 – Part of the PRINT USING Routine – “ENDNUM”
Jump point for when we figure out that we are at the end of a string of digits within a USING string
2DB5 ENDNUMPOP HL E1Get the value of the current BASIC program pointer from the STACK and put it in HL
2DB6POP AF F1Load Register A with the flag that tells us whether there are more values to process in the value list.
2DB7-2DB8If there are no more values in the value list to process, then JUMP to FLDFIN because we are done with the PRINT
2DB9PUSH BC C5Save 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
2DBAPUSH DE D5Save the flags (held in D) and the number of leading digits (held in E) to the STACK
2DBB-2DBDCALL 2337H CALL FRMEVLCD 37 23Read 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
2DBEPOP DE D1Restore the flags (held in D) and the number of leading digits (held in E) from the STACK
2DBFPOP BC C1Restore 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
2DC0PUSH BC C5Save 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
2DC1PUSH HL E5Save the value of the current BASIC program pointer in HL to the STACK
2DC2LD B,E 43Set Register B to hold the number of leading digits (i.e., the number of characters to the left of the decimal point)
2DC3LD A,B 78We 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
2DC4ADD A,C 81Then 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-2DC6CP 19H FE 19Check to see if the total number of characters in Register A is greater than 24. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
2DC7-2DC9JP NC,1E4AH JP NC,FCERRD2 4A 1EDisplay a FC ERROR message if the total number of digits is greater than 24
2DCALD A,D 7ALoad Register A with the flags (held in Register D)
2DCB-2DCCOR 80H F6 80Turn on the “USING” bit in the flags
2DCD-2DCFCALL 0FBEH CALL PUFOUTCD BE 0FPrepare to print by calling the FLOATING TO ASCII routine at 0FBEH (whcih converts a single or double precision number in ACCumulator to its ASCII equivalent which will be stored at the buffer pointed to by HL using the format codes in the A, B, and C registers
2DD0-2DD2CALL 28A7H CALL STROUTCD A7 28Call the WRITE MESSAGE routine at 28A7H to print the message pointed to by HL.
NOTE:
- The routine at 28A7 displays the message pointed to by HL on current system output device (usually video).
- The string to be displayed must be terminated by a byte of machine zeros or a carriage return code 0D.
- If terminated with a carriage return, control is returned to the caller after taking the DOS exit at 41D0H (JP 5B99H).
POP HL E1Top of a loop. Get the value of the current BASIC program pointer from the STACK and put it in HL
2DD4DEC HL 2BDecrement the value of the current BASIC program pointer in HL so we can test to see what the terminator was
2DD5We 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.
2DD6SCF 37Set the Carry flag to indicate that a CRLF is desired
2DD7-2DD8If 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-2DDBLD (40DEH),A LD (FLGINP),A 32 DE 40Set the flag that the value HAS been printed!
2DDC-2DDDCP 3BH CP “;” FE 3BCheck 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.
2DE0-2DE1CP 2CH CP “,” FE 2CCheck to see if the character at the location of the current BASIC program pointer in Register A is a comma. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
2DE2-2DE4JP NZ,1997H JP NZ,SNERRC2 97 19If 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.
POP BC C1Restore the number of characters remaining to be procesed in the USING string into Register B
2DE7EX DE,HL EBSwap DE and HL so that DE will point to the location of the current BASIC program pointer. We don’t care about HL.
2DE8POP HL E1Restore the position in the USING string from the STACK and put it in HL
2DE9PUSH HL E5Save the position in the USING string (held in HL) to the STACK
2DEAPUSH AF F5Save the flag that indicates whether or not the value list has terminated to the STACK
2DEBPUSH DE D5Save 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.
2DECLD A,(HL) 7ELoad Register A with the USING string’s length at the location of the USING string’s VARPTR in HL
2DEDSUB B 90Subtract the number of characers which were already scanned
2DEEINC HL 23Bump the pointer to the “USING” strings string data
2DEFLD C,(HL) 4ELoad Register C with the LSB of the USING string’s address at the location of the USING string’s VARPTR in HL
2DF0INC HL 23Bump the value of the USING string’s VARPTR in HL
2DF1LD H,(HL) 66Load Register H with the MSB of the USING string’s address at the location of the USING string’s VARPTR in HL
2DF2LD L,C 69Load Register L with the LSB of the USING string’s address in Register C
2DF3-2DF4LD D,00H 16 00Zero Register D so that Register Pair DE can be a 16 bit offset of whatever is held in A.
2DF5LD E,A 5FLoad Register E with the USING string’s offset in Register A
2DF6ADD HL,DE 19Add 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
2DF7LD A,B 78Load Register A with the number of characters left to scan
2DF8OR A B7Check to see if this is the end of the USING string
2DF9-2DFBJP NZ,2D03H JP NZ,PRCCHRC2 03 2DIf there are still more string characters to scan, JUMP to PRCCHR to do so
2DFE-2E00 – Part of the PRINT USING Routine – “REUSIN”
We will wind up here when we are done processing a numeric field
2E01-2E03CALL 032AH CALL OUTDOCD 2A 03Go send the FINAL character (held in Register A) to the current output device
POP HL E1Get the value of the current BASIC program pointer from the STACK and put it in HL
2E05POP AF F1Restore the flag which indicates whether or not the value list has ended into Register A
2E06-2E08JP NZ,2CCBH JP NZ,REUSSTC2 CB 2CIf the value list has NOT ended, JUMP back to REUSST to reuse the USING string
CALL C,20FEH CALL C,CRDODC FE 20If 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
2E0CEX (SP),HL E3Swap (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
2E10POP HL E1Get the value of the current BASIC program pointer from the STACK and put it in HL
2E14-2E15 – Part of the PRINT USING Routine – “SMSTRF”
We will wind up here when the “!” indicating a single character string field has been scanned
2E16-2E17LD A,0F1H 3E F1Z-80 Trick. By putting a 3E in front of the F1 (which is POP AF , to clear the STACK) that POP AF gets skipped if flowing down in the code
POP AF F1(Skipped if passing down) Clear the STACK *dumping the HL that was being saved in case it turned out that this wasn’t actually a string)
2E18DEC B 05Decrement the USING string character count (tracked in Register B)
2E1CPOP HL E1Get the value of the current BASIC program pointer from the STACK and put it in HL
2E1DPOP AF F1Get the flag which indicates whether there are more values in the value list into Register A
2E1E-2E1FIf there are no more values in the value list, then we are done so JUMP back to 2E09H
2E20PUSH BC C5Save the number of characters still to be scanned from the USING string (tracked in B) to the STACK
2E21-2E23CALL 2337H CALL FRMEVLCD 37 23Read 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
2E27POP BC C1Restore the field width (a/k/a the number of characters to be printed) into Register C
2E28PUSH BC C5Save the USING string’s length and the number of characters to be printed in BC to the STACK
2E29PUSH HL E5Save the value of the current BASIC program pointer in HL to the STACK
2E2A-2E2CLD HL,(4121H) LD HL,(FACLO) 2A 21 41Load HL with the string’s VARPTR in ACCumulator
2E2DLD B,C 41Load Register B with field width (a/k/a the number of characters to be printed)
2E2E-2E2FLD C,00H 0E 00Zero Register C so that we can use the LEFT$ routine
2E30PUSH BC C5Save the length of the string to be printed in Register B to the STACK (as we will need that for space padding)
2E31-2E33CALL 2A68H CALL LEFTUSCD 68 2ATruncate the string to B characters via a call to the LEFT$ routine
2E37-2E39LD HL,(4121H) LD HL,(FACLO) 2A 21 41Load HL with the string’s VARPTR in ACCumulator so we can see if we need to pad the string
2E3APOP AF F1Get the field width (a/k/a the length of the string to be printed) from the STACK and put it in Register A
2E3BSUB (HL) 96Determine 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
2E3CLD B,A 47Save the amount of padding needed into Register B
2E3D-2E3ELD A,20H 3E 20Load Register A with a SPACE
2E3FINC B 04Bump 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.
2E41-2E43JP Z,2DD3H JP Z,FNSTRFCA D3 2DIf all of the spaces have been printed, Jump back to 2DD3H to see if the value list ended and to resume scanning
2E49 – Part of the PRINT USING Routine – “PLSPRT”
When a “+” is detected in the “USING” string and a numeric field follows, a bit in Register D should be set, otherwise + should be printed. Since deciding whether a numeric field follows is very difficult, the bit is always set in Register D. At the point it is decided a character is not part of a numeric field, this routine is called to see if the bit in Register D is set, which means a plus preceded the character and should be printed
2E49 PLSPRTPUSH AF F5Save the current character (held in Register A) to the STACK
2E4ALD A,D 7AWe need to test the PLUS BIT in D, so first load Register A with the value in Register D
2E4BOR A B7Check 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-2E4DLD A,2BH LD A,”+” 3E 2BPrepare to print the + by loading Register A with a +
2E4E-2E50CALL NZ,032AH CALL NZ,OUTDOC4 2A 03If the bit was set (i.e., A was non-zero), then send a + to the current output device
2E51POP AF F1Get the current character from the STACK and put it in Register A
2E52RET C9RETurn 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
LD (409AH),A LD (ERRFLG),A 32 9A 40Reset the EDIT flag.
Note: 409AH holds the ERROR/RESUME flag
2E56-2E58LD HL,(40EAH) LD HL,(ERRLIN) 2A EA 40Load HL with the line number to be edited.
Note: 40EAH-40EBH holds the line number with error
2E59OR H B4OR Register A with the MSB of the error line number in Register H
2E5AAND L A5Combine 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
2E5BINC A 3CBump 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
2E5CEX DE,HL EBSwap DE and HL so that DE now holds the line number to edit.
2E5DRET Z C8If 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
2E60-2E62 EDITCALL 1E4FH CALL LINSPCCD 4F 1EGet the first line number by calling 1E4F – returns in in DE
2E63RET NZ C0If the zero flag got set, there was no line number, so return
2E66-2E68LD (40ECH),HL LD (DOT),HL 22 EC 40Save 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
2E69EX DE,HL EBLoad HL with the line number to be edited
2E6A-2E6CCALL 1B2CH CALL FNDLINCD 2C 1BFind 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
2E70
2E71LD H,B
LD L,C 60At this point, the line number has been found. Let HL=BC so that HL also points to the location in RAM of the line number being edited
2E72
2E73INC HL
INC HL 23Bump the value of the memory pointer in HL twice to now point to the first byte of the line.
2E74LD C,(HL) 4ELoad Register C with first byte of the line number being edited
2E75INC HL 23Bump the value of the memory pointer in HL to point to the second byte of the line being edited
2E76LD B,(HL) 46Load Register B with second byte of the line number being edited
2E77INC HL 23Bump the value of the memory pointer in HL to now point to the first byte of the actual line
2E78PUSH BC C5Save the line number to the STACK
2E79-2E7BCALL 2B7EH CALL BUFLINCD 7E 2BGOSUB to 2B7EH move the BASIC line at the location of the memory pointer in HL into a memory buffer and untokenize the BASIC line
2E7D INLEDPUSH HL E5Save the value of the line number in HL to the STACK
2E7E-2E80CALL 0FAFH CALL LINPRTCD AF 0FConvert the line number to ASCII and print it out by calling the HL TO ASCII routine at 0FAFH (which converts the value in the HL (assumed to be an integer) to ASCII and display it at the current cursor position on the video screen)
2E81-2E82LD A,20H 3E 20Load Register A with a space
2E86-2E88LD HL,(40A7H) LD HL,(BUFPNT) 2A A7 40Load HL with the starting address of the expanded version of the current line from the input buffer.
Note: 40A7H-40A8H holds the input Buffer pointer
2E89-2E8ALD A,0EH 3E 0ELoad Register A with the “turn on the cursor” character
2E8EPUSH HL E5Save the value of the input buffer pointer (in HL) to the STACK
2E8F-2E90LD C,FFH 0E FFLoad Register C with the number of characters examined so far with FFH because the next line is going to INC it by 1 to make it 0
2E92LD A,(HL) 7ELoad Register A with the character at the location of the input buffer pointer in HL
2E93OR A B7Check to see if the character in Register A is an end of the BASIC line character
2E94INC HL 23Bump the value of the input buffer pointer in HL
2E95-2E96Loop back to 2E91H until the end of the BASIC line has been found
2E97POP HL E1At this point, C will be the maximum number of characters in the line at issue. Put the start of the expanded buffer into HL
2E98LD B,A 47Set the current position in the BASIC line being edited (tracked by Register B) to ZERO
2E99-2E9A DISPEDLD D,00H 16 00Assume the repetition count for the upcoming command (tracked by Register D) is zero
2D9E-2E9F DISPSUB 30H 20 15We need to test to see if the character was alphabetic or alphanumeric so we subtract 30H from it
2EA2-2EA3CP 0AH FE 0ACheck 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.
2EA6LD E,A 5FLoad Register E with the binary value of the character in Register A
2EA7LD A,D 7APut the repetition value into Register A
2EA8RLCA 07Multiply the value in Register A by two (so now A has multiplied by 2)
2EA9RLCA 07Multiply the value in Register A by two (so now A has multiplied by 4)
2EAAADD A,D 82Add the value in Register D to the value in Register A (so now A has multiplied by 5)
2EABRLCA 07Multiply the value in Register A by two (so now A has multiplied by 10). Now the “ones place” is empty.
2EACADD A,E 83Add the value in Register E to the value in Register A in the “ones place”
2EADLD D,A 57Load Register D with the value in Register A
2EB0H – LEVEL II BASIC EDIT ROUTINE – “NOTDGI”
While getting user command input within an edit, we wind up here if the user enters a non-numeric character (i.e., the actual command, and not just the repetition number which precedes it)
2EB0 NOTDGIPUSH HL E5Save the value of the input buffer pointer in HL to the STACK
2EB1-2EB3LD HL,2E99H LD HL,DISPED 21 99 2ELoad HL with the return address of 2E99H
2EB4EX (SP),HL E3Exchange the value of the return address in HL with the value of the input buffer pointer to the STACK
2EB5DEC D 15We 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
2EB6INC D 14… and then incrementing the numeric value in Register D to set the flags
2EB7-2EB9JP NZ,2EBBH JP NZ,NTZERDC2 BB 2EIf we had a received a repetition count already, then JUMP to 2EBBH
2EBAINC D 14Otherwise, set the repetition count (held in Register D) to be one
CP 0D8H FE D8Check to see if the character in Register A is a BACKSPACE character. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
2EBD-2EBFJP Z,2FD2H JP Z,DELEDCA D2 2FIf the character in Register A is a BACKSPACE character, JUMP to DELED
2EC0-2EC1CP 0DDH FE DDCheck to see if the character in Register A is a CARRIAGE RETURN . If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
2EC2-2EC4JP Z,2FE0H JP Z,CREDCA E0 2FIf the character in Register A is a CARRIAGE RETURN , JUMP to CRED
2EC5-2EC6CP 0F0H FE F0Check 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.
That’s it for non-alphabetic instructions, so we need to need to convert a lower case command to upper case
2EC9-2ECACP 31H FE 31Check 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.
2ECD-2ECESUB 20H D6 20Convert the lowercase character in Register A to uppercase
CP 21H FE 21Check 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.
2ED4-2ED5CP 1CH FE 1CCheck 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.
2ED9-2EDACP 23H FE 23Check 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.
2EDD-2EDECP 19H FE 19Check 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.
2EE2-2EE3CP 14H FE 14Check 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.
2EE7-2EE8CP 13H FE 13Check 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.
2EEC-2EEDCP 15H FE 15Check 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.
2EF1-2EF2CP 28H FE 28Check 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.
2EF6-2EF7CP 1BH FE 1BCheck 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.
2EFA-2EFBCP 18H FE 18Check to see if the character in Register A is an H . If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
2EFC-2EFEJP Z,2F75H JP Z,HEDCA 75 2FJump if the character in Register A is an H (i.e., HACK off the rest of the line and then enter INSERT mode)
2EFF-2F00CP 11H FE 11Check 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.
2F01RET NZ C0Return if the character in Register A isn’t an A
2F02 – EDIT Command – Cancel and Restore Logic.
2F02POP BC C1Clean up the STACK (i.e., remove the DISPI return address)
2F03POP DE D1Get 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 SPEDLD A,(HL) 7ELoad Register A with the character at the location of the input buffer pointer in HL
2F0BOR A B7Check to see if the character in Register A is an end of the BASIC line character
2F0CRET Z C8Return if the character in Register A is an end of the BASIC line character
2F0DINC B 04Bump the character position in Register B
2F11INC HL 23Bump the value of the pointer in HL
2F12DEC D 15Decrement the number of times to perform the operation in Register D
2F15RET C9RETurn to CALLer
2F16 – EDIT Command – KILL Logic – “KED” .
2F17-2F19LD HL,2F5FH LD HL,TYPSLH 21 5F 2FLoad HL with the return address of 2F5FH (which will print the final !
2F1AEX (SP),HL E3Exchange the value of the return address in HL with the value of the input buffer pointer to the STACK
2F1BSCF 37Set the KILL/SEARCH flag for KILL since CARRY flag signals KILL
2F1D-2F1FCALL 0384H CALL INCHRCD 84 03Go scan the keyboard for the character the user wants to SEARCH for
2F20LD E,A 5FSave the character the user wants to SEARCH for into Register E
2F21POP AF F1Get the KILL/SEARCH flag from the STACK
2F22PUSH AF F5Save the KILL/SEARCH flag to the STACK
2F23-2F25CALL C,2F5FH CALL C,TYPSLHDC 5F 2FIf KILL (because the CARRY flag was set) then GOSUB to 2F5FH to print a !
LD A,(HL) 7ELoad Register A with the character at the location of the input buffer pointer in HL
2F27OR A B7Check to see if the character in Register A is an end of the BASIC line character
2F28-2F2AJP Z,2F3EH JP Z,POPARTCA 3E 2FJump down to 2F3EH if the character in Register A is an end of the BASIC line character
2F2EPOP AF F1Get the KILL/SEARCH flag from the STACK
2F2FPUSH AF F5Save the KILL/SEARCH flag to the STACK
2F30-2F32CALL C,2FA1H CALL C,DELCHRDC A1 2FIf the CARRY flag is set, that means we are in KILL mode so GOSUB to 2FA1H to delete the character from the input buffer
2F33-2F34Jump to 2F37H if KILL. Note, we do not move the HL pointer in this case because DELCHR already moved it.
2F35INC HL 23If we are here, it must be SEARCH! So bump to the next character
2F36INC B 04Bump the value of the character position in Register B
LD A,(HL) 7ERegardless of whether we are SEARCH or KILL, load Register A with the character at the location of the current input buffer pointer in HL
2F38CP E BBCheck 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.
2F3BDEC D 15Decrement the number of times to perform the operation in Register D (as initially specified by the user by entering a number before the command)
2F3FRET C9RETurn to CALLer
2F40 – EDIT Command – LIST Logic – “LED” .
CALL 2B75H CALL LISPRTCD 75 2BSince 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
2F46POP BC C1Clear off the RETURN address to DISPED
2F47-2F49JP 2E7CH JP LLEDC3 7C 2EJump to 2E7CH (to display the current line number and await the next EDIT command)
2F4A – EDIT Command – DELETE Logic – “DED”
LD A,(HL) 7ELoad Register A with the character at the location of the input buffer pointer in HL
2F4BOR A B7Check to see if the character in Register A is an end of the BASIC line character
2F5CRET Z 15Return if the character in Register A is an end of the BASIC line character
LD A,(HL) 7ELoad Register A with the character at the location of the input buffer pointer in HL
2F53OR A B7Check to see if the character in Register A is an end of the BASIC line character
2F54-2F5BJump to 2F5FH if the character in Register A is an end of the BASIC line character
2F5CDEC D 15Decrement the number of times to perform the operation in Register D (as initially specified by the user by entering a number before the command)
2F64RET C9RETurn to CALLer
2F65 – EDIT Command – CHANGE Logic – “CED” .
2F65 CEDLD A,(HL) 7ELoad Register A with the character at the location of the input buffer pointer in HL
2F66OR A B7Check to see if the character in Register A is an end of the BASIC line character
2F67RET Z C8Return if the character in Register A is an end of the BASIC line character
CALL 0384H CALL INCHRCD 84 03Go get the character to put in the input buffer from the keyboard
2F6BLD (HL),A 77Save the character in Register A at the memory location of the input buffer pointer in HL
2F6FINC HL 23Bump the value of the input buffer pointer in HL
2F70INC B 04Bump the character position in Register B
2F71DEC D 15Decrement the number of times to perform the operation in Register D (as initially specified by the user by entering a number before the command)
2F74RET C9RETurn to CALLer
2F75 – EDIT Command – HACK/INSERT Logic – “HED”
2F75-2F76 HEDLD (HL),00H 36 00Set the line end to be the current position.
2F77LD C,B 48Load Register C with the character position in Register B which will now be the line length
LD D,0FFH 16 FFPrepare for the next CALL to find the end of the line by loading Register D with the number of times to perform the operation
2F80OR A B7Check to see if a key was pressed
2F84-2F85CP 08H FE 08Check to see if the character in Register A is a backspace character . If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
2F86-2F87Jump to 2F92H if the character in Register A is a backspace character
2F88-2F89CP 0DH FE 0DCheck to see if the character in Register A is a carriage return . If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
2F8A-2F8CJP Z,2FE0H JP Z,CREDCA E0 2FJump to 2FE0H if the character in Register A is a carriage return
2F8D-2F8ECP 1BH FE 1BCheck 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.
2F8FRET Z C8Return if the character in Register A is shift up arrow
2F92 – EDIT Command – BACKSPACE CURSOR Logic – “TYPARW” .
2F94 TYPAR1DEC B 05Decrement the character position in Register B
2F95INC B 04Bump the character position in Register B
2F96-2F97If this is the first character of the BASIC line Jump forward to 2FB7H
2F9BDEC HL 2BDecrement the value of the input buffer pointer in HL
2F9CDEC B 05Decrement the character position in Register B
2F9D-2F9FLD DE,2F7DH LD DE,IED 11 7D 2FLoad DE with a return address of 2F7DH
2FA0PUSH DE D5Save the value of the return address in DE to the STACK
2FA1 – LEVEL II BASIC EDIT ROUTINE – “DELCHR”
This subroutine will delete the character pointed to by Register Pair HL and will correct Register C
2FA1 DELCHRPUSH HL E5Save the value of the input buffer pointer in HL to the STACK
2FA2DEC C 0DDecrement the character position in Register C
LD A,(HL) 7ELoad Register A with the character at the location of the input buffer pointer in HL
2FA4OR A B7Check to see if the character in Register A is an end of the BASIC line character
2FA5SCF 37Set the Carry flag to signal that DELCHR was called
2FA6-2FA8JP Z,0890H JP Z,POPHRTCA 90 08If the character in Register A is an end of the BASIC line character then we are done compressing so Jump to 0890H
2FA9INC HL 23Bump the value of the input buffer pointer in HL
2FAALD A,(HL) 7ELoad Register A with the character at the location of the input buffer pointer in HL
2FABDEC HL 2BDecrement the value of the input buffer pointer in HL
2FACLD (HL),A 77Save the character in Register A at the location of the current input buffer pointer in HL
2FADINC HL 23Bump the value of the input buffer pointer in HL
2FB0 – EDIT Command – ADD A CHARACTER Logic – “NTARRW” .
2FB1LD A,C 79Load Register A with the number of characters in the input buffer (i.e., the length of the line) in Register C
2FB2-2FB3CP FFH CP BUFLEN FE FFWe 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.
Jump forward to 2FB9H if the maximum BASIC line length hasn’t been reached
2FB6POP AF F1Get the character to be inserted from the STACK and put it in Register A
SUB B 90Subtract 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
2FBAINC C 0CBump the number of characters in the input buffer in Register C
2FBBINC B 04Bump the character position in Register B
2FBCPUSH BC C5Save the character position and the number of characters in the input buffer in BC to the STACK
2FBDEX DE,HL EBLoad DE with the input buffer pointer in HL
2FBELD L,A 6FLoad Register L with the number of bytes to move
2FBF-2FC0LD H,00H 26 00Zero Register H so that the number of bytes to move can be done in a 16 bit Register Pair.
2FC1ADD HL,DE 19Add the value of the input buffer pointer in DE to the character count in HL
2FC2LD B,H 44Load Register B with the MSB of the end of the BASIC line pointer in Register H
2FC3LD C,L 4DLoad Register C with the LSB of the end of the BASIC line pointer in Register L
2FC4INC HL 23Bump the value of the end of the BASIC line pointer in HL
2FC8POP BC C1Get the character position and the number of characters in the input buffer from the STACK and put it in BC
2FC9POP AF F1Get the character to be inserted from the STACK and put it in Register A
2FCALD (HL),A 77Save the character in Register A at the location of the current input buffer pointer in HL
2FCEINC HL 23Bump the value of the input buffer pointer in HL
2FD2 – EDIT Command – BACKSPACE Logic – “DELED” .
LD A,B 78Top 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
2FD3OR A B7Check to see if this is the start of the BASIC line
2FD4RET Z C8Return if this is the start of the BASIC line
2FD6DEC HL 2BDecrement the value of the buffer pointer in HL
2FD7-2FD8LD A,08H 3E 08Load Register A with a backspace the cursor character
2FDCDEC D 15Decrement the number of times to perform the operation in Register D
2FDFRET C9RETurn to CALLer
CALL 2B75H CALL LISPRTCD 75 2BSince 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
2FE6POP BC C1Clean up the STACK (to remove the DISPED return address)
2FE7POP DE D1Get the BASIC line number (in binary) from the STACK and put it in DE
2FE8LD A,D 7ALoad Register A with the MSB of the BASIC line number in Register D
2FE9AND E A3Combine the LSB of the BASIC line number in Register E with the MSB of the BASIC line number in Register A
2FEAINC A 3CBump the combined BASIC line number in Register A
LD HL,(40A7H) LD HL,(BUFPNT) 2A A7 40Load HL with the starting address of the input buffer.
Note: 40A7H-40A8H holds the input Buffer pointer
2FEEDEC HL 2BDecrement the value of the input buffer pointer in HL
2FEFRET Z C8Return if this is the Level II BASIC command mode
SCF 37Set the Carry flag to to fool the INSERT code; this flags the line number has having been seen
2FF1INC HL 23Bump the value of the input buffer pointer in HL
2FF2PUSH AF F5Save the command mode flag in AF to the STACK
2FF6 – EDIT Command – QUIT Logic – “QED” .
2FF6 QEDPOP BC C1Get rid of the DISPED return address
2FF7POP DE D1Get the line number off of the stack
2FFB-2FFFNOP 00THE END OF THE LEVEL II BASIC ROMS
2FFB-2FFFNOP 00Nothing here
*2FFB-2FFCSBC A,0C3HIn ROM v1.2 this is just garbage
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.
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).
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).
2532 – Binary Minus Routine – “DOMIN”
Note: 40F3H-40F4H is a temporary storage location
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.
NOTE: The RST 20H routine determines the type of the current value in ACCumulator and returns a combination of STATUS flags and unique numeric values in the A Register according to the data mode flag (40AFH). The results are returned as follows:
- Integer = NZ/C/M/E and A is -1
- String = Z/C/P/E and A is 0
- Single Precision = NZ/C/P/O and A is 1
- and Double Precision is NZ/NC/P/E and A is 5.
254E – This routine processes an expression for SNG( to MID$( – “ISFUN”
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.
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.
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.
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.
If the values match, set the current result in zero. If they do not match, set the current result to -1
25C4 – NOT Routine – “NOTER”
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
Note: 40AFH holds Current number type flag
25E9 – AND and OR Routines – “DANDOR”
According to the original ROM source, this routine applies the AND and OR operators and should be used to implement all logical operators
Whenever an operator is applied, its precedence is in Register B
This fact is used to distinguish between AND and OR
The right hand argument is coerced to integer, just as the left hand one was when it was pushed on the STACK
25F7 – OR logic.
25FD – AND logic – “NOTOR”
2603 – Dimension and Variable Searching Routine – “DIMCON”
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.
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
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.
Note: 40AEH holds LOCATE/CREATE variable flag
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.
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.
NOTE: 4101H-411AH holds Variable Declaration Table
NOTE: 40AFH holds Current number type flag
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.
Note: 40DCH holds FOR flag
- Note: 40F9H-40FAH holds the starting address of the simple variable storage area.
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.
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.
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.
Note: 40FDH-40FEH holds Free memory pointer
NOTE: 40FDH-40FEH holds Free memory pointer
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.
26D5 – This routine is ZERO out all variable types and skip any RETurn – “FINZER”
LD (4124H),A LD (FAC),A 32 24 41Zero ACCumulator so that all single-precision and double-precision variables become zero
26D8POP BC C1Clean up the STACK (i.e., remove the length of the variable)
26D9LD H,A 67Zero Register H to clear out integers as well
26DALD L,A 6FZero Register L to clear out integers as well
26DB-26DDLD (4121H),HL LD (FACLO),HL 22 21 41Zero the string pointer location in ACCumulator
26DEWe need to check the value of the current number type flag, so we call the TEST DATA MODE routine at RST 20H.
NOTE: The RST 20H routine determines the type of the current value in ACCumulator and returns a combination of STATUS flags and unique numeric values in the A Register according to the data mode flag (40AFH). The results are returned as follows:- Integer = NZ/C/M/E and A is -1
- String = Z/C/P/E and A is 0
- Single Precision = NZ/C/P/O and A is 1
- and Double Precision is NZ/NC/P/E and A is 5.
26DF-26E0If 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-26E3LD HL,1928H LD HL,REDDY-1 21 28 19If 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-26E6LD (4121H),HL LD (FACLO),HL 22 21 41Save the value in HL as the current string pointer, which is now null.
POP HL E1Get the value of the current BASIC program pointer from the STACK and put it in HL
26E8RET C9RETurn (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.
26EA-26ECLD HL,(40AEH) LD HL,(DIMFLG) 2A AE 40Load 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
26EDEX (SP),HL E3Swap (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
26EELD D,A 57Zero Register D (which will hold the number of dimension)
26F0PUSH BC C5Save the variable’s name in BC to the STACK
26F1-26F3CALL 1E45H CALL INTIDXCD 45 1EGo 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
26F4POP BC C1Get the variable’s name from the STACK (1st and 2nd character) and put it in BC
26F5POP AF F1Get the variable’s number of dimension so far from the STACK and put it in Register A
26F6EX DE,HL EBSwap 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
26F7EX (SP),HL E3Swap (SP) and HL so that HL will now hold DIMFLG and VALTYP and the array subscript will be at the stop of the STACK
26F8PUSH HL E5Save the DIMGFLG and VALTYP (in HL) to the STACK
26F9EX DE,HL EBSwap 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.
26FAINC A 3CBump the number of dimensions evaluated in Register A
26FBLD D,A 57Load Register D with the number of dimensions evaluated in Register A
26FCLD A,(HL) 7ELoad Register A with the character at the location of the current BASIC program pointer in HL
26FD-26FECP 2CH FE 2CCheck to see if the character at the location of the current BASIC program pointer in Register A is a , . If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
26FF-2700If the character at the location of the current BASIC program pointer in Register A is a , , then we have more dimensions to process, so JUMP back to INDLOP to process again
2701-2702Since 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 SUBSOKLD (40F3H),HL LD (TEMP2),HL 22 F3 40Save the value of the current BASIC program pointer in HL into the TEMP2 storage area.
2706POP HL E1Get the DIMFLG and VALTYP from the STACK and put it in HL.
2707-2709LD (40AEH),HL LD (DIMFLG),HL 22 AE 40Save the value of the DIMFLG and VALTYP into the DIMFLG location in RAM.
NOTE: 40AEH holds LOCATE/CREATE variable flag
270APUSH DE D5Save 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-270DLD HL,(40FBH) LD HL,(ARYTAB) 2A FB 40We 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-270FLD A,19H 3E 19Z-80 Trick to skip the next command of ADD HL,DE if falling through
ADD HL,DE 19Advance past the current array as we know it isn’t the correct one. Note: 40FBH-40FCH holds the array variables pointer
2710EX DE,HL EBSwap DE and HL so that DE holds the current search point. We don’t care about HL.
2711-2713LD HL,(40FDH) LD HL,(STREND) 2A FD 40Load HL with the place to STOP the search (i.e., the value of the free memory pointer).
Note: 40FDH-40FEH holds Free memory pointer
2714EX DE,HL EBSwap DE and HL so that DE now holds the place to stop the search and HL holds the current search point.
2715Now 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-2718LD A,(40AFH) LD A,(VALTYP) 3A AF 40Load Register A with the value of the current number type flag.
Note: 40AFH holds Current number type flag
2719-271AIf 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
271BCP (HL) BECompare 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.
271CINC HL 23Bump the value of the array variables pointer in HL
271D-271EJump forward (but still in this loop) to 2727H if the number type flags don’t match
271FLD A,(HL) 7ELoad Register A with the first character of the variable name at the location of the array variables pointer in HL
2720CP C B9Check 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.
2721INC HL 23Bump the value of the array variables pointer in HL
2722-2723Jump forward (but still in this loop) to 2728H if the first characters of the variable names don’t match
2724LD A,(HL) 7ELoad Register A with the second character of the variable name at the location of the array variables pointer in HL
2725CP B B8Compare 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-2727LD A,23H 3E 23This part of a Z-80 Trick. Will load A with 23H if passing through, and not do the following INC HL.
INC HL 23Bump the value of the array variables pointer in HL. HL should now point to the LENGTH entry of the array being looked at
2729LD E,(HL) 5ELoad Register E with the LSB of the LENGTH of the array being looked at
272AINC HL 23Bump the value of the array variables pointer in HL
272BLD D,(HL) 56Load Register D with the MSB of the LENGTH of the array being looked at
272CINC HL 23Bump the value of the array variables pointer in HL
272D-272EIf 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-2731LD A,(40AEH) LD A,(DIMFLG) 3A AE 40Load 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
2732OR A B7Since 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-2734LD E,12H 1E 12Prepare for an error if this routine was NOT called by “DIM” by loading Register E with the ?DD ERROR code
2735-2737JP NZ,19A2H JP NZ,ERRORC2 A2 19If 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.
2738POP AF F1Get the number of dimension evaluated from the STACK and put it in Register A
2739SUB (HL) 96To 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 DIM med)
273A-273CJP Z,2795H JP Z,GETDEFCA 95 27If they match then we are done so JUMP down to 2795H to read the indices
273D – ?BS ERROR entry point – “BSER”
273F-2741JP 19A2H JP ERRORC3 A2 19Display 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.
LD (HL),A 77Save the variable type for the array in Register A at the location of the array variables pointer in HL
2743INC HL 23Bump 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)
2744LD E,A 5FLoad Register E with the variable type flag for the current variable
2745-2746LD D,00H 16 00Zero Register D so that Register Pair DE can be the size of one value of the type VALTYP
2747POP AF F1Get the number of dimensions evaluated from the STACK and put it in Register A
2748LD (HL),C 71Save the second character of the variable’s name in Register C at the location of the array variables pointer in HL
2749INC HL 23Bump 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)
274ALD (HL),B 70Save the first character of the variable’s name in Register B at the location of the array variables pointer in HL
274BINC HL 23Bump the value of the array variables pointer in HL to the LSB of the offset to the next entry
274CLD C,A 4FIn preparation for the next CALL, load Register C with the number of two byte entries needed to store the size of each dimension
274D-274FCALL 1963H CALL GETSTKCD 63 19Figure the amount of memory space left between HL and the free memory and get the space needed as set in Register C
2750INC HL 23Next 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
2751INC HL 23Bump the value of the array variables pointer in HL. These 2 INC’s skip over the offset entry
2752-2754LD (40D8H),HL LD (TEMP3),HL 22 D8 40Next 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
2755LD (HL),C 71Save the number of dimension at the location of the array variables pointer in HL
2756INC HL 23Bump the value of the array variables pointer in HL to point to the first subscript entry in the array table
2757-2759LD A,(40AEH) LD A,(DIMFLG) 3A AE 40Load 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
275ARLA 17Set the CARRY flag accordingly
275BLD A,C 79Load Register A with the number of dimension evaluated in Register C
LD BC,000BH 01 0B 00Top 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
If the NC flag is set, then we did not arrive here from DIM, so JUMP forward to 2763H if the array is being created because it certainly wasn’t found
2761POP BC C1Get a subscript/index from the STACK and put it in BC
2762INC BC 03Bump the value of the subscript in BC by one for the ZERO entry.
2763 NOTDIMLD (HL),C 71Top of a loop. Save the LSB of the subscript’s value in Register C at the location of the array variables pointer in HL
2764INC HL 23Bump the value of the array variables pointer in HL
2765LD (HL),B 70Save the MSB of the subscript’s value in Register B at the location of the array variables pointer in HL
2766INC HL 23Bump the value of the array variables pointer in HL
2767PUSH AF F5Save the number of dimensions evaluated in Register A (and the CARRY aflag results from DIMFLG) to the STACK
2768-276ACALL 0BAAH CALL UMULTCD AA 0BGo multiply the size of the subscript by the value of the number type flag to determine the amount of memory necessary for the subscript
276BPOP AF F1Get the number of domensions that the CARRY FLAG (DIMFLG) from the STACK and put it in Register A
276CDEC A 3DDecrement the counter of the number of dimensions to check by one
276D-276EJump back to 275CH if there are anymore subscripts to be evaluated
276FPUSH AF F5If 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
2770LD B,D 42Load Register B with the MSB of the array’s length in Register D
2771LD C,E 4BLoad Register C with the LSB of the array’s length in Register E. Now BC = size of the array in bytes
2772EX DE,HL EBSwap DE and HL so that DE now has the start of the values and HL has the end of the values
2773ADD HL,DE 19Add the length of the array in HL to the value of the array variable pointer in DE
JR C,273DH JR C,BSER38 C7If that addition triggered the CARRY FLAG then we are out of RAM so JUMP back to 273DH and throw a ?BS ERROR
2776-2778CALL 196CH
CALL REASONCD 6C 19We now know there is room in RAM, so GOSUB to “REASON” to make sure there is room for the values
2779-277BLD (40FDH),HL LD (STREND),HL 22 FD 40Update the end of storage pointer with the end of the array (held in HL).
Note: 40FDH-40FEH holds free memory pointer
DEC HL 2BNow we need to zero the new array. First, decrement the value of the array pointer in HL
277D-277ELD (HL),00H 36 00Zero the location of the array pointer in HL
277FNow we need to compare the array pointer in HL with the array variables pointer in DE, so we call the COMPARE DE:HL routine at RST 10H.
The RST 10H routine parses the characters starting at HL+1 for the first non-SPACE,non-09H,non-0BH character it finds. On exit, Register A will hold that character, and the C FLAG is set if its alphabetic, and NC FLAG if its alphanumeric. All strings must have a 00H at the end.
2780-2781If the NZ FLAG is set, then we have more entries to ZERO, so loop until the array has been cleared
2782INC BC 03Load 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
2783LD D,A 57Zero Register D
2784-2786LD HL,(40D8H) HL,(TEMP3) 2A D8 40Load HL with the array variables pointer (=the number of indices).
Note: 40D8H-40D9H holds Temporary storage location
2787LD E,(HL) 5ELoad Register E with the number of dimension for the array at the location of the array variables pointer in HL
2788EX DE,HL EBSwap DE and HL so that HL now holds the number of dimensions and DE holds the value of the array variables pointer
2789ADD HL,HL 29Multiply the number of subscripts for the array in HL by two
278AADD HL,BC 09Add 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
278BEX DE,HL EBSwap 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
278CDEC HL 2BWe 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
278DDEC HL 2BDecrement the value of the array variables pointer in HL
278ELD (HL),E 73Save the LSB of the size of the array in Register E at the location of the array variables pointer in HL
278FINC HL 23Bump the value of the array variables pointer in HL
2790LD (HL),D 72Save the MSB of size of the array array in Register D at the location of the array variables pointer in HL
2791INC HL 23Bump the value of the array variables pointer in HL
2792POP AF F1Get the value of the DIMFLG (i.e., the CARRY BIT) and a 0 into Register A
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).
2796LD C,A 4FZero Register C. Now BC = 0 = CURTOL
2797LD A,(HL) 7ELoad Register A with the number of dimensions for the array at the location of the array variables pointer in HL
2798INC HL 23Bump the value of the array variables pointer in HL to one entry past the number of dimensions
2799LD D,0E1H 16 E1Z-80 Trick to hide the next instruction (POP HL) if proceeding downward
279BLD E,(HL) 5ENext, 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
279CINC HL 23Bump the value of the array variables pointer in HL
279DLD D,(HL) 56Load Register D with the MSB of the subscript limit at the location of the array variables pointer in HL
279EINC HL 23Bump the value of the array variables pointer in HL
279FEX (SP),HL E3Swap 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
27A0PUSH AF F5Save the number of dimensions for the array in Register A to the STACK
27A1Now 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.
JP NC,273DH JP NC,BSERD2 3D 27If the current inex is too big, then we need to throw a ?BS ERROR via a JUMP to 273DH
27A8ADD HL,DE 19Add the index to CURTOL
27A9POP AF F1Get the number of dimensions for the array from the STACK and put it in Register A
27AADEC A 3DWe checked one, so cross one off the list and see if there are anymore dimensions to be evaluated
27ABLD B,H 44Load Register B with the MSB of the subscript pointer in Register H
27ACLD C,L 4DLoad Register C with the LSB of the subscript pointer in Register L. Now BC = CURTOL for the start of the next loop.
27AD-27AELoop back to 279AH until all of the subscripts have been evaluated
27AF-27B1LD A,(40AFH) LD A,(VALTYP) 3A AF 40Get the number type flag for the current array; which also doubles for how big the values are
NOTE: 40AFH holds Current number type flag
27B2
27B3LD B,H
LD C,L 44We are going to need to multiply by THREE, so we need to save the original value into BC as well.
27B4ADD HL,HL 29Multiply the subscript pointer in HL by two
27B5-27B6SUB 04H D6 04Check the value of the number type flag in Register A because we would be done if we have an integer or a string.
Jump forward to 27BDH if the current number type is an integer or string
27B9ADD HL,HL 29It isn’t an integer or a string so once again multiply the subscript pointer in HL by two (so now it is multiplied by 4)
27BA-27BBJump forward to 27C2H if the current number type is single precision as we then have enough bytes.
27BCADD HL,HL 29It must be double precision, so once again multiply the subscript pointer in HL by two (so now it is multiplied by 8)
27BE-27C0JP PO,27C2H JP PO,DONMULE2 C2 27Jump forward to 27C2H if the current number type isn’t a string
27C1ADD HL,BC 09The current number type is a string so add the value of the original subscript pointer in BC to the subscript pointer in HL
27C3ADD HL,BC 09Add 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
27C4EX DE,HL EBLoad DE with the variable pointer in HL
LD HL,(40F3H) LD HL,(TEMP2) 2A F3 40Get the value of the current BASIC program pointer and put it in HL.
Note: 40F3H-40F4H is a temporary storage location
27C8RET C9RETurn 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.
27CAPUSH HL E5Save the value of the current BASIC program pointer in HL to the STACK
27CB-27CDLD (40AFH),A LD (VALTYP),A 32 AF 40Zero the number type flag.
NOTE: 40AFH holds Current number type flag
27CE-27D0CALL 27D4H CALL FRECD D4 27Determine how much space there is via a GOSUB to the FRE routine at 27D4H
27D1POP HL E1Get the value of the current BASIC program pointer from the STACK and put it in HL
27D2We 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.
27D3RET C9Return to BASIC
27D4-27F4 – LEVEL II BASIC FRE ROUTINE – “FRE”
LD HL,(40FDH) LD HL,(STREND) 2A FD 40Load 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
27D7EX DE,HL EBLoad DE with the value of the free memory pointer in HL for subtraction
27D8-27DALD HL,0000H 21 00 00Zero HL
27DBADD HL,SP 39Add the value in HL (which is zero) to the current value of the STACK pointer so that the STACK pointer is now in HL
27DCWe need to check the value of the current number type flag, so we call the TEST DATA MODE routine at RST 20H.
NOTE: The RST 20H routine determines the type of the current value in ACCumulator and returns a combination of STATUS flags and unique numeric values in the A Register according to the data mode flag (40AFH). The results are returned as follows:- Integer = NZ/C/M/E and A is -1
- String = Z/C/P/E and A is 0
- Single Precision = NZ/C/P/O and A is 1
- and Double Precision is NZ/NC/P/E and A is 5.
27DD-27DEIf that test shows we do NOT have a STRING (meaning this was really a MEM call, jump to forward to 27ECH
27DF-27E1CALL 29DAH CALL FREFACCD DA 29Free up the argument and set up to give some free string space
27E5-27E7LD HL,(40A0H) LD HL,(STKTOP) 2A A0 40Load HL with the start of string space pointer / bottom of free space.
NOTE: 40A0H-40A1H holds the start of string space pointer
27E8EX DE,HL EBLoad DE with the start of string space pointer in HL
27E9-27EBLD HL,(40D6H) LD HL,(FRETOP) 2A D6 40Load 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 GIVDBLLD A,L 7DPrepare to do HL = HL – DE. First, load Register A with the LSB of the next available location in string space pointer in Register L
27EDSUB E 93Subtract 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
27EELD L,A 6FLoad Register L with the LSB of the amount of string space remaining in Register A
27EFLD A,H 7CLoad Register A with the MSB of the next available location in string space pointer in Register H
27F0SBC A,D 9ASubtract 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
27F1LD H,A 67Load Register H with the MSB of the amount of string space remaining in Register A
27F2-27F4JP 0C66H JP INEG2C3 66 0CJump to 0C66H to convert the difference between HL and DE to single precision and then RETurn out of the routine
27F5-27FD – LEVEL II BASIC POS( ROUTINE – “POS”
27F5-27F7 POSLD A,(40A6H) LD A,(TTYPOS) 3A A6 40Load Register A with the current cursor line position.
Note: 40A6H holds the current cursor line position
LD L,A 6FLoad Register L with the value of the current cursor line position in Register A.
27F9XOR A AFZero Register A
27FA GIVINTLD H,A 67Load Register H with zero, so now HL is 00 + cursor position
27FE-2818 – LEVEL II BASIC USR(x) ROUTINE – “USRFN”
27FE-2780 USRFNCALL 41A9H CALL USROUT CD A9 41GOSUB to DOS to see if DOS wants to deal with this
2801We need the next character so call the EXAMINE NEXT SYMBOL routine at RST 10H.
The RST 10H routine parses the characters starting at HL+1 for the first non-SPACE,non-09H,non-0BH character it finds. On exit, Register A will hold that character, and the C FLAG is set if its alphabetic, and NC FLAG if its alphanumeric. All strings must have a 00H at the end.
2802-2804CALL 252CH CALL PARCHKCD 2C 25GOSUB to 252CH to evaluate the expression at the location of the current BASIC program pointer in HL and return with the result in ACCumulator
2805PUSH HL E5Save the value of the current BASIC program pointer in HL (=the address of the next element in the code string) to the STACK
2806-2808LD HL,0890H LD HL,POPHRT 21 90 08Load HL with the return address of 0890H which will clear the STACK before returning to BASIC
2809PUSH HL E5Save the value of the return address in HL to the STACK
280A-280CLD A,(40AFH) LD A,(VALTYP) 3A AF 40Load Register A with the value of the current number type flag for the argument provided.
Note: 40AFH holds Current number type flag
280DPUSH AF F5Save the value of the current number type flag in Register A.
(02=INT, 03=STR, 04=SNG, 08=DBL)
280E-280FCP 03H FE 03Check to see if the current value is a string. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
2810-2812CALL Z,29DAH CALL Z,FREFACCC DA 29If the current result is a string then GOSUB to 29DAH to get the free the space and get the string address into HL
2813POP AF F1Restore the number type flag into Register A
2814EX DE,HL EBLoad DE with the (possible) value of the pointer to the string (in HL)
2815-2817LD HL,(408EH) 2A 8E 40Load 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.
2818JP (HL)E9Jump 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.
PUSH HL E5Save the pointer to the current character in the BASIC program being evaluated to the STACK
281A-281BAND 07H E6 07Mask 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-281ELD HL,18A1H LD HL,FRCTBL 21 A1 18Load HL with the address of the arithmetic conversion routines
281FLD C,A 4FLoad Register C with the value of the number type flag in Register A.
(02=INT, 03=STR, 04=SNG, 08=DBL)
2820-2821LD B,00H 06 00Zero Register B. Now BC holds 00 + type and will be the two byte offset into the table
2822ADD HL,BC 09Add the offset (of BC) to the base arithmetic conversion routines, to find the right jump point
2823-2825CALL 2586H CALL DISPATCD 86 25GOSUB to 2586H to convert the current result in REG l to its proper number type
2826POP HL E1Restore the pointer to the current character in the BASIC program being evaluated to HL
2827RET C9RETurn 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.
2829-282BLD HL,(40A2H) LD HL,(CURLIN) 2A A2 40Load HL with the value of the current BASIC line number (which is stored at 40A2H-40A3H).
282CINC HL 23Bump 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
282DLD A,H 7CLoad Register A with the MSB of the current BASIC line number in Register H
282EOR L B5Combine 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.
282FPOP HL E1Restore whatever was in HL on entry back into HL
2830RET NZ C0Return if there is a line number (i.e., this isn’t the command mode) and otherwise fall through to the ?ID ERROR routine
2831 – ID ERROR entry point.
2831-2832LD E,16H 1E 16Load Register E with the ?ID ERROR code
2836-2856 – STRING ROUTINE – STR$ logic – “STR$”
2836-2838 STR$CALL 0FBDH CALL FOUTCD BD 0FGOSUB to 0FBDH to convert the current result in ACCumulator to an ASCII string
2839-283B STR$1CALL 2865H CALL STRLITCD 65 28Scan it and turn it into a string (make a temporary string work area entry)
LD BC,2A2BH LD BC,FINBCK 01 2B 2ALoad BC with a return address of 2A2BH (which cleans the STACK and then jumps to 2884H)
2842PUSH BC C5Save the value of the return address in BC to the STACK
The next routine, STRCPY, creates a copy of the string pointed to by Register Pair HL. On exit, DE points to DSCTMP which has the string information.
2843 STRCPYLD A,(HL) 7ELoad Register A with the string’s length at the location of the string’s VARPTR in HL
2844INC HL 23Bump the value of the string’s VARPTR in HL
2845PUSH HL E5Save the value of the string’s VARPTR in HL to the STACK
2846-2848CALL 28BFH CALL GETSPACD BF 28GOSUB to 28BFH to test the remaining string area to make sure that the new string will fit
2849POP HL E1Reload HL with the string’s VARPTR. This is the destination to where the string should be copied.
284ALD C,(HL) 4ELoad Register C with the LSB of the string’s address at the location of the string’s VARPTR in HL
284BINC HL 23Bump the value of the string’s VARPTR in HL
284CLD B,(HL) 46Load Register B with the MSB of the string’s address at the location of the string’s VARPTR in HL
284D-284FCALL 285AH CALL STRAD2CD 5A 28GOSUB to 285AH to save the string’s length and the string’s address at 40D3H, so as to set up DSCTMP
2850PUSH HL E5Save the pointer to STRAD2 (which is 40D3H) to the STACK
2851LD L,A 6FLoad Register L with the string’s length (from Register A)
2852-2854CALL 29CEH CALL MOVSTRCD CE 29GOSUB to 29CEH to move L characters from the temp area (of BC) to the string data area (in DE)
2855POP DE D1Restore the pointer to DSCTMP (40D3H) into Register Pair DE
2856RET C9RETurn to CALLer
2857-2864 – STRING ROUTINE – “STRINI”
CALL 28BFH CALL GETSPACD BF 28GOSUB 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
LD HL,40D3H LD HL,DSCTMP 21 D3 40Load HL with the address of the temporary string parameter storage area.
Note: 40D3H-40D5H holds Used for temporary string VARPTR’s
285D STRAD1PUSH HL E5Save the address of the temporary string parameter area in HL to the STACK
285ELD (HL),A 77Save the string’s length in Register A at the location of the temporary string parameter storage pointer in HL
285F PUTDEIINC HL 23The 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
2860LD (HL),E 73Save the LSB of the string’s address in Register E at the location of the temporary string parameter storage pointer in HL
2861INC HL 23Bump the value of the temporary string parameter storage pointer in HL
2862LD (HL),D 72Save the MSB of the string’s address in Register D at the location of the temporary string parameter storage pointer in HL
2863POP HL E1Get the address of the temporary string parameter storage area from the STACK and put it in HL
2864RET C9RETurn 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.
LD B,22H 06 22Load Register B with a “ (which is really the end of the quote search character)
PUSH HL E5Save 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-286BLD C,0FFH 0E FFLoad Register C with a -1
INC HL 23Bump the value of the current BASIC program pointer in HL to skip over that initial “
286DLD A,(HL) 7ELoad Register A with the character at the location of the current BASIC program pointer in HL
286EINC C 0CBump the counter in Register C
286FOR A B7Check to see if the character at the location of the current BASIC program pointer in Register A is an end of the BASIC line character
2870-2871Jump 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
2872CP D BACheck to see if the character at the location of the current BASIC program pointer in Register A is the same as the terminating character in Register D. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
2873-2874Jump 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
2875CP B B8Check to see if the character at the location of the current BASIC program pointer in Register A is the same at the terminating character in Register B. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
2876-2877Loop 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
CP 22H FE 22Check to see if the character at the location of the current BASIC program pointer in Register A is a quote. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
287A-287CCALL Z,1D78H CALL Z,CHRGTRCC 78 1DIf 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)
287DEX (SP),HL E3Exchange the value of the current BASIC program pointer in HL with the string’s address to the STACK
287EINC HL 23Bump the string’s address in HL until it points to the first character of the string
287FEX DE,HL EBLoad DE with the temporary pointer string’s address in HL
2880LD A,C 79Load Register A with the string’s length from Register C
2881-2883CALL 285AH CALL STRAD2CD 5A 28GOSUB to 285AH to save the string’s length and the string’s address into 40D3H (i.e., DSCTMP)
LD DE,40D3H LD DE,DSCTMP 11 D3 40Load DE with the address of the string parameter storage area.
Note: 40D3H-40D5H holds Used for temporary string VARPTR’s
LD A,D5H 3E D5This 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 PUTTMPPUSH DE D5Save a pointer to the stat of the string to the STACK
2889-288BLD HL,(40B3H) LD HL,(TEMPPT) 2A B3 40Load 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-288ELD (4121H),HL LD (FACLO),HL 22 21 41Save 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-2890LD A,03H 3E 03Load Register A with the string number type flag
2891-2893LD (40AFH),A LD (VALTYP),A 32 AF 40Save the value in Register A as the current number type flag.
Note: 40AFH holds current number type flag
2897-2899LD DE,40D6H LD DE,FRETOP 11 D6 40Depending on how we got here, DE will be different. If the jump was into PUTTMP, then DE will NOT equal FRETOP.
289AWe 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-289DLD (40B3H),HL LD (TEMPPT),HL 22 B3 40Save 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
289EPOP HL E1Get the value of the current BASIC program pointer from the STACK and put it in HL
289FLD A,(HL) 7ELoad Register A with the character at the location of the current BASIC program pointer in HL
28A0RET NZ C0Return if the updated temporary string work area location wasn’t beyond the end of the temporary string work area (meaning it overflowed, because if it overflowed .)
28A1 – ST ERROR entry point.
28A1-28A2LD E,1EH 1E 1ELoad Register E with a ?ST ERROR code
28A3-28A5JP 19A2H JP ERRORC3 A2 19Display 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 STROUIINC HL 23Bump 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.
CALL 2865H CALL STRLITCD 65 28Go build a temporary string work area entry for the message at FACLOthe location of the current BASIC program pointer in HL
If the routine entry is at STRPRT, then it just prints the string whose descriptor is held in FACLO
28AA-28AC STRPRTCALL 29DAH CALL FREFACCD DA 29GOSUB to 29DAH to build a temporary string work area entry for the message pointed to by FACLO
28AD-28AFCALL 09C4H CALL GETBCDCD C4 09Go get the string’s length in Register D and the string’s address in BC
28B0INC D 14Bump the value of the string’s length in Register D in preparation for the following loop which starts with a DEC D
28B1 STRPR2DEC D 15Top of a loop. Decrement the value of the string’s length in Register D
28B2RET Z C8Return if all of the characters in the string have been sent to the current output device.
28B4-28B6CALL 032AH CALL OUTDOCD 2A 03Go send the character in Register A to the current output device
28B7-28B8CP 0DH FE 0DCheck to see if the character in Register A is a CARRIAGE RETURN . If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
28B9-28BBCALL Z,2103H CALL Z,CRFINCC 03 21Jump to 2103H if the character in Register A is a carriage return
28BCINC BC 03Bump the value of the string pointer in BC
28BD-28BEJR 28B1H JR STRPR218 F2Loop 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.
OR A B7Make sure A is not zero. A ZERO FLAG will signal that garbage collection has happened
28C0-28C1LD C,0F1H 0E F1Z-80 Trick. If passing through, the C just changes and the POP AF which follows is ignored.
28C1 TRYGI2POP AF F1Get the string’s length from the STACK and put it in Register A
28C2PUSH AF F5Save the length of the string in Register A to the STACK
28C3-28C5LD HL,(40A0H) LD HL,(STKTOP) 2A A0 40Load HL with the poinmter to the bottom of the string space. 40A0H-40A1H holds the start of string space pointer
28C6EX DE,HL EBMove the bottom of the string space pointer into DE. We don’t care what happens to HL
28C7-28C9LD HL,(40D6H) LD HL,(FRETOP) 2A D6 40Load HL with the pointer to the TOP of free space.
Note: 40D6H-40D7H holds the next available location in string space pointer
28CACPL 2FComplement the string’s length in Register A so that it is negative
28CBLD C,A 4FThe 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-28CDLD B,0FFH 06 FFLoad Register B with a -1 so that BC will be the negative length of the string
28CEADD HL,BC 09Add the negative string’s length in BC to the top of free space pointer in HL
28CFINC HL 23Bump the value of the adjusted next available location in string space pointer in HL
28D0We 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 CARRY FLAG is set then we do not have enough room for the string, so lets JUMP forward to 28DAH to do some garbae collection.
28D3-28D5LD (40D6H),HL LD (FRETOP),HL 22 D6 40Save the value in HL as new bottom of MEMORY
28D6INC HL 23Bump the value of HL to point to the string
28D7EX DE,HL EBLoad DE with the pointer to the string
28D9RET C9RETurn to CALLer
28DA-298E – STRING ROUTINE – “GARBAG”
28DB-28DCLD E,1AH 1E 1ALoad Register E with an ?OS ERROR code
28DD-28DFJP Z,19A2H JP Z,ERRORCA A2 19If 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
28E0CP A BFOtherwise, 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.
28E1PUSH AF F5Save the garbage collection flag to the STACK
LD BC,28C1H LD BC,TRYGI2 01 C1 28Load BC with a return address of 28C1H (which would retry allocation)
28E5PUSH BC C5Save that return address to the STACK
LD HL,(40B1H) LD HL,(MEMSIZ) 2A B1 40Load HL with the top of memory pointer.
Note: 40B1H-40B2H holds MEMORY SIZE? pointer
LD (40D6H),HL LD (FRETOP),HL 22 D6 40Save 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-28EELD HL,0000H 21 00 00Zero HL
28EFPUSH HL E5Save the value in HL to the STACK to indicate that we didn’t find a variable on this pass
28F0-28F2LD HL,(40A0H) LD HL,(STKTOP) 2A A0 40Load 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
28F3PUSH HL E5Save high address (start of string space pointer in HL) to the STACK
28F4-28F6LD HL,40B5H LD HL,TEMPST 21 B5 40Load HL with the start of the temporary string work area pointer.
Note: 40B5H-40D2H holds Temporary string work area
28F7
“TVAR”EX DE,HL EBLoad DE with the start of the temporary string work area pointer in HL
28F8-28FALD HL,(40B3H) LD HL,(TEMPPT) 2A B3 40Load 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
28FBEX DE,HL EBExchange 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
28FCWe need to see if 40B3H is pointing to the first entry (40B5H) – if the start of the temporary string work area pointer in HL is the same as the next available location in the temporary string work area pointer, so we call the COMPARE DE:HL routine at RST 10H.
The RST 10H routine parses the characters starting at HL+1 for the first non-SPACE,non-09H,non-0BH character it finds. On exit, Register A will hold that character, and the C FLAG is set if its alphabetic, and NC FLAG if its alphanumeric. All strings must have a 00H at the end.
28FD-28FFLD BC,28F7H LD BC,TVAR 01 F7 28Load BC with a return address of 28F7H
2900-2902JP NZ,294AH JP NZ,DVAR2C2 4A 29Jump to 294AH to do the temporary variable garbage collection if the temporary string work area isn’t empty
2903 SVARSLD HL,(40F9H) LD HL,(VARTAB) 2A F9 40Load HL with the start of the simple variables pointer.
NOTE: 40F9H-40FAH holds the starting address of the simple variable storage area
2907-2909LD HL,(40FBH) LD HL,(ARYTAB) 2A FB 40Load 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
290AEX DE,HL EBSwap DE and HL so that DE holds the end and HL holds the start.
290BNow we need to check to see if the simple variables pointer in HL is the same as the array variables pointer in DE, so we call the COMPARE DE:HL routine at RST 10H.
The RST 10H routine parses the characters starting at HL+1 for the first non-SPACE,non-09H,non-0BH character it finds. On exit, Register A will hold that character, and the C FLAG is set if its alphabetic, and NC FLAG if its alphanumeric. All strings must have a 00H at the end.
290C-290DIf 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.
290ELD A,(HL) 7ELoad Register A with second character of the variable name
290FINC HL 23Bump the value of the simple variables pointer in HL
2910INC HL 23Bump the simple variables pointer in HL
2911INC HL 23Bump the value of the simple variables pointer in HL. HL should now point to the value of the variable.
2912-2913CP 03H FE 03Check to see if the variable at the location of the simple variables pointer is a string. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
2914-2915Jump to 291AH if the variable at the location of the simple variables pointer in HL isn’t a string
2919XOR A AFZero Register A to indicate that we should not be skipping anything else.
291A SKPVARLD E,A 5FZero Register E
291B-291CLD D,00H 16 00Zero Register D. Now DE should be the number of characters to skip.
291DADD HL,DE 19Add the number of characters to skip (held in DE) to the simple variables pointer in HL
291E-291FJR 2906H JR SVAR18 E6Loop back to 2906H until all of the simple variables have been checked
2922-2924LD HL,(40FDH) LD HL,(STREND) 2A FD 40Load HL with the end of the arrays / start of free memory pointer.
Note: 40FDH-40FEH holds Free memory pointer
2925EX DE,HL EBExchange the value of the array variables pointer in DE with the value of the free memory pointer in HL
2926We need to see if we are donee with arrays, so we check to see if the array variables pointer in HL is the same as the free memory pointer in DE, so we call the COMPARE DE:HL routine at RST 10H.
The RST 10H routine parses the characters starting at HL+1 for the first non-SPACE,non-09H,non-0BH character it finds. On exit, Register A will hold that character, and the C FLAG is set if its alphabetic, and NC FLAG if its alphanumeric. All strings must have a 00H at the end.
2927-2929JP Z,296BH JP Z,GRBPASCA 6B 29Jump if the array variables pointer in Register HL is the same as the start of the free memory pointer in DE
292ALD A,(HL) 7ELoad Register A with the number type flag at the location of the array variables pointer in HL
292BINC HL 23Bump the value of the array variables pointer in HL
292C-292ECALL 09C2H CALL MOVRMCD C2 09Get 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)
292FPUSH HL E5Save the pointer to the DIMS to the STACK
2930ADD HL,BC 09Add the value of the offset to the next array in BC to the value of the array variables pointer in HL
2931-2932CP 03H FE 03Check to see if the array being examined is a string. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
2933-2934If the array being examined isn’t a string then skip it via a JUMP to 2920H
2935-2937LD (40D8H),HL LD (TEMP3),HL 22 D8 40Save the address of the end of the array being examined.
Note: 40D8H-40D9H holds Temporary storage location
2938POP HL E1Get the value of the array variables pointer from the STACK and put it in HL
2939LD C,(HL) 4ELoad Register C with the number of subscripts for the array at the location of the array variables pointer in HL
293A-293BLD B,00H 06 00Zero Register B so that BC holds the number of dimensions
293CADD HL,BC 09Add the number of subscripts in the array in BC to the value of the array variables pointer in HL
293DADD HL,BC 09Add 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.
293EINC HL 23Bump the value of the array variables pointer in HL one more time to account for #DIMs.
293F ARYSTREX DE,HL EBLoad DE with the value of the current position in the array variables pointer in HL
2940-2942LD HL,(40D8H) LD HL,(TEMP3) 2A D8 40Load HL with the address of the end of this array.
Note: 40D8H-40D9H holds Temporary storage location
2943EX DE,HL EBSwap DE and HL so that HL now points to the current position
2944We need to test for the end of the array space so we need to check to see if the array variables pointer in HL is the same as the address of the next array in DE, so we call the COMPARE DE:HL routine at RST 10H.
The RST 10H routine parses the characters starting at HL+1 for the first non-SPACE,non-09H,non-0BH character it finds. On exit, Register A will hold that character, and the C FLAG is set if its alphabetic, and NC FLAG if its alphanumeric. All strings must have a 00H at the end.
2945-2946If the Z FLAG is set then we are at the end of an array so JUMP to 2921H to try the next array
294COR (HL) B6Load Register A with the length of the string at the location of the array variables pointer in HL
294DINC HL 23Bump the value of the array variables pointer in HL
294ELD E,(HL) 5ELoad Register E with the LSB of the string’s address at the location of the array variables pointer in HL
294FINC HL 23Bump the value of the array variables pointer in HL
2950LD D,(HL) 56Load 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.
2951INC HL 23Bump the value of the array variables pointer in HL
2952RET Z C8Return if the string’s length in Register A is equal to zero
2955-2957LD HL,(40D6H) LD HL,(FRETOP) 2A D6 40Load HL with the location of the the top of string free space.
NOTE: 40D6H-40D7H holds the next available location in string space pointer
2958We 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
295ALD H,B
LD L,C 60Let HL = BC
295BRET C D8If 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
295DEX (SP),HL E3Swap (SP) and HL so that the return address is back on the STACK and HL holds the maximum number seen
295ENow 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.
295FEX (SP),HL E3Swap (SP) and HL so that the return address is back in HL and the STACK holds the maximum number seen
2960PUSH HL E5Save the return address in HL to the STACK
2961
2962LD H,B
LD L,C 60Let HL = BC
2963RET NC D0Return if the string’s address in DE is below the string space pointer
2965POP AF F1Clean up the STACK (remove the MAX SEEN)
2966POP AF F1Clean up the STACK (remove the VARIABLE POINTER)
2967PUSH HL E5Save the value of the array variables pointer in HL to the STACK
2968PUSH DE D5Save the new MAX pointer in DE to the STACK
2969PUSH BC C5Save the value of the return address in BC to the STACK
296ARET C9RETurn to CALLer
If we are here, we have made one complete pass through the string variables.
296B GRBPASPOP DE D1Load DE with the address of the last string put into the temporary string work area (aka the MAX pointer)
296CPOP HL E1Get the variable pointer from the STACK and put it in HL
296DLD A,L 7DLoad Register A with the LSB of the variable pointer in Register L
296EOR H B4Combine 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
296FRET Z C8If HL=0 then we are at the end of the garbage collection, so return
DEC HL 2BDecrement the value of the temporary string work area pointer in HL, currently just past the string descriptor
2971LD B,(HL) 46Load Register B with the MSB of the string’s address at the location of the temporary string work area pointer in HL
2972DEC HL 2BDecrement the value of the temporary string work area pointer in HL
2973LD C,(HL) 4ELoad 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.
2974PUSH HL E5Save 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.
2975DEC HL 2BDecrement the value of the temporary string work area pointer in HL
2976LD L,(HL) 6ELoad Register L with the string’s length at the location of the temporary string work area pointer in HL
2977-2978LD H,00H 26 00Zero Register H so that HL is now the string’s character count
2979ADD HL,BC 09Add the length of the string in HL to the string’s address in BC. HL now points just beyond the string.
297ALD D,B 50Load Register D with the MSB of the string’s address in Register B
297BLD E,C 59Load Register E with the LSB of the string’s address in Register C. DE now is the original pointer to the string.
297CDEC HL 2BDecrement the value of the string’s ending address in HL to avoid moving one beyond the string
297DLD B,H 44Load Register B with the MSB of the string’s ending address in Register H
297ELD C,L 4DLoad Register C with the LSB of the string’s ending address in Register L. BC now points to the top of the string
297F-2981LD HL,(40D6H) LD HL,(FRETOP) 2A D6 40Load HL with the top of free space.
NOTE: 40D6H-40D7H holds the next available location in string space pointer
2982-2984CALL 1958H CALL BLTUCCD 58 19Move the string from the temporary storage location to string space
2985POP HL E1Get back the pointer to the description of the variable from the STACK and put it in HL
2986LD (HL),C 71Save the LSB of the string’s permanent address (held in Register C) to (HL)
2987INC HL 23Bump the value of the temporary string work area pointer in HL
2988LD (HL),B 70Save the MSB of the string’s permanent address (held in Register C) to (HL)
2989LD L,C 69Load Register L with the LSB of the string’s address in Register C
298ALD H,B 60Load Register H with the MSB of the string’s address in Register B. Register Pair HL will now be the new pointer to the string.
298BDEC HL 2BDecrement the string’s address in HL to adjust FRETOP
298F-29C5 – STRING ADDITION ROUTINE – Concatenate two strings – “CAT”
This routine concatenates two strings. The first is pointed to by FACLO and HL points to the character after the “+” sign in on the command line.
2990PUSH HL E5Save the value of the current BASIC program pointer in HL to the STACK
2991-2993LD HL,(4121H) LD HL,(FACLO) 2A 21 41Load HL with the first string’s VARPTR (from ACCumulator)
2994EX (SP),HL E3Exchange the value of the first string’s VARPTR in HL with the value of the current BASIC program to the STACK
2995-2997CALL 249FH CALL EVALCD 9F 24GOSUB to 249FH to evaluate the expression at the location of the current BASIC program pointer in HL
2998EX (SP),HL E3Exchange the value of the current BASIC program pointer in HL with the value of the first string’s VARPTR to the STACK
299CLD A,(HL) 7ELoad Register A with the first string’s length at the location of the first string’s VARPTR in HL
299DPUSH HL E5Save the value of the first string’s descriptor (VARPTR) in HL to the STACK
299E-29A0LD HL,(4121H) LD HL,(FACLO) 2A 21 41Load HL with the second string’s VARPTR in ACCumulator
29A1PUSH HL E5Save the second string’s VARPTR in HL to the STACK
29A2ADD A,(HL) 86Add the length of the second string at the location of the second string’s VARPTR in HL to the length of the first string in Register A
29A3-29A4LD E,1CH 1E 1CLoad Register E with a ?LS ERROR codein case the two string lengths are not less than 256.
29A5-29A7JP C,19A2H JP C,ERRORDA A2 19Display a ?LS ERROR message if the combined lengths of the strings is greater than 255
29A8-29AACALL 2857H CALL STRINICD 57 28Go make sure that there is enough string space for the new string
29ABPOP DE D1Get the second string’s VARPTR from the STACK and put it in DE
29AFEX (SP),HL E3Exchange the second string’s VARPTR in HL with the first string’s VARPTR to the STACK
29B3PUSH HL E5Save the value of the first string’s VARPTR in HL to the STACK
29B4-29B6 INCSTRLD HL,(40D4H) LD HL,(DSCTMP+1) 2A D4 40Load HL with the pointer to the first string’s address
29B7EX DE,HL EBLoad DE with the first string’s address in HL
29BE-29C0LD HL,2349H LD HL,TSTOP 21 49 23Load HL with the return address
29C1EX (SP),HL E3Exchange the value of the return address in HL with the value of the current BASIC program pointer to the STACK
29C2PUSH HL E5Save the value of the current BASIC program pointer in HL to the STACK
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
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.
29C8LD A,(HL) 7ELoad Register A with the string’s length at the location of the string’s VARPTR in HL
29C9INC HL 23Bump the value of the string’s VARPTR in HL
29CALD C,(HL) 4ELoad Register C with the LSB of the string’s address at the location of the string’s VARPTR in HL
29CBINC HL 23Bump the value of the string’s VARPTR in HL
29CCLD B,(HL) 46Load 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.
29CDLD L,A 6FLoad Register L with the string’s length in Register A
INC L 2CIncrement the value of the string’s length in Register L in preparation for the next instruction which is a loop.
29D0RET Z C8If L hits zero then we have moved all the characters, so RETurn
LD A,(BC) 0AIf 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
29D2LD (DE),A 12Save the character in Register A at the location of the string storage pointer in DE
29D3INC BC 03Bump the value of the string pointer in BC
29D4INC DE 13Bump the value of the string storage pointer in DE
29D7-29F4 – STRING ROUTINE – “FRESTR”
According to the original ROM source code, FRETMP is passed a pointer to a string descriptor in Register Pair DE and is returned in Register Pair HL. All the other registers are modified. A check to is made to see if the string descriptor in Register Pair DE points to is the last temporary descriptor allocated by PUTNEW. If so, the temporary is freed up by the updating of TEMPPT. If a temporary is freed up, a further check is made to see if the string data that that string temporary pointed to is the the lowest part of string space in use. If so, FRETMP is updated to reflect the fact that that space is no longer in use.
This routine is a contination of VAL , FRE , and PRINT processing. A jump to here would include the need to get a string’s VARPTR and put it in HL.
CALL 0AF4H CALL CHKSTRCD F4 0AGOSUB to 0AF4H to make sure that the current result in REG l is a string
CALL 29F5H CALL FRETMSCD F5 29Check to see if the string is the last entry in the temporary string work area
29E1EX DE,HL EBLoad HL with the value of the string’s VARPTR in DE
29E2RET NZ C0Return if the string isn’t the last entry in the temporary string work area
29E4LD D,B 50Load Register D with the MSB of the string’s address in Register B
29E5LD E,C 59Load Register E with the LSB of the string’s address in Register C. DE now points to the string.
29E6DEC DE 1BDecrement the value of the string’s address in DE
29E7LD C,(HL) 4ELoad Register C with the string’s length at the location of the string’s VARPTR in HL
29E8-29EALD HL,(40D6H) LD HL,(FRETOP) 2A D6 40Load 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
29EBWe need to see if the current string is the last one defined in the string area by seeing if the string’s address in DE is the same as the next available location in string space pointer in HL, so we call the COMPARE DE:HL routine at RST 10H.
The RST 10H routine parses the characters starting at HL+1 for the first non-SPACE,non-09H,non-0BH character it finds. On exit, Register A will hold that character, and the C FLAG is set if its alphabetic, and NC FLAG if its alphanumeric. All strings must have a 00H at the end.
29EC-29EDJump forward to 29F3H if the string’s address in DE isn’t the same as the next available location in string space pointer in HL
29EELD B,A 47If is the last one defined then we need to update the current string pointer so first we load Register B with the value in Register A
29EFADD HL,BC 09Add the length of the string in BC to the next available location in string space pointer in HL
29F0-29F2LD (40D6H),HL LD (FRETOP),HL 22 D6 40Save the adjusted next available location in string space pointer in HL.
Note: 40D6H-40D7H holds the next available location in string space pointer
29F4RET C9RETurn to CALLer
29F5-2A02 – STRING ROUTINE – – “FRETMS”
Test to see if the string in DE is the last string used in the temporary string work area.
LD HL,(40B3H) LD HL,(TEMPPT) 2A B3 40Load HL with the temporary string work area pointer.
Note: 40B3H-40B4H holds the next available location in the temporary string work area pointer
29F8DEC HL 2BDecrement the value of the temporary string work area pointer in HL which backs up two words
29F9LD B,(HL) 46Load Register B with the MSB of the string’s address at the location of the temporary string work area pointer in HL
29FADEC HL 2BDecrement the value of the temporary string work area pointer in HL
29FBLD C,(HL) 4ELoad Register C with the LSB of the string’s address at the location of the temporary string work area pointer in HL
29FCDEC HL 2BDecrement the value of the temporary string work area pointer in HL
29FDWe 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.
29FERET NZ C0If the Z FLAG is set then we are done freeing space, so RETURN
LD (40B3H),HL LD (TEMPPT),HL 22 B3 40Save 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
2A02RET C9RETurn to CALLer
2A03-2A0E – LEVEL II BASIC LEN ROUTINE – “LEN”
2A03-2A05 LENLD BC,27F8H LD BC,SNGFLT 01 F8 27Load BC with the return address of 27F8H
2A06PUSH BC C5Save the return address of 27F8H (in BC) to the STACK
CALL 29D7H CALL FRESTRCD D7 29GOSUB to 29D7H to free up the temporary variable pointed to by FACLO
2A0AXOR A AFZero Register A so as to force a numeric flag
2A0BLD D,A 57Zero Register D so that DE can be used when E is set.
2A0CLD A,(HL) 7ELoad Register A with the string’s length at the location of the string’s VARPTR in HL
2A0DOR A B7Set the flags according to the string’s length in Register A
2A0ERET C9RETurn to CALLer
2A0F-2A1E – LEVEL II BASIC ASC ROUTINE – “ASC”
2A0F-2A11 ASCLD BC,27F8H LD BC,SNGFLT 01 F8 27Load BC with the return address of 27F8H
2A12PUSH BC C5Save the return address of 27F8H (in BC) to the STACK
CALL 2A07H CALL LEN1CD 07 2AGOSUB to 2A07H (which itself is a GOSUB to 29D7H) to get string’s VARPTR into HL and the string’s length into Register A
2A16-2A18JP Z,1E4AH JP Z,FCERRCA 4A 1EIf the Z FLAG is set, then this was a null string (bad argument), so display a ?FC ERROR
2A19INC HL 23Bump the value of the string’s VARPTR in HL
2A1ALD E,(HL) 5ELoad Register E with the LSB of the address of the string’s data at the location of the string’s VARPTR in HL
2A1BINC HL 23Bump the value of the string’s VARPTR in HL
2A1CLD D,(HL) 56Load Register D with the MSB of the address of the string’s data at the location of the string’s VARPTR in HL
2A1DLD A,(DE) 1ALoad Register A with the first character at the location of the string pointer in DE
2A1ERET C9RETurn to CALLer
2A1F-2A2E – LEVEL II BASIC CHR$ ROUTINE – “CHR$”
2A1F-2A20 CHR$LD A,01H 3E 01Load Register A with the length of the string to be created
2A21-2A23CALL 2857H CALL STRINICD 57 28GOSUB to 2857H to save the string’s length in Register A and value and set up the string’s address
2A24-2A26CALL 2B1FH CALL CONINTCD 1F 2BGOSUB to 2B1FH to evaluate the expression at the location of the current BASIC program pointer in HL and return with the integer result in DE
2A27-2A29 SETSTRLD HL,(40D4H) LD HL,(DSCTMP+1) 2A D4 40Load HL with the temporary string’s address
2A2ALD (HL),E 73Save the character in Register E at the location of the string pointer in HL
POP BC C1Clean up the STACK so that the RETURN address is another one that is next in the STACK.
2A2F-2A60 – LEVEL II BASIC STRING$ ROUTINE – “STRNG$”
We have the STRING$ command, but now we need the next character so we call a RST 10H to bump the value of the current BASIC program pointer until it points to the next character, call the EXAMINE NEXT SYMBOL routine at RST 10H.
The RST 10H routine parses the characters starting at HL+1 for the first non-SPACE,non-09H,non-0BH character it finds. On exit, Register A will hold that character, and the C FLAG is set if its alphabetic, and NC FLAG if its alphanumeric. All strings must have a 00H at the end.
2A30-2A31Since the character at the location of the current BASIC program pointer in HL must be a ( , call the COMPARE SYMBOL routine at RST 08H.
NOTE: The RST 08H routine compares the symbol in the input string pointed to by HL Register to the value in the location following the RST 08 call.- If there is a match, control is returned to the next execution address (i.e, the RST 08H instruction + 2) with the next symbol in the A Register and HL incremented by one.
- If the two characters do not match, a syntax error message is given and control returns to the Input Phase).
2A32-2A34CALL 2B1CH CALL GETBYTCD 1C 2BThis 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
2A34DEC HL 2BBackspace the code string. This is a Z-80 trick because this code was part of the above call instruction
2A35PUSH DE D5Save the string’s length (“N”) (currently in DE) to the STACK
2A36-2A37RST 08 ⇒ 2C SYNCHK “,” CF 2CNow we have STRING$(nnn so the next character needs to be a , . To test for the character at the location of the current BASIC program pointer in HL being a , , call the COMPARE SYMBOL routine which compares the symbol in the input string pointed to by HL Register to the value in the location following the RST 08 call. If there is a match, control is returned to address of the RST 08 instruction + 2 with the next symbol in the A Register and HL incremented by one. If the two characters do not match, a syntax error message is given and control returns to the Input Phase)
2A38-2A3ACALL 2337H CALL FRMEVLCD 37 23Now we have STRING$(xxx, and an expression so GOSUB to 2337H to evaluate the expression at the location of the current BASIC program pointer in HL and return with the result in ACCumulator
2A3B-2A3CNow 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).
2A3DEX (SP),HL E3We 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
2A3EPUSH HL E5Save the string’s length (“N”) in HL to the STACK so that we can test it to make sure it is an integer
2A3FWe need to check the value of the current data type flag, so we call the TEST DATA MODE routine at RST 20H.
NOTE: The RST 20H routine determines the type of the current value in ACCumulator and returns a combination of STATUS flags and unique numeric values in the A Register according to the data mode flag (40AFH). The results are returned as follows:- Integer = NZ/C/M/E and A is -1
- String = Z/C/P/E and A is 0
- Single Precision = NZ/C/P/O and A is 1
- and Double Precision is NZ/NC/P/E and A is 5.
2A42-2A44CALL 2B1FH CALL CONINTCD 1F 2BWe now know that “N” is at least a number, so we GOSUB to 2B1FH to convert the current result in ACCumulator to an integer and return with the 8-bit result in Register A
2A45-2A46JR 2A4AH JR CALSPA18 03Skip the next instruction (which would load the string address and 1st character) by jumping to 2A4AH
CALL 2A13H CALL ASC2CD 13 2AGo get the first character in the string and return with it in Register A. This is the character that will be repeated
2A4BPUSH AF F5Save the character for the string (held in Register A) to the STACK
2A4C SPACE2PUSH AF F5and then save it to the STACK again
2A4DLD A,E 7BLoad Register A with “N” (held in Register E)
2A4E-2A4FCALL 2857H CALL STRINICD 57 28GOSUB to 2857H to allocate N bytes in the temporary string work area
2A51LD E,A 5FLoad Register E with “N” (held in Register A)
2A52POP AF F1Get the character for the string (“X”) from the STACK and put it in Register A
2A53INC E 1CTo set the status flags we need to increase and then decrease E. First, bump the value of the string’s length in Register E
2A54DEC E 1D. and then decrement the string’s length in Register E
2A55-2A56If “N” was zero (so that the string is now complete), jump back to 2A2BH
2A57-2A59LD HL,(40D4H) LD HL,(DSCTMP+1) 2A D4 40If we are here, we have not finished building the STRING$ string so now we load HL with the string’s address and get ready to loop
LD (HL),A 77Save the character in Register A (“X”) at the location of the string pointer in HL
2A5BINC HL 23Bump the value of the string pointer in HL
2A5CDEC E 1DDecrement the string’s length in Register E
2A5D-2A5EJR NZ,2A5AH20 FBLoop back to 2A5AH to keep filling (HL) until the string of X’s has been completed
2A61-2A90 – LEVEL II BASIC LEFT$( ROUTINE – “LEFT$”
On entry, HL=address of LEFT$$, the STACK = string address, STACK+1 = n, and DE = code string address.
2A61-2A63 LEFT$CALL 2ADFH CALL PREAMCD DF 2AGo check the syntax. The character at the location of the current BASIC program pointer in HL must be a )
2A64XOR A AFZero Register A because the string pointer never changes
EX (SP),HL E3Exchange the value of the current BASIC program pointer in HL with the string’s VARPTR to the STACK
2A66LD C,A 4FZero Register C
2A67-2A68LD A,0E5H 3E E5Z-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
PUSH HL E5Save 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 LEFT2PUSH HL E5Save the value of the string’s VARPTR in HL to the STACK
2A6ALD A,(HL) 7ELoad Register A with the string’s length at the location of the string’s VARPTR in HL
2A6BCP B B8Check 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
2A6ELD A,B 78Load Register A with the new string’s TRUNCATED length in Register B
2A6F-2A71LD DE,000EH 11 0E 00Z-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
2A72PUSH BC C5Save the offset in BC to the STACK
2A76POP BC C1Get the offset from the STACK and put it in BC
2A77POP HL E1Get the string’s VARPTR from the STACK and put it in HL
2A78PUSH HL E5Save the string’s VARPTR in HL to the STACK
2A79INC HL 23Bump HL to now point to the address of the string
2A7ALD B,(HL) 46Load Register B with the LSB of the string’s address at the location of the string’s VARPTR in HL
2A7BINC HL 23Bump the value of the string’s VARPTR in HL
2A7CLD H,(HL) 66Load Register H with the MSB of the string’s address at the location of the string’s VARPTR in HL
2A7DLD L,B 68Load Register L with the LSB of the string’s address in Register B
2A7E-2A7FLD B,00H 06 00Zero Register B so that BC can be used
2A80ADD HL,BC 09Add the string’s length in BC to the string’s address in HL
2A81LD B,H 44Load Register B with the MSB of the string’s ending address in Register H
2A82LD C,L 4DLoad Register C with the LSB of the string’s ending address in Register L
2A83-2A85CALL 285AH CALL STRAD2CD 5A 28Go save the string’s length (held in A) and the string’s starting address (held in DE)
2A86LD L,A 6FLoad Register L with the string’s length (i.e., the number of characters to move) held in Register A
2A8APOP DE D1Clean up the STACK
2A91-2A99 – LEVEL II BASIC RIGHT$ ROUTINE – “RIGHT$”
2A91-2A93CALL 2ADFH CALL PREAMCD DF 2AGo check the syntax. The character at the location of the current BASIC program pointer in HL must be a )
2A94POP DE D1Get the string’s VARPTR from the STACK and put it in DE
2A95PUSH DE D5Save the string’s VARPTR in DE to the STACK
2A96LD A,(DE) 1ALoad Register A with the string’s length (held at the location of the string’s VARPTR in DE)
2A97SUB B 90Subtract the new string’s length in Register B from the string’s length in Register A to isolate the number of bytes
2A9A-2AC4 – LEVEL II BASIC MID$ ROUTINE – “MID$”
The original ROM source code clarifies that if the number provided is greater than the actual length of the string, a NULL value is returned. If the second number (the number of characters) exceeds the end of the string, the maximum amount of available characters are returned.
2A9A MID$EX DE,HL EBLoad HL with the value of the current BASIC program pointer (held in DE)
2A9BLD A,(HL) 7ELoad Register A with the terminal character, currently held at the location of the current BASIC program pointer in HL
2A9C-2A9ECALL 2AE2H CALL PREAM2CD E2 2AGOSUB to 2AE2H to get the offset in Register B and the string’s VARPTR in DE
2A9FINC B 04We need to set the status flags to correspond to the offset position value so we first bump the value of the string’s position in Register B
2AA0DEC B 05… and then we decrement the value of the string’s offset position in Register B
2AA4PUSH BC C5Save the value of the offset position (held in Register B) to the STACK
2AA5-2AA6LD E,0FFH 1E FFLoad Register E with the default string’s length of 256 in case no number of bytes are given
2AA7-2AA8CP 29H CP “)” FE 29More syntax checking. Here we need to test for a ) at the location of the current BASIC program pointer. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
2AA9-2AAAJR Z,2AB0H JR Z,MID228 05Jump to 2AB0H if the character at the location of the current BASIC program pointer in Register A is a )
2AAB-2AACIf it wasn’t a ) , it had best be a , so we need to test the character at the location of the current BASIC program pointer in HL by calling the COMPARE SYMBOL routine at RST 08H.
NOTE: The RST 08H routine compares the symbol in the input string pointed to by HL Register to the value in the location following the RST 08 call.- If there is a match, control is returned to the next execution address (i.e, the RST 08H instruction + 2) with the next symbol in the A Register and HL incremented by one.
- If the two characters do not match, a syntax error message is given and control returns to the Input Phase).
2AAD-2AAFCALL 2B1CH CALL GETBYTCD 1C 2BGo evaluate the expression at the location of the current BASIC program pointer in HL and return with the integer result in DE. Now the byte count is in DE as an integer
2AB0-2AB1Since 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).
2AB2POP AF F1Get the offset from the STACK and put it in Register A
2AB3EX (SP),HL E3Exchange the value of the current BASIC program pointer in HL with the value of the string’s VARPTR to the STACK
LD BC,2A69H LD BC,LEFT2 01 69 2ALoad BC with 2A69H as the return address (which is in the LEFT$ routine)
2AB7PUSH BC C5Save the return address in BC to the STACK
2AB8DEC A 3DDecrement the value of the requested offset in Register A so that we have a starting position minus 1
2AB9CP (HL) BECompare 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-2ABBLD B,00H 06 00Zero Register B
2ABCRET NC D0If the offset pointer ispast the end of the string we are going to return a null
2ABELD A,(HL) 7ELoad Register A with the string’s length at the location of the string’s VARPTR in HL
2ABFSUB C 91Subtract the index (the second argument) in Register C from the string’s length in Register A
2AC0CP E BBCompare 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.
2AC1LD B,A 47Load Register B with the calculated string’s length in Register A
2AC2RET C D8If we are not going to truncate, then just use the partial string we already have and Return to 2A69H
2AC4RET C9Return to 2A69H aka LEFT2
2AC5-2ADE – LEVEL II BASIC VAL ROUTINE – “VAL”
2AC5-2AC7 VALCALL 2A07H CALL LEN1CD 07 2AGo get the string’s length in Register A and the string’s VARPTR in HL
2AC8-2ACAJP Z,27F8H JP Z,SNGFLTCA F8 27Jump to 27F8H if the string’s length in Register A is equal to zero
2ACBLD E,A 5FLoad Register E with the string’s length at the location of the string’s VARPTR in HL.
The original ROM source explains that we need to do some fancy footwork here to handle the case where the two strings are stored next to each other.
2ACCINC HL 23Bump the value of the string’s VARPTR in HL
2ACDLD A,(HL) 7ELoad Register A with the LSB of the string’s address at the location of the string’s VARPTR in HL
2ACEINC HL 23Bump the value of the string’s VARPTR in HL
2ACFLD H,(HL) 66Load Register H with the MSB of the string’s address at the location of the string’s VARPTR in HL
2AD0LD L,A 6FLoad Register L with the LSB of the string’s address in Register A
2AD1PUSH HL E5Save the value of the string’s address in HL to the STACK
2AD2ADD HL,DE 19Add the string’s length in DE to the string’s address in HL
2AD3LD B,(HL) 46Load Register B with the last character of the string at the location of the string pointer in HL
2AD4LD (HL),D 72Save the zero in Register D at the location of the string pointer in HL
2AD5EX (SP),HL E3Exchange the string’s ending address in HL with the string’s address to the STACK
2AD6PUSH BC C5Save the last character of the string in Register B to the STACK
2AD7LD A,(HL) 7ELoad Register A with the first character of the argument
2AD8-2ADACALL 0E65H CALL FINDBLCD 65 0ECall 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)
2ADBPOP BC C1Get the modified character of the next string into Register B
2ADCPOP HL E1Get the pointer to the modified character back into HL
2ADDLD (HL),B 70Restore the character.
2ADERET C9RETurn 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.
2AE0-2AE1Since 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).
2AE3POP DE D1Get the number of bytes to isolate from the string (from the STACK) and put it in DE
2AE4PUSH BC C5Save the return address in BC to the STACK
2AE5LD B,E 43Load Register B with the number of bytes in Register E
2AE6RET C9RETurn to CALLer
2AE7H-2AEE – Process a LEFT-HAND-SIDE MID$ – “ISMID$”
CP 7AH CP MIDTK-$END FE 7AThis routine is designed to handle a left-size MID$ call. So check to see if the character at the location of the current BASIC program pointer in Register A is trying to process a left hand side MID$. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
2AE9-2AEBJP NZ,1997H JP NZ,SNERRC2 97 19Display a ?SN ERROR message if that is not what is going on.
2AEC-2AEEJP 41D9H JP DLHSMDC3 D9 41JUMP to DOS to see if DOS wants to deal with this.
2AEF-2AF7 – LEVEL II BASIC INP ROUTINE – “FNINP”
2AEF-2AF1 FNINPCALL 2B1FH CALL CONINTCD 1F 2BGo evaluate the expression at the location of the current BASIC program pointer in HL and return with the port number in Register A
2AF2-2AF4LD (4094H),A LD (STAINP+1),A 32 94 40Save the value of the port number (from Register A) into 4094H, which is in the middle of a routine.
2AF5-2AF1CALL 4093H CALL STAINP CD 1F 2BPerform in INP on the channel held in Register A
2AF8-2B00 – LEVEL II BASIC OUT ROUTINE – “FNOUT”
2AFB-2AFDJP 4096H JP OUTWRDCD 0E 2BDo the OUT and RETurn
2B01-2B0D – EVALUATE EXPRESSION ROUTINE
“GETINT”
This evaluates an expression and leaves the result in DE as an integer.
2B01 GETINTWe 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.
CALL 2337H CALL FRMEVLCD 37 23Go 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)).
2B06-2B08CALL 0A7FH CALL FRCINTCD 7F 0ACall 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)
2B09EX DE,HL EBLoad DE with the integer result in HL
2B0APOP HL E1Get the value of the current BASIC program pointer from the STACK and put it in HL
2B0BLD A,D 7ALoad Register A with the MSB of the integer result in Register D
2B0COR A B7Test the value of the MSB in Register A
2B0DRET C9RETurn to CALLer
2B0E-2B16 – EVALUATE EXPRESSION ROUTINE – OUT continues here – “SETIO”
CALL 2B1CH CALL GETBYTCD 1C 2BGOSUB to 2B1CH to evaluate the expression at the location of the current BASIC program pointer in HL and return with the 8-bit value in Register A
2B11-2B13LD (4094H),A LD (STAINP+1),A 32 94 40Save the 8-bit value in Register A in the DOS address of 4094H to set up for WAIT
2B14-2B16LD (4097H),A LD (OUTWRD+1),A 32 97 40Save the 8-bit value in Register A in the DOS address of 4097H to set up for OUT
2B17-2B1A – CHECK SYNTAX ROUTINE – This checks to see if the next character is a “ and contnues on to 2B1CH if it is, and errors out if it isn’t.
2B17-2B18Since 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).
2B1B-2B28 – EVALUATE EXPRESSION ROUTINE – This is called by PRINT TAB – “GTBYTC” .
2B1B GTBYTCWe need the next character in the BASIC program so call the EXAMINE NEXT SYMBOL routine at RST 10H.
The RST 10H routine parses the characters starting at HL+1 for the first non-SPACE,non-09H,non-0BH character it finds. On exit, Register A will hold that character, and the C FLAG is set if its alphabetic, and NC FLAG if its alphanumeric. All strings must have a 00H at the end.
2B1C – Common Conversion Routine – “GETBYT”
This routine converts a numeric ASCII string pointed to by the HL into a hexadecimal value and places the result in the A register. If the result is larger than 255 (FFH) then an FC ERROR (Illegal function call) will be generated. After execution the HL will point to the delimiter. If the delimiter is a zero byte or a colon (3AH) then the Z flag will be set. Any other delimiter will cause the Z flag to be reset.
2B1C-2B1E GETBYTCALL 2337H CALL FRMEVLCD 37 23GOSUB to 2337H to evaluate the formula/expression at the location of the current BASIC program pointer in HL and return with the result in REG l
2B1F-2B21 CONINTCALL 2B05H CALL INTFR2CD 05 2BGOSUB to 2B05H to convert the result in ACCumulator to an integer and return with the integer result in DE. Flags are set based on Register D.
2B22-2B24JP NZ,1E4AH JP NZ,FCERRC2 4A 1EIf the result is greater than 255, display a ?FC ERROR message
2B25DEC HL 2BDecrement the value of the current BASIC program pointer in HL
2B26We 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.
2B27LD A,E 7BLoad Register A with the 8-bit result in Register E so that both A and E have the result.
2B28RET C9RETurn 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 LLISTLD A,01H 3E 01Load Register A with the printer output device code
2B2B-2B2DLD (409CH),A LD (PRTFLG),A 32 9C 40Save the value in Register A as the current output device flag.
Note: 409CH holds the current output device flag: -1=cassette, 0=video and 1=printer
2B2E-2B74 – LEVEL II BASIC LIST ROUTINE – “LIST”
On entry the STACK has the return address, then the first basic line number to be listed, then the last basic line number to be listed.
2B2E LISTPOP BC C1Get rid of the the return address on the STACK
2B2F-2B31CALL 1B10H CALL SCNLINCD 10 1BGo evaluate the range of line numbers given at the location of the current BASIC program pointer in HL
2B32PUSH BC C5Save the address of the first BASIC line (held in BC) to the STACK
LD HL,FFFFH 21 FF FFLoad 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-2B38LD (40A2H),HL LD (CURLIN),HL 22 A2 40Save the value in HL as the current BASIC line number (which is stored at 40A2H-40A3H).
2B39POP HL E1Get the address of the first BASIC line to be listed (from the STACK) and put it in HL
2B3APOP DE D1Get the value of the last BASIC line number to be listed (from the STACK) and put it in DE
2B3BLD C,(HL) 4ELoad Register C with the LSB of the next BASIC line pointer at the location of the memory pointer in HL
2B3CINC HL 23Bump the value of the memory pointer in HL
2B3DLD B,(HL) 46Load Register B with the MSB of the next BASIC line pointer at the location of the memory pointer in HL
2B3EINC HL 23Bump the value of the memory pointer in HL
2B3FLD A,B 78Load Register A with the MSB of the next BASIC line pointer in Register B
2B40OR C B1Combine the LSB of the next BASIC line pointer in Register C with the MSB of the next BASIC line pointer in Register A. This will let us test for the end of the BASIC program
2B41-2B43JP Z,1A19H JP Z,READYCA 19 1AIf we are at the elast line, then STOP and JUMP to 1A19H to the READY PROMPT.
2B44-2B46CALL 41DFH CALL EXCHDSCD DF 41GOSUB to DOS to see if DOS wants to do anything here.
2B47-2B49CALL 1D9BH CALL ISCNTCCD 9B 1DGo scan the keyboard to see if the BREAK key or the shift – @ key was pressed
2B4APUSH BC C5Save the address of the next BASIC line in BC to the STACK
2B4BLD C,(HL) 4EWe 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
2B4CINC HL 23Bump the value of the memory pointer in HL
2B4DLD B,(HL) 46Load Register B with the MSB of the BASIC line number at the location of the memory pointer in HL
2B4EINC HL 23Bump the value of the memory pointer in HL
2B4FPUSH BC C5Save the BASIC line number in BC to the STACK
2B50EX (SP),HL E3Swap (SP) and HL so that the line number is now in HL
2B51EX DE,HL EBSwap DE and HL so that the last BASIC line number is now in HL
2B52We 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.
2B53POP BC C1Get the pointer to the location on the BASIC program line being processed and put it in BC
2B54-2B56JP C,1A18H JP C,STPRDYDA 18 1AIf the BASIC line number in DE is greater than the last BASIC line number in HL then we have gone past the end, so we are done processing!
2B57EX (SP),HL E3Swap (SP) and HL so that the last BASIC line number is now on the STACK
2B58PUSH HL E5Save the address of the next BASIC line in HL to the STACK
2B59PUSH BC C5Save the pointer to the location on the BASIC program line being processed to the STACK
2B5AEX DE,HL EBLoad HL with the BASIC line number (from DE)
2B5B-2B5DLD (40ECH),HL LD (DOT),HL 22 EC 40Save the BASIC line number in HL into DOT for use later in EDIT or LIST.
Note: 40ECH-40EDH holds EDIT line number
2B5E-2B60CALL 0FAFH CALL LINPRTCD AF 0FCall 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-2B62LD A,20H 3E 20Load Register A with a space
2B63POP HL E1Get the value of the memory pointer from the STACK and put it in HL
2B67-2B69CALL 2B7EH CALL BUFLINCD 7E 2BGOSUB to 2B7EH move the BASIC line at the location of the memory pointer in HL into the input buffer and untokenize the BASIC line
2B6A-2B6CLD HL,(40A7H) LD HL,(BUFPNT) 2A A7 40Load HL with the starting address of the input buffer.
Note: 40A7H-40A8H holds the input Buffer pointer
2B6D-2B6FCALL 2B75H CALL LISPRTCD 75 2BSince 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
2B75-2B7D – DISPLAY MESSAGE ROUTINE – “LISPRT”
This is the PRINT MESSAGE routine which writes string pointed to by HL to the current output device. String must be terminated by a byte of zeros. This call is different from 28A7H because it does not use the literal string pool area, but it does use the same display routine and it takes the same DOS Exit at 41C1H. Uses all registers. This routine can be called without loading the BASIC utility, if a C9H (RET) is stored in 41C1H.
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.
LD A,(HL) 7ELoad Register A with the character at the location of the memory pointer in HL
2B76OR A B7Check to see if the character in Register A is an end of the string character (00H)
2B77RET Z C8Return if the character in Register A is an end of the string character
CALL 032AH CALL OUTDOCD 2A 03Go send the character in Register A to the current output device
2B7BINC HL 23Bump the value of the memory pointer in HL
2B7C-2B7DJR 2B75H JR LISPRT18 F7Loop 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.
2B7F-2B81LD HL,(40A7H) LD HL,(BUFPNT) 2A A7 40Load HL with the starting address of the input buffer.
Note: 40A7H-40A8H holds the input Buffer pointer
2B82
2B83LD B,H
LD C,L 44LET Register Pair BC = Register Pair HL
2B84POP HL E1Get the value of the BASIC line pointer from the STACK and put it in HL
2B85-2B86LD D,FFH LD D,BUFLEN 16 FFLoad Register D with the maximum length of an untokenized line
2B8ADEC D 15Decrement the character count in Register D
2B8BRET Z C8Return if 256 characters have been moved into the input buffer
LD A,(HL) 7ELoad Register A with the character at the location of the BASIC line pointer in HL
2B8DOR A B7Set 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)
2B8EINC HL 23Bump the value of the BASIC line pointer in HL to the next character in the code string
2B8FLD (BC),A 02Save 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.
2B90RET Z C8Return if the character in Register A is an end of the BASIC line character
JP P,2B89H JP P,PLOOPF2 89 2BIf the character in A is just a regular character (i.e., not a token), then JUMP back to 2B89H
2B94-2B95CP 0FBH CP SNGQTK FE FBCheck to see if the character in Register A is a ‘ token. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
2B96-2B97Jump 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-2B9BDEC BC
DEC BC
DEC BC
DEC BC 0BFirst, 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-2B9FINC D
INC D
INC D
INC D 14Then, 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.
CP 95H CP $ELSE FE 95Check to see if the character in Register A is an ELSE token. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
2BA2-2BA4CALL Z,0B24H CALL Z,DCXVBRTCC 24 0BIf 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
DEC BC 0BThis 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-2BA6SUB 7FH D6 7FNext, 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
2BA7PUSH HL E5Save the value of the BASIC line pointer in HL to the STACK. Register L holds the reserved word number at this point.
2BA8LD E,A 5FLoad Register E with the character in Register A
2BA9-2BABLD HL,1650H LD HL,RESLST 21 50 16Load HL with the starting address of the reserved words list
LD A,(HL) 7ELoad Register A with the character at the location of the reserved words list pointer in HL
2BADOR A B7Test 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.
2BAEINC HL 23Bump the value of the reserved words list pointer in HL
2BAF-2BB1JP P,2BACH JP P,LOPRESF2 AC 2BIf the character at the location of the reserved words pointer in Register A doesn’t have bit 7 set then Jump back to 2BACH.
2BB2DEC E 1DDecrement the counter
2BB3-2BB4Jump back to 2BACH if this isn’t the reserved word for the token
2BB5-2BB6AND 7FH E6 7FReset bit 7 of the character in Register A by ANDing it against 0111 1111. This is to eliminate the MSB for “EDIT” and for disk I/O
LD (BC),A 02Save the character in Register A at the location of the input buffer pointer in BC
2BB8INC BC 03Bump the value of the input buffer pointer in BC
2BB9DEC D 15Decrement the value of the character counter in Register D
2BBA-2BBCJP Z,28D8H JP Z,PPSWRTCA D8 28If the Z FLAG has been set, then the character counter for the buffer has been exhausted and the buffer is now full, so JUMP back to 28D8H
2BBDLD A,(HL) 7ELoad Register A with the character at the location of the reserved words pointer in HL
2BBEINC HL 23Bump the reserved words pointer in HL
2BBFOR A B7Test the value of the character in Register A
2BC0-2BC2JP P,2BB7H JP P,MORPURF2 B7 2BKeep getting characters in this reserved word until we hit the next reserved word
2BC3POP HL E1Get the value of the BASIC line pointer from the STACK and put it in HL
2BC4-2BC5JR 2B8CH JR PLOOP218 C6Jump back to 2B8CH to continue processing the BASIC line being interpreted
2BC6-2BF4 – LEVEL II BASIC DELETE ROUTINE – “DELETE”
2BC6-2BC8 DELETECALL 1B10H CALL SCNLINCD 10 1BGOSUB to 1B10H to evaluate the line numbers at the location of the current BASIC program pointer in HL
2BC9POP DE D1Get the value of the last BASIC line number to be deleted (in binary) from the STACK and put it in DE
2BCAPUSH BC C5Save the address of the first BASIC line to be deleted in BC to the STACK
2BCBPUSH BC C5Save the address of the first BASIC line to be deleted in BC to the STACK AGAIN!
2BCC-2BCECALL 1B2CH CALL FNDLINCD 2C 1BGOSUB 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
Since the first line number provided MUST be found, if FNDLIN returns with the NC FLAG set (i.e., not found) we must JUMP to 2BD6H to show a ?FC ERROR
2BD1
2BD2LD D,H
LD E,L 54Let Register Pair DE = Register Pair HL
2BD3EX (SP),HL E3Exchange the last BASIC line’s address in HL with the first BASIC line’s address to the STACK
2BD4PUSH HL E5Save the pointer to the first line in range to the STACK
2BD5We 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.
JP NC,1E4AH JP NC,FCERRD2 4A 1EDisplay a ?FC ERROR message if the first BASIC lines address in HL is greater than or equal to the last BASIC line’s address in DE
2BD9-2BDBLD HL,1929H LD HL,REDDY 21 29 19Load HL with the starting address of the BASIC READY message
2BDC-2BDECALL 28A7H CALL STROUTCD A7 28Call the WRITE MESSAGE routine at 28A7H to print the message pointed to by HL.
2BDFPOP BC C1Get the first BASIC line’s address from the STACK and put it in BC
2BE0-2BE2LD HL,1AE8H LD HL,FINI 21 E8 1ALoad HL with the return address
2BE3EX (SP),HL E3Swap (SP) and HL so that HL now points to the next BASIC line’s address …
2BE5-2BE7LD HL,(40F9H) LD HL,(VARTAB) 2A F9 40Load HL with the end of the BASIC program pointer.
- Note: 40F9H-40FAH holds the starting address of the simple variable storage area.
LD A,(DE) 1ALoad Register A with the character at the location of the memory pointer in DE
2BE9LD (BC),A 02Save the character in Register A at the location of the memory pointer in BC
2BEAINC BC 03Bump the value of the memory pointer in BC
2BEBINC DE 13Bump the value of the memory pointer in DE
2BECNow we need to check to see if the memory pointer in DE equals the end of the BASIC program pointer in HL, so we call the COMPARE DE:HL routine at RST 10H.
The RST 10H routine parses the characters starting at HL+1 for the first non-SPACE,non-09H,non-0BH character it finds. On exit, Register A will hold that character, and the C FLAG is set if its alphabetic, and NC FLAG if its alphanumeric. All strings must have a 00H at the end.
2BED-2BEELoop back to 2BE8H until the memory pointer in DE equals the end of the BASIC program pointer in HL
2BEFLD H,B 60Load Register H with the MSB of the memory pointer in Register B
2BF0LD L,C 69Load Register L with the LSB of the memory pointer in Register C
2BF1-2BF3LD (40F9H),HL LD (VARTAB),HL 22 F9 40Save 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.
2BF4RET C9RETurn to CALLer
2BF5-2C1E – LEVEL II BASIC CSAVE ROUTINE – “CSAVE”
The original ROM source code says that the CSAVE command dump’s BASIC’s core. Three D3H’s are written, followed by a 1 character filename. At the end 3 zeros in a row are written.
2BF5-2BF7 CSAVECALL 0284H CALL CWRTONCD 84 02Calls the WRITE LEADER routine at 0284H (which writes a Level II leader on the cassette unit set in Register A)
2BF8CALL 2337H CALL FRMEVLCD 37 232BFAH Go evaluate the rest of the CSAVE expression at the location of the current BASIC program pointer in HL and return with the result in REG l
2BFBPUSH HL E5Save the value of the current BASIC program pointer in HL to the STACK so we can get it back at the end of the routine
2BFF-2C00LD A,D3H 3E D3Load Register A with the filename header byte (=D3H which is a “S” with the sign bit on)
2C01-2C03CALL 0264H CALL CASOUTCD 64 02the 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
2C07LD A,(DE) 1ALoad Register A with the first character of the filename at the location of the filename pointer in DE
2C08-2C0ACALL 0264H CALL CASOUTCD 64 02the 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-2C0DLD HL,(40A4H) LD HL,(TXTTAB) 2A A4 40Load 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).
2C0EEX DE,HL EBLoad DE with the start of the BASIC program pointer in HL
2C0F-2C11LD HL,(40F9H) LD HL,(VARTAB) 2A F9 40Load HL with the end of the BASIC program pointer.
- Note: 40F9H-40FAH holds the starting address of the simple variable storage area.
LD A,(DE) 1ATop 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
2C13INC DE 13Bump the value of the memory pointer in DE
2C14-2C16CALL 0264H CALL CASOUTCD 64 02the 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)
2C17Now we need to check to see if the memory pointer in DE is equal to the end of the BASIC program pointer in HL, so we call the COMPARE DE:HL routine at RST 10H.
The RST 10H routine parses the characters starting at HL+1 for the first non-SPACE,non-09H,non-0BH character it finds. On exit, Register A will hold that character, and the C FLAG is set if its alphabetic, and NC FLAG if its alphanumeric. All strings must have a 00H at the end.
2C18-2C19Loop back to 2C12H until the memory pointer in DE is equal to the end of the BASIC program pointer in HL
2C1DPOP HL E1Get the value of the current BASIC program pointer from the STACK and put it in HL
2C1ERET C9RETurn to CALLer
2C1F-2CA4 – LEVEL II BASIC CLOAD ROUTINE – ROM v1.0 – “CLOAD”
2C22LD A,(HL) 7ELoad Register A with the character at the location of the current BASIC program pointer in HL
2C23-2C24SUB 0B2H SUB $PRINT D6 B2Check to see if the character at the location of the current BASIC program pointer in Register A is a ? , meaning that CLOAD? was requested.
Jump to the CLOAD? routine at 2C29H if the character at the location of the current BASIC program pointer in Register A is a ?
2C27XOR A AFOK – So this is now a straight CLOAD . First, zero Register A
2C28LD BC,232F 01 2F 23Z-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
2C2AINC HL 23Bump the value of the current BASIC program pointer in HL until it points to the next character after the ? in CLOAD?
2C2BPUSH AF F5Save the CLOAD / CLOAD? flag in Register A to the STACK
2C2CDEC HL 2BDecrement the value of the current BASIC program pointer in HL so we can see if we are at the end
2C2DWe need the next character in the BASIC program so call the EXAMINE NEXT SYMBOL routine at RST 10H.
The RST 10H routine parses the characters starting at HL+1 for the first non-SPACE,non-09H,non-0BH character it finds. On exit, Register A will hold that character, and the C FLAG is set if its alphabetic, and NC FLAG if its alphanumeric. All strings must have a 00H at the end.
2C2E-2C2FLD A,00H 3E 00Zero Register A to allow for any filename
2C30-2C31Jump if the character at the location of the current BASIC program pointer in HL is an end of the BASIC statement character
2C32-2C34CALL 2337H CALL FRMEVLCD 37 23To get the filename we need to GOSUB to 2337H to evaluate the expression at the location of the current BASIC program pointer in HL and return with the result in ACCumulator
2C35-2C37CALL 2A13H CALL ASC2CD 13 2AMake sure the length is good, and save the pointer to the filename to Register Pair DE
2C38LD A,(DE) 1ALoad Register A with the first character of the filename at the location of the filename pointer in DE
2C3APOP AF F1Get the value of the CLOAD / CLOAD? flag from the STACK and put it in Register A
2C3BOR A B7Test the value of the CLOAD / CLOAD? flag in Register A (since CPL doesn’t set any flags)
2C3CLD H,A 67Load Register H with the value of the CLOAD / CLOAD? flag in Register A
2C3D-2C3FLD (4121H),HL LD (FACLO),HL 22 21 41Save the value of the CLOAD / CLOAD? flag and the filename in HL in ACCumulator
2C43-2C45LD HL,(4121H) LD HL,(FACLO) 2A 21 41Load HL with the CLOAD / CLOAD? flag and the filename in ACCumulator
*2C1F-2CA4 – LEVEL II BASIC CLOAD ROUTINE – ROM v1.3
*2C1FSUB 0B2HTest for CLOAD?
*2C23XOR ASo we know that we have a CLOAD and not a CLOAD?, so clear Register A and continue
*2C2401Z-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
CPLSince A is Zero going into this command, once this complement code is exected, A=-1 if CLOAD?, 0000 if CLOAD
*2C26INC HLIncrement HL to the filname of the CLOAD / CLOAD? flag
*2C27PUSH AFSave the CLOAD / CLOAD? flag in Register A to the STACK
*2C28LD A,(HL)Set the next element from the code string, which should be the filename
*2C29OR ASet status flags
*2C32LD A,(DE)Get the filename
*2C33LD L,AMove the filename into Register L
*2C34POP AFRestore the CLOAD / CLOAD? flag
*2C35OR ASet the status Register according to that flag
*2C36LD H,AH will now hold CLOAD / CLOAD? flag, and L will hold the filename
*2C37LD (4121H),HL LD (FACLO),HLPut the flag and filename into ACCumulator
*2C3DLD HL,0000HCause the drive to be selected
*2C43LD HL,(4121H) LD HL,(FACLO)Restore the CLOAD / CLOAD? flag and filename
Common code between ROM v1.0 and v1.2 continues here.
2C46EX DE,HL EBLoad D with the CLOAD/CLOAD? flag and load Register E with the filename
CALL 0235H CALL CASINCD 35 02Calls 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-2C4DSUB 0D3H D6 D3Check to see if the character in Register A is a filename header byte
2C4E-2C4FLoop if the character in Register A isn’t a filename header byte
2C50-2C51Loop back to 2C49H until three filename header bytes have been read
2C52-2C54CALL 0235H CALL CASINCD 35 02Now 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)
2C55INC E 1CWe 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
2C56DEC E 1DDecrement the value of the filename in Register E
2C57-2C58Jump to 2C5CH (to pretend the filename matched) if no filename was specified
2C59CP E BBIf we are here, then the user has supplied a filename which is held in Register E AND we have the first byte from the tape in Register A, so we need to compare the filename specified in Register E with the character in Register A. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
2C5A-2C5BJump 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
LD HL,(40A4H) LD HL,(TXTTAB) 2A A4 40If 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.
LD B,03H 06 03Load Register B with the number of zeros to look for to stop the load (which is 3)
CALL 0235H CALL CASINCD 35 02Calls 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)
2C64LD E,A 5FPreserve the character that was just read from tape into Register E
2C65SUB (HL) 96Compare 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
2C66AND D A2Combine the subtracted result in Register A with the value of the CLOAD / CLOAD? flag in Register D. Why is this tricky? Because D is always 0 for a CLOAD, so when you AND against 0, you always get 0. If this was CLOAD?, nothing would happen as a result of this.
2C67-2C68Jump to 2C8AH if CLOAD? was selected but the bytes don’t match
2C69LD (HL),E 73At this point either CLOAD? was selected and the bytes match, or CLOAD was selected. Either way, save the character we read from the tape (held in Register E) to the location of the memory pointer in HL
2C6A-2C6CCALL 196CH
CALL REASONCD 6C 19Make sure there is more room, and toss a ?OM ERROR if there isn’t.
2C6DLD A,(HL) 7ELoad Register A with the character at the location of the memory pointer in HL
2C6EOR A B7Check to see if the byte just read in Register A is equal to zero
2C6FINC HL 23Bump the value of the memory pointer in HL
2C70-2C71Loop if the byte in Register A isn’t equal to zero (meaning that it isn’t end of program or end of statement)
2C72-2C74CALL 022CH CALL BCASINCD 2C 02Call the BLINK ASTERISK routine at 022CH which alternatively displays and clears an asterisk in the upper right hand corner of the video display
2C75-2C76Do that loop until three zeros in a row have been read from the cassette recorder
2C77-2C79LD (40F9H),HL LD (VARTAB),HL 22 F9 40By 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 OKCASSLD HL,1929H LD HL,REDDY 21 29 19Load HL with the starting address of the BASIC READY message
2C75-2C76Do that loop until three zeros in a row have been read from the cassette recorder
2C83-2C85LD HL,(40A4H) LD HL,(TXTTAB) 2A A4 40Load 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).
2C86PUSH HL E5Save the start of the BASIC program pointer in HL to the STACK. FINI will need this value there.
LD HL,2CA5H LD HL,NOOKCS 21 A5 2CLoad HL with the starting address of the BAD message
2C8D-2C8FCALL 28A7H CALL STROUTCD A7 28Call the WRITE MESSAGE routine at 28A7H to print the message pointed to by HL.
NOTE:
- The routine at 28A7 displays the message pointed to by HL on current system output device (usually video).
- The string to be displayed must be terminated by a byte of machine zeros or a carriage return code 0D.
- If terminated with a carriage return, control is returned to the caller after taking the DOS exit at 41D0H (JP 5B99H).
2C90-2C92JP 1A18 JP STPRDYC3 18 1AJUMP to STPRDY to pop NEWSTT from the STACK and then fall into the READY routine
LD B,03H 06 03Load Register B with the number of zeros to be found to stop the search
CALL 0235H CALL CASINCD 35 02Calls 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)
2C9BOR A B7Check to see if the character in Register A is equal to zero
2C9E-2C9FLoop until three zeros in a row have been read from the cassette recorder
2CA0-2CA2CALL 0296H CALL CSRDON + 3CD 96 02Calls 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)
2CA5-2CA9 – MESSAGE STORAGE LOCATION – “NOOKCS”
2CA5-2CA9 NOOKCS“BAD” + 0DH + 00H 42The BAD message is stored here
2CAA-2CB0 – LEVEL II BASIC PEEK ROUTINE – “PEEK”
The original ROM source code says that PEEK only accepts positive numbers up to 32767 and POKE will only take an address up to 32767. Negative numbers can be used to refer to locations higher than 32767, the correspondence is given by subtracting 65536 from locations higher than 32767 or by specifying a positive number up to 65535
On entry, ACCumulator to have the peek location, and on exit ACCumulator to have the peeked value.
2CAA-2CAC PEEKCALL 0A7FH CALL FRCINTCD 7F 0ACall 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)
2CADLD A,(HL) 7ELoad Register A with the value at the location of the memory pointer in HL
2CAE-2CB0JP 27F8H JP SNGFLTC3 F8 27Go save the 8-bit value in Register A as the current result in ACCumulator
2CB1-2CBC – LEVEL II BASIC POKE ROUTINE – “POKE”
2CB1-2CB3 POKECALL 2B02H CALL GETIN2CD 02 2BGo evaluate the expression at the location of the current BASIC program pointer in HL and return with the integer result in DE
2CB4PUSH DE D5Save the address the user wants to POKE to (held in DE) to the STACK
2CB5-2CB6Since the character at the location of the current BASIC program pointer in HL must be a , , call the COMPARE SYMBOL routine at RST 08H.
NOTE: The RST 08H routine compares the symbol in the input string pointed to by HL Register to the value in the location following the RST 08 call.- If there is a match, control is returned to the next execution address (i.e, the RST 08H instruction + 2) with the next symbol in the A Register and HL incremented by one.
- If the two characters do not match, a syntax error message is given and control returns to the Input Phase).
2CB7-2CB9CALL 2B1CH CALL GETBYTCD 1C 2BGOSUB 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
2CBAPOP DE D1Get the address the user wants to POKE to from the STACK and put it in DE
2CBBLD (DE),A 12Save the value the user wanted to poke (held in Register A) in the location that the user wants to POKE to (held in DE)
2CBCRET C9RETurn 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
Vernon Hester has reported an error in the PRINT USING routine. A PRINT USING statement with a negative sign at the end of the field prints a negative sign after negative numbers and prints a space for positive numbers. However, if the field specifiers in the string also has two asterisks at the beginning of the field, the ROM prints an asterisk instead of a space after a positive number.
Example: PRINT USING “**####-“;1234 will display **1234* instead of **1234 SPACE
CALL 2338H CALL FRMCHKCD 38 23Go evaluate the string expression at the location of the current BASIC program pointer in HL
2CC0-2CC2CALL 0AF4H CALL CHKSTRCD F4 0AGo make sure the expression that was just evaluated was a string
2CC3-2CC4Since 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).
2CC5EX DE,HL EBSwap DE and HL so that DE now holds the current BASIC program pointer
2CC6-2CC8LD HL,(4121H) LD HL,(FACLO) 2A 21 41Load HL with the USING string’s VARPTR
LD A,(40DEH) LD A,(FLGINP) 3A DE 40Load Register A with the value of the READ/INPUT flag, which is being used here to track if we printed out a value on the prior scan.
2CCEOR A B7Check to see if that flag indivates that we did, or did not, print out a value last time.
2CCF-2CD0If we did not print out a value last time, we have an error, so JUMP down to 2CDDH
2CD1POP DE D1Restore the pointer to the “USING” string decription from the STACK into DE
2CD2EX DE,HL EBSwap 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.
PUSH HL E5Save the pointer to the “USING” string descriptor (i.e., the USING string’s VARPTR) in HL to the STACK
2CD4XOR A AFZero Register A and all the flags.
2CD5-2CD7LD (40DEH),A LD (FLGINP),A 32 DE 40Clear the flag we are using to see if we printed the values or not.
2CD8CP D BATurn 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.
2CD9PUSH AF F5Save the flag indicating if the value list has ended or not to the STACK
2CDAPUSH DE D5Save the pointer into the value list to the STACK
2CDBLD B,(HL) 46Load Register B with the USING string’s length
2CDCOR B B0Check to see if the USING string’s length in Register B is equal to zero
2CE0INC HL 23Bump the pointer to the USING string’s data in HL by 1
2CE1LD C,(HL) 4ELoad Register C with the LSB of the USING string’s address at the location of the USING string’s VARPTR in HL
2CE2INC HL 23Bump the value of the USING string’s VARPTR in HL
2CE3LD H,(HL) 66Load Register H with the MSB of the USING string’s address at the location of the USING string’s VARPTR in HL
2CE4LD L,C 69Load Register L with the LSB of the USING string’s address in Register C
2CE8PUSH HL E5Save the pointer to the USING string pointer in HL to the top of the STACK
2CE9-2CEALD C,02H 0E 02Since the \\ string field length is two plus number of enclosed spaces, add two
LD A,(HL) 7ELoad Register A with the character at the location of the USING string pointer in HL
2CECINC HL 23Bump the value of the USING string data pointer in HL
2CED-2CEECP 25H CP CSTRNG FE 25Check to see if the character in Register A is a %, which acts as a field terminator. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
2CEF-2CF1JP Z,2E17H JP Z,ISSTRFCA 17 2EIf it is a “%” then JUMP to 2E17H to evaluate a string and print
2CF2-2CF3CP 20H FE 20Check to see if the character in Register A is a ” “, which acts as a field extender. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
2CF4-2CF5If the character is not a field extender, then it isn’t a string field, so JUMP down a few opcodes to 2CF9H
2CF6INC C 0CIncrement the field width (tracked in in Register C)
2CF7-2CF8Decrement 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 NOSTRFPOP HL E1Restore the pointer to the “USING” string’s data into Register Pair HL
2CFALD B,E 43Load Register B with the USING string’s length
2CFB-2CFCLD A,25H LD A,CSTRNG 3E 25Restore 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
CALL 2E49H CALL PLSPRTCD 49 2EIf a + came before the character, make sure to print it
2D00-2D02CALL 032AH CALL OUTDOCD 2A 03Once that has been printed, now we print the character in Register A since we know it isn’t part of a field
XOR A AFWe 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
2D04LD E,A 5FZero Register E
2D05LD D,A 57Zero Register D
CALL 2E49H CALL PLSPRTCD 49 2EGo print a leading + if necessary (i.e., to allow for multiple plusses)
2D09LD D,A 57Set 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.
2D0ALD A,(HL) 7ELoad Register A with the next field description character in the USING string
2D0BINC HL 23Bump the value of the USING string pointer in HL
2D0C-2D0DCP 21H CP “!” FE 21Check 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.
2D11-2D12CP 23H CP “#” FE 23Check 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.
2D15DEC B 05Since every other possibility is actually a two character field, decrement the value of the string’s length in Register B onem ore time
2D16-2D18JP Z,2DFEH JP Z,REUSINCA FE 2DIf 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-2D1ACP 2BH CP “+” FE 2BCheck 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-2D1CLD A,08H 3E 08Set 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
2D1FDEC HL 2BDecrement the value of the USING string pointer so we can re-get the character.
2D20LD A,(HL) 7ELoad Register A with the (current) character at the location of the USING string pointer in HL
2D21INC HL 23Bump the value of the USING string pointer in HL
2D22-2D23CP 2EH CP “.” FE 2ECheck to see if the character in Register A is a . (i.e., a numeric field with trailing digits). If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
2D24-2D25Jump if the character in Register A is a . to scan with Register E holding the number of digits before the “.” as 0
2D26-2D27CP 25H CP CSTRNG FE 25Check to see if the character in Register A is a % (i.e., a really big string field). If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
2D28-2D29Jump to see if it is really a string field if the character in Register A is a %
2D2ACP (HL) BECheck to see if the next character matches the current character in the the USING string. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
2D2B-2D2CIf the NZ flag is set, then we can’t have a $$ or a ** , so all remaining possibilities are exhausted, so JUMP to NEWUCH
2D2D-2D2ECP 24H CP “$” FE 24Check 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.
2D31-2D32CP 2AH CP “*” FE 2ACheck to see if the double character is a ** . If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
2D33-2D34If 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
2D35LD A,B 78Prepare 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-2D37CP 02H FE 02Check 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.
2D38INC HL 23Bump the value of the USING string pointer in HL
2D39-2D3AJump to 2D3EH if the USING string’s length in Register A isn’t at least two
2D3BLD A,(HL) 7ELoad Register A with the character at the location of the USING string pointer in HL
2D3C-2D3DCP 24H CP “$” FE 24Check 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.
2D40-2D41If we did not ultimately get a **$ then JUMP (noting we do NOT set the dollar sign flag)
2D42DEC B 05Decrement the value of the USING string’s length to take the $ into account
2D43INC E 1CBump the field width tracker to account for the floating dollar sign
2D44-2D45CP 0AFH FE AFZ-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.
2D46-2D47ADD A,10H C6 10Mask Register A to set the bit for a floating dollar sign flag.
2D48INC HL 23Bump the value of the USING string pointer in HL to go past the special characters
2D4AADD A,D 82Combine the bits in Register D into the flag tracker
2D4BLD D,A 57Preserve the modified flag tracker into Register D.
2D4D-2D4ELD C,00H 0E 00Set the number of digits to the right of the decimal point (tracked in Register C) to 0
2D4FDEC B 05Check to see if there are any more characters by decrementing the value of the string’s length in Register B
2D50-2D51If 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.
2D52LD A,(HL) 7ELoad Register A with the next character at the location of the USING string pointer in HL
2D53INC HL 23Bump the value of the USING string pointer in HL
2D54-2D55CP 2EH CP “.” FE 2ECheck to see if the character in Register A is a . (i.e., a trailing digit). If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
2D56-2D57If yes, then need to use a special scan loop to scan after the decimal point, so JUMP to AFTDOT
2D58-2D59CP 23H CP “#” FE 23Check to see if the character in Register A is a # (i.e., a leading digit). If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
2D5A-2DIf yes, increment the count and keep scanning via a JUMP to NUMNUM
2D5C-2D5DCP 2CH CP “,” FE 2CCheck to see if the character in Register A is a , . If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
2D5E-2D5FIf there is no comma, then JUMP to FINNUM because there are no more leading digits and we need to check for “^^^”
2D60LD A,D 7AIf we are here, then a comma was requested. Turn on the COMMA bit
2D61-2D62OR 40H F6 40Mask the flag in Register A for ,
2D63LD D,A 57Load Register D with the value of the flag in Register A
2D66 – Part of the PRINT USING Routine – “DOTNUM”
Jumped here when a “.” is seen in the USING string. THis means that we are starting a numeric field ONLY if it is followed by a “#”
2D66 DOTNUMLD A,(HL) 7ELoad Register A with the next character of the USING string
2D67-2D68CP 23H FE 23Check to see if the character in Register A is a # (i.e., a numeric field following a “.”). If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
2D69-2D6ALD A,2EH LD A,”.” 3E 2ELoad Register A with a decimal point
2D6B-2D6CIf it isn’t a “.” then JUMP AWAY to NEWUCH with A holding a “.” so that a “.” will get printed
2D6D-2D6ELD C,01H 0E 01If it was a “.” then we have a numeric field to process. First, set C with the number of characters to the right of the decimal point
2D6FINC HL 23Bump the value of the USING string pointer in HL
INC C 0CBump the number of digits to the right of the decimal point (tracked in Register C)
2D71DEC B 05Decrement the value of the USING STRING’s length to test to see if there are more characters
2D72-2D73If the USING string length is now ZERO, JUMP to ENDNUS to stop scanning
2D74LD A,(HL) 7ELoad Register A with the character at the location of the USING string pointer in HL
2D75INC HL 23Bump the value of the USING string pointer in HL
2D76-2D77CP 23H FE 23Check to see if the character in Register A is a # ; meaning that there are more digits after the decimal point. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
2D78-2D79If 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
PUSH DE D5Save the value of the flag (tracked in D) and the number of leading digits (tracked in E) to the STACK
2D7B-2D7DLD DE,2D97H LD DE,NOTSCI 11 97 2DLoad DE with the return address in case this is not a scientific notation
2D7EPUSH DE D5Save the value of the return address in DE to the STACK
2D7F
2D80LD D,H
LD E,L 54Let DE = HL in case we need to rememer HL
2D81-2D82CP 5BH FE 5BCheck 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.
2D83RET NZ C0Return if the character in Register A isn’t an up arrow
CP (HL) BECheck 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.
2D85RET NZ C0Return 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)
2D87CP (HL) BECheck 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.
2D88RET NZ C0Return 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)
2D8ACP (HL) BECheck 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.
2D8BRET NZ C0Return 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)
INC HL 23Bump the value of the USING string pointer in HL. If we are here we have a #.^^^^ format
2D8DLD A,B 78Now 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-2D8FSUB 04H D6 04Check to see if there are at least 4 characters left in the USING string
2D90RET C D8Return to 2D97 if there aren’t at least four characters left in the USING string
POP DE D1If there are at least 4 characters left, then clean up the STACK by removing the NOTSCI return address
2D92POP DE D1Get the flag and the count of the characters to the left of the decimal point from the STACK and put it in DE
2D93LD B,A 47Load Register B with the new USING string’s length in Register A
2D94INC D 14Set the exponential notation flag (tracked in Register D)
2D95INC HL 23Bump the value of the USING string pointer in HL
2D96JP Z,0D1EBH CA EB D1Z-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,HL EB(Ignored if passing through) Restore the old HL into HL
2D98POP DE D1(Ignored if passing through) Restore the flags into Register D and the number of leading digits into Register E
LD A,D 7AWe 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
2D9ADEC HL 2BDecrement the value of the USING string pointer in HL
2D9BINC E 1CBump the number of characters to the left of the decimal point in Register E to take into account the leading plus
2D9C-2D9DAND 08H E6 08Mask Register A to NOT check for a trailing sign
2D9E-2D9FIf that AND leaves us with a NZ, then we are all done with the field, so JUMP to ENDNUM
2DA0DEC E 1DOtherwise, 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
2DA1LD A,B 78Check to see if there are more characters by first loading Register A with the USING string’s length from Register B
2DA2OR A B7Check to see if this is the end of the USING string
2DA3-2DA4If we are out of characters, then we are all done, so JUMP to ENDNUM
2DA5LD A,(HL) 7EIf there ARE more characters, then fill Register A with the character at the location of the USING string pointer in HL
2DA6-2DA7SUB 2DH SUB “-“ D6 2DCheck to see if the character in Register A is a – (i.e., a trailing minus)
2DAA-2DABCP 0FEH CP “+” – “-“ FE FECheck 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.
2DAE-2DAFLD A,08H 3E 08If we are here then we did have a trailing “+” so first set the flag for a POSITIVE “+”
2DB2ADD A,D 82Combine the value of the flag in Register D with the value of the flag in Register A
2DB3LD D,A 57Load Register D with the current flags
2DB4DEC B 05Decrement the value of the USING string’s length in Register B by 1 to account for the trailing sign
2DB5 – Part of the PRINT USING Routine – “ENDNUM”
Jump point for when we figure out that we are at the end of a string of digits within a USING string
2DB5 ENDNUMPOP HL E1Get the value of the current BASIC program pointer from the STACK and put it in HL
2DB6POP AF F1Load Register A with the flag that tells us whether there are more values to process in the value list.
2DB7-2DB8If there are no more values in the value list to process, then JUMP to FLDFIN because we are done with the PRINT
2DB9PUSH BC C5Save 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
2DBAPUSH DE D5Save the flags (held in D) and the number of leading digits (held in E) to the STACK
2DBB-2DBDCALL 2337H CALL FRMEVLCD 37 23Read 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
2DBEPOP DE D1Restore the flags (held in D) and the number of leading digits (held in E) from the STACK
2DBFPOP BC C1Restore 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
2DC0PUSH BC C5Save 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
2DC1PUSH HL E5Save the value of the current BASIC program pointer in HL to the STACK
2DC2LD B,E 43Set Register B to hold the number of leading digits (i.e., the number of characters to the left of the decimal point)
2DC3LD A,B 78We 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
2DC4ADD A,C 81Then 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-2DC6CP 19H FE 19Check to see if the total number of characters in Register A is greater than 24. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
2DC7-2DC9JP NC,1E4AH JP NC,FCERRD2 4A 1EDisplay a FC ERROR message if the total number of digits is greater than 24
2DCALD A,D 7ALoad Register A with the flags (held in Register D)
2DCB-2DCCOR 80H F6 80Turn on the “USING” bit in the flags
2DCD-2DCFCALL 0FBEH CALL PUFOUTCD BE 0FPrepare to print by calling the FLOATING TO ASCII routine at 0FBEH (whcih converts a single or double precision number in ACCumulator to its ASCII equivalent which will be stored at the buffer pointed to by HL using the format codes in the A, B, and C registers
2DD0-2DD2CALL 28A7H CALL STROUTCD A7 28Call the WRITE MESSAGE routine at 28A7H to print the message pointed to by HL.
NOTE:
- The routine at 28A7 displays the message pointed to by HL on current system output device (usually video).
- The string to be displayed must be terminated by a byte of machine zeros or a carriage return code 0D.
- If terminated with a carriage return, control is returned to the caller after taking the DOS exit at 41D0H (JP 5B99H).
POP HL E1Top of a loop. Get the value of the current BASIC program pointer from the STACK and put it in HL
2DD4DEC HL 2BDecrement the value of the current BASIC program pointer in HL so we can test to see what the terminator was
2DD5We 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.
2DD6SCF 37Set the Carry flag to indicate that a CRLF is desired
2DD7-2DD8If 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-2DDBLD (40DEH),A LD (FLGINP),A 32 DE 40Set the flag that the value HAS been printed!
2DDC-2DDDCP 3BH CP “;” FE 3BCheck 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.
2DE0-2DE1CP 2CH CP “,” FE 2CCheck to see if the character at the location of the current BASIC program pointer in Register A is a comma. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
2DE2-2DE4JP NZ,1997H JP NZ,SNERRC2 97 19If 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.
POP BC C1Restore the number of characters remaining to be procesed in the USING string into Register B
2DE7EX DE,HL EBSwap DE and HL so that DE will point to the location of the current BASIC program pointer. We don’t care about HL.
2DE8POP HL E1Restore the position in the USING string from the STACK and put it in HL
2DE9PUSH HL E5Save the position in the USING string (held in HL) to the STACK
2DEAPUSH AF F5Save the flag that indicates whether or not the value list has terminated to the STACK
2DEBPUSH DE D5Save 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.
2DECLD A,(HL) 7ELoad Register A with the USING string’s length at the location of the USING string’s VARPTR in HL
2DEDSUB B 90Subtract the number of characers which were already scanned
2DEEINC HL 23Bump the pointer to the “USING” strings string data
2DEFLD C,(HL) 4ELoad Register C with the LSB of the USING string’s address at the location of the USING string’s VARPTR in HL
2DF0INC HL 23Bump the value of the USING string’s VARPTR in HL
2DF1LD H,(HL) 66Load Register H with the MSB of the USING string’s address at the location of the USING string’s VARPTR in HL
2DF2LD L,C 69Load Register L with the LSB of the USING string’s address in Register C
2DF3-2DF4LD D,00H 16 00Zero Register D so that Register Pair DE can be a 16 bit offset of whatever is held in A.
2DF5LD E,A 5FLoad Register E with the USING string’s offset in Register A
2DF6ADD HL,DE 19Add 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
2DF7LD A,B 78Load Register A with the number of characters left to scan
2DF8OR A B7Check to see if this is the end of the USING string
2DF9-2DFBJP NZ,2D03H JP NZ,PRCCHRC2 03 2DIf there are still more string characters to scan, JUMP to PRCCHR to do so
2DFE-2E00 – Part of the PRINT USING Routine – “REUSIN”
We will wind up here when we are done processing a numeric field
2E01-2E03CALL 032AH CALL OUTDOCD 2A 03Go send the FINAL character (held in Register A) to the current output device
POP HL E1Get the value of the current BASIC program pointer from the STACK and put it in HL
2E05POP AF F1Restore the flag which indicates whether or not the value list has ended into Register A
2E06-2E08JP NZ,2CCBH JP NZ,REUSSTC2 CB 2CIf the value list has NOT ended, JUMP back to REUSST to reuse the USING string
CALL C,20FEH CALL C,CRDODC FE 20If 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
2E0CEX (SP),HL E3Swap (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
2E10POP HL E1Get the value of the current BASIC program pointer from the STACK and put it in HL
2E14-2E15 – Part of the PRINT USING Routine – “SMSTRF”
We will wind up here when the “!” indicating a single character string field has been scanned
2E16-2E17LD A,0F1H 3E F1Z-80 Trick. By putting a 3E in front of the F1 (which is POP AF , to clear the STACK) that POP AF gets skipped if flowing down in the code
POP AF F1(Skipped if passing down) Clear the STACK *dumping the HL that was being saved in case it turned out that this wasn’t actually a string)
2E18DEC B 05Decrement the USING string character count (tracked in Register B)
2E1CPOP HL E1Get the value of the current BASIC program pointer from the STACK and put it in HL
2E1DPOP AF F1Get the flag which indicates whether there are more values in the value list into Register A
2E1E-2E1FIf there are no more values in the value list, then we are done so JUMP back to 2E09H
2E20PUSH BC C5Save the number of characters still to be scanned from the USING string (tracked in B) to the STACK
2E21-2E23CALL 2337H CALL FRMEVLCD 37 23Read 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
2E27POP BC C1Restore the field width (a/k/a the number of characters to be printed) into Register C
2E28PUSH BC C5Save the USING string’s length and the number of characters to be printed in BC to the STACK
2E29PUSH HL E5Save the value of the current BASIC program pointer in HL to the STACK
2E2A-2E2CLD HL,(4121H) LD HL,(FACLO) 2A 21 41Load HL with the string’s VARPTR in ACCumulator
2E2DLD B,C 41Load Register B with field width (a/k/a the number of characters to be printed)
2E2E-2E2FLD C,00H 0E 00Zero Register C so that we can use the LEFT$ routine
2E30PUSH BC C5Save the length of the string to be printed in Register B to the STACK (as we will need that for space padding)
2E31-2E33CALL 2A68H CALL LEFTUSCD 68 2ATruncate the string to B characters via a call to the LEFT$ routine
2E37-2E39LD HL,(4121H) LD HL,(FACLO) 2A 21 41Load HL with the string’s VARPTR in ACCumulator so we can see if we need to pad the string
2E3APOP AF F1Get the field width (a/k/a the length of the string to be printed) from the STACK and put it in Register A
2E3BSUB (HL) 96Determine 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
2E3CLD B,A 47Save the amount of padding needed into Register B
2E3D-2E3ELD A,20H 3E 20Load Register A with a SPACE
2E3FINC B 04Bump 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.
2E41-2E43JP Z,2DD3H JP Z,FNSTRFCA D3 2DIf all of the spaces have been printed, Jump back to 2DD3H to see if the value list ended and to resume scanning
2E49 – Part of the PRINT USING Routine – “PLSPRT”
When a “+” is detected in the “USING” string and a numeric field follows, a bit in Register D should be set, otherwise + should be printed. Since deciding whether a numeric field follows is very difficult, the bit is always set in Register D. At the point it is decided a character is not part of a numeric field, this routine is called to see if the bit in Register D is set, which means a plus preceded the character and should be printed
2E49 PLSPRTPUSH AF F5Save the current character (held in Register A) to the STACK
2E4ALD A,D 7AWe need to test the PLUS BIT in D, so first load Register A with the value in Register D
2E4BOR A B7Check 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-2E4DLD A,2BH LD A,”+” 3E 2BPrepare to print the + by loading Register A with a +
2E4E-2E50CALL NZ,032AH CALL NZ,OUTDOC4 2A 03If the bit was set (i.e., A was non-zero), then send a + to the current output device
2E51POP AF F1Get the current character from the STACK and put it in Register A
2E52RET C9RETurn 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
LD (409AH),A LD (ERRFLG),A 32 9A 40Reset the EDIT flag.
Note: 409AH holds the ERROR/RESUME flag
2E56-2E58LD HL,(40EAH) LD HL,(ERRLIN) 2A EA 40Load HL with the line number to be edited.
Note: 40EAH-40EBH holds the line number with error
2E59OR H B4OR Register A with the MSB of the error line number in Register H
2E5AAND L A5Combine 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
2E5BINC A 3CBump 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
2E5CEX DE,HL EBSwap DE and HL so that DE now holds the line number to edit.
2E5DRET Z C8If 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
2E60-2E62 EDITCALL 1E4FH CALL LINSPCCD 4F 1EGet the first line number by calling 1E4F – returns in in DE
2E63RET NZ C0If the zero flag got set, there was no line number, so return
2E66-2E68LD (40ECH),HL LD (DOT),HL 22 EC 40Save 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
2E69EX DE,HL EBLoad HL with the line number to be edited
2E6A-2E6CCALL 1B2CH CALL FNDLINCD 2C 1BFind 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
2E70
2E71LD H,B
LD L,C 60At this point, the line number has been found. Let HL=BC so that HL also points to the location in RAM of the line number being edited
2E72
2E73INC HL
INC HL 23Bump the value of the memory pointer in HL twice to now point to the first byte of the line.
2E74LD C,(HL) 4ELoad Register C with first byte of the line number being edited
2E75INC HL 23Bump the value of the memory pointer in HL to point to the second byte of the line being edited
2E76LD B,(HL) 46Load Register B with second byte of the line number being edited
2E77INC HL 23Bump the value of the memory pointer in HL to now point to the first byte of the actual line
2E78PUSH BC C5Save the line number to the STACK
2E79-2E7BCALL 2B7EH CALL BUFLINCD 7E 2BGOSUB to 2B7EH move the BASIC line at the location of the memory pointer in HL into a memory buffer and untokenize the BASIC line
2E7D INLEDPUSH HL E5Save the value of the line number in HL to the STACK
2E7E-2E80CALL 0FAFH CALL LINPRTCD AF 0FConvert the line number to ASCII and print it out by calling the HL TO ASCII routine at 0FAFH (which converts the value in the HL (assumed to be an integer) to ASCII and display it at the current cursor position on the video screen)
2E81-2E82LD A,20H 3E 20Load Register A with a space
2E86-2E88LD HL,(40A7H) LD HL,(BUFPNT) 2A A7 40Load HL with the starting address of the expanded version of the current line from the input buffer.
Note: 40A7H-40A8H holds the input Buffer pointer
2E89-2E8ALD A,0EH 3E 0ELoad Register A with the “turn on the cursor” character
2E8EPUSH HL E5Save the value of the input buffer pointer (in HL) to the STACK
2E8F-2E90LD C,FFH 0E FFLoad Register C with the number of characters examined so far with FFH because the next line is going to INC it by 1 to make it 0
2E92LD A,(HL) 7ELoad Register A with the character at the location of the input buffer pointer in HL
2E93OR A B7Check to see if the character in Register A is an end of the BASIC line character
2E94INC HL 23Bump the value of the input buffer pointer in HL
2E95-2E96Loop back to 2E91H until the end of the BASIC line has been found
2E97POP HL E1At this point, C will be the maximum number of characters in the line at issue. Put the start of the expanded buffer into HL
2E98LD B,A 47Set the current position in the BASIC line being edited (tracked by Register B) to ZERO
2E99-2E9A DISPEDLD D,00H 16 00Assume the repetition count for the upcoming command (tracked by Register D) is zero
2D9E-2E9F DISPSUB 30H 20 15We need to test to see if the character was alphabetic or alphanumeric so we subtract 30H from it
2EA2-2EA3CP 0AH FE 0ACheck 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.
2EA6LD E,A 5FLoad Register E with the binary value of the character in Register A
2EA7LD A,D 7APut the repetition value into Register A
2EA8RLCA 07Multiply the value in Register A by two (so now A has multiplied by 2)
2EA9RLCA 07Multiply the value in Register A by two (so now A has multiplied by 4)
2EAAADD A,D 82Add the value in Register D to the value in Register A (so now A has multiplied by 5)
2EABRLCA 07Multiply the value in Register A by two (so now A has multiplied by 10). Now the “ones place” is empty.
2EACADD A,E 83Add the value in Register E to the value in Register A in the “ones place”
2EADLD D,A 57Load Register D with the value in Register A
2EB0H – LEVEL II BASIC EDIT ROUTINE – “NOTDGI”
While getting user command input within an edit, we wind up here if the user enters a non-numeric character (i.e., the actual command, and not just the repetition number which precedes it)
2EB0 NOTDGIPUSH HL E5Save the value of the input buffer pointer in HL to the STACK
2EB1-2EB3LD HL,2E99H LD HL,DISPED 21 99 2ELoad HL with the return address of 2E99H
2EB4EX (SP),HL E3Exchange the value of the return address in HL with the value of the input buffer pointer to the STACK
2EB5DEC D 15We 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
2EB6INC D 14… and then incrementing the numeric value in Register D to set the flags
2EB7-2EB9JP NZ,2EBBH JP NZ,NTZERDC2 BB 2EIf we had a received a repetition count already, then JUMP to 2EBBH
2EBAINC D 14Otherwise, set the repetition count (held in Register D) to be one
CP 0D8H FE D8Check to see if the character in Register A is a BACKSPACE character. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
2EBD-2EBFJP Z,2FD2H JP Z,DELEDCA D2 2FIf the character in Register A is a BACKSPACE character, JUMP to DELED
2EC0-2EC1CP 0DDH FE DDCheck to see if the character in Register A is a CARRIAGE RETURN . If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
2EC2-2EC4JP Z,2FE0H JP Z,CREDCA E0 2FIf the character in Register A is a CARRIAGE RETURN , JUMP to CRED
2EC5-2EC6CP 0F0H FE F0Check 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.
That’s it for non-alphabetic instructions, so we need to need to convert a lower case command to upper case
2EC9-2ECACP 31H FE 31Check 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.
2ECD-2ECESUB 20H D6 20Convert the lowercase character in Register A to uppercase
CP 21H FE 21Check 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.
2ED4-2ED5CP 1CH FE 1CCheck 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.
2ED9-2EDACP 23H FE 23Check 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.
2EDD-2EDECP 19H FE 19Check 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.
2EE2-2EE3CP 14H FE 14Check 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.
2EE7-2EE8CP 13H FE 13Check 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.
2EEC-2EEDCP 15H FE 15Check 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.
2EF1-2EF2CP 28H FE 28Check 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.
2EF6-2EF7CP 1BH FE 1BCheck 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.
2EFA-2EFBCP 18H FE 18Check to see if the character in Register A is an H . If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
2EFC-2EFEJP Z,2F75H JP Z,HEDCA 75 2FJump if the character in Register A is an H (i.e., HACK off the rest of the line and then enter INSERT mode)
2EFF-2F00CP 11H FE 11Check 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.
2F01RET NZ C0Return if the character in Register A isn’t an A
2F02 – EDIT Command – Cancel and Restore Logic.
2F02POP BC C1Clean up the STACK (i.e., remove the DISPI return address)
2F03POP DE D1Get 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 SPEDLD A,(HL) 7ELoad Register A with the character at the location of the input buffer pointer in HL
2F0BOR A B7Check to see if the character in Register A is an end of the BASIC line character
2F0CRET Z C8Return if the character in Register A is an end of the BASIC line character
2F0DINC B 04Bump the character position in Register B
2F11INC HL 23Bump the value of the pointer in HL
2F12DEC D 15Decrement the number of times to perform the operation in Register D
2F15RET C9RETurn to CALLer
2F16 – EDIT Command – KILL Logic – “KED” .
2F17-2F19LD HL,2F5FH LD HL,TYPSLH 21 5F 2FLoad HL with the return address of 2F5FH (which will print the final !
2F1AEX (SP),HL E3Exchange the value of the return address in HL with the value of the input buffer pointer to the STACK
2F1BSCF 37Set the KILL/SEARCH flag for KILL since CARRY flag signals KILL
2F1D-2F1FCALL 0384H CALL INCHRCD 84 03Go scan the keyboard for the character the user wants to SEARCH for
2F20LD E,A 5FSave the character the user wants to SEARCH for into Register E
2F21POP AF F1Get the KILL/SEARCH flag from the STACK
2F22PUSH AF F5Save the KILL/SEARCH flag to the STACK
2F23-2F25CALL C,2F5FH CALL C,TYPSLHDC 5F 2FIf KILL (because the CARRY flag was set) then GOSUB to 2F5FH to print a !
LD A,(HL) 7ELoad Register A with the character at the location of the input buffer pointer in HL
2F27OR A B7Check to see if the character in Register A is an end of the BASIC line character
2F28-2F2AJP Z,2F3EH JP Z,POPARTCA 3E 2FJump down to 2F3EH if the character in Register A is an end of the BASIC line character
2F2EPOP AF F1Get the KILL/SEARCH flag from the STACK
2F2FPUSH AF F5Save the KILL/SEARCH flag to the STACK
2F30-2F32CALL C,2FA1H CALL C,DELCHRDC A1 2FIf the CARRY flag is set, that means we are in KILL mode so GOSUB to 2FA1H to delete the character from the input buffer
2F33-2F34Jump to 2F37H if KILL. Note, we do not move the HL pointer in this case because DELCHR already moved it.
2F35INC HL 23If we are here, it must be SEARCH! So bump to the next character
2F36INC B 04Bump the value of the character position in Register B
LD A,(HL) 7ERegardless of whether we are SEARCH or KILL, load Register A with the character at the location of the current input buffer pointer in HL
2F38CP E BBCheck 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.
2F3BDEC D 15Decrement the number of times to perform the operation in Register D (as initially specified by the user by entering a number before the command)
2F3FRET C9RETurn to CALLer
2F40 – EDIT Command – LIST Logic – “LED” .
CALL 2B75H CALL LISPRTCD 75 2BSince 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
2F46POP BC C1Clear off the RETURN address to DISPED
2F47-2F49JP 2E7CH JP LLEDC3 7C 2EJump to 2E7CH (to display the current line number and await the next EDIT command)
2F4A – EDIT Command – DELETE Logic – “DED”
LD A,(HL) 7ELoad Register A with the character at the location of the input buffer pointer in HL
2F4BOR A B7Check to see if the character in Register A is an end of the BASIC line character
2F5CRET Z 15Return if the character in Register A is an end of the BASIC line character
LD A,(HL) 7ELoad Register A with the character at the location of the input buffer pointer in HL
2F53OR A B7Check to see if the character in Register A is an end of the BASIC line character
2F54-2F5BJump to 2F5FH if the character in Register A is an end of the BASIC line character
2F5CDEC D 15Decrement the number of times to perform the operation in Register D (as initially specified by the user by entering a number before the command)
2F64RET C9RETurn to CALLer
2F65 – EDIT Command – CHANGE Logic – “CED” .
2F65 CEDLD A,(HL) 7ELoad Register A with the character at the location of the input buffer pointer in HL
2F66OR A B7Check to see if the character in Register A is an end of the BASIC line character
2F67RET Z C8Return if the character in Register A is an end of the BASIC line character
CALL 0384H CALL INCHRCD 84 03Go get the character to put in the input buffer from the keyboard
2F6BLD (HL),A 77Save the character in Register A at the memory location of the input buffer pointer in HL
2F6FINC HL 23Bump the value of the input buffer pointer in HL
2F70INC B 04Bump the character position in Register B
2F71DEC D 15Decrement the number of times to perform the operation in Register D (as initially specified by the user by entering a number before the command)
2F74RET C9RETurn to CALLer
2F75 – EDIT Command – HACK/INSERT Logic – “HED”
2F75-2F76 HEDLD (HL),00H 36 00Set the line end to be the current position.
2F77LD C,B 48Load Register C with the character position in Register B which will now be the line length
LD D,0FFH 16 FFPrepare for the next CALL to find the end of the line by loading Register D with the number of times to perform the operation
2F80OR A B7Check to see if a key was pressed
2F84-2F85CP 08H FE 08Check to see if the character in Register A is a backspace character . If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
2F86-2F87Jump to 2F92H if the character in Register A is a backspace character
2F88-2F89CP 0DH FE 0DCheck to see if the character in Register A is a carriage return . If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
2F8A-2F8CJP Z,2FE0H JP Z,CREDCA E0 2FJump to 2FE0H if the character in Register A is a carriage return
2F8D-2F8ECP 1BH FE 1BCheck 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.
2F8FRET Z C8Return if the character in Register A is shift up arrow
2F92 – EDIT Command – BACKSPACE CURSOR Logic – “TYPARW” .
2F94 TYPAR1DEC B 05Decrement the character position in Register B
2F95INC B 04Bump the character position in Register B
2F96-2F97If this is the first character of the BASIC line Jump forward to 2FB7H
2F9BDEC HL 2BDecrement the value of the input buffer pointer in HL
2F9CDEC B 05Decrement the character position in Register B
2F9D-2F9FLD DE,2F7DH LD DE,IED 11 7D 2FLoad DE with a return address of 2F7DH
2FA0PUSH DE D5Save the value of the return address in DE to the STACK
2FA1 – LEVEL II BASIC EDIT ROUTINE – “DELCHR”
This subroutine will delete the character pointed to by Register Pair HL and will correct Register C
2FA1 DELCHRPUSH HL E5Save the value of the input buffer pointer in HL to the STACK
2FA2DEC C 0DDecrement the character position in Register C
LD A,(HL) 7ELoad Register A with the character at the location of the input buffer pointer in HL
2FA4OR A B7Check to see if the character in Register A is an end of the BASIC line character
2FA5SCF 37Set the Carry flag to signal that DELCHR was called
2FA6-2FA8JP Z,0890H JP Z,POPHRTCA 90 08If the character in Register A is an end of the BASIC line character then we are done compressing so Jump to 0890H
2FA9INC HL 23Bump the value of the input buffer pointer in HL
2FAALD A,(HL) 7ELoad Register A with the character at the location of the input buffer pointer in HL
2FABDEC HL 2BDecrement the value of the input buffer pointer in HL
2FACLD (HL),A 77Save the character in Register A at the location of the current input buffer pointer in HL
2FADINC HL 23Bump the value of the input buffer pointer in HL
2FB0 – EDIT Command – ADD A CHARACTER Logic – “NTARRW” .
2FB1LD A,C 79Load Register A with the number of characters in the input buffer (i.e., the length of the line) in Register C
2FB2-2FB3CP FFH CP BUFLEN FE FFWe 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.
Jump forward to 2FB9H if the maximum BASIC line length hasn’t been reached
2FB6POP AF F1Get the character to be inserted from the STACK and put it in Register A
SUB B 90Subtract 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
2FBAINC C 0CBump the number of characters in the input buffer in Register C
2FBBINC B 04Bump the character position in Register B
2FBCPUSH BC C5Save the character position and the number of characters in the input buffer in BC to the STACK
2FBDEX DE,HL EBLoad DE with the input buffer pointer in HL
2FBELD L,A 6FLoad Register L with the number of bytes to move
2FBF-2FC0LD H,00H 26 00Zero Register H so that the number of bytes to move can be done in a 16 bit Register Pair.
2FC1ADD HL,DE 19Add the value of the input buffer pointer in DE to the character count in HL
2FC2LD B,H 44Load Register B with the MSB of the end of the BASIC line pointer in Register H
2FC3LD C,L 4DLoad Register C with the LSB of the end of the BASIC line pointer in Register L
2FC4INC HL 23Bump the value of the end of the BASIC line pointer in HL
2FC8POP BC C1Get the character position and the number of characters in the input buffer from the STACK and put it in BC
2FC9POP AF F1Get the character to be inserted from the STACK and put it in Register A
2FCALD (HL),A 77Save the character in Register A at the location of the current input buffer pointer in HL
2FCEINC HL 23Bump the value of the input buffer pointer in HL
2FD2 – EDIT Command – BACKSPACE Logic – “DELED” .
LD A,B 78Top 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
2FD3OR A B7Check to see if this is the start of the BASIC line
2FD4RET Z C8Return if this is the start of the BASIC line
2FD6DEC HL 2BDecrement the value of the buffer pointer in HL
2FD7-2FD8LD A,08H 3E 08Load Register A with a backspace the cursor character
2FDCDEC D 15Decrement the number of times to perform the operation in Register D
2FDFRET C9RETurn to CALLer
CALL 2B75H CALL LISPRTCD 75 2BSince 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
2FE6POP BC C1Clean up the STACK (to remove the DISPED return address)
2FE7POP DE D1Get the BASIC line number (in binary) from the STACK and put it in DE
2FE8LD A,D 7ALoad Register A with the MSB of the BASIC line number in Register D
2FE9AND E A3Combine the LSB of the BASIC line number in Register E with the MSB of the BASIC line number in Register A
2FEAINC A 3CBump the combined BASIC line number in Register A
LD HL,(40A7H) LD HL,(BUFPNT) 2A A7 40Load HL with the starting address of the input buffer.
Note: 40A7H-40A8H holds the input Buffer pointer
2FEEDEC HL 2BDecrement the value of the input buffer pointer in HL
2FEFRET Z C8Return if this is the Level II BASIC command mode
SCF 37Set the Carry flag to to fool the INSERT code; this flags the line number has having been seen
2FF1INC HL 23Bump the value of the input buffer pointer in HL
2FF2PUSH AF F5Save the command mode flag in AF to the STACK
2FF6 – EDIT Command – QUIT Logic – “QED” .
2FF6 QEDPOP BC C1Get rid of the DISPED return address
2FF7POP DE D1Get the line number off of the stack
2FFB-2FFFNOP 00THE END OF THE LEVEL II BASIC ROMS
2FFB-2FFFNOP 00Nothing here
*2FFB-2FFCSBC A,0C3HIn ROM v1.2 this is just garbage
NOTE: The RST 20H routine determines the type of the current value in ACCumulator and returns a combination of STATUS flags and unique numeric values in the A Register according to the data mode flag (40AFH). The results are returned as follows:
- Integer = NZ/C/M/E and A is -1
- String = Z/C/P/E and A is 0
- Single Precision = NZ/C/P/O and A is 1
- and Double Precision is NZ/NC/P/E and A is 5.
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
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
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).
NOTE: 40AEH holds LOCATE/CREATE variable flag
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.
Note: 40FDH-40FEH holds Free memory pointer
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.
Note: 40AFH holds Current number type flag
Note: 40AEH holds LOCATE/CREATE variable flag
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.
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:
- 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
Note: 40D8H-40D9H holds temporary storage location
Note: 40AEH holds LOCATE/CREATE variable flag
CALL REASONCD 6C 19
Note: 40FDH-40FEH holds free memory pointer
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.
Note: 40D8H-40D9H holds Temporary storage location
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
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.
NOTE: 40AFH holds Current number type flag
27B3
LD C,L 44
Note: 40F3H-40F4H is a temporary storage location
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.
27CAPUSH HL E5Save the value of the current BASIC program pointer in HL to the STACK
27CB-27CDLD (40AFH),A LD (VALTYP),A 32 AF 40Zero the number type flag.
NOTE: 40AFH holds Current number type flag
27CE-27D0CALL 27D4H CALL FRECD D4 27Determine how much space there is via a GOSUB to the FRE routine at 27D4H
27D1POP HL E1Get the value of the current BASIC program pointer from the STACK and put it in HL
27D2We 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.
27D3RET C9Return to BASIC
27D4-27F4 – LEVEL II BASIC FRE ROUTINE – “FRE”
LD HL,(40FDH) LD HL,(STREND) 2A FD 40Load 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
27D7EX DE,HL EBLoad DE with the value of the free memory pointer in HL for subtraction
27D8-27DALD HL,0000H 21 00 00Zero HL
27DBADD HL,SP 39Add the value in HL (which is zero) to the current value of the STACK pointer so that the STACK pointer is now in HL
27DCWe need to check the value of the current number type flag, so we call the TEST DATA MODE routine at RST 20H.
NOTE: The RST 20H routine determines the type of the current value in ACCumulator and returns a combination of STATUS flags and unique numeric values in the A Register according to the data mode flag (40AFH). The results are returned as follows:- Integer = NZ/C/M/E and A is -1
- String = Z/C/P/E and A is 0
- Single Precision = NZ/C/P/O and A is 1
- and Double Precision is NZ/NC/P/E and A is 5.
27DD-27DEIf that test shows we do NOT have a STRING (meaning this was really a MEM call, jump to forward to 27ECH
27DF-27E1CALL 29DAH CALL FREFACCD DA 29Free up the argument and set up to give some free string space
27E5-27E7LD HL,(40A0H) LD HL,(STKTOP) 2A A0 40Load HL with the start of string space pointer / bottom of free space.
NOTE: 40A0H-40A1H holds the start of string space pointer
27E8EX DE,HL EBLoad DE with the start of string space pointer in HL
27E9-27EBLD HL,(40D6H) LD HL,(FRETOP) 2A D6 40Load 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 GIVDBLLD A,L 7DPrepare to do HL = HL – DE. First, load Register A with the LSB of the next available location in string space pointer in Register L
27EDSUB E 93Subtract 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
27EELD L,A 6FLoad Register L with the LSB of the amount of string space remaining in Register A
27EFLD A,H 7CLoad Register A with the MSB of the next available location in string space pointer in Register H
27F0SBC A,D 9ASubtract 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
27F1LD H,A 67Load Register H with the MSB of the amount of string space remaining in Register A
27F2-27F4JP 0C66H JP INEG2C3 66 0CJump to 0C66H to convert the difference between HL and DE to single precision and then RETurn out of the routine
27F5-27FD – LEVEL II BASIC POS( ROUTINE – “POS”
27F5-27F7 POSLD A,(40A6H) LD A,(TTYPOS) 3A A6 40Load Register A with the current cursor line position.
Note: 40A6H holds the current cursor line position
LD L,A 6FLoad Register L with the value of the current cursor line position in Register A.
27F9XOR A AFZero Register A
27FA GIVINTLD H,A 67Load Register H with zero, so now HL is 00 + cursor position
27FE-2818 – LEVEL II BASIC USR(x) ROUTINE – “USRFN”
27FE-2780 USRFNCALL 41A9H CALL USROUT CD A9 41GOSUB to DOS to see if DOS wants to deal with this
2801We need the next character so call the EXAMINE NEXT SYMBOL routine at RST 10H.
The RST 10H routine parses the characters starting at HL+1 for the first non-SPACE,non-09H,non-0BH character it finds. On exit, Register A will hold that character, and the C FLAG is set if its alphabetic, and NC FLAG if its alphanumeric. All strings must have a 00H at the end.
2802-2804CALL 252CH CALL PARCHKCD 2C 25GOSUB to 252CH to evaluate the expression at the location of the current BASIC program pointer in HL and return with the result in ACCumulator
2805PUSH HL E5Save the value of the current BASIC program pointer in HL (=the address of the next element in the code string) to the STACK
2806-2808LD HL,0890H LD HL,POPHRT 21 90 08Load HL with the return address of 0890H which will clear the STACK before returning to BASIC
2809PUSH HL E5Save the value of the return address in HL to the STACK
280A-280CLD A,(40AFH) LD A,(VALTYP) 3A AF 40Load Register A with the value of the current number type flag for the argument provided.
Note: 40AFH holds Current number type flag
280DPUSH AF F5Save the value of the current number type flag in Register A.
(02=INT, 03=STR, 04=SNG, 08=DBL)
280E-280FCP 03H FE 03Check to see if the current value is a string. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
2810-2812CALL Z,29DAH CALL Z,FREFACCC DA 29If the current result is a string then GOSUB to 29DAH to get the free the space and get the string address into HL
2813POP AF F1Restore the number type flag into Register A
2814EX DE,HL EBLoad DE with the (possible) value of the pointer to the string (in HL)
2815-2817LD HL,(408EH) 2A 8E 40Load 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.
2818JP (HL)E9Jump 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.
PUSH HL E5Save the pointer to the current character in the BASIC program being evaluated to the STACK
281A-281BAND 07H E6 07Mask 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-281ELD HL,18A1H LD HL,FRCTBL 21 A1 18Load HL with the address of the arithmetic conversion routines
281FLD C,A 4FLoad Register C with the value of the number type flag in Register A.
(02=INT, 03=STR, 04=SNG, 08=DBL)
2820-2821LD B,00H 06 00Zero Register B. Now BC holds 00 + type and will be the two byte offset into the table
2822ADD HL,BC 09Add the offset (of BC) to the base arithmetic conversion routines, to find the right jump point
2823-2825CALL 2586H CALL DISPATCD 86 25GOSUB to 2586H to convert the current result in REG l to its proper number type
2826POP HL E1Restore the pointer to the current character in the BASIC program being evaluated to HL
2827RET C9RETurn 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.
2829-282BLD HL,(40A2H) LD HL,(CURLIN) 2A A2 40Load HL with the value of the current BASIC line number (which is stored at 40A2H-40A3H).
282CINC HL 23Bump 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
282DLD A,H 7CLoad Register A with the MSB of the current BASIC line number in Register H
282EOR L B5Combine 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.
282FPOP HL E1Restore whatever was in HL on entry back into HL
2830RET NZ C0Return if there is a line number (i.e., this isn’t the command mode) and otherwise fall through to the ?ID ERROR routine
2831 – ID ERROR entry point.
2831-2832LD E,16H 1E 16Load Register E with the ?ID ERROR code
2836-2856 – STRING ROUTINE – STR$ logic – “STR$”
2836-2838 STR$CALL 0FBDH CALL FOUTCD BD 0FGOSUB to 0FBDH to convert the current result in ACCumulator to an ASCII string
2839-283B STR$1CALL 2865H CALL STRLITCD 65 28Scan it and turn it into a string (make a temporary string work area entry)
LD BC,2A2BH LD BC,FINBCK 01 2B 2ALoad BC with a return address of 2A2BH (which cleans the STACK and then jumps to 2884H)
2842PUSH BC C5Save the value of the return address in BC to the STACK
The next routine, STRCPY, creates a copy of the string pointed to by Register Pair HL. On exit, DE points to DSCTMP which has the string information.
2843 STRCPYLD A,(HL) 7ELoad Register A with the string’s length at the location of the string’s VARPTR in HL
2844INC HL 23Bump the value of the string’s VARPTR in HL
2845PUSH HL E5Save the value of the string’s VARPTR in HL to the STACK
2846-2848CALL 28BFH CALL GETSPACD BF 28GOSUB to 28BFH to test the remaining string area to make sure that the new string will fit
2849POP HL E1Reload HL with the string’s VARPTR. This is the destination to where the string should be copied.
284ALD C,(HL) 4ELoad Register C with the LSB of the string’s address at the location of the string’s VARPTR in HL
284BINC HL 23Bump the value of the string’s VARPTR in HL
284CLD B,(HL) 46Load Register B with the MSB of the string’s address at the location of the string’s VARPTR in HL
284D-284FCALL 285AH CALL STRAD2CD 5A 28GOSUB to 285AH to save the string’s length and the string’s address at 40D3H, so as to set up DSCTMP
2850PUSH HL E5Save the pointer to STRAD2 (which is 40D3H) to the STACK
2851LD L,A 6FLoad Register L with the string’s length (from Register A)
2852-2854CALL 29CEH CALL MOVSTRCD CE 29GOSUB to 29CEH to move L characters from the temp area (of BC) to the string data area (in DE)
2855POP DE D1Restore the pointer to DSCTMP (40D3H) into Register Pair DE
2856RET C9RETurn to CALLer
2857-2864 – STRING ROUTINE – “STRINI”
CALL 28BFH CALL GETSPACD BF 28GOSUB 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
LD HL,40D3H LD HL,DSCTMP 21 D3 40Load HL with the address of the temporary string parameter storage area.
Note: 40D3H-40D5H holds Used for temporary string VARPTR’s
285D STRAD1PUSH HL E5Save the address of the temporary string parameter area in HL to the STACK
285ELD (HL),A 77Save the string’s length in Register A at the location of the temporary string parameter storage pointer in HL
285F PUTDEIINC HL 23The 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
2860LD (HL),E 73Save the LSB of the string’s address in Register E at the location of the temporary string parameter storage pointer in HL
2861INC HL 23Bump the value of the temporary string parameter storage pointer in HL
2862LD (HL),D 72Save the MSB of the string’s address in Register D at the location of the temporary string parameter storage pointer in HL
2863POP HL E1Get the address of the temporary string parameter storage area from the STACK and put it in HL
2864RET C9RETurn 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.
LD B,22H 06 22Load Register B with a “ (which is really the end of the quote search character)
PUSH HL E5Save 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-286BLD C,0FFH 0E FFLoad Register C with a -1
INC HL 23Bump the value of the current BASIC program pointer in HL to skip over that initial “
286DLD A,(HL) 7ELoad Register A with the character at the location of the current BASIC program pointer in HL
286EINC C 0CBump the counter in Register C
286FOR A B7Check to see if the character at the location of the current BASIC program pointer in Register A is an end of the BASIC line character
2870-2871Jump 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
2872CP D BACheck to see if the character at the location of the current BASIC program pointer in Register A is the same as the terminating character in Register D. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
2873-2874Jump 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
2875CP B B8Check to see if the character at the location of the current BASIC program pointer in Register A is the same at the terminating character in Register B. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
2876-2877Loop 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
CP 22H FE 22Check to see if the character at the location of the current BASIC program pointer in Register A is a quote. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
287A-287CCALL Z,1D78H CALL Z,CHRGTRCC 78 1DIf 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)
287DEX (SP),HL E3Exchange the value of the current BASIC program pointer in HL with the string’s address to the STACK
287EINC HL 23Bump the string’s address in HL until it points to the first character of the string
287FEX DE,HL EBLoad DE with the temporary pointer string’s address in HL
2880LD A,C 79Load Register A with the string’s length from Register C
2881-2883CALL 285AH CALL STRAD2CD 5A 28GOSUB to 285AH to save the string’s length and the string’s address into 40D3H (i.e., DSCTMP)
LD DE,40D3H LD DE,DSCTMP 11 D3 40Load DE with the address of the string parameter storage area.
Note: 40D3H-40D5H holds Used for temporary string VARPTR’s
LD A,D5H 3E D5This 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 PUTTMPPUSH DE D5Save a pointer to the stat of the string to the STACK
2889-288BLD HL,(40B3H) LD HL,(TEMPPT) 2A B3 40Load 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-288ELD (4121H),HL LD (FACLO),HL 22 21 41Save 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-2890LD A,03H 3E 03Load Register A with the string number type flag
2891-2893LD (40AFH),A LD (VALTYP),A 32 AF 40Save the value in Register A as the current number type flag.
Note: 40AFH holds current number type flag
2897-2899LD DE,40D6H LD DE,FRETOP 11 D6 40Depending on how we got here, DE will be different. If the jump was into PUTTMP, then DE will NOT equal FRETOP.
289AWe 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-289DLD (40B3H),HL LD (TEMPPT),HL 22 B3 40Save 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
289EPOP HL E1Get the value of the current BASIC program pointer from the STACK and put it in HL
289FLD A,(HL) 7ELoad Register A with the character at the location of the current BASIC program pointer in HL
28A0RET NZ C0Return if the updated temporary string work area location wasn’t beyond the end of the temporary string work area (meaning it overflowed, because if it overflowed .)
28A1 – ST ERROR entry point.
28A1-28A2LD E,1EH 1E 1ELoad Register E with a ?ST ERROR code
28A3-28A5JP 19A2H JP ERRORC3 A2 19Display 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 STROUIINC HL 23Bump 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.
CALL 2865H CALL STRLITCD 65 28Go build a temporary string work area entry for the message at FACLOthe location of the current BASIC program pointer in HL
If the routine entry is at STRPRT, then it just prints the string whose descriptor is held in FACLO
28AA-28AC STRPRTCALL 29DAH CALL FREFACCD DA 29GOSUB to 29DAH to build a temporary string work area entry for the message pointed to by FACLO
28AD-28AFCALL 09C4H CALL GETBCDCD C4 09Go get the string’s length in Register D and the string’s address in BC
28B0INC D 14Bump the value of the string’s length in Register D in preparation for the following loop which starts with a DEC D
28B1 STRPR2DEC D 15Top of a loop. Decrement the value of the string’s length in Register D
28B2RET Z C8Return if all of the characters in the string have been sent to the current output device.
28B4-28B6CALL 032AH CALL OUTDOCD 2A 03Go send the character in Register A to the current output device
28B7-28B8CP 0DH FE 0DCheck to see if the character in Register A is a CARRIAGE RETURN . If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
28B9-28BBCALL Z,2103H CALL Z,CRFINCC 03 21Jump to 2103H if the character in Register A is a carriage return
28BCINC BC 03Bump the value of the string pointer in BC
28BD-28BEJR 28B1H JR STRPR218 F2Loop 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.
OR A B7Make sure A is not zero. A ZERO FLAG will signal that garbage collection has happened
28C0-28C1LD C,0F1H 0E F1Z-80 Trick. If passing through, the C just changes and the POP AF which follows is ignored.
28C1 TRYGI2POP AF F1Get the string’s length from the STACK and put it in Register A
28C2PUSH AF F5Save the length of the string in Register A to the STACK
28C3-28C5LD HL,(40A0H) LD HL,(STKTOP) 2A A0 40Load HL with the poinmter to the bottom of the string space. 40A0H-40A1H holds the start of string space pointer
28C6EX DE,HL EBMove the bottom of the string space pointer into DE. We don’t care what happens to HL
28C7-28C9LD HL,(40D6H) LD HL,(FRETOP) 2A D6 40Load HL with the pointer to the TOP of free space.
Note: 40D6H-40D7H holds the next available location in string space pointer
28CACPL 2FComplement the string’s length in Register A so that it is negative
28CBLD C,A 4FThe 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-28CDLD B,0FFH 06 FFLoad Register B with a -1 so that BC will be the negative length of the string
28CEADD HL,BC 09Add the negative string’s length in BC to the top of free space pointer in HL
28CFINC HL 23Bump the value of the adjusted next available location in string space pointer in HL
28D0We 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 CARRY FLAG is set then we do not have enough room for the string, so lets JUMP forward to 28DAH to do some garbae collection.
28D3-28D5LD (40D6H),HL LD (FRETOP),HL 22 D6 40Save the value in HL as new bottom of MEMORY
28D6INC HL 23Bump the value of HL to point to the string
28D7EX DE,HL EBLoad DE with the pointer to the string
28D9RET C9RETurn to CALLer
28DA-298E – STRING ROUTINE – “GARBAG”
28DB-28DCLD E,1AH 1E 1ALoad Register E with an ?OS ERROR code
28DD-28DFJP Z,19A2H JP Z,ERRORCA A2 19If 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
28E0CP A BFOtherwise, 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.
28E1PUSH AF F5Save the garbage collection flag to the STACK
LD BC,28C1H LD BC,TRYGI2 01 C1 28Load BC with a return address of 28C1H (which would retry allocation)
28E5PUSH BC C5Save that return address to the STACK
LD HL,(40B1H) LD HL,(MEMSIZ) 2A B1 40Load HL with the top of memory pointer.
Note: 40B1H-40B2H holds MEMORY SIZE? pointer
LD (40D6H),HL LD (FRETOP),HL 22 D6 40Save 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-28EELD HL,0000H 21 00 00Zero HL
28EFPUSH HL E5Save the value in HL to the STACK to indicate that we didn’t find a variable on this pass
28F0-28F2LD HL,(40A0H) LD HL,(STKTOP) 2A A0 40Load 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
28F3PUSH HL E5Save high address (start of string space pointer in HL) to the STACK
28F4-28F6LD HL,40B5H LD HL,TEMPST 21 B5 40Load HL with the start of the temporary string work area pointer.
Note: 40B5H-40D2H holds Temporary string work area
28F7
“TVAR”EX DE,HL EBLoad DE with the start of the temporary string work area pointer in HL
28F8-28FALD HL,(40B3H) LD HL,(TEMPPT) 2A B3 40Load 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
28FBEX DE,HL EBExchange 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
28FCWe need to see if 40B3H is pointing to the first entry (40B5H) – if the start of the temporary string work area pointer in HL is the same as the next available location in the temporary string work area pointer, so we call the COMPARE DE:HL routine at RST 10H.
The RST 10H routine parses the characters starting at HL+1 for the first non-SPACE,non-09H,non-0BH character it finds. On exit, Register A will hold that character, and the C FLAG is set if its alphabetic, and NC FLAG if its alphanumeric. All strings must have a 00H at the end.
28FD-28FFLD BC,28F7H LD BC,TVAR 01 F7 28Load BC with a return address of 28F7H
2900-2902JP NZ,294AH JP NZ,DVAR2C2 4A 29Jump to 294AH to do the temporary variable garbage collection if the temporary string work area isn’t empty
2903 SVARSLD HL,(40F9H) LD HL,(VARTAB) 2A F9 40Load HL with the start of the simple variables pointer.
NOTE: 40F9H-40FAH holds the starting address of the simple variable storage area
2907-2909LD HL,(40FBH) LD HL,(ARYTAB) 2A FB 40Load 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
290AEX DE,HL EBSwap DE and HL so that DE holds the end and HL holds the start.
290BNow we need to check to see if the simple variables pointer in HL is the same as the array variables pointer in DE, so we call the COMPARE DE:HL routine at RST 10H.
The RST 10H routine parses the characters starting at HL+1 for the first non-SPACE,non-09H,non-0BH character it finds. On exit, Register A will hold that character, and the C FLAG is set if its alphabetic, and NC FLAG if its alphanumeric. All strings must have a 00H at the end.
290C-290DIf 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.
290ELD A,(HL) 7ELoad Register A with second character of the variable name
290FINC HL 23Bump the value of the simple variables pointer in HL
2910INC HL 23Bump the simple variables pointer in HL
2911INC HL 23Bump the value of the simple variables pointer in HL. HL should now point to the value of the variable.
2912-2913CP 03H FE 03Check to see if the variable at the location of the simple variables pointer is a string. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
2914-2915Jump to 291AH if the variable at the location of the simple variables pointer in HL isn’t a string
2919XOR A AFZero Register A to indicate that we should not be skipping anything else.
291A SKPVARLD E,A 5FZero Register E
291B-291CLD D,00H 16 00Zero Register D. Now DE should be the number of characters to skip.
291DADD HL,DE 19Add the number of characters to skip (held in DE) to the simple variables pointer in HL
291E-291FJR 2906H JR SVAR18 E6Loop back to 2906H until all of the simple variables have been checked
2922-2924LD HL,(40FDH) LD HL,(STREND) 2A FD 40Load HL with the end of the arrays / start of free memory pointer.
Note: 40FDH-40FEH holds Free memory pointer
2925EX DE,HL EBExchange the value of the array variables pointer in DE with the value of the free memory pointer in HL
2926We need to see if we are donee with arrays, so we check to see if the array variables pointer in HL is the same as the free memory pointer in DE, so we call the COMPARE DE:HL routine at RST 10H.
The RST 10H routine parses the characters starting at HL+1 for the first non-SPACE,non-09H,non-0BH character it finds. On exit, Register A will hold that character, and the C FLAG is set if its alphabetic, and NC FLAG if its alphanumeric. All strings must have a 00H at the end.
2927-2929JP Z,296BH JP Z,GRBPASCA 6B 29Jump if the array variables pointer in Register HL is the same as the start of the free memory pointer in DE
292ALD A,(HL) 7ELoad Register A with the number type flag at the location of the array variables pointer in HL
292BINC HL 23Bump the value of the array variables pointer in HL
292C-292ECALL 09C2H CALL MOVRMCD C2 09Get 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)
292FPUSH HL E5Save the pointer to the DIMS to the STACK
2930ADD HL,BC 09Add the value of the offset to the next array in BC to the value of the array variables pointer in HL
2931-2932CP 03H FE 03Check to see if the array being examined is a string. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
2933-2934If the array being examined isn’t a string then skip it via a JUMP to 2920H
2935-2937LD (40D8H),HL LD (TEMP3),HL 22 D8 40Save the address of the end of the array being examined.
Note: 40D8H-40D9H holds Temporary storage location
2938POP HL E1Get the value of the array variables pointer from the STACK and put it in HL
2939LD C,(HL) 4ELoad Register C with the number of subscripts for the array at the location of the array variables pointer in HL
293A-293BLD B,00H 06 00Zero Register B so that BC holds the number of dimensions
293CADD HL,BC 09Add the number of subscripts in the array in BC to the value of the array variables pointer in HL
293DADD HL,BC 09Add 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.
293EINC HL 23Bump the value of the array variables pointer in HL one more time to account for #DIMs.
293F ARYSTREX DE,HL EBLoad DE with the value of the current position in the array variables pointer in HL
2940-2942LD HL,(40D8H) LD HL,(TEMP3) 2A D8 40Load HL with the address of the end of this array.
Note: 40D8H-40D9H holds Temporary storage location
2943EX DE,HL EBSwap DE and HL so that HL now points to the current position
2944We need to test for the end of the array space so we need to check to see if the array variables pointer in HL is the same as the address of the next array in DE, so we call the COMPARE DE:HL routine at RST 10H.
The RST 10H routine parses the characters starting at HL+1 for the first non-SPACE,non-09H,non-0BH character it finds. On exit, Register A will hold that character, and the C FLAG is set if its alphabetic, and NC FLAG if its alphanumeric. All strings must have a 00H at the end.
2945-2946If the Z FLAG is set then we are at the end of an array so JUMP to 2921H to try the next array
294COR (HL) B6Load Register A with the length of the string at the location of the array variables pointer in HL
294DINC HL 23Bump the value of the array variables pointer in HL
294ELD E,(HL) 5ELoad Register E with the LSB of the string’s address at the location of the array variables pointer in HL
294FINC HL 23Bump the value of the array variables pointer in HL
2950LD D,(HL) 56Load 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.
2951INC HL 23Bump the value of the array variables pointer in HL
2952RET Z C8Return if the string’s length in Register A is equal to zero
2955-2957LD HL,(40D6H) LD HL,(FRETOP) 2A D6 40Load HL with the location of the the top of string free space.
NOTE: 40D6H-40D7H holds the next available location in string space pointer
2958We 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
295ALD H,B
LD L,C 60Let HL = BC
295BRET C D8If 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
295DEX (SP),HL E3Swap (SP) and HL so that the return address is back on the STACK and HL holds the maximum number seen
295ENow 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.
295FEX (SP),HL E3Swap (SP) and HL so that the return address is back in HL and the STACK holds the maximum number seen
2960PUSH HL E5Save the return address in HL to the STACK
2961
2962LD H,B
LD L,C 60Let HL = BC
2963RET NC D0Return if the string’s address in DE is below the string space pointer
2965POP AF F1Clean up the STACK (remove the MAX SEEN)
2966POP AF F1Clean up the STACK (remove the VARIABLE POINTER)
2967PUSH HL E5Save the value of the array variables pointer in HL to the STACK
2968PUSH DE D5Save the new MAX pointer in DE to the STACK
2969PUSH BC C5Save the value of the return address in BC to the STACK
296ARET C9RETurn to CALLer
If we are here, we have made one complete pass through the string variables.
296B GRBPASPOP DE D1Load DE with the address of the last string put into the temporary string work area (aka the MAX pointer)
296CPOP HL E1Get the variable pointer from the STACK and put it in HL
296DLD A,L 7DLoad Register A with the LSB of the variable pointer in Register L
296EOR H B4Combine 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
296FRET Z C8If HL=0 then we are at the end of the garbage collection, so return
DEC HL 2BDecrement the value of the temporary string work area pointer in HL, currently just past the string descriptor
2971LD B,(HL) 46Load Register B with the MSB of the string’s address at the location of the temporary string work area pointer in HL
2972DEC HL 2BDecrement the value of the temporary string work area pointer in HL
2973LD C,(HL) 4ELoad 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.
2974PUSH HL E5Save 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.
2975DEC HL 2BDecrement the value of the temporary string work area pointer in HL
2976LD L,(HL) 6ELoad Register L with the string’s length at the location of the temporary string work area pointer in HL
2977-2978LD H,00H 26 00Zero Register H so that HL is now the string’s character count
2979ADD HL,BC 09Add the length of the string in HL to the string’s address in BC. HL now points just beyond the string.
297ALD D,B 50Load Register D with the MSB of the string’s address in Register B
297BLD E,C 59Load Register E with the LSB of the string’s address in Register C. DE now is the original pointer to the string.
297CDEC HL 2BDecrement the value of the string’s ending address in HL to avoid moving one beyond the string
297DLD B,H 44Load Register B with the MSB of the string’s ending address in Register H
297ELD C,L 4DLoad Register C with the LSB of the string’s ending address in Register L. BC now points to the top of the string
297F-2981LD HL,(40D6H) LD HL,(FRETOP) 2A D6 40Load HL with the top of free space.
NOTE: 40D6H-40D7H holds the next available location in string space pointer
2982-2984CALL 1958H CALL BLTUCCD 58 19Move the string from the temporary storage location to string space
2985POP HL E1Get back the pointer to the description of the variable from the STACK and put it in HL
2986LD (HL),C 71Save the LSB of the string’s permanent address (held in Register C) to (HL)
2987INC HL 23Bump the value of the temporary string work area pointer in HL
2988LD (HL),B 70Save the MSB of the string’s permanent address (held in Register C) to (HL)
2989LD L,C 69Load Register L with the LSB of the string’s address in Register C
298ALD H,B 60Load Register H with the MSB of the string’s address in Register B. Register Pair HL will now be the new pointer to the string.
298BDEC HL 2BDecrement the string’s address in HL to adjust FRETOP
298F-29C5 – STRING ADDITION ROUTINE – Concatenate two strings – “CAT”
This routine concatenates two strings. The first is pointed to by FACLO and HL points to the character after the “+” sign in on the command line.
2990PUSH HL E5Save the value of the current BASIC program pointer in HL to the STACK
2991-2993LD HL,(4121H) LD HL,(FACLO) 2A 21 41Load HL with the first string’s VARPTR (from ACCumulator)
2994EX (SP),HL E3Exchange the value of the first string’s VARPTR in HL with the value of the current BASIC program to the STACK
2995-2997CALL 249FH CALL EVALCD 9F 24GOSUB to 249FH to evaluate the expression at the location of the current BASIC program pointer in HL
2998EX (SP),HL E3Exchange the value of the current BASIC program pointer in HL with the value of the first string’s VARPTR to the STACK
299CLD A,(HL) 7ELoad Register A with the first string’s length at the location of the first string’s VARPTR in HL
299DPUSH HL E5Save the value of the first string’s descriptor (VARPTR) in HL to the STACK
299E-29A0LD HL,(4121H) LD HL,(FACLO) 2A 21 41Load HL with the second string’s VARPTR in ACCumulator
29A1PUSH HL E5Save the second string’s VARPTR in HL to the STACK
29A2ADD A,(HL) 86Add the length of the second string at the location of the second string’s VARPTR in HL to the length of the first string in Register A
29A3-29A4LD E,1CH 1E 1CLoad Register E with a ?LS ERROR codein case the two string lengths are not less than 256.
29A5-29A7JP C,19A2H JP C,ERRORDA A2 19Display a ?LS ERROR message if the combined lengths of the strings is greater than 255
29A8-29AACALL 2857H CALL STRINICD 57 28Go make sure that there is enough string space for the new string
29ABPOP DE D1Get the second string’s VARPTR from the STACK and put it in DE
29AFEX (SP),HL E3Exchange the second string’s VARPTR in HL with the first string’s VARPTR to the STACK
29B3PUSH HL E5Save the value of the first string’s VARPTR in HL to the STACK
29B4-29B6 INCSTRLD HL,(40D4H) LD HL,(DSCTMP+1) 2A D4 40Load HL with the pointer to the first string’s address
29B7EX DE,HL EBLoad DE with the first string’s address in HL
29BE-29C0LD HL,2349H LD HL,TSTOP 21 49 23Load HL with the return address
29C1EX (SP),HL E3Exchange the value of the return address in HL with the value of the current BASIC program pointer to the STACK
29C2PUSH HL E5Save the value of the current BASIC program pointer in HL to the STACK
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
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.
29C8LD A,(HL) 7ELoad Register A with the string’s length at the location of the string’s VARPTR in HL
29C9INC HL 23Bump the value of the string’s VARPTR in HL
29CALD C,(HL) 4ELoad Register C with the LSB of the string’s address at the location of the string’s VARPTR in HL
29CBINC HL 23Bump the value of the string’s VARPTR in HL
29CCLD B,(HL) 46Load 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.
29CDLD L,A 6FLoad Register L with the string’s length in Register A
INC L 2CIncrement the value of the string’s length in Register L in preparation for the next instruction which is a loop.
29D0RET Z C8If L hits zero then we have moved all the characters, so RETurn
LD A,(BC) 0AIf 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
29D2LD (DE),A 12Save the character in Register A at the location of the string storage pointer in DE
29D3INC BC 03Bump the value of the string pointer in BC
29D4INC DE 13Bump the value of the string storage pointer in DE
29D7-29F4 – STRING ROUTINE – “FRESTR”
According to the original ROM source code, FRETMP is passed a pointer to a string descriptor in Register Pair DE and is returned in Register Pair HL. All the other registers are modified. A check to is made to see if the string descriptor in Register Pair DE points to is the last temporary descriptor allocated by PUTNEW. If so, the temporary is freed up by the updating of TEMPPT. If a temporary is freed up, a further check is made to see if the string data that that string temporary pointed to is the the lowest part of string space in use. If so, FRETMP is updated to reflect the fact that that space is no longer in use.
This routine is a contination of VAL , FRE , and PRINT processing. A jump to here would include the need to get a string’s VARPTR and put it in HL.
CALL 0AF4H CALL CHKSTRCD F4 0AGOSUB to 0AF4H to make sure that the current result in REG l is a string
CALL 29F5H CALL FRETMSCD F5 29Check to see if the string is the last entry in the temporary string work area
29E1EX DE,HL EBLoad HL with the value of the string’s VARPTR in DE
29E2RET NZ C0Return if the string isn’t the last entry in the temporary string work area
29E4LD D,B 50Load Register D with the MSB of the string’s address in Register B
29E5LD E,C 59Load Register E with the LSB of the string’s address in Register C. DE now points to the string.
29E6DEC DE 1BDecrement the value of the string’s address in DE
29E7LD C,(HL) 4ELoad Register C with the string’s length at the location of the string’s VARPTR in HL
29E8-29EALD HL,(40D6H) LD HL,(FRETOP) 2A D6 40Load 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
29EBWe need to see if the current string is the last one defined in the string area by seeing if the string’s address in DE is the same as the next available location in string space pointer in HL, so we call the COMPARE DE:HL routine at RST 10H.
The RST 10H routine parses the characters starting at HL+1 for the first non-SPACE,non-09H,non-0BH character it finds. On exit, Register A will hold that character, and the C FLAG is set if its alphabetic, and NC FLAG if its alphanumeric. All strings must have a 00H at the end.
29EC-29EDJump forward to 29F3H if the string’s address in DE isn’t the same as the next available location in string space pointer in HL
29EELD B,A 47If is the last one defined then we need to update the current string pointer so first we load Register B with the value in Register A
29EFADD HL,BC 09Add the length of the string in BC to the next available location in string space pointer in HL
29F0-29F2LD (40D6H),HL LD (FRETOP),HL 22 D6 40Save the adjusted next available location in string space pointer in HL.
Note: 40D6H-40D7H holds the next available location in string space pointer
29F4RET C9RETurn to CALLer
29F5-2A02 – STRING ROUTINE – – “FRETMS”
Test to see if the string in DE is the last string used in the temporary string work area.
LD HL,(40B3H) LD HL,(TEMPPT) 2A B3 40Load HL with the temporary string work area pointer.
Note: 40B3H-40B4H holds the next available location in the temporary string work area pointer
29F8DEC HL 2BDecrement the value of the temporary string work area pointer in HL which backs up two words
29F9LD B,(HL) 46Load Register B with the MSB of the string’s address at the location of the temporary string work area pointer in HL
29FADEC HL 2BDecrement the value of the temporary string work area pointer in HL
29FBLD C,(HL) 4ELoad Register C with the LSB of the string’s address at the location of the temporary string work area pointer in HL
29FCDEC HL 2BDecrement the value of the temporary string work area pointer in HL
29FDWe 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.
29FERET NZ C0If the Z FLAG is set then we are done freeing space, so RETURN
LD (40B3H),HL LD (TEMPPT),HL 22 B3 40Save 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
2A02RET C9RETurn to CALLer
2A03-2A0E – LEVEL II BASIC LEN ROUTINE – “LEN”
2A03-2A05 LENLD BC,27F8H LD BC,SNGFLT 01 F8 27Load BC with the return address of 27F8H
2A06PUSH BC C5Save the return address of 27F8H (in BC) to the STACK
CALL 29D7H CALL FRESTRCD D7 29GOSUB to 29D7H to free up the temporary variable pointed to by FACLO
2A0AXOR A AFZero Register A so as to force a numeric flag
2A0BLD D,A 57Zero Register D so that DE can be used when E is set.
2A0CLD A,(HL) 7ELoad Register A with the string’s length at the location of the string’s VARPTR in HL
2A0DOR A B7Set the flags according to the string’s length in Register A
2A0ERET C9RETurn to CALLer
2A0F-2A1E – LEVEL II BASIC ASC ROUTINE – “ASC”
2A0F-2A11 ASCLD BC,27F8H LD BC,SNGFLT 01 F8 27Load BC with the return address of 27F8H
2A12PUSH BC C5Save the return address of 27F8H (in BC) to the STACK
CALL 2A07H CALL LEN1CD 07 2AGOSUB to 2A07H (which itself is a GOSUB to 29D7H) to get string’s VARPTR into HL and the string’s length into Register A
2A16-2A18JP Z,1E4AH JP Z,FCERRCA 4A 1EIf the Z FLAG is set, then this was a null string (bad argument), so display a ?FC ERROR
2A19INC HL 23Bump the value of the string’s VARPTR in HL
2A1ALD E,(HL) 5ELoad Register E with the LSB of the address of the string’s data at the location of the string’s VARPTR in HL
2A1BINC HL 23Bump the value of the string’s VARPTR in HL
2A1CLD D,(HL) 56Load Register D with the MSB of the address of the string’s data at the location of the string’s VARPTR in HL
2A1DLD A,(DE) 1ALoad Register A with the first character at the location of the string pointer in DE
2A1ERET C9RETurn to CALLer
2A1F-2A2E – LEVEL II BASIC CHR$ ROUTINE – “CHR$”
2A1F-2A20 CHR$LD A,01H 3E 01Load Register A with the length of the string to be created
2A21-2A23CALL 2857H CALL STRINICD 57 28GOSUB to 2857H to save the string’s length in Register A and value and set up the string’s address
2A24-2A26CALL 2B1FH CALL CONINTCD 1F 2BGOSUB to 2B1FH to evaluate the expression at the location of the current BASIC program pointer in HL and return with the integer result in DE
2A27-2A29 SETSTRLD HL,(40D4H) LD HL,(DSCTMP+1) 2A D4 40Load HL with the temporary string’s address
2A2ALD (HL),E 73Save the character in Register E at the location of the string pointer in HL
POP BC C1Clean up the STACK so that the RETURN address is another one that is next in the STACK.
2A2F-2A60 – LEVEL II BASIC STRING$ ROUTINE – “STRNG$”
We have the STRING$ command, but now we need the next character so we call a RST 10H to bump the value of the current BASIC program pointer until it points to the next character, call the EXAMINE NEXT SYMBOL routine at RST 10H.
The RST 10H routine parses the characters starting at HL+1 for the first non-SPACE,non-09H,non-0BH character it finds. On exit, Register A will hold that character, and the C FLAG is set if its alphabetic, and NC FLAG if its alphanumeric. All strings must have a 00H at the end.
2A30-2A31Since the character at the location of the current BASIC program pointer in HL must be a ( , call the COMPARE SYMBOL routine at RST 08H.
NOTE: The RST 08H routine compares the symbol in the input string pointed to by HL Register to the value in the location following the RST 08 call.- If there is a match, control is returned to the next execution address (i.e, the RST 08H instruction + 2) with the next symbol in the A Register and HL incremented by one.
- If the two characters do not match, a syntax error message is given and control returns to the Input Phase).
2A32-2A34CALL 2B1CH CALL GETBYTCD 1C 2BThis 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
2A34DEC HL 2BBackspace the code string. This is a Z-80 trick because this code was part of the above call instruction
2A35PUSH DE D5Save the string’s length (“N”) (currently in DE) to the STACK
2A36-2A37RST 08 ⇒ 2C SYNCHK “,” CF 2CNow we have STRING$(nnn so the next character needs to be a , . To test for the character at the location of the current BASIC program pointer in HL being a , , call the COMPARE SYMBOL routine which compares the symbol in the input string pointed to by HL Register to the value in the location following the RST 08 call. If there is a match, control is returned to address of the RST 08 instruction + 2 with the next symbol in the A Register and HL incremented by one. If the two characters do not match, a syntax error message is given and control returns to the Input Phase)
2A38-2A3ACALL 2337H CALL FRMEVLCD 37 23Now we have STRING$(xxx, and an expression so GOSUB to 2337H to evaluate the expression at the location of the current BASIC program pointer in HL and return with the result in ACCumulator
2A3B-2A3CNow 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).
2A3DEX (SP),HL E3We 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
2A3EPUSH HL E5Save the string’s length (“N”) in HL to the STACK so that we can test it to make sure it is an integer
2A3FWe need to check the value of the current data type flag, so we call the TEST DATA MODE routine at RST 20H.
NOTE: The RST 20H routine determines the type of the current value in ACCumulator and returns a combination of STATUS flags and unique numeric values in the A Register according to the data mode flag (40AFH). The results are returned as follows:- Integer = NZ/C/M/E and A is -1
- String = Z/C/P/E and A is 0
- Single Precision = NZ/C/P/O and A is 1
- and Double Precision is NZ/NC/P/E and A is 5.
2A42-2A44CALL 2B1FH CALL CONINTCD 1F 2BWe now know that “N” is at least a number, so we GOSUB to 2B1FH to convert the current result in ACCumulator to an integer and return with the 8-bit result in Register A
2A45-2A46JR 2A4AH JR CALSPA18 03Skip the next instruction (which would load the string address and 1st character) by jumping to 2A4AH
CALL 2A13H CALL ASC2CD 13 2AGo get the first character in the string and return with it in Register A. This is the character that will be repeated
2A4BPUSH AF F5Save the character for the string (held in Register A) to the STACK
2A4C SPACE2PUSH AF F5and then save it to the STACK again
2A4DLD A,E 7BLoad Register A with “N” (held in Register E)
2A4E-2A4FCALL 2857H CALL STRINICD 57 28GOSUB to 2857H to allocate N bytes in the temporary string work area
2A51LD E,A 5FLoad Register E with “N” (held in Register A)
2A52POP AF F1Get the character for the string (“X”) from the STACK and put it in Register A
2A53INC E 1CTo set the status flags we need to increase and then decrease E. First, bump the value of the string’s length in Register E
2A54DEC E 1D. and then decrement the string’s length in Register E
2A55-2A56If “N” was zero (so that the string is now complete), jump back to 2A2BH
2A57-2A59LD HL,(40D4H) LD HL,(DSCTMP+1) 2A D4 40If we are here, we have not finished building the STRING$ string so now we load HL with the string’s address and get ready to loop
LD (HL),A 77Save the character in Register A (“X”) at the location of the string pointer in HL
2A5BINC HL 23Bump the value of the string pointer in HL
2A5CDEC E 1DDecrement the string’s length in Register E
2A5D-2A5EJR NZ,2A5AH20 FBLoop back to 2A5AH to keep filling (HL) until the string of X’s has been completed
2A61-2A90 – LEVEL II BASIC LEFT$( ROUTINE – “LEFT$”
On entry, HL=address of LEFT$$, the STACK = string address, STACK+1 = n, and DE = code string address.
2A61-2A63 LEFT$CALL 2ADFH CALL PREAMCD DF 2AGo check the syntax. The character at the location of the current BASIC program pointer in HL must be a )
2A64XOR A AFZero Register A because the string pointer never changes
EX (SP),HL E3Exchange the value of the current BASIC program pointer in HL with the string’s VARPTR to the STACK
2A66LD C,A 4FZero Register C
2A67-2A68LD A,0E5H 3E E5Z-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
PUSH HL E5Save 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 LEFT2PUSH HL E5Save the value of the string’s VARPTR in HL to the STACK
2A6ALD A,(HL) 7ELoad Register A with the string’s length at the location of the string’s VARPTR in HL
2A6BCP B B8Check 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
2A6ELD A,B 78Load Register A with the new string’s TRUNCATED length in Register B
2A6F-2A71LD DE,000EH 11 0E 00Z-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
2A72PUSH BC C5Save the offset in BC to the STACK
2A76POP BC C1Get the offset from the STACK and put it in BC
2A77POP HL E1Get the string’s VARPTR from the STACK and put it in HL
2A78PUSH HL E5Save the string’s VARPTR in HL to the STACK
2A79INC HL 23Bump HL to now point to the address of the string
2A7ALD B,(HL) 46Load Register B with the LSB of the string’s address at the location of the string’s VARPTR in HL
2A7BINC HL 23Bump the value of the string’s VARPTR in HL
2A7CLD H,(HL) 66Load Register H with the MSB of the string’s address at the location of the string’s VARPTR in HL
2A7DLD L,B 68Load Register L with the LSB of the string’s address in Register B
2A7E-2A7FLD B,00H 06 00Zero Register B so that BC can be used
2A80ADD HL,BC 09Add the string’s length in BC to the string’s address in HL
2A81LD B,H 44Load Register B with the MSB of the string’s ending address in Register H
2A82LD C,L 4DLoad Register C with the LSB of the string’s ending address in Register L
2A83-2A85CALL 285AH CALL STRAD2CD 5A 28Go save the string’s length (held in A) and the string’s starting address (held in DE)
2A86LD L,A 6FLoad Register L with the string’s length (i.e., the number of characters to move) held in Register A
2A8APOP DE D1Clean up the STACK
2A91-2A99 – LEVEL II BASIC RIGHT$ ROUTINE – “RIGHT$”
2A91-2A93CALL 2ADFH CALL PREAMCD DF 2AGo check the syntax. The character at the location of the current BASIC program pointer in HL must be a )
2A94POP DE D1Get the string’s VARPTR from the STACK and put it in DE
2A95PUSH DE D5Save the string’s VARPTR in DE to the STACK
2A96LD A,(DE) 1ALoad Register A with the string’s length (held at the location of the string’s VARPTR in DE)
2A97SUB B 90Subtract the new string’s length in Register B from the string’s length in Register A to isolate the number of bytes
2A9A-2AC4 – LEVEL II BASIC MID$ ROUTINE – “MID$”
The original ROM source code clarifies that if the number provided is greater than the actual length of the string, a NULL value is returned. If the second number (the number of characters) exceeds the end of the string, the maximum amount of available characters are returned.
2A9A MID$EX DE,HL EBLoad HL with the value of the current BASIC program pointer (held in DE)
2A9BLD A,(HL) 7ELoad Register A with the terminal character, currently held at the location of the current BASIC program pointer in HL
2A9C-2A9ECALL 2AE2H CALL PREAM2CD E2 2AGOSUB to 2AE2H to get the offset in Register B and the string’s VARPTR in DE
2A9FINC B 04We need to set the status flags to correspond to the offset position value so we first bump the value of the string’s position in Register B
2AA0DEC B 05… and then we decrement the value of the string’s offset position in Register B
2AA4PUSH BC C5Save the value of the offset position (held in Register B) to the STACK
2AA5-2AA6LD E,0FFH 1E FFLoad Register E with the default string’s length of 256 in case no number of bytes are given
2AA7-2AA8CP 29H CP “)” FE 29More syntax checking. Here we need to test for a ) at the location of the current BASIC program pointer. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
2AA9-2AAAJR Z,2AB0H JR Z,MID228 05Jump to 2AB0H if the character at the location of the current BASIC program pointer in Register A is a )
2AAB-2AACIf it wasn’t a ) , it had best be a , so we need to test the character at the location of the current BASIC program pointer in HL by calling the COMPARE SYMBOL routine at RST 08H.
NOTE: The RST 08H routine compares the symbol in the input string pointed to by HL Register to the value in the location following the RST 08 call.- If there is a match, control is returned to the next execution address (i.e, the RST 08H instruction + 2) with the next symbol in the A Register and HL incremented by one.
- If the two characters do not match, a syntax error message is given and control returns to the Input Phase).
2AAD-2AAFCALL 2B1CH CALL GETBYTCD 1C 2BGo evaluate the expression at the location of the current BASIC program pointer in HL and return with the integer result in DE. Now the byte count is in DE as an integer
2AB0-2AB1Since 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).
2AB2POP AF F1Get the offset from the STACK and put it in Register A
2AB3EX (SP),HL E3Exchange the value of the current BASIC program pointer in HL with the value of the string’s VARPTR to the STACK
LD BC,2A69H LD BC,LEFT2 01 69 2ALoad BC with 2A69H as the return address (which is in the LEFT$ routine)
2AB7PUSH BC C5Save the return address in BC to the STACK
2AB8DEC A 3DDecrement the value of the requested offset in Register A so that we have a starting position minus 1
2AB9CP (HL) BECompare 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-2ABBLD B,00H 06 00Zero Register B
2ABCRET NC D0If the offset pointer ispast the end of the string we are going to return a null
2ABELD A,(HL) 7ELoad Register A with the string’s length at the location of the string’s VARPTR in HL
2ABFSUB C 91Subtract the index (the second argument) in Register C from the string’s length in Register A
2AC0CP E BBCompare 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.
2AC1LD B,A 47Load Register B with the calculated string’s length in Register A
2AC2RET C D8If we are not going to truncate, then just use the partial string we already have and Return to 2A69H
2AC4RET C9Return to 2A69H aka LEFT2
2AC5-2ADE – LEVEL II BASIC VAL ROUTINE – “VAL”
2AC5-2AC7 VALCALL 2A07H CALL LEN1CD 07 2AGo get the string’s length in Register A and the string’s VARPTR in HL
2AC8-2ACAJP Z,27F8H JP Z,SNGFLTCA F8 27Jump to 27F8H if the string’s length in Register A is equal to zero
2ACBLD E,A 5FLoad Register E with the string’s length at the location of the string’s VARPTR in HL.
The original ROM source explains that we need to do some fancy footwork here to handle the case where the two strings are stored next to each other.
2ACCINC HL 23Bump the value of the string’s VARPTR in HL
2ACDLD A,(HL) 7ELoad Register A with the LSB of the string’s address at the location of the string’s VARPTR in HL
2ACEINC HL 23Bump the value of the string’s VARPTR in HL
2ACFLD H,(HL) 66Load Register H with the MSB of the string’s address at the location of the string’s VARPTR in HL
2AD0LD L,A 6FLoad Register L with the LSB of the string’s address in Register A
2AD1PUSH HL E5Save the value of the string’s address in HL to the STACK
2AD2ADD HL,DE 19Add the string’s length in DE to the string’s address in HL
2AD3LD B,(HL) 46Load Register B with the last character of the string at the location of the string pointer in HL
2AD4LD (HL),D 72Save the zero in Register D at the location of the string pointer in HL
2AD5EX (SP),HL E3Exchange the string’s ending address in HL with the string’s address to the STACK
2AD6PUSH BC C5Save the last character of the string in Register B to the STACK
2AD7LD A,(HL) 7ELoad Register A with the first character of the argument
2AD8-2ADACALL 0E65H CALL FINDBLCD 65 0ECall 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)
2ADBPOP BC C1Get the modified character of the next string into Register B
2ADCPOP HL E1Get the pointer to the modified character back into HL
2ADDLD (HL),B 70Restore the character.
2ADERET C9RETurn 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.
2AE0-2AE1Since 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).
2AE3POP DE D1Get the number of bytes to isolate from the string (from the STACK) and put it in DE
2AE4PUSH BC C5Save the return address in BC to the STACK
2AE5LD B,E 43Load Register B with the number of bytes in Register E
2AE6RET C9RETurn to CALLer
2AE7H-2AEE – Process a LEFT-HAND-SIDE MID$ – “ISMID$”
CP 7AH CP MIDTK-$END FE 7AThis routine is designed to handle a left-size MID$ call. So check to see if the character at the location of the current BASIC program pointer in Register A is trying to process a left hand side MID$. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
2AE9-2AEBJP NZ,1997H JP NZ,SNERRC2 97 19Display a ?SN ERROR message if that is not what is going on.
2AEC-2AEEJP 41D9H JP DLHSMDC3 D9 41JUMP to DOS to see if DOS wants to deal with this.
2AEF-2AF7 – LEVEL II BASIC INP ROUTINE – “FNINP”
2AEF-2AF1 FNINPCALL 2B1FH CALL CONINTCD 1F 2BGo evaluate the expression at the location of the current BASIC program pointer in HL and return with the port number in Register A
2AF2-2AF4LD (4094H),A LD (STAINP+1),A 32 94 40Save the value of the port number (from Register A) into 4094H, which is in the middle of a routine.
2AF5-2AF1CALL 4093H CALL STAINP CD 1F 2BPerform in INP on the channel held in Register A
2AF8-2B00 – LEVEL II BASIC OUT ROUTINE – “FNOUT”
2AFB-2AFDJP 4096H JP OUTWRDCD 0E 2BDo the OUT and RETurn
2B01-2B0D – EVALUATE EXPRESSION ROUTINE
“GETINT”
This evaluates an expression and leaves the result in DE as an integer.
2B01 GETINTWe 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.
CALL 2337H CALL FRMEVLCD 37 23Go 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)).
2B06-2B08CALL 0A7FH CALL FRCINTCD 7F 0ACall 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)
2B09EX DE,HL EBLoad DE with the integer result in HL
2B0APOP HL E1Get the value of the current BASIC program pointer from the STACK and put it in HL
2B0BLD A,D 7ALoad Register A with the MSB of the integer result in Register D
2B0COR A B7Test the value of the MSB in Register A
2B0DRET C9RETurn to CALLer
2B0E-2B16 – EVALUATE EXPRESSION ROUTINE – OUT continues here – “SETIO”
CALL 2B1CH CALL GETBYTCD 1C 2BGOSUB to 2B1CH to evaluate the expression at the location of the current BASIC program pointer in HL and return with the 8-bit value in Register A
2B11-2B13LD (4094H),A LD (STAINP+1),A 32 94 40Save the 8-bit value in Register A in the DOS address of 4094H to set up for WAIT
2B14-2B16LD (4097H),A LD (OUTWRD+1),A 32 97 40Save the 8-bit value in Register A in the DOS address of 4097H to set up for OUT
2B17-2B1A – CHECK SYNTAX ROUTINE – This checks to see if the next character is a “ and contnues on to 2B1CH if it is, and errors out if it isn’t.
2B17-2B18Since 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).
2B1B-2B28 – EVALUATE EXPRESSION ROUTINE – This is called by PRINT TAB – “GTBYTC” .
2B1B GTBYTCWe need the next character in the BASIC program so call the EXAMINE NEXT SYMBOL routine at RST 10H.
The RST 10H routine parses the characters starting at HL+1 for the first non-SPACE,non-09H,non-0BH character it finds. On exit, Register A will hold that character, and the C FLAG is set if its alphabetic, and NC FLAG if its alphanumeric. All strings must have a 00H at the end.
2B1C – Common Conversion Routine – “GETBYT”
This routine converts a numeric ASCII string pointed to by the HL into a hexadecimal value and places the result in the A register. If the result is larger than 255 (FFH) then an FC ERROR (Illegal function call) will be generated. After execution the HL will point to the delimiter. If the delimiter is a zero byte or a colon (3AH) then the Z flag will be set. Any other delimiter will cause the Z flag to be reset.
2B1C-2B1E GETBYTCALL 2337H CALL FRMEVLCD 37 23GOSUB to 2337H to evaluate the formula/expression at the location of the current BASIC program pointer in HL and return with the result in REG l
2B1F-2B21 CONINTCALL 2B05H CALL INTFR2CD 05 2BGOSUB to 2B05H to convert the result in ACCumulator to an integer and return with the integer result in DE. Flags are set based on Register D.
2B22-2B24JP NZ,1E4AH JP NZ,FCERRC2 4A 1EIf the result is greater than 255, display a ?FC ERROR message
2B25DEC HL 2BDecrement the value of the current BASIC program pointer in HL
2B26We 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.
2B27LD A,E 7BLoad Register A with the 8-bit result in Register E so that both A and E have the result.
2B28RET C9RETurn 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 LLISTLD A,01H 3E 01Load Register A with the printer output device code
2B2B-2B2DLD (409CH),A LD (PRTFLG),A 32 9C 40Save the value in Register A as the current output device flag.
Note: 409CH holds the current output device flag: -1=cassette, 0=video and 1=printer
2B2E-2B74 – LEVEL II BASIC LIST ROUTINE – “LIST”
On entry the STACK has the return address, then the first basic line number to be listed, then the last basic line number to be listed.
2B2E LISTPOP BC C1Get rid of the the return address on the STACK
2B2F-2B31CALL 1B10H CALL SCNLINCD 10 1BGo evaluate the range of line numbers given at the location of the current BASIC program pointer in HL
2B32PUSH BC C5Save the address of the first BASIC line (held in BC) to the STACK
LD HL,FFFFH 21 FF FFLoad 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-2B38LD (40A2H),HL LD (CURLIN),HL 22 A2 40Save the value in HL as the current BASIC line number (which is stored at 40A2H-40A3H).
2B39POP HL E1Get the address of the first BASIC line to be listed (from the STACK) and put it in HL
2B3APOP DE D1Get the value of the last BASIC line number to be listed (from the STACK) and put it in DE
2B3BLD C,(HL) 4ELoad Register C with the LSB of the next BASIC line pointer at the location of the memory pointer in HL
2B3CINC HL 23Bump the value of the memory pointer in HL
2B3DLD B,(HL) 46Load Register B with the MSB of the next BASIC line pointer at the location of the memory pointer in HL
2B3EINC HL 23Bump the value of the memory pointer in HL
2B3FLD A,B 78Load Register A with the MSB of the next BASIC line pointer in Register B
2B40OR C B1Combine the LSB of the next BASIC line pointer in Register C with the MSB of the next BASIC line pointer in Register A. This will let us test for the end of the BASIC program
2B41-2B43JP Z,1A19H JP Z,READYCA 19 1AIf we are at the elast line, then STOP and JUMP to 1A19H to the READY PROMPT.
2B44-2B46CALL 41DFH CALL EXCHDSCD DF 41GOSUB to DOS to see if DOS wants to do anything here.
2B47-2B49CALL 1D9BH CALL ISCNTCCD 9B 1DGo scan the keyboard to see if the BREAK key or the shift – @ key was pressed
2B4APUSH BC C5Save the address of the next BASIC line in BC to the STACK
2B4BLD C,(HL) 4EWe 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
2B4CINC HL 23Bump the value of the memory pointer in HL
2B4DLD B,(HL) 46Load Register B with the MSB of the BASIC line number at the location of the memory pointer in HL
2B4EINC HL 23Bump the value of the memory pointer in HL
2B4FPUSH BC C5Save the BASIC line number in BC to the STACK
2B50EX (SP),HL E3Swap (SP) and HL so that the line number is now in HL
2B51EX DE,HL EBSwap DE and HL so that the last BASIC line number is now in HL
2B52We 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.
2B53POP BC C1Get the pointer to the location on the BASIC program line being processed and put it in BC
2B54-2B56JP C,1A18H JP C,STPRDYDA 18 1AIf the BASIC line number in DE is greater than the last BASIC line number in HL then we have gone past the end, so we are done processing!
2B57EX (SP),HL E3Swap (SP) and HL so that the last BASIC line number is now on the STACK
2B58PUSH HL E5Save the address of the next BASIC line in HL to the STACK
2B59PUSH BC C5Save the pointer to the location on the BASIC program line being processed to the STACK
2B5AEX DE,HL EBLoad HL with the BASIC line number (from DE)
2B5B-2B5DLD (40ECH),HL LD (DOT),HL 22 EC 40Save the BASIC line number in HL into DOT for use later in EDIT or LIST.
Note: 40ECH-40EDH holds EDIT line number
2B5E-2B60CALL 0FAFH CALL LINPRTCD AF 0FCall 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-2B62LD A,20H 3E 20Load Register A with a space
2B63POP HL E1Get the value of the memory pointer from the STACK and put it in HL
2B67-2B69CALL 2B7EH CALL BUFLINCD 7E 2BGOSUB to 2B7EH move the BASIC line at the location of the memory pointer in HL into the input buffer and untokenize the BASIC line
2B6A-2B6CLD HL,(40A7H) LD HL,(BUFPNT) 2A A7 40Load HL with the starting address of the input buffer.
Note: 40A7H-40A8H holds the input Buffer pointer
2B6D-2B6FCALL 2B75H CALL LISPRTCD 75 2BSince 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
2B75-2B7D – DISPLAY MESSAGE ROUTINE – “LISPRT”
This is the PRINT MESSAGE routine which writes string pointed to by HL to the current output device. String must be terminated by a byte of zeros. This call is different from 28A7H because it does not use the literal string pool area, but it does use the same display routine and it takes the same DOS Exit at 41C1H. Uses all registers. This routine can be called without loading the BASIC utility, if a C9H (RET) is stored in 41C1H.
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.
LD A,(HL) 7ELoad Register A with the character at the location of the memory pointer in HL
2B76OR A B7Check to see if the character in Register A is an end of the string character (00H)
2B77RET Z C8Return if the character in Register A is an end of the string character
CALL 032AH CALL OUTDOCD 2A 03Go send the character in Register A to the current output device
2B7BINC HL 23Bump the value of the memory pointer in HL
2B7C-2B7DJR 2B75H JR LISPRT18 F7Loop 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.
2B7F-2B81LD HL,(40A7H) LD HL,(BUFPNT) 2A A7 40Load HL with the starting address of the input buffer.
Note: 40A7H-40A8H holds the input Buffer pointer
2B82
2B83LD B,H
LD C,L 44LET Register Pair BC = Register Pair HL
2B84POP HL E1Get the value of the BASIC line pointer from the STACK and put it in HL
2B85-2B86LD D,FFH LD D,BUFLEN 16 FFLoad Register D with the maximum length of an untokenized line
2B8ADEC D 15Decrement the character count in Register D
2B8BRET Z C8Return if 256 characters have been moved into the input buffer
LD A,(HL) 7ELoad Register A with the character at the location of the BASIC line pointer in HL
2B8DOR A B7Set 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)
2B8EINC HL 23Bump the value of the BASIC line pointer in HL to the next character in the code string
2B8FLD (BC),A 02Save 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.
2B90RET Z C8Return if the character in Register A is an end of the BASIC line character
JP P,2B89H JP P,PLOOPF2 89 2BIf the character in A is just a regular character (i.e., not a token), then JUMP back to 2B89H
2B94-2B95CP 0FBH CP SNGQTK FE FBCheck to see if the character in Register A is a ‘ token. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
2B96-2B97Jump 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-2B9BDEC BC
DEC BC
DEC BC
DEC BC 0BFirst, 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-2B9FINC D
INC D
INC D
INC D 14Then, 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.
CP 95H CP $ELSE FE 95Check to see if the character in Register A is an ELSE token. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
2BA2-2BA4CALL Z,0B24H CALL Z,DCXVBRTCC 24 0BIf 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
DEC BC 0BThis 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-2BA6SUB 7FH D6 7FNext, 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
2BA7PUSH HL E5Save the value of the BASIC line pointer in HL to the STACK. Register L holds the reserved word number at this point.
2BA8LD E,A 5FLoad Register E with the character in Register A
2BA9-2BABLD HL,1650H LD HL,RESLST 21 50 16Load HL with the starting address of the reserved words list
LD A,(HL) 7ELoad Register A with the character at the location of the reserved words list pointer in HL
2BADOR A B7Test 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.
2BAEINC HL 23Bump the value of the reserved words list pointer in HL
2BAF-2BB1JP P,2BACH JP P,LOPRESF2 AC 2BIf the character at the location of the reserved words pointer in Register A doesn’t have bit 7 set then Jump back to 2BACH.
2BB2DEC E 1DDecrement the counter
2BB3-2BB4Jump back to 2BACH if this isn’t the reserved word for the token
2BB5-2BB6AND 7FH E6 7FReset bit 7 of the character in Register A by ANDing it against 0111 1111. This is to eliminate the MSB for “EDIT” and for disk I/O
LD (BC),A 02Save the character in Register A at the location of the input buffer pointer in BC
2BB8INC BC 03Bump the value of the input buffer pointer in BC
2BB9DEC D 15Decrement the value of the character counter in Register D
2BBA-2BBCJP Z,28D8H JP Z,PPSWRTCA D8 28If the Z FLAG has been set, then the character counter for the buffer has been exhausted and the buffer is now full, so JUMP back to 28D8H
2BBDLD A,(HL) 7ELoad Register A with the character at the location of the reserved words pointer in HL
2BBEINC HL 23Bump the reserved words pointer in HL
2BBFOR A B7Test the value of the character in Register A
2BC0-2BC2JP P,2BB7H JP P,MORPURF2 B7 2BKeep getting characters in this reserved word until we hit the next reserved word
2BC3POP HL E1Get the value of the BASIC line pointer from the STACK and put it in HL
2BC4-2BC5JR 2B8CH JR PLOOP218 C6Jump back to 2B8CH to continue processing the BASIC line being interpreted
2BC6-2BF4 – LEVEL II BASIC DELETE ROUTINE – “DELETE”
2BC6-2BC8 DELETECALL 1B10H CALL SCNLINCD 10 1BGOSUB to 1B10H to evaluate the line numbers at the location of the current BASIC program pointer in HL
2BC9POP DE D1Get the value of the last BASIC line number to be deleted (in binary) from the STACK and put it in DE
2BCAPUSH BC C5Save the address of the first BASIC line to be deleted in BC to the STACK
2BCBPUSH BC C5Save the address of the first BASIC line to be deleted in BC to the STACK AGAIN!
2BCC-2BCECALL 1B2CH CALL FNDLINCD 2C 1BGOSUB 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
Since the first line number provided MUST be found, if FNDLIN returns with the NC FLAG set (i.e., not found) we must JUMP to 2BD6H to show a ?FC ERROR
2BD1
2BD2LD D,H
LD E,L 54Let Register Pair DE = Register Pair HL
2BD3EX (SP),HL E3Exchange the last BASIC line’s address in HL with the first BASIC line’s address to the STACK
2BD4PUSH HL E5Save the pointer to the first line in range to the STACK
2BD5We 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.
JP NC,1E4AH JP NC,FCERRD2 4A 1EDisplay a ?FC ERROR message if the first BASIC lines address in HL is greater than or equal to the last BASIC line’s address in DE
2BD9-2BDBLD HL,1929H LD HL,REDDY 21 29 19Load HL with the starting address of the BASIC READY message
2BDC-2BDECALL 28A7H CALL STROUTCD A7 28Call the WRITE MESSAGE routine at 28A7H to print the message pointed to by HL.
2BDFPOP BC C1Get the first BASIC line’s address from the STACK and put it in BC
2BE0-2BE2LD HL,1AE8H LD HL,FINI 21 E8 1ALoad HL with the return address
2BE3EX (SP),HL E3Swap (SP) and HL so that HL now points to the next BASIC line’s address …
2BE5-2BE7LD HL,(40F9H) LD HL,(VARTAB) 2A F9 40Load HL with the end of the BASIC program pointer.
- Note: 40F9H-40FAH holds the starting address of the simple variable storage area.
LD A,(DE) 1ALoad Register A with the character at the location of the memory pointer in DE
2BE9LD (BC),A 02Save the character in Register A at the location of the memory pointer in BC
2BEAINC BC 03Bump the value of the memory pointer in BC
2BEBINC DE 13Bump the value of the memory pointer in DE
2BECNow we need to check to see if the memory pointer in DE equals the end of the BASIC program pointer in HL, so we call the COMPARE DE:HL routine at RST 10H.
The RST 10H routine parses the characters starting at HL+1 for the first non-SPACE,non-09H,non-0BH character it finds. On exit, Register A will hold that character, and the C FLAG is set if its alphabetic, and NC FLAG if its alphanumeric. All strings must have a 00H at the end.
2BED-2BEELoop back to 2BE8H until the memory pointer in DE equals the end of the BASIC program pointer in HL
2BEFLD H,B 60Load Register H with the MSB of the memory pointer in Register B
2BF0LD L,C 69Load Register L with the LSB of the memory pointer in Register C
2BF1-2BF3LD (40F9H),HL LD (VARTAB),HL 22 F9 40Save 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.
2BF4RET C9RETurn to CALLer
2BF5-2C1E – LEVEL II BASIC CSAVE ROUTINE – “CSAVE”
The original ROM source code says that the CSAVE command dump’s BASIC’s core. Three D3H’s are written, followed by a 1 character filename. At the end 3 zeros in a row are written.
2BF5-2BF7 CSAVECALL 0284H CALL CWRTONCD 84 02Calls the WRITE LEADER routine at 0284H (which writes a Level II leader on the cassette unit set in Register A)
2BF8CALL 2337H CALL FRMEVLCD 37 232BFAH Go evaluate the rest of the CSAVE expression at the location of the current BASIC program pointer in HL and return with the result in REG l
2BFBPUSH HL E5Save the value of the current BASIC program pointer in HL to the STACK so we can get it back at the end of the routine
2BFF-2C00LD A,D3H 3E D3Load Register A with the filename header byte (=D3H which is a “S” with the sign bit on)
2C01-2C03CALL 0264H CALL CASOUTCD 64 02the 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
2C07LD A,(DE) 1ALoad Register A with the first character of the filename at the location of the filename pointer in DE
2C08-2C0ACALL 0264H CALL CASOUTCD 64 02the 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-2C0DLD HL,(40A4H) LD HL,(TXTTAB) 2A A4 40Load 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).
2C0EEX DE,HL EBLoad DE with the start of the BASIC program pointer in HL
2C0F-2C11LD HL,(40F9H) LD HL,(VARTAB) 2A F9 40Load HL with the end of the BASIC program pointer.
- Note: 40F9H-40FAH holds the starting address of the simple variable storage area.
LD A,(DE) 1ATop 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
2C13INC DE 13Bump the value of the memory pointer in DE
2C14-2C16CALL 0264H CALL CASOUTCD 64 02the 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)
2C17Now we need to check to see if the memory pointer in DE is equal to the end of the BASIC program pointer in HL, so we call the COMPARE DE:HL routine at RST 10H.
The RST 10H routine parses the characters starting at HL+1 for the first non-SPACE,non-09H,non-0BH character it finds. On exit, Register A will hold that character, and the C FLAG is set if its alphabetic, and NC FLAG if its alphanumeric. All strings must have a 00H at the end.
2C18-2C19Loop back to 2C12H until the memory pointer in DE is equal to the end of the BASIC program pointer in HL
2C1DPOP HL E1Get the value of the current BASIC program pointer from the STACK and put it in HL
2C1ERET C9RETurn to CALLer
2C1F-2CA4 – LEVEL II BASIC CLOAD ROUTINE – ROM v1.0 – “CLOAD”
2C22LD A,(HL) 7ELoad Register A with the character at the location of the current BASIC program pointer in HL
2C23-2C24SUB 0B2H SUB $PRINT D6 B2Check to see if the character at the location of the current BASIC program pointer in Register A is a ? , meaning that CLOAD? was requested.
Jump to the CLOAD? routine at 2C29H if the character at the location of the current BASIC program pointer in Register A is a ?
2C27XOR A AFOK – So this is now a straight CLOAD . First, zero Register A
2C28LD BC,232F 01 2F 23Z-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
2C2AINC HL 23Bump the value of the current BASIC program pointer in HL until it points to the next character after the ? in CLOAD?
2C2BPUSH AF F5Save the CLOAD / CLOAD? flag in Register A to the STACK
2C2CDEC HL 2BDecrement the value of the current BASIC program pointer in HL so we can see if we are at the end
2C2DWe need the next character in the BASIC program so call the EXAMINE NEXT SYMBOL routine at RST 10H.
The RST 10H routine parses the characters starting at HL+1 for the first non-SPACE,non-09H,non-0BH character it finds. On exit, Register A will hold that character, and the C FLAG is set if its alphabetic, and NC FLAG if its alphanumeric. All strings must have a 00H at the end.
2C2E-2C2FLD A,00H 3E 00Zero Register A to allow for any filename
2C30-2C31Jump if the character at the location of the current BASIC program pointer in HL is an end of the BASIC statement character
2C32-2C34CALL 2337H CALL FRMEVLCD 37 23To get the filename we need to GOSUB to 2337H to evaluate the expression at the location of the current BASIC program pointer in HL and return with the result in ACCumulator
2C35-2C37CALL 2A13H CALL ASC2CD 13 2AMake sure the length is good, and save the pointer to the filename to Register Pair DE
2C38LD A,(DE) 1ALoad Register A with the first character of the filename at the location of the filename pointer in DE
2C3APOP AF F1Get the value of the CLOAD / CLOAD? flag from the STACK and put it in Register A
2C3BOR A B7Test the value of the CLOAD / CLOAD? flag in Register A (since CPL doesn’t set any flags)
2C3CLD H,A 67Load Register H with the value of the CLOAD / CLOAD? flag in Register A
2C3D-2C3FLD (4121H),HL LD (FACLO),HL 22 21 41Save the value of the CLOAD / CLOAD? flag and the filename in HL in ACCumulator
2C43-2C45LD HL,(4121H) LD HL,(FACLO) 2A 21 41Load HL with the CLOAD / CLOAD? flag and the filename in ACCumulator
*2C1F-2CA4 – LEVEL II BASIC CLOAD ROUTINE – ROM v1.3
*2C1FSUB 0B2HTest for CLOAD?
*2C23XOR ASo we know that we have a CLOAD and not a CLOAD?, so clear Register A and continue
*2C2401Z-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
CPLSince A is Zero going into this command, once this complement code is exected, A=-1 if CLOAD?, 0000 if CLOAD
*2C26INC HLIncrement HL to the filname of the CLOAD / CLOAD? flag
*2C27PUSH AFSave the CLOAD / CLOAD? flag in Register A to the STACK
*2C28LD A,(HL)Set the next element from the code string, which should be the filename
*2C29OR ASet status flags
*2C32LD A,(DE)Get the filename
*2C33LD L,AMove the filename into Register L
*2C34POP AFRestore the CLOAD / CLOAD? flag
*2C35OR ASet the status Register according to that flag
*2C36LD H,AH will now hold CLOAD / CLOAD? flag, and L will hold the filename
*2C37LD (4121H),HL LD (FACLO),HLPut the flag and filename into ACCumulator
*2C3DLD HL,0000HCause the drive to be selected
*2C43LD HL,(4121H) LD HL,(FACLO)Restore the CLOAD / CLOAD? flag and filename
Common code between ROM v1.0 and v1.2 continues here.
2C46EX DE,HL EBLoad D with the CLOAD/CLOAD? flag and load Register E with the filename
CALL 0235H CALL CASINCD 35 02Calls 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-2C4DSUB 0D3H D6 D3Check to see if the character in Register A is a filename header byte
2C4E-2C4FLoop if the character in Register A isn’t a filename header byte
2C50-2C51Loop back to 2C49H until three filename header bytes have been read
2C52-2C54CALL 0235H CALL CASINCD 35 02Now 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)
2C55INC E 1CWe 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
2C56DEC E 1DDecrement the value of the filename in Register E
2C57-2C58Jump to 2C5CH (to pretend the filename matched) if no filename was specified
2C59CP E BBIf we are here, then the user has supplied a filename which is held in Register E AND we have the first byte from the tape in Register A, so we need to compare the filename specified in Register E with the character in Register A. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
2C5A-2C5BJump 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
LD HL,(40A4H) LD HL,(TXTTAB) 2A A4 40If 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.
LD B,03H 06 03Load Register B with the number of zeros to look for to stop the load (which is 3)
CALL 0235H CALL CASINCD 35 02Calls 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)
2C64LD E,A 5FPreserve the character that was just read from tape into Register E
2C65SUB (HL) 96Compare 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
2C66AND D A2Combine the subtracted result in Register A with the value of the CLOAD / CLOAD? flag in Register D. Why is this tricky? Because D is always 0 for a CLOAD, so when you AND against 0, you always get 0. If this was CLOAD?, nothing would happen as a result of this.
2C67-2C68Jump to 2C8AH if CLOAD? was selected but the bytes don’t match
2C69LD (HL),E 73At this point either CLOAD? was selected and the bytes match, or CLOAD was selected. Either way, save the character we read from the tape (held in Register E) to the location of the memory pointer in HL
2C6A-2C6CCALL 196CH
CALL REASONCD 6C 19Make sure there is more room, and toss a ?OM ERROR if there isn’t.
2C6DLD A,(HL) 7ELoad Register A with the character at the location of the memory pointer in HL
2C6EOR A B7Check to see if the byte just read in Register A is equal to zero
2C6FINC HL 23Bump the value of the memory pointer in HL
2C70-2C71Loop if the byte in Register A isn’t equal to zero (meaning that it isn’t end of program or end of statement)
2C72-2C74CALL 022CH CALL BCASINCD 2C 02Call the BLINK ASTERISK routine at 022CH which alternatively displays and clears an asterisk in the upper right hand corner of the video display
2C75-2C76Do that loop until three zeros in a row have been read from the cassette recorder
2C77-2C79LD (40F9H),HL LD (VARTAB),HL 22 F9 40By 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 OKCASSLD HL,1929H LD HL,REDDY 21 29 19Load HL with the starting address of the BASIC READY message
2C75-2C76Do that loop until three zeros in a row have been read from the cassette recorder
2C83-2C85LD HL,(40A4H) LD HL,(TXTTAB) 2A A4 40Load 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).
2C86PUSH HL E5Save the start of the BASIC program pointer in HL to the STACK. FINI will need this value there.
LD HL,2CA5H LD HL,NOOKCS 21 A5 2CLoad HL with the starting address of the BAD message
2C8D-2C8FCALL 28A7H CALL STROUTCD A7 28Call the WRITE MESSAGE routine at 28A7H to print the message pointed to by HL.
NOTE:
- The routine at 28A7 displays the message pointed to by HL on current system output device (usually video).
- The string to be displayed must be terminated by a byte of machine zeros or a carriage return code 0D.
- If terminated with a carriage return, control is returned to the caller after taking the DOS exit at 41D0H (JP 5B99H).
2C90-2C92JP 1A18 JP STPRDYC3 18 1AJUMP to STPRDY to pop NEWSTT from the STACK and then fall into the READY routine
LD B,03H 06 03Load Register B with the number of zeros to be found to stop the search
CALL 0235H CALL CASINCD 35 02Calls 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)
2C9BOR A B7Check to see if the character in Register A is equal to zero
2C9E-2C9FLoop until three zeros in a row have been read from the cassette recorder
2CA0-2CA2CALL 0296H CALL CSRDON + 3CD 96 02Calls 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)
2CA5-2CA9 – MESSAGE STORAGE LOCATION – “NOOKCS”
2CA5-2CA9 NOOKCS“BAD” + 0DH + 00H 42The BAD message is stored here
2CAA-2CB0 – LEVEL II BASIC PEEK ROUTINE – “PEEK”
The original ROM source code says that PEEK only accepts positive numbers up to 32767 and POKE will only take an address up to 32767. Negative numbers can be used to refer to locations higher than 32767, the correspondence is given by subtracting 65536 from locations higher than 32767 or by specifying a positive number up to 65535
On entry, ACCumulator to have the peek location, and on exit ACCumulator to have the peeked value.
2CAA-2CAC PEEKCALL 0A7FH CALL FRCINTCD 7F 0ACall 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)
2CADLD A,(HL) 7ELoad Register A with the value at the location of the memory pointer in HL
2CAE-2CB0JP 27F8H JP SNGFLTC3 F8 27Go save the 8-bit value in Register A as the current result in ACCumulator
2CB1-2CBC – LEVEL II BASIC POKE ROUTINE – “POKE”
2CB1-2CB3 POKECALL 2B02H CALL GETIN2CD 02 2BGo evaluate the expression at the location of the current BASIC program pointer in HL and return with the integer result in DE
2CB4PUSH DE D5Save the address the user wants to POKE to (held in DE) to the STACK
2CB5-2CB6Since the character at the location of the current BASIC program pointer in HL must be a , , call the COMPARE SYMBOL routine at RST 08H.
NOTE: The RST 08H routine compares the symbol in the input string pointed to by HL Register to the value in the location following the RST 08 call.- If there is a match, control is returned to the next execution address (i.e, the RST 08H instruction + 2) with the next symbol in the A Register and HL incremented by one.
- If the two characters do not match, a syntax error message is given and control returns to the Input Phase).
2CB7-2CB9CALL 2B1CH CALL GETBYTCD 1C 2BGOSUB 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
2CBAPOP DE D1Get the address the user wants to POKE to from the STACK and put it in DE
2CBBLD (DE),A 12Save the value the user wanted to poke (held in Register A) in the location that the user wants to POKE to (held in DE)
2CBCRET C9RETurn 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
Vernon Hester has reported an error in the PRINT USING routine. A PRINT USING statement with a negative sign at the end of the field prints a negative sign after negative numbers and prints a space for positive numbers. However, if the field specifiers in the string also has two asterisks at the beginning of the field, the ROM prints an asterisk instead of a space after a positive number.
Example: PRINT USING “**####-“;1234 will display **1234* instead of **1234 SPACE
CALL 2338H CALL FRMCHKCD 38 23Go evaluate the string expression at the location of the current BASIC program pointer in HL
2CC0-2CC2CALL 0AF4H CALL CHKSTRCD F4 0AGo make sure the expression that was just evaluated was a string
2CC3-2CC4Since 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).
2CC5EX DE,HL EBSwap DE and HL so that DE now holds the current BASIC program pointer
2CC6-2CC8LD HL,(4121H) LD HL,(FACLO) 2A 21 41Load HL with the USING string’s VARPTR
LD A,(40DEH) LD A,(FLGINP) 3A DE 40Load Register A with the value of the READ/INPUT flag, which is being used here to track if we printed out a value on the prior scan.
2CCEOR A B7Check to see if that flag indivates that we did, or did not, print out a value last time.
2CCF-2CD0If we did not print out a value last time, we have an error, so JUMP down to 2CDDH
2CD1POP DE D1Restore the pointer to the “USING” string decription from the STACK into DE
2CD2EX DE,HL EBSwap 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.
PUSH HL E5Save the pointer to the “USING” string descriptor (i.e., the USING string’s VARPTR) in HL to the STACK
2CD4XOR A AFZero Register A and all the flags.
2CD5-2CD7LD (40DEH),A LD (FLGINP),A 32 DE 40Clear the flag we are using to see if we printed the values or not.
2CD8CP D BATurn 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.
2CD9PUSH AF F5Save the flag indicating if the value list has ended or not to the STACK
2CDAPUSH DE D5Save the pointer into the value list to the STACK
2CDBLD B,(HL) 46Load Register B with the USING string’s length
2CDCOR B B0Check to see if the USING string’s length in Register B is equal to zero
2CE0INC HL 23Bump the pointer to the USING string’s data in HL by 1
2CE1LD C,(HL) 4ELoad Register C with the LSB of the USING string’s address at the location of the USING string’s VARPTR in HL
2CE2INC HL 23Bump the value of the USING string’s VARPTR in HL
2CE3LD H,(HL) 66Load Register H with the MSB of the USING string’s address at the location of the USING string’s VARPTR in HL
2CE4LD L,C 69Load Register L with the LSB of the USING string’s address in Register C
2CE8PUSH HL E5Save the pointer to the USING string pointer in HL to the top of the STACK
2CE9-2CEALD C,02H 0E 02Since the \\ string field length is two plus number of enclosed spaces, add two
LD A,(HL) 7ELoad Register A with the character at the location of the USING string pointer in HL
2CECINC HL 23Bump the value of the USING string data pointer in HL
2CED-2CEECP 25H CP CSTRNG FE 25Check to see if the character in Register A is a %, which acts as a field terminator. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
2CEF-2CF1JP Z,2E17H JP Z,ISSTRFCA 17 2EIf it is a “%” then JUMP to 2E17H to evaluate a string and print
2CF2-2CF3CP 20H FE 20Check to see if the character in Register A is a ” “, which acts as a field extender. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
2CF4-2CF5If the character is not a field extender, then it isn’t a string field, so JUMP down a few opcodes to 2CF9H
2CF6INC C 0CIncrement the field width (tracked in in Register C)
2CF7-2CF8Decrement 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 NOSTRFPOP HL E1Restore the pointer to the “USING” string’s data into Register Pair HL
2CFALD B,E 43Load Register B with the USING string’s length
2CFB-2CFCLD A,25H LD A,CSTRNG 3E 25Restore 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
CALL 2E49H CALL PLSPRTCD 49 2EIf a + came before the character, make sure to print it
2D00-2D02CALL 032AH CALL OUTDOCD 2A 03Once that has been printed, now we print the character in Register A since we know it isn’t part of a field
XOR A AFWe 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
2D04LD E,A 5FZero Register E
2D05LD D,A 57Zero Register D
CALL 2E49H CALL PLSPRTCD 49 2EGo print a leading + if necessary (i.e., to allow for multiple plusses)
2D09LD D,A 57Set 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.
2D0ALD A,(HL) 7ELoad Register A with the next field description character in the USING string
2D0BINC HL 23Bump the value of the USING string pointer in HL
2D0C-2D0DCP 21H CP “!” FE 21Check 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.
2D11-2D12CP 23H CP “#” FE 23Check 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.
2D15DEC B 05Since every other possibility is actually a two character field, decrement the value of the string’s length in Register B onem ore time
2D16-2D18JP Z,2DFEH JP Z,REUSINCA FE 2DIf 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-2D1ACP 2BH CP “+” FE 2BCheck 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-2D1CLD A,08H 3E 08Set 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
2D1FDEC HL 2BDecrement the value of the USING string pointer so we can re-get the character.
2D20LD A,(HL) 7ELoad Register A with the (current) character at the location of the USING string pointer in HL
2D21INC HL 23Bump the value of the USING string pointer in HL
2D22-2D23CP 2EH CP “.” FE 2ECheck to see if the character in Register A is a . (i.e., a numeric field with trailing digits). If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
2D24-2D25Jump if the character in Register A is a . to scan with Register E holding the number of digits before the “.” as 0
2D26-2D27CP 25H CP CSTRNG FE 25Check to see if the character in Register A is a % (i.e., a really big string field). If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
2D28-2D29Jump to see if it is really a string field if the character in Register A is a %
2D2ACP (HL) BECheck to see if the next character matches the current character in the the USING string. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
2D2B-2D2CIf the NZ flag is set, then we can’t have a $$ or a ** , so all remaining possibilities are exhausted, so JUMP to NEWUCH
2D2D-2D2ECP 24H CP “$” FE 24Check 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.
2D31-2D32CP 2AH CP “*” FE 2ACheck to see if the double character is a ** . If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
2D33-2D34If 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
2D35LD A,B 78Prepare 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-2D37CP 02H FE 02Check 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.
2D38INC HL 23Bump the value of the USING string pointer in HL
2D39-2D3AJump to 2D3EH if the USING string’s length in Register A isn’t at least two
2D3BLD A,(HL) 7ELoad Register A with the character at the location of the USING string pointer in HL
2D3C-2D3DCP 24H CP “$” FE 24Check 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.
2D40-2D41If we did not ultimately get a **$ then JUMP (noting we do NOT set the dollar sign flag)
2D42DEC B 05Decrement the value of the USING string’s length to take the $ into account
2D43INC E 1CBump the field width tracker to account for the floating dollar sign
2D44-2D45CP 0AFH FE AFZ-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.
2D46-2D47ADD A,10H C6 10Mask Register A to set the bit for a floating dollar sign flag.
2D48INC HL 23Bump the value of the USING string pointer in HL to go past the special characters
2D4AADD A,D 82Combine the bits in Register D into the flag tracker
2D4BLD D,A 57Preserve the modified flag tracker into Register D.
2D4D-2D4ELD C,00H 0E 00Set the number of digits to the right of the decimal point (tracked in Register C) to 0
2D4FDEC B 05Check to see if there are any more characters by decrementing the value of the string’s length in Register B
2D50-2D51If 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.
2D52LD A,(HL) 7ELoad Register A with the next character at the location of the USING string pointer in HL
2D53INC HL 23Bump the value of the USING string pointer in HL
2D54-2D55CP 2EH CP “.” FE 2ECheck to see if the character in Register A is a . (i.e., a trailing digit). If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
2D56-2D57If yes, then need to use a special scan loop to scan after the decimal point, so JUMP to AFTDOT
2D58-2D59CP 23H CP “#” FE 23Check to see if the character in Register A is a # (i.e., a leading digit). If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
2D5A-2DIf yes, increment the count and keep scanning via a JUMP to NUMNUM
2D5C-2D5DCP 2CH CP “,” FE 2CCheck to see if the character in Register A is a , . If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
2D5E-2D5FIf there is no comma, then JUMP to FINNUM because there are no more leading digits and we need to check for “^^^”
2D60LD A,D 7AIf we are here, then a comma was requested. Turn on the COMMA bit
2D61-2D62OR 40H F6 40Mask the flag in Register A for ,
2D63LD D,A 57Load Register D with the value of the flag in Register A
2D66 – Part of the PRINT USING Routine – “DOTNUM”
Jumped here when a “.” is seen in the USING string. THis means that we are starting a numeric field ONLY if it is followed by a “#”
2D66 DOTNUMLD A,(HL) 7ELoad Register A with the next character of the USING string
2D67-2D68CP 23H FE 23Check to see if the character in Register A is a # (i.e., a numeric field following a “.”). If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
2D69-2D6ALD A,2EH LD A,”.” 3E 2ELoad Register A with a decimal point
2D6B-2D6CIf it isn’t a “.” then JUMP AWAY to NEWUCH with A holding a “.” so that a “.” will get printed
2D6D-2D6ELD C,01H 0E 01If it was a “.” then we have a numeric field to process. First, set C with the number of characters to the right of the decimal point
2D6FINC HL 23Bump the value of the USING string pointer in HL
INC C 0CBump the number of digits to the right of the decimal point (tracked in Register C)
2D71DEC B 05Decrement the value of the USING STRING’s length to test to see if there are more characters
2D72-2D73If the USING string length is now ZERO, JUMP to ENDNUS to stop scanning
2D74LD A,(HL) 7ELoad Register A with the character at the location of the USING string pointer in HL
2D75INC HL 23Bump the value of the USING string pointer in HL
2D76-2D77CP 23H FE 23Check to see if the character in Register A is a # ; meaning that there are more digits after the decimal point. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
2D78-2D79If 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
PUSH DE D5Save the value of the flag (tracked in D) and the number of leading digits (tracked in E) to the STACK
2D7B-2D7DLD DE,2D97H LD DE,NOTSCI 11 97 2DLoad DE with the return address in case this is not a scientific notation
2D7EPUSH DE D5Save the value of the return address in DE to the STACK
2D7F
2D80LD D,H
LD E,L 54Let DE = HL in case we need to rememer HL
2D81-2D82CP 5BH FE 5BCheck 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.
2D83RET NZ C0Return if the character in Register A isn’t an up arrow
CP (HL) BECheck 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.
2D85RET NZ C0Return 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)
2D87CP (HL) BECheck 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.
2D88RET NZ C0Return 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)
2D8ACP (HL) BECheck 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.
2D8BRET NZ C0Return 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)
INC HL 23Bump the value of the USING string pointer in HL. If we are here we have a #.^^^^ format
2D8DLD A,B 78Now 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-2D8FSUB 04H D6 04Check to see if there are at least 4 characters left in the USING string
2D90RET C D8Return to 2D97 if there aren’t at least four characters left in the USING string
POP DE D1If there are at least 4 characters left, then clean up the STACK by removing the NOTSCI return address
2D92POP DE D1Get the flag and the count of the characters to the left of the decimal point from the STACK and put it in DE
2D93LD B,A 47Load Register B with the new USING string’s length in Register A
2D94INC D 14Set the exponential notation flag (tracked in Register D)
2D95INC HL 23Bump the value of the USING string pointer in HL
2D96JP Z,0D1EBH CA EB D1Z-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,HL EB(Ignored if passing through) Restore the old HL into HL
2D98POP DE D1(Ignored if passing through) Restore the flags into Register D and the number of leading digits into Register E
LD A,D 7AWe 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
2D9ADEC HL 2BDecrement the value of the USING string pointer in HL
2D9BINC E 1CBump the number of characters to the left of the decimal point in Register E to take into account the leading plus
2D9C-2D9DAND 08H E6 08Mask Register A to NOT check for a trailing sign
2D9E-2D9FIf that AND leaves us with a NZ, then we are all done with the field, so JUMP to ENDNUM
2DA0DEC E 1DOtherwise, 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
2DA1LD A,B 78Check to see if there are more characters by first loading Register A with the USING string’s length from Register B
2DA2OR A B7Check to see if this is the end of the USING string
2DA3-2DA4If we are out of characters, then we are all done, so JUMP to ENDNUM
2DA5LD A,(HL) 7EIf there ARE more characters, then fill Register A with the character at the location of the USING string pointer in HL
2DA6-2DA7SUB 2DH SUB “-“ D6 2DCheck to see if the character in Register A is a – (i.e., a trailing minus)
2DAA-2DABCP 0FEH CP “+” – “-“ FE FECheck 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.
2DAE-2DAFLD A,08H 3E 08If we are here then we did have a trailing “+” so first set the flag for a POSITIVE “+”
2DB2ADD A,D 82Combine the value of the flag in Register D with the value of the flag in Register A
2DB3LD D,A 57Load Register D with the current flags
2DB4DEC B 05Decrement the value of the USING string’s length in Register B by 1 to account for the trailing sign
2DB5 – Part of the PRINT USING Routine – “ENDNUM”
Jump point for when we figure out that we are at the end of a string of digits within a USING string
2DB5 ENDNUMPOP HL E1Get the value of the current BASIC program pointer from the STACK and put it in HL
2DB6POP AF F1Load Register A with the flag that tells us whether there are more values to process in the value list.
2DB7-2DB8If there are no more values in the value list to process, then JUMP to FLDFIN because we are done with the PRINT
2DB9PUSH BC C5Save 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
2DBAPUSH DE D5Save the flags (held in D) and the number of leading digits (held in E) to the STACK
2DBB-2DBDCALL 2337H CALL FRMEVLCD 37 23Read 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
2DBEPOP DE D1Restore the flags (held in D) and the number of leading digits (held in E) from the STACK
2DBFPOP BC C1Restore 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
2DC0PUSH BC C5Save 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
2DC1PUSH HL E5Save the value of the current BASIC program pointer in HL to the STACK
2DC2LD B,E 43Set Register B to hold the number of leading digits (i.e., the number of characters to the left of the decimal point)
2DC3LD A,B 78We 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
2DC4ADD A,C 81Then 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-2DC6CP 19H FE 19Check to see if the total number of characters in Register A is greater than 24. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
2DC7-2DC9JP NC,1E4AH JP NC,FCERRD2 4A 1EDisplay a FC ERROR message if the total number of digits is greater than 24
2DCALD A,D 7ALoad Register A with the flags (held in Register D)
2DCB-2DCCOR 80H F6 80Turn on the “USING” bit in the flags
2DCD-2DCFCALL 0FBEH CALL PUFOUTCD BE 0FPrepare to print by calling the FLOATING TO ASCII routine at 0FBEH (whcih converts a single or double precision number in ACCumulator to its ASCII equivalent which will be stored at the buffer pointed to by HL using the format codes in the A, B, and C registers
2DD0-2DD2CALL 28A7H CALL STROUTCD A7 28Call the WRITE MESSAGE routine at 28A7H to print the message pointed to by HL.
NOTE:
- The routine at 28A7 displays the message pointed to by HL on current system output device (usually video).
- The string to be displayed must be terminated by a byte of machine zeros or a carriage return code 0D.
- If terminated with a carriage return, control is returned to the caller after taking the DOS exit at 41D0H (JP 5B99H).
POP HL E1Top of a loop. Get the value of the current BASIC program pointer from the STACK and put it in HL
2DD4DEC HL 2BDecrement the value of the current BASIC program pointer in HL so we can test to see what the terminator was
2DD5We 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.
2DD6SCF 37Set the Carry flag to indicate that a CRLF is desired
2DD7-2DD8If 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-2DDBLD (40DEH),A LD (FLGINP),A 32 DE 40Set the flag that the value HAS been printed!
2DDC-2DDDCP 3BH CP “;” FE 3BCheck 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.
2DE0-2DE1CP 2CH CP “,” FE 2CCheck to see if the character at the location of the current BASIC program pointer in Register A is a comma. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
2DE2-2DE4JP NZ,1997H JP NZ,SNERRC2 97 19If 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.
POP BC C1Restore the number of characters remaining to be procesed in the USING string into Register B
2DE7EX DE,HL EBSwap DE and HL so that DE will point to the location of the current BASIC program pointer. We don’t care about HL.
2DE8POP HL E1Restore the position in the USING string from the STACK and put it in HL
2DE9PUSH HL E5Save the position in the USING string (held in HL) to the STACK
2DEAPUSH AF F5Save the flag that indicates whether or not the value list has terminated to the STACK
2DEBPUSH DE D5Save 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.
2DECLD A,(HL) 7ELoad Register A with the USING string’s length at the location of the USING string’s VARPTR in HL
2DEDSUB B 90Subtract the number of characers which were already scanned
2DEEINC HL 23Bump the pointer to the “USING” strings string data
2DEFLD C,(HL) 4ELoad Register C with the LSB of the USING string’s address at the location of the USING string’s VARPTR in HL
2DF0INC HL 23Bump the value of the USING string’s VARPTR in HL
2DF1LD H,(HL) 66Load Register H with the MSB of the USING string’s address at the location of the USING string’s VARPTR in HL
2DF2LD L,C 69Load Register L with the LSB of the USING string’s address in Register C
2DF3-2DF4LD D,00H 16 00Zero Register D so that Register Pair DE can be a 16 bit offset of whatever is held in A.
2DF5LD E,A 5FLoad Register E with the USING string’s offset in Register A
2DF6ADD HL,DE 19Add 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
2DF7LD A,B 78Load Register A with the number of characters left to scan
2DF8OR A B7Check to see if this is the end of the USING string
2DF9-2DFBJP NZ,2D03H JP NZ,PRCCHRC2 03 2DIf there are still more string characters to scan, JUMP to PRCCHR to do so
2DFE-2E00 – Part of the PRINT USING Routine – “REUSIN”
We will wind up here when we are done processing a numeric field
2E01-2E03CALL 032AH CALL OUTDOCD 2A 03Go send the FINAL character (held in Register A) to the current output device
POP HL E1Get the value of the current BASIC program pointer from the STACK and put it in HL
2E05POP AF F1Restore the flag which indicates whether or not the value list has ended into Register A
2E06-2E08JP NZ,2CCBH JP NZ,REUSSTC2 CB 2CIf the value list has NOT ended, JUMP back to REUSST to reuse the USING string
CALL C,20FEH CALL C,CRDODC FE 20If 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
2E0CEX (SP),HL E3Swap (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
2E10POP HL E1Get the value of the current BASIC program pointer from the STACK and put it in HL
2E14-2E15 – Part of the PRINT USING Routine – “SMSTRF”
We will wind up here when the “!” indicating a single character string field has been scanned
2E16-2E17LD A,0F1H 3E F1Z-80 Trick. By putting a 3E in front of the F1 (which is POP AF , to clear the STACK) that POP AF gets skipped if flowing down in the code
POP AF F1(Skipped if passing down) Clear the STACK *dumping the HL that was being saved in case it turned out that this wasn’t actually a string)
2E18DEC B 05Decrement the USING string character count (tracked in Register B)
2E1CPOP HL E1Get the value of the current BASIC program pointer from the STACK and put it in HL
2E1DPOP AF F1Get the flag which indicates whether there are more values in the value list into Register A
2E1E-2E1FIf there are no more values in the value list, then we are done so JUMP back to 2E09H
2E20PUSH BC C5Save the number of characters still to be scanned from the USING string (tracked in B) to the STACK
2E21-2E23CALL 2337H CALL FRMEVLCD 37 23Read 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
2E27POP BC C1Restore the field width (a/k/a the number of characters to be printed) into Register C
2E28PUSH BC C5Save the USING string’s length and the number of characters to be printed in BC to the STACK
2E29PUSH HL E5Save the value of the current BASIC program pointer in HL to the STACK
2E2A-2E2CLD HL,(4121H) LD HL,(FACLO) 2A 21 41Load HL with the string’s VARPTR in ACCumulator
2E2DLD B,C 41Load Register B with field width (a/k/a the number of characters to be printed)
2E2E-2E2FLD C,00H 0E 00Zero Register C so that we can use the LEFT$ routine
2E30PUSH BC C5Save the length of the string to be printed in Register B to the STACK (as we will need that for space padding)
2E31-2E33CALL 2A68H CALL LEFTUSCD 68 2ATruncate the string to B characters via a call to the LEFT$ routine
2E37-2E39LD HL,(4121H) LD HL,(FACLO) 2A 21 41Load HL with the string’s VARPTR in ACCumulator so we can see if we need to pad the string
2E3APOP AF F1Get the field width (a/k/a the length of the string to be printed) from the STACK and put it in Register A
2E3BSUB (HL) 96Determine 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
2E3CLD B,A 47Save the amount of padding needed into Register B
2E3D-2E3ELD A,20H 3E 20Load Register A with a SPACE
2E3FINC B 04Bump 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.
2E41-2E43JP Z,2DD3H JP Z,FNSTRFCA D3 2DIf all of the spaces have been printed, Jump back to 2DD3H to see if the value list ended and to resume scanning
2E49 – Part of the PRINT USING Routine – “PLSPRT”
When a “+” is detected in the “USING” string and a numeric field follows, a bit in Register D should be set, otherwise + should be printed. Since deciding whether a numeric field follows is very difficult, the bit is always set in Register D. At the point it is decided a character is not part of a numeric field, this routine is called to see if the bit in Register D is set, which means a plus preceded the character and should be printed
2E49 PLSPRTPUSH AF F5Save the current character (held in Register A) to the STACK
2E4ALD A,D 7AWe need to test the PLUS BIT in D, so first load Register A with the value in Register D
2E4BOR A B7Check 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-2E4DLD A,2BH LD A,”+” 3E 2BPrepare to print the + by loading Register A with a +
2E4E-2E50CALL NZ,032AH CALL NZ,OUTDOC4 2A 03If the bit was set (i.e., A was non-zero), then send a + to the current output device
2E51POP AF F1Get the current character from the STACK and put it in Register A
2E52RET C9RETurn 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
LD (409AH),A LD (ERRFLG),A 32 9A 40Reset the EDIT flag.
Note: 409AH holds the ERROR/RESUME flag
2E56-2E58LD HL,(40EAH) LD HL,(ERRLIN) 2A EA 40Load HL with the line number to be edited.
Note: 40EAH-40EBH holds the line number with error
2E59OR H B4OR Register A with the MSB of the error line number in Register H
2E5AAND L A5Combine 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
2E5BINC A 3CBump 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
2E5CEX DE,HL EBSwap DE and HL so that DE now holds the line number to edit.
2E5DRET Z C8If 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
2E60-2E62 EDITCALL 1E4FH CALL LINSPCCD 4F 1EGet the first line number by calling 1E4F – returns in in DE
2E63RET NZ C0If the zero flag got set, there was no line number, so return
2E66-2E68LD (40ECH),HL LD (DOT),HL 22 EC 40Save 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
2E69EX DE,HL EBLoad HL with the line number to be edited
2E6A-2E6CCALL 1B2CH CALL FNDLINCD 2C 1BFind 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
2E70
2E71LD H,B
LD L,C 60At this point, the line number has been found. Let HL=BC so that HL also points to the location in RAM of the line number being edited
2E72
2E73INC HL
INC HL 23Bump the value of the memory pointer in HL twice to now point to the first byte of the line.
2E74LD C,(HL) 4ELoad Register C with first byte of the line number being edited
2E75INC HL 23Bump the value of the memory pointer in HL to point to the second byte of the line being edited
2E76LD B,(HL) 46Load Register B with second byte of the line number being edited
2E77INC HL 23Bump the value of the memory pointer in HL to now point to the first byte of the actual line
2E78PUSH BC C5Save the line number to the STACK
2E79-2E7BCALL 2B7EH CALL BUFLINCD 7E 2BGOSUB to 2B7EH move the BASIC line at the location of the memory pointer in HL into a memory buffer and untokenize the BASIC line
2E7D INLEDPUSH HL E5Save the value of the line number in HL to the STACK
2E7E-2E80CALL 0FAFH CALL LINPRTCD AF 0FConvert the line number to ASCII and print it out by calling the HL TO ASCII routine at 0FAFH (which converts the value in the HL (assumed to be an integer) to ASCII and display it at the current cursor position on the video screen)
2E81-2E82LD A,20H 3E 20Load Register A with a space
2E86-2E88LD HL,(40A7H) LD HL,(BUFPNT) 2A A7 40Load HL with the starting address of the expanded version of the current line from the input buffer.
Note: 40A7H-40A8H holds the input Buffer pointer
2E89-2E8ALD A,0EH 3E 0ELoad Register A with the “turn on the cursor” character
2E8EPUSH HL E5Save the value of the input buffer pointer (in HL) to the STACK
2E8F-2E90LD C,FFH 0E FFLoad Register C with the number of characters examined so far with FFH because the next line is going to INC it by 1 to make it 0
2E92LD A,(HL) 7ELoad Register A with the character at the location of the input buffer pointer in HL
2E93OR A B7Check to see if the character in Register A is an end of the BASIC line character
2E94INC HL 23Bump the value of the input buffer pointer in HL
2E95-2E96Loop back to 2E91H until the end of the BASIC line has been found
2E97POP HL E1At this point, C will be the maximum number of characters in the line at issue. Put the start of the expanded buffer into HL
2E98LD B,A 47Set the current position in the BASIC line being edited (tracked by Register B) to ZERO
2E99-2E9A DISPEDLD D,00H 16 00Assume the repetition count for the upcoming command (tracked by Register D) is zero
2D9E-2E9F DISPSUB 30H 20 15We need to test to see if the character was alphabetic or alphanumeric so we subtract 30H from it
2EA2-2EA3CP 0AH FE 0ACheck 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.
2EA6LD E,A 5FLoad Register E with the binary value of the character in Register A
2EA7LD A,D 7APut the repetition value into Register A
2EA8RLCA 07Multiply the value in Register A by two (so now A has multiplied by 2)
2EA9RLCA 07Multiply the value in Register A by two (so now A has multiplied by 4)
2EAAADD A,D 82Add the value in Register D to the value in Register A (so now A has multiplied by 5)
2EABRLCA 07Multiply the value in Register A by two (so now A has multiplied by 10). Now the “ones place” is empty.
2EACADD A,E 83Add the value in Register E to the value in Register A in the “ones place”
2EADLD D,A 57Load Register D with the value in Register A
2EB0H – LEVEL II BASIC EDIT ROUTINE – “NOTDGI”
While getting user command input within an edit, we wind up here if the user enters a non-numeric character (i.e., the actual command, and not just the repetition number which precedes it)
2EB0 NOTDGIPUSH HL E5Save the value of the input buffer pointer in HL to the STACK
2EB1-2EB3LD HL,2E99H LD HL,DISPED 21 99 2ELoad HL with the return address of 2E99H
2EB4EX (SP),HL E3Exchange the value of the return address in HL with the value of the input buffer pointer to the STACK
2EB5DEC D 15We 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
2EB6INC D 14… and then incrementing the numeric value in Register D to set the flags
2EB7-2EB9JP NZ,2EBBH JP NZ,NTZERDC2 BB 2EIf we had a received a repetition count already, then JUMP to 2EBBH
2EBAINC D 14Otherwise, set the repetition count (held in Register D) to be one
CP 0D8H FE D8Check to see if the character in Register A is a BACKSPACE character. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
2EBD-2EBFJP Z,2FD2H JP Z,DELEDCA D2 2FIf the character in Register A is a BACKSPACE character, JUMP to DELED
2EC0-2EC1CP 0DDH FE DDCheck to see if the character in Register A is a CARRIAGE RETURN . If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
2EC2-2EC4JP Z,2FE0H JP Z,CREDCA E0 2FIf the character in Register A is a CARRIAGE RETURN , JUMP to CRED
2EC5-2EC6CP 0F0H FE F0Check 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.
That’s it for non-alphabetic instructions, so we need to need to convert a lower case command to upper case
2EC9-2ECACP 31H FE 31Check 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.
2ECD-2ECESUB 20H D6 20Convert the lowercase character in Register A to uppercase
CP 21H FE 21Check 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.
2ED4-2ED5CP 1CH FE 1CCheck 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.
2ED9-2EDACP 23H FE 23Check 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.
2EDD-2EDECP 19H FE 19Check 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.
2EE2-2EE3CP 14H FE 14Check 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.
2EE7-2EE8CP 13H FE 13Check 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.
2EEC-2EEDCP 15H FE 15Check 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.
2EF1-2EF2CP 28H FE 28Check 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.
2EF6-2EF7CP 1BH FE 1BCheck 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.
2EFA-2EFBCP 18H FE 18Check to see if the character in Register A is an H . If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
2EFC-2EFEJP Z,2F75H JP Z,HEDCA 75 2FJump if the character in Register A is an H (i.e., HACK off the rest of the line and then enter INSERT mode)
2EFF-2F00CP 11H FE 11Check 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.
2F01RET NZ C0Return if the character in Register A isn’t an A
2F02 – EDIT Command – Cancel and Restore Logic.
2F02POP BC C1Clean up the STACK (i.e., remove the DISPI return address)
2F03POP DE D1Get 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 SPEDLD A,(HL) 7ELoad Register A with the character at the location of the input buffer pointer in HL
2F0BOR A B7Check to see if the character in Register A is an end of the BASIC line character
2F0CRET Z C8Return if the character in Register A is an end of the BASIC line character
2F0DINC B 04Bump the character position in Register B
2F11INC HL 23Bump the value of the pointer in HL
2F12DEC D 15Decrement the number of times to perform the operation in Register D
2F15RET C9RETurn to CALLer
2F16 – EDIT Command – KILL Logic – “KED” .
2F17-2F19LD HL,2F5FH LD HL,TYPSLH 21 5F 2FLoad HL with the return address of 2F5FH (which will print the final !
2F1AEX (SP),HL E3Exchange the value of the return address in HL with the value of the input buffer pointer to the STACK
2F1BSCF 37Set the KILL/SEARCH flag for KILL since CARRY flag signals KILL
2F1D-2F1FCALL 0384H CALL INCHRCD 84 03Go scan the keyboard for the character the user wants to SEARCH for
2F20LD E,A 5FSave the character the user wants to SEARCH for into Register E
2F21POP AF F1Get the KILL/SEARCH flag from the STACK
2F22PUSH AF F5Save the KILL/SEARCH flag to the STACK
2F23-2F25CALL C,2F5FH CALL C,TYPSLHDC 5F 2FIf KILL (because the CARRY flag was set) then GOSUB to 2F5FH to print a !
LD A,(HL) 7ELoad Register A with the character at the location of the input buffer pointer in HL
2F27OR A B7Check to see if the character in Register A is an end of the BASIC line character
2F28-2F2AJP Z,2F3EH JP Z,POPARTCA 3E 2FJump down to 2F3EH if the character in Register A is an end of the BASIC line character
2F2EPOP AF F1Get the KILL/SEARCH flag from the STACK
2F2FPUSH AF F5Save the KILL/SEARCH flag to the STACK
2F30-2F32CALL C,2FA1H CALL C,DELCHRDC A1 2FIf the CARRY flag is set, that means we are in KILL mode so GOSUB to 2FA1H to delete the character from the input buffer
2F33-2F34Jump to 2F37H if KILL. Note, we do not move the HL pointer in this case because DELCHR already moved it.
2F35INC HL 23If we are here, it must be SEARCH! So bump to the next character
2F36INC B 04Bump the value of the character position in Register B
LD A,(HL) 7ERegardless of whether we are SEARCH or KILL, load Register A with the character at the location of the current input buffer pointer in HL
2F38CP E BBCheck 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.
2F3BDEC D 15Decrement the number of times to perform the operation in Register D (as initially specified by the user by entering a number before the command)
2F3FRET C9RETurn to CALLer
2F40 – EDIT Command – LIST Logic – “LED” .
CALL 2B75H CALL LISPRTCD 75 2BSince 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
2F46POP BC C1Clear off the RETURN address to DISPED
2F47-2F49JP 2E7CH JP LLEDC3 7C 2EJump to 2E7CH (to display the current line number and await the next EDIT command)
2F4A – EDIT Command – DELETE Logic – “DED”
LD A,(HL) 7ELoad Register A with the character at the location of the input buffer pointer in HL
2F4BOR A B7Check to see if the character in Register A is an end of the BASIC line character
2F5CRET Z 15Return if the character in Register A is an end of the BASIC line character
LD A,(HL) 7ELoad Register A with the character at the location of the input buffer pointer in HL
2F53OR A B7Check to see if the character in Register A is an end of the BASIC line character
2F54-2F5BJump to 2F5FH if the character in Register A is an end of the BASIC line character
2F5CDEC D 15Decrement the number of times to perform the operation in Register D (as initially specified by the user by entering a number before the command)
2F64RET C9RETurn to CALLer
2F65 – EDIT Command – CHANGE Logic – “CED” .
2F65 CEDLD A,(HL) 7ELoad Register A with the character at the location of the input buffer pointer in HL
2F66OR A B7Check to see if the character in Register A is an end of the BASIC line character
2F67RET Z C8Return if the character in Register A is an end of the BASIC line character
CALL 0384H CALL INCHRCD 84 03Go get the character to put in the input buffer from the keyboard
2F6BLD (HL),A 77Save the character in Register A at the memory location of the input buffer pointer in HL
2F6FINC HL 23Bump the value of the input buffer pointer in HL
2F70INC B 04Bump the character position in Register B
2F71DEC D 15Decrement the number of times to perform the operation in Register D (as initially specified by the user by entering a number before the command)
2F74RET C9RETurn to CALLer
2F75 – EDIT Command – HACK/INSERT Logic – “HED”
2F75-2F76 HEDLD (HL),00H 36 00Set the line end to be the current position.
2F77LD C,B 48Load Register C with the character position in Register B which will now be the line length
LD D,0FFH 16 FFPrepare for the next CALL to find the end of the line by loading Register D with the number of times to perform the operation
2F80OR A B7Check to see if a key was pressed
2F84-2F85CP 08H FE 08Check to see if the character in Register A is a backspace character . If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
2F86-2F87Jump to 2F92H if the character in Register A is a backspace character
2F88-2F89CP 0DH FE 0DCheck to see if the character in Register A is a carriage return . If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
2F8A-2F8CJP Z,2FE0H JP Z,CREDCA E0 2FJump to 2FE0H if the character in Register A is a carriage return
2F8D-2F8ECP 1BH FE 1BCheck 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.
2F8FRET Z C8Return if the character in Register A is shift up arrow
2F92 – EDIT Command – BACKSPACE CURSOR Logic – “TYPARW” .
2F94 TYPAR1DEC B 05Decrement the character position in Register B
2F95INC B 04Bump the character position in Register B
2F96-2F97If this is the first character of the BASIC line Jump forward to 2FB7H
2F9BDEC HL 2BDecrement the value of the input buffer pointer in HL
2F9CDEC B 05Decrement the character position in Register B
2F9D-2F9FLD DE,2F7DH LD DE,IED 11 7D 2FLoad DE with a return address of 2F7DH
2FA0PUSH DE D5Save the value of the return address in DE to the STACK
2FA1 – LEVEL II BASIC EDIT ROUTINE – “DELCHR”
This subroutine will delete the character pointed to by Register Pair HL and will correct Register C
2FA1 DELCHRPUSH HL E5Save the value of the input buffer pointer in HL to the STACK
2FA2DEC C 0DDecrement the character position in Register C
LD A,(HL) 7ELoad Register A with the character at the location of the input buffer pointer in HL
2FA4OR A B7Check to see if the character in Register A is an end of the BASIC line character
2FA5SCF 37Set the Carry flag to signal that DELCHR was called
2FA6-2FA8JP Z,0890H JP Z,POPHRTCA 90 08If the character in Register A is an end of the BASIC line character then we are done compressing so Jump to 0890H
2FA9INC HL 23Bump the value of the input buffer pointer in HL
2FAALD A,(HL) 7ELoad Register A with the character at the location of the input buffer pointer in HL
2FABDEC HL 2BDecrement the value of the input buffer pointer in HL
2FACLD (HL),A 77Save the character in Register A at the location of the current input buffer pointer in HL
2FADINC HL 23Bump the value of the input buffer pointer in HL
2FB0 – EDIT Command – ADD A CHARACTER Logic – “NTARRW” .
2FB1LD A,C 79Load Register A with the number of characters in the input buffer (i.e., the length of the line) in Register C
2FB2-2FB3CP FFH CP BUFLEN FE FFWe 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.
Jump forward to 2FB9H if the maximum BASIC line length hasn’t been reached
2FB6POP AF F1Get the character to be inserted from the STACK and put it in Register A
SUB B 90Subtract 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
2FBAINC C 0CBump the number of characters in the input buffer in Register C
2FBBINC B 04Bump the character position in Register B
2FBCPUSH BC C5Save the character position and the number of characters in the input buffer in BC to the STACK
2FBDEX DE,HL EBLoad DE with the input buffer pointer in HL
2FBELD L,A 6FLoad Register L with the number of bytes to move
2FBF-2FC0LD H,00H 26 00Zero Register H so that the number of bytes to move can be done in a 16 bit Register Pair.
2FC1ADD HL,DE 19Add the value of the input buffer pointer in DE to the character count in HL
2FC2LD B,H 44Load Register B with the MSB of the end of the BASIC line pointer in Register H
2FC3LD C,L 4DLoad Register C with the LSB of the end of the BASIC line pointer in Register L
2FC4INC HL 23Bump the value of the end of the BASIC line pointer in HL
2FC8POP BC C1Get the character position and the number of characters in the input buffer from the STACK and put it in BC
2FC9POP AF F1Get the character to be inserted from the STACK and put it in Register A
2FCALD (HL),A 77Save the character in Register A at the location of the current input buffer pointer in HL
2FCEINC HL 23Bump the value of the input buffer pointer in HL
2FD2 – EDIT Command – BACKSPACE Logic – “DELED” .
LD A,B 78Top 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
2FD3OR A B7Check to see if this is the start of the BASIC line
2FD4RET Z C8Return if this is the start of the BASIC line
2FD6DEC HL 2BDecrement the value of the buffer pointer in HL
2FD7-2FD8LD A,08H 3E 08Load Register A with a backspace the cursor character
2FDCDEC D 15Decrement the number of times to perform the operation in Register D
2FDFRET C9RETurn to CALLer
CALL 2B75H CALL LISPRTCD 75 2BSince 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
2FE6POP BC C1Clean up the STACK (to remove the DISPED return address)
2FE7POP DE D1Get the BASIC line number (in binary) from the STACK and put it in DE
2FE8LD A,D 7ALoad Register A with the MSB of the BASIC line number in Register D
2FE9AND E A3Combine the LSB of the BASIC line number in Register E with the MSB of the BASIC line number in Register A
2FEAINC A 3CBump the combined BASIC line number in Register A
LD HL,(40A7H) LD HL,(BUFPNT) 2A A7 40Load HL with the starting address of the input buffer.
Note: 40A7H-40A8H holds the input Buffer pointer
2FEEDEC HL 2BDecrement the value of the input buffer pointer in HL
2FEFRET Z C8Return if this is the Level II BASIC command mode
SCF 37Set the Carry flag to to fool the INSERT code; this flags the line number has having been seen
2FF1INC HL 23Bump the value of the input buffer pointer in HL
2FF2PUSH AF F5Save the command mode flag in AF to the STACK
2FF6 – EDIT Command – QUIT Logic – “QED” .
2FF6 QEDPOP BC C1Get rid of the DISPED return address
2FF7POP DE D1Get the line number off of the stack
2FFB-2FFFNOP 00THE END OF THE LEVEL II BASIC ROMS
2FFB-2FFFNOP 00Nothing here
*2FFB-2FFCSBC A,0C3HIn ROM v1.2 this is just garbage
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.
NOTE: 40AFH holds Current number type flag
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.
NOTE: 40FDH-40FEH holds Free memory pointer
NOTE: The RST 20H routine determines the type of the current value in ACCumulator and returns a combination of STATUS flags and unique numeric values in the A Register according to the data mode flag (40AFH). The results are returned as follows:
- Integer = NZ/C/M/E and A is -1
- String = Z/C/P/E and A is 0
- Single Precision = NZ/C/P/O and A is 1
- and Double Precision is NZ/NC/P/E and A is 5.
NOTE: 40A0H-40A1H holds the start of string space pointer
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.
27F5-27FD – LEVEL II BASIC POS( ROUTINE – “POS”
Note: 40A6H holds the current cursor line position
27FE-2818 – LEVEL II BASIC USR(x) ROUTINE – “USRFN”
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.
Note: 40AFH holds Current number type flag
(02=INT, 03=STR, 04=SNG, 08=DBL)
2819-2827 – CONVERSION ROUTINE – “DOCNVF”
Usually called by LET to convert the result of arithmetic routines to the proper destination type.
(02=INT, 03=STR, 04=SNG, 08=DBL)
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.
2831 – ID ERROR entry point.
2836-2856 – STRING ROUTINE – STR$ logic – “STR$”
The next routine, STRCPY, creates a copy of the string pointed to by Register Pair HL. On exit, DE points to DSCTMP which has the string information.
2857-2864 – STRING ROUTINE – “STRINI”
Note: 40D3H-40D5H holds Used for temporary string VARPTR’s
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.
Note: 40D3H-40D5H holds Used for temporary string VARPTR’s
Note: 40B3H-40B4H holds the next available location in the temporary string work area pointer
Note: 40AFH holds current number type flag
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.
Note: 40B3H-40B4H holds the next available location in the temporary string work area pointer
28A1 – ST ERROR entry point.
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.
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.
If the routine entry is at STRPRT, then it just prints the string whose descriptor is held in FACLO
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.
Note: 40D6H-40D7H holds the next available location in string space pointer
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.
28DA-298E – STRING ROUTINE – “GARBAG”
Note: 40B1H-40B2H holds MEMORY SIZE? pointer
Note: 40D6H-40D7H holds the next available location in string space pointer
NOTE: 40A0H-40A1H holds the start of string space pointer
Note: 40B5H-40D2H holds Temporary string work area
“TVAR”
NOTE: 40B3H-40B4H holds the next available location in the temporary string work area pointer
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.
NOTE: 40F9H-40FAH holds the starting address of the simple variable storage area
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.
Note: 40FDH-40FEH holds Free memory pointer
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.
Note: 40D8H-40D9H holds Temporary storage location
Note: 40D8H-40D9H holds Temporary storage location
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.
NOTE: 40D6H-40D7H holds the next available location in string space pointer
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.
295A
LD L,C 60
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.
2962
LD L,C 60
If we are here, we have made one complete pass through the string variables.
NOTE: 40D6H-40D7H holds the next available location in string space pointer
298F-29C5 – STRING ADDITION ROUTINE – Concatenate two strings – “CAT”
This routine concatenates two strings. The first is pointed to by FACLO and HL points to the character after the “+” sign in on the command line.
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
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.
29D7-29F4 – STRING ROUTINE – “FRESTR”
According to the original ROM source code, FRETMP is passed a pointer to a string descriptor in Register Pair DE and is returned in Register Pair HL. All the other registers are modified. A check to is made to see if the string descriptor in Register Pair DE points to is the last temporary descriptor allocated by PUTNEW. If so, the temporary is freed up by the updating of TEMPPT. If a temporary is freed up, a further check is made to see if the string data that that string temporary pointed to is the the lowest part of string space in use. If so, FRETMP is updated to reflect the fact that that space is no longer in use.
This routine is a contination of VAL , FRE , and PRINT processing. A jump to here would include the need to get a string’s VARPTR and put it in HL.
Note: 40D6H-40D7H holds the next available location in string space pointer
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.
Note: 40D6H-40D7H holds the next available location in string space pointer
29F5-2A02 – STRING ROUTINE – – “FRETMS”
Test to see if the string in DE is the last string used in the temporary string work area.
Note: 40B3H-40B4H holds the next available location in the temporary string work area pointer
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.
Note: 40B3H-40B4H holds the next available location in the temporary string work area pointer
2A03-2A0E – LEVEL II BASIC LEN ROUTINE – “LEN”
2A0F-2A1E – LEVEL II BASIC ASC ROUTINE – “ASC”
2A1F-2A2E – LEVEL II BASIC CHR$ ROUTINE – “CHR$”
2A2F-2A60 – LEVEL II BASIC STRING$ ROUTINE – “STRNG$”
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.
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).
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).
NOTE: The RST 20H routine determines the type of the current value in ACCumulator and returns a combination of STATUS flags and unique numeric values in the A Register according to the data mode flag (40AFH). The results are returned as follows:
- Integer = NZ/C/M/E and A is -1
- String = Z/C/P/E and A is 0
- Single Precision = NZ/C/P/O and A is 1
- and Double Precision is NZ/NC/P/E and A is 5.
2A61-2A90 – LEVEL II BASIC LEFT$( ROUTINE – “LEFT$”
On entry, HL=address of LEFT$$, the STACK = string address, STACK+1 = n, and DE = code string address.
2A61-2A63 LEFT$CALL 2ADFH CALL PREAMCD DF 2AGo check the syntax. The character at the location of the current BASIC program pointer in HL must be a )
2A64XOR A AFZero Register A because the string pointer never changes
EX (SP),HL E3Exchange the value of the current BASIC program pointer in HL with the string’s VARPTR to the STACK
2A66LD C,A 4FZero Register C
2A67-2A68LD A,0E5H 3E E5Z-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
PUSH HL E5Save 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 LEFT2PUSH HL E5Save the value of the string’s VARPTR in HL to the STACK
2A6ALD A,(HL) 7ELoad Register A with the string’s length at the location of the string’s VARPTR in HL
2A6BCP B B8Check 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
2A6ELD A,B 78Load Register A with the new string’s TRUNCATED length in Register B
2A6F-2A71LD DE,000EH 11 0E 00Z-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
2A72PUSH BC C5Save the offset in BC to the STACK
2A76POP BC C1Get the offset from the STACK and put it in BC
2A77POP HL E1Get the string’s VARPTR from the STACK and put it in HL
2A78PUSH HL E5Save the string’s VARPTR in HL to the STACK
2A79INC HL 23Bump HL to now point to the address of the string
2A7ALD B,(HL) 46Load Register B with the LSB of the string’s address at the location of the string’s VARPTR in HL
2A7BINC HL 23Bump the value of the string’s VARPTR in HL
2A7CLD H,(HL) 66Load Register H with the MSB of the string’s address at the location of the string’s VARPTR in HL
2A7DLD L,B 68Load Register L with the LSB of the string’s address in Register B
2A7E-2A7FLD B,00H 06 00Zero Register B so that BC can be used
2A80ADD HL,BC 09Add the string’s length in BC to the string’s address in HL
2A81LD B,H 44Load Register B with the MSB of the string’s ending address in Register H
2A82LD C,L 4DLoad Register C with the LSB of the string’s ending address in Register L
2A83-2A85CALL 285AH CALL STRAD2CD 5A 28Go save the string’s length (held in A) and the string’s starting address (held in DE)
2A86LD L,A 6FLoad Register L with the string’s length (i.e., the number of characters to move) held in Register A
2A8APOP DE D1Clean up the STACK
2A91-2A99 – LEVEL II BASIC RIGHT$ ROUTINE – “RIGHT$”
2A91-2A93CALL 2ADFH CALL PREAMCD DF 2AGo check the syntax. The character at the location of the current BASIC program pointer in HL must be a )
2A94POP DE D1Get the string’s VARPTR from the STACK and put it in DE
2A95PUSH DE D5Save the string’s VARPTR in DE to the STACK
2A96LD A,(DE) 1ALoad Register A with the string’s length (held at the location of the string’s VARPTR in DE)
2A97SUB B 90Subtract the new string’s length in Register B from the string’s length in Register A to isolate the number of bytes
2A9A-2AC4 – LEVEL II BASIC MID$ ROUTINE – “MID$”
The original ROM source code clarifies that if the number provided is greater than the actual length of the string, a NULL value is returned. If the second number (the number of characters) exceeds the end of the string, the maximum amount of available characters are returned.
2A9A MID$EX DE,HL EBLoad HL with the value of the current BASIC program pointer (held in DE)
2A9BLD A,(HL) 7ELoad Register A with the terminal character, currently held at the location of the current BASIC program pointer in HL
2A9C-2A9ECALL 2AE2H CALL PREAM2CD E2 2AGOSUB to 2AE2H to get the offset in Register B and the string’s VARPTR in DE
2A9FINC B 04We need to set the status flags to correspond to the offset position value so we first bump the value of the string’s position in Register B
2AA0DEC B 05… and then we decrement the value of the string’s offset position in Register B
2AA4PUSH BC C5Save the value of the offset position (held in Register B) to the STACK
2AA5-2AA6LD E,0FFH 1E FFLoad Register E with the default string’s length of 256 in case no number of bytes are given
2AA7-2AA8CP 29H CP “)” FE 29More syntax checking. Here we need to test for a ) at the location of the current BASIC program pointer. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
2AA9-2AAAJR Z,2AB0H JR Z,MID228 05Jump to 2AB0H if the character at the location of the current BASIC program pointer in Register A is a )
2AAB-2AACIf it wasn’t a ) , it had best be a , so we need to test the character at the location of the current BASIC program pointer in HL by calling the COMPARE SYMBOL routine at RST 08H.
NOTE: The RST 08H routine compares the symbol in the input string pointed to by HL Register to the value in the location following the RST 08 call.- If there is a match, control is returned to the next execution address (i.e, the RST 08H instruction + 2) with the next symbol in the A Register and HL incremented by one.
- If the two characters do not match, a syntax error message is given and control returns to the Input Phase).
2AAD-2AAFCALL 2B1CH CALL GETBYTCD 1C 2BGo evaluate the expression at the location of the current BASIC program pointer in HL and return with the integer result in DE. Now the byte count is in DE as an integer
2AB0-2AB1Since 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).
2AB2POP AF F1Get the offset from the STACK and put it in Register A
2AB3EX (SP),HL E3Exchange the value of the current BASIC program pointer in HL with the value of the string’s VARPTR to the STACK
LD BC,2A69H LD BC,LEFT2 01 69 2ALoad BC with 2A69H as the return address (which is in the LEFT$ routine)
2AB7PUSH BC C5Save the return address in BC to the STACK
2AB8DEC A 3DDecrement the value of the requested offset in Register A so that we have a starting position minus 1
2AB9CP (HL) BECompare 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-2ABBLD B,00H 06 00Zero Register B
2ABCRET NC D0If the offset pointer ispast the end of the string we are going to return a null
2ABELD A,(HL) 7ELoad Register A with the string’s length at the location of the string’s VARPTR in HL
2ABFSUB C 91Subtract the index (the second argument) in Register C from the string’s length in Register A
2AC0CP E BBCompare 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.
2AC1LD B,A 47Load Register B with the calculated string’s length in Register A
2AC2RET C D8If we are not going to truncate, then just use the partial string we already have and Return to 2A69H
2AC4RET C9Return to 2A69H aka LEFT2
2AC5-2ADE – LEVEL II BASIC VAL ROUTINE – “VAL”
2AC5-2AC7 VALCALL 2A07H CALL LEN1CD 07 2AGo get the string’s length in Register A and the string’s VARPTR in HL
2AC8-2ACAJP Z,27F8H JP Z,SNGFLTCA F8 27Jump to 27F8H if the string’s length in Register A is equal to zero
2ACBLD E,A 5FLoad Register E with the string’s length at the location of the string’s VARPTR in HL.
The original ROM source explains that we need to do some fancy footwork here to handle the case where the two strings are stored next to each other.
2ACCINC HL 23Bump the value of the string’s VARPTR in HL
2ACDLD A,(HL) 7ELoad Register A with the LSB of the string’s address at the location of the string’s VARPTR in HL
2ACEINC HL 23Bump the value of the string’s VARPTR in HL
2ACFLD H,(HL) 66Load Register H with the MSB of the string’s address at the location of the string’s VARPTR in HL
2AD0LD L,A 6FLoad Register L with the LSB of the string’s address in Register A
2AD1PUSH HL E5Save the value of the string’s address in HL to the STACK
2AD2ADD HL,DE 19Add the string’s length in DE to the string’s address in HL
2AD3LD B,(HL) 46Load Register B with the last character of the string at the location of the string pointer in HL
2AD4LD (HL),D 72Save the zero in Register D at the location of the string pointer in HL
2AD5EX (SP),HL E3Exchange the string’s ending address in HL with the string’s address to the STACK
2AD6PUSH BC C5Save the last character of the string in Register B to the STACK
2AD7LD A,(HL) 7ELoad Register A with the first character of the argument
2AD8-2ADACALL 0E65H CALL FINDBLCD 65 0ECall 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)
2ADBPOP BC C1Get the modified character of the next string into Register B
2ADCPOP HL E1Get the pointer to the modified character back into HL
2ADDLD (HL),B 70Restore the character.
2ADERET C9RETurn 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.
2AE0-2AE1Since 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).
2AE3POP DE D1Get the number of bytes to isolate from the string (from the STACK) and put it in DE
2AE4PUSH BC C5Save the return address in BC to the STACK
2AE5LD B,E 43Load Register B with the number of bytes in Register E
2AE6RET C9RETurn to CALLer
2AE7H-2AEE – Process a LEFT-HAND-SIDE MID$ – “ISMID$”
CP 7AH CP MIDTK-$END FE 7AThis routine is designed to handle a left-size MID$ call. So check to see if the character at the location of the current BASIC program pointer in Register A is trying to process a left hand side MID$. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
2AE9-2AEBJP NZ,1997H JP NZ,SNERRC2 97 19Display a ?SN ERROR message if that is not what is going on.
2AEC-2AEEJP 41D9H JP DLHSMDC3 D9 41JUMP to DOS to see if DOS wants to deal with this.
2AEF-2AF7 – LEVEL II BASIC INP ROUTINE – “FNINP”
2AEF-2AF1 FNINPCALL 2B1FH CALL CONINTCD 1F 2BGo evaluate the expression at the location of the current BASIC program pointer in HL and return with the port number in Register A
2AF2-2AF4LD (4094H),A LD (STAINP+1),A 32 94 40Save the value of the port number (from Register A) into 4094H, which is in the middle of a routine.
2AF5-2AF1CALL 4093H CALL STAINP CD 1F 2BPerform in INP on the channel held in Register A
2AF8-2B00 – LEVEL II BASIC OUT ROUTINE – “FNOUT”
2AFB-2AFDJP 4096H JP OUTWRDCD 0E 2BDo the OUT and RETurn
2B01-2B0D – EVALUATE EXPRESSION ROUTINE
“GETINT”
This evaluates an expression and leaves the result in DE as an integer.
2B01 GETINTWe 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.
CALL 2337H CALL FRMEVLCD 37 23Go 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)).
2B06-2B08CALL 0A7FH CALL FRCINTCD 7F 0ACall 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)
2B09EX DE,HL EBLoad DE with the integer result in HL
2B0APOP HL E1Get the value of the current BASIC program pointer from the STACK and put it in HL
2B0BLD A,D 7ALoad Register A with the MSB of the integer result in Register D
2B0COR A B7Test the value of the MSB in Register A
2B0DRET C9RETurn to CALLer
2B0E-2B16 – EVALUATE EXPRESSION ROUTINE – OUT continues here – “SETIO”
CALL 2B1CH CALL GETBYTCD 1C 2BGOSUB to 2B1CH to evaluate the expression at the location of the current BASIC program pointer in HL and return with the 8-bit value in Register A
2B11-2B13LD (4094H),A LD (STAINP+1),A 32 94 40Save the 8-bit value in Register A in the DOS address of 4094H to set up for WAIT
2B14-2B16LD (4097H),A LD (OUTWRD+1),A 32 97 40Save the 8-bit value in Register A in the DOS address of 4097H to set up for OUT
2B17-2B1A – CHECK SYNTAX ROUTINE – This checks to see if the next character is a “ and contnues on to 2B1CH if it is, and errors out if it isn’t.
2B17-2B18Since 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).
2B1B-2B28 – EVALUATE EXPRESSION ROUTINE – This is called by PRINT TAB – “GTBYTC” .
2B1B GTBYTCWe need the next character in the BASIC program so call the EXAMINE NEXT SYMBOL routine at RST 10H.
The RST 10H routine parses the characters starting at HL+1 for the first non-SPACE,non-09H,non-0BH character it finds. On exit, Register A will hold that character, and the C FLAG is set if its alphabetic, and NC FLAG if its alphanumeric. All strings must have a 00H at the end.
2B1C – Common Conversion Routine – “GETBYT”
This routine converts a numeric ASCII string pointed to by the HL into a hexadecimal value and places the result in the A register. If the result is larger than 255 (FFH) then an FC ERROR (Illegal function call) will be generated. After execution the HL will point to the delimiter. If the delimiter is a zero byte or a colon (3AH) then the Z flag will be set. Any other delimiter will cause the Z flag to be reset.
2B1C-2B1E GETBYTCALL 2337H CALL FRMEVLCD 37 23GOSUB to 2337H to evaluate the formula/expression at the location of the current BASIC program pointer in HL and return with the result in REG l
2B1F-2B21 CONINTCALL 2B05H CALL INTFR2CD 05 2BGOSUB to 2B05H to convert the result in ACCumulator to an integer and return with the integer result in DE. Flags are set based on Register D.
2B22-2B24JP NZ,1E4AH JP NZ,FCERRC2 4A 1EIf the result is greater than 255, display a ?FC ERROR message
2B25DEC HL 2BDecrement the value of the current BASIC program pointer in HL
2B26We 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.
2B27LD A,E 7BLoad Register A with the 8-bit result in Register E so that both A and E have the result.
2B28RET C9RETurn 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 LLISTLD A,01H 3E 01Load Register A with the printer output device code
2B2B-2B2DLD (409CH),A LD (PRTFLG),A 32 9C 40Save the value in Register A as the current output device flag.
Note: 409CH holds the current output device flag: -1=cassette, 0=video and 1=printer
2B2E-2B74 – LEVEL II BASIC LIST ROUTINE – “LIST”
On entry the STACK has the return address, then the first basic line number to be listed, then the last basic line number to be listed.
2B2E LISTPOP BC C1Get rid of the the return address on the STACK
2B2F-2B31CALL 1B10H CALL SCNLINCD 10 1BGo evaluate the range of line numbers given at the location of the current BASIC program pointer in HL
2B32PUSH BC C5Save the address of the first BASIC line (held in BC) to the STACK
LD HL,FFFFH 21 FF FFLoad 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-2B38LD (40A2H),HL LD (CURLIN),HL 22 A2 40Save the value in HL as the current BASIC line number (which is stored at 40A2H-40A3H).
2B39POP HL E1Get the address of the first BASIC line to be listed (from the STACK) and put it in HL
2B3APOP DE D1Get the value of the last BASIC line number to be listed (from the STACK) and put it in DE
2B3BLD C,(HL) 4ELoad Register C with the LSB of the next BASIC line pointer at the location of the memory pointer in HL
2B3CINC HL 23Bump the value of the memory pointer in HL
2B3DLD B,(HL) 46Load Register B with the MSB of the next BASIC line pointer at the location of the memory pointer in HL
2B3EINC HL 23Bump the value of the memory pointer in HL
2B3FLD A,B 78Load Register A with the MSB of the next BASIC line pointer in Register B
2B40OR C B1Combine the LSB of the next BASIC line pointer in Register C with the MSB of the next BASIC line pointer in Register A. This will let us test for the end of the BASIC program
2B41-2B43JP Z,1A19H JP Z,READYCA 19 1AIf we are at the elast line, then STOP and JUMP to 1A19H to the READY PROMPT.
2B44-2B46CALL 41DFH CALL EXCHDSCD DF 41GOSUB to DOS to see if DOS wants to do anything here.
2B47-2B49CALL 1D9BH CALL ISCNTCCD 9B 1DGo scan the keyboard to see if the BREAK key or the shift – @ key was pressed
2B4APUSH BC C5Save the address of the next BASIC line in BC to the STACK
2B4BLD C,(HL) 4EWe 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
2B4CINC HL 23Bump the value of the memory pointer in HL
2B4DLD B,(HL) 46Load Register B with the MSB of the BASIC line number at the location of the memory pointer in HL
2B4EINC HL 23Bump the value of the memory pointer in HL
2B4FPUSH BC C5Save the BASIC line number in BC to the STACK
2B50EX (SP),HL E3Swap (SP) and HL so that the line number is now in HL
2B51EX DE,HL EBSwap DE and HL so that the last BASIC line number is now in HL
2B52We 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.
2B53POP BC C1Get the pointer to the location on the BASIC program line being processed and put it in BC
2B54-2B56JP C,1A18H JP C,STPRDYDA 18 1AIf the BASIC line number in DE is greater than the last BASIC line number in HL then we have gone past the end, so we are done processing!
2B57EX (SP),HL E3Swap (SP) and HL so that the last BASIC line number is now on the STACK
2B58PUSH HL E5Save the address of the next BASIC line in HL to the STACK
2B59PUSH BC C5Save the pointer to the location on the BASIC program line being processed to the STACK
2B5AEX DE,HL EBLoad HL with the BASIC line number (from DE)
2B5B-2B5DLD (40ECH),HL LD (DOT),HL 22 EC 40Save the BASIC line number in HL into DOT for use later in EDIT or LIST.
Note: 40ECH-40EDH holds EDIT line number
2B5E-2B60CALL 0FAFH CALL LINPRTCD AF 0FCall 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-2B62LD A,20H 3E 20Load Register A with a space
2B63POP HL E1Get the value of the memory pointer from the STACK and put it in HL
2B67-2B69CALL 2B7EH CALL BUFLINCD 7E 2BGOSUB to 2B7EH move the BASIC line at the location of the memory pointer in HL into the input buffer and untokenize the BASIC line
2B6A-2B6CLD HL,(40A7H) LD HL,(BUFPNT) 2A A7 40Load HL with the starting address of the input buffer.
Note: 40A7H-40A8H holds the input Buffer pointer
2B6D-2B6FCALL 2B75H CALL LISPRTCD 75 2BSince 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
2B75-2B7D – DISPLAY MESSAGE ROUTINE – “LISPRT”
This is the PRINT MESSAGE routine which writes string pointed to by HL to the current output device. String must be terminated by a byte of zeros. This call is different from 28A7H because it does not use the literal string pool area, but it does use the same display routine and it takes the same DOS Exit at 41C1H. Uses all registers. This routine can be called without loading the BASIC utility, if a C9H (RET) is stored in 41C1H.
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.
LD A,(HL) 7ELoad Register A with the character at the location of the memory pointer in HL
2B76OR A B7Check to see if the character in Register A is an end of the string character (00H)
2B77RET Z C8Return if the character in Register A is an end of the string character
CALL 032AH CALL OUTDOCD 2A 03Go send the character in Register A to the current output device
2B7BINC HL 23Bump the value of the memory pointer in HL
2B7C-2B7DJR 2B75H JR LISPRT18 F7Loop 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.
2B7F-2B81LD HL,(40A7H) LD HL,(BUFPNT) 2A A7 40Load HL with the starting address of the input buffer.
Note: 40A7H-40A8H holds the input Buffer pointer
2B82
2B83LD B,H
LD C,L 44LET Register Pair BC = Register Pair HL
2B84POP HL E1Get the value of the BASIC line pointer from the STACK and put it in HL
2B85-2B86LD D,FFH LD D,BUFLEN 16 FFLoad Register D with the maximum length of an untokenized line
2B8ADEC D 15Decrement the character count in Register D
2B8BRET Z C8Return if 256 characters have been moved into the input buffer
LD A,(HL) 7ELoad Register A with the character at the location of the BASIC line pointer in HL
2B8DOR A B7Set 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)
2B8EINC HL 23Bump the value of the BASIC line pointer in HL to the next character in the code string
2B8FLD (BC),A 02Save 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.
2B90RET Z C8Return if the character in Register A is an end of the BASIC line character
JP P,2B89H JP P,PLOOPF2 89 2BIf the character in A is just a regular character (i.e., not a token), then JUMP back to 2B89H
2B94-2B95CP 0FBH CP SNGQTK FE FBCheck to see if the character in Register A is a ‘ token. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
2B96-2B97Jump 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-2B9BDEC BC
DEC BC
DEC BC
DEC BC 0BFirst, 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-2B9FINC D
INC D
INC D
INC D 14Then, 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.
CP 95H CP $ELSE FE 95Check to see if the character in Register A is an ELSE token. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
2BA2-2BA4CALL Z,0B24H CALL Z,DCXVBRTCC 24 0BIf 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
DEC BC 0BThis 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-2BA6SUB 7FH D6 7FNext, 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
2BA7PUSH HL E5Save the value of the BASIC line pointer in HL to the STACK. Register L holds the reserved word number at this point.
2BA8LD E,A 5FLoad Register E with the character in Register A
2BA9-2BABLD HL,1650H LD HL,RESLST 21 50 16Load HL with the starting address of the reserved words list
LD A,(HL) 7ELoad Register A with the character at the location of the reserved words list pointer in HL
2BADOR A B7Test 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.
2BAEINC HL 23Bump the value of the reserved words list pointer in HL
2BAF-2BB1JP P,2BACH JP P,LOPRESF2 AC 2BIf the character at the location of the reserved words pointer in Register A doesn’t have bit 7 set then Jump back to 2BACH.
2BB2DEC E 1DDecrement the counter
2BB3-2BB4Jump back to 2BACH if this isn’t the reserved word for the token
2BB5-2BB6AND 7FH E6 7FReset bit 7 of the character in Register A by ANDing it against 0111 1111. This is to eliminate the MSB for “EDIT” and for disk I/O
LD (BC),A 02Save the character in Register A at the location of the input buffer pointer in BC
2BB8INC BC 03Bump the value of the input buffer pointer in BC
2BB9DEC D 15Decrement the value of the character counter in Register D
2BBA-2BBCJP Z,28D8H JP Z,PPSWRTCA D8 28If the Z FLAG has been set, then the character counter for the buffer has been exhausted and the buffer is now full, so JUMP back to 28D8H
2BBDLD A,(HL) 7ELoad Register A with the character at the location of the reserved words pointer in HL
2BBEINC HL 23Bump the reserved words pointer in HL
2BBFOR A B7Test the value of the character in Register A
2BC0-2BC2JP P,2BB7H JP P,MORPURF2 B7 2BKeep getting characters in this reserved word until we hit the next reserved word
2BC3POP HL E1Get the value of the BASIC line pointer from the STACK and put it in HL
2BC4-2BC5JR 2B8CH JR PLOOP218 C6Jump back to 2B8CH to continue processing the BASIC line being interpreted
2BC6-2BF4 – LEVEL II BASIC DELETE ROUTINE – “DELETE”
2BC6-2BC8 DELETECALL 1B10H CALL SCNLINCD 10 1BGOSUB to 1B10H to evaluate the line numbers at the location of the current BASIC program pointer in HL
2BC9POP DE D1Get the value of the last BASIC line number to be deleted (in binary) from the STACK and put it in DE
2BCAPUSH BC C5Save the address of the first BASIC line to be deleted in BC to the STACK
2BCBPUSH BC C5Save the address of the first BASIC line to be deleted in BC to the STACK AGAIN!
2BCC-2BCECALL 1B2CH CALL FNDLINCD 2C 1BGOSUB 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
Since the first line number provided MUST be found, if FNDLIN returns with the NC FLAG set (i.e., not found) we must JUMP to 2BD6H to show a ?FC ERROR
2BD1
2BD2LD D,H
LD E,L 54Let Register Pair DE = Register Pair HL
2BD3EX (SP),HL E3Exchange the last BASIC line’s address in HL with the first BASIC line’s address to the STACK
2BD4PUSH HL E5Save the pointer to the first line in range to the STACK
2BD5We 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.
JP NC,1E4AH JP NC,FCERRD2 4A 1EDisplay a ?FC ERROR message if the first BASIC lines address in HL is greater than or equal to the last BASIC line’s address in DE
2BD9-2BDBLD HL,1929H LD HL,REDDY 21 29 19Load HL with the starting address of the BASIC READY message
2BDC-2BDECALL 28A7H CALL STROUTCD A7 28Call the WRITE MESSAGE routine at 28A7H to print the message pointed to by HL.
2BDFPOP BC C1Get the first BASIC line’s address from the STACK and put it in BC
2BE0-2BE2LD HL,1AE8H LD HL,FINI 21 E8 1ALoad HL with the return address
2BE3EX (SP),HL E3Swap (SP) and HL so that HL now points to the next BASIC line’s address …
2BE5-2BE7LD HL,(40F9H) LD HL,(VARTAB) 2A F9 40Load HL with the end of the BASIC program pointer.
- Note: 40F9H-40FAH holds the starting address of the simple variable storage area.
LD A,(DE) 1ALoad Register A with the character at the location of the memory pointer in DE
2BE9LD (BC),A 02Save the character in Register A at the location of the memory pointer in BC
2BEAINC BC 03Bump the value of the memory pointer in BC
2BEBINC DE 13Bump the value of the memory pointer in DE
2BECNow we need to check to see if the memory pointer in DE equals the end of the BASIC program pointer in HL, so we call the COMPARE DE:HL routine at RST 10H.
The RST 10H routine parses the characters starting at HL+1 for the first non-SPACE,non-09H,non-0BH character it finds. On exit, Register A will hold that character, and the C FLAG is set if its alphabetic, and NC FLAG if its alphanumeric. All strings must have a 00H at the end.
2BED-2BEELoop back to 2BE8H until the memory pointer in DE equals the end of the BASIC program pointer in HL
2BEFLD H,B 60Load Register H with the MSB of the memory pointer in Register B
2BF0LD L,C 69Load Register L with the LSB of the memory pointer in Register C
2BF1-2BF3LD (40F9H),HL LD (VARTAB),HL 22 F9 40Save 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.
2BF4RET C9RETurn to CALLer
2BF5-2C1E – LEVEL II BASIC CSAVE ROUTINE – “CSAVE”
The original ROM source code says that the CSAVE command dump’s BASIC’s core. Three D3H’s are written, followed by a 1 character filename. At the end 3 zeros in a row are written.
2BF5-2BF7 CSAVECALL 0284H CALL CWRTONCD 84 02Calls the WRITE LEADER routine at 0284H (which writes a Level II leader on the cassette unit set in Register A)
2BF8CALL 2337H CALL FRMEVLCD 37 232BFAH Go evaluate the rest of the CSAVE expression at the location of the current BASIC program pointer in HL and return with the result in REG l
2BFBPUSH HL E5Save the value of the current BASIC program pointer in HL to the STACK so we can get it back at the end of the routine
2BFF-2C00LD A,D3H 3E D3Load Register A with the filename header byte (=D3H which is a “S” with the sign bit on)
2C01-2C03CALL 0264H CALL CASOUTCD 64 02the 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
2C07LD A,(DE) 1ALoad Register A with the first character of the filename at the location of the filename pointer in DE
2C08-2C0ACALL 0264H CALL CASOUTCD 64 02the 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-2C0DLD HL,(40A4H) LD HL,(TXTTAB) 2A A4 40Load 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).
2C0EEX DE,HL EBLoad DE with the start of the BASIC program pointer in HL
2C0F-2C11LD HL,(40F9H) LD HL,(VARTAB) 2A F9 40Load HL with the end of the BASIC program pointer.
- Note: 40F9H-40FAH holds the starting address of the simple variable storage area.
LD A,(DE) 1ATop 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
2C13INC DE 13Bump the value of the memory pointer in DE
2C14-2C16CALL 0264H CALL CASOUTCD 64 02the 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)
2C17Now we need to check to see if the memory pointer in DE is equal to the end of the BASIC program pointer in HL, so we call the COMPARE DE:HL routine at RST 10H.
The RST 10H routine parses the characters starting at HL+1 for the first non-SPACE,non-09H,non-0BH character it finds. On exit, Register A will hold that character, and the C FLAG is set if its alphabetic, and NC FLAG if its alphanumeric. All strings must have a 00H at the end.
2C18-2C19Loop back to 2C12H until the memory pointer in DE is equal to the end of the BASIC program pointer in HL
2C1DPOP HL E1Get the value of the current BASIC program pointer from the STACK and put it in HL
2C1ERET C9RETurn to CALLer
2C1F-2CA4 – LEVEL II BASIC CLOAD ROUTINE – ROM v1.0 – “CLOAD”
2C22LD A,(HL) 7ELoad Register A with the character at the location of the current BASIC program pointer in HL
2C23-2C24SUB 0B2H SUB $PRINT D6 B2Check to see if the character at the location of the current BASIC program pointer in Register A is a ? , meaning that CLOAD? was requested.
Jump to the CLOAD? routine at 2C29H if the character at the location of the current BASIC program pointer in Register A is a ?
2C27XOR A AFOK – So this is now a straight CLOAD . First, zero Register A
2C28LD BC,232F 01 2F 23Z-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
2C2AINC HL 23Bump the value of the current BASIC program pointer in HL until it points to the next character after the ? in CLOAD?
2C2BPUSH AF F5Save the CLOAD / CLOAD? flag in Register A to the STACK
2C2CDEC HL 2BDecrement the value of the current BASIC program pointer in HL so we can see if we are at the end
2C2DWe need the next character in the BASIC program so call the EXAMINE NEXT SYMBOL routine at RST 10H.
The RST 10H routine parses the characters starting at HL+1 for the first non-SPACE,non-09H,non-0BH character it finds. On exit, Register A will hold that character, and the C FLAG is set if its alphabetic, and NC FLAG if its alphanumeric. All strings must have a 00H at the end.
2C2E-2C2FLD A,00H 3E 00Zero Register A to allow for any filename
2C30-2C31Jump if the character at the location of the current BASIC program pointer in HL is an end of the BASIC statement character
2C32-2C34CALL 2337H CALL FRMEVLCD 37 23To get the filename we need to GOSUB to 2337H to evaluate the expression at the location of the current BASIC program pointer in HL and return with the result in ACCumulator
2C35-2C37CALL 2A13H CALL ASC2CD 13 2AMake sure the length is good, and save the pointer to the filename to Register Pair DE
2C38LD A,(DE) 1ALoad Register A with the first character of the filename at the location of the filename pointer in DE
2C3APOP AF F1Get the value of the CLOAD / CLOAD? flag from the STACK and put it in Register A
2C3BOR A B7Test the value of the CLOAD / CLOAD? flag in Register A (since CPL doesn’t set any flags)
2C3CLD H,A 67Load Register H with the value of the CLOAD / CLOAD? flag in Register A
2C3D-2C3FLD (4121H),HL LD (FACLO),HL 22 21 41Save the value of the CLOAD / CLOAD? flag and the filename in HL in ACCumulator
2C43-2C45LD HL,(4121H) LD HL,(FACLO) 2A 21 41Load HL with the CLOAD / CLOAD? flag and the filename in ACCumulator
*2C1F-2CA4 – LEVEL II BASIC CLOAD ROUTINE – ROM v1.3
*2C1FSUB 0B2HTest for CLOAD?
*2C23XOR ASo we know that we have a CLOAD and not a CLOAD?, so clear Register A and continue
*2C2401Z-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
CPLSince A is Zero going into this command, once this complement code is exected, A=-1 if CLOAD?, 0000 if CLOAD
*2C26INC HLIncrement HL to the filname of the CLOAD / CLOAD? flag
*2C27PUSH AFSave the CLOAD / CLOAD? flag in Register A to the STACK
*2C28LD A,(HL)Set the next element from the code string, which should be the filename
*2C29OR ASet status flags
*2C32LD A,(DE)Get the filename
*2C33LD L,AMove the filename into Register L
*2C34POP AFRestore the CLOAD / CLOAD? flag
*2C35OR ASet the status Register according to that flag
*2C36LD H,AH will now hold CLOAD / CLOAD? flag, and L will hold the filename
*2C37LD (4121H),HL LD (FACLO),HLPut the flag and filename into ACCumulator
*2C3DLD HL,0000HCause the drive to be selected
*2C43LD HL,(4121H) LD HL,(FACLO)Restore the CLOAD / CLOAD? flag and filename
Common code between ROM v1.0 and v1.2 continues here.
2C46EX DE,HL EBLoad D with the CLOAD/CLOAD? flag and load Register E with the filename
CALL 0235H CALL CASINCD 35 02Calls 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-2C4DSUB 0D3H D6 D3Check to see if the character in Register A is a filename header byte
2C4E-2C4FLoop if the character in Register A isn’t a filename header byte
2C50-2C51Loop back to 2C49H until three filename header bytes have been read
2C52-2C54CALL 0235H CALL CASINCD 35 02Now 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)
2C55INC E 1CWe 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
2C56DEC E 1DDecrement the value of the filename in Register E
2C57-2C58Jump to 2C5CH (to pretend the filename matched) if no filename was specified
2C59CP E BBIf we are here, then the user has supplied a filename which is held in Register E AND we have the first byte from the tape in Register A, so we need to compare the filename specified in Register E with the character in Register A. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
2C5A-2C5BJump 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
LD HL,(40A4H) LD HL,(TXTTAB) 2A A4 40If 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.
LD B,03H 06 03Load Register B with the number of zeros to look for to stop the load (which is 3)
CALL 0235H CALL CASINCD 35 02Calls 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)
2C64LD E,A 5FPreserve the character that was just read from tape into Register E
2C65SUB (HL) 96Compare 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
2C66AND D A2Combine the subtracted result in Register A with the value of the CLOAD / CLOAD? flag in Register D. Why is this tricky? Because D is always 0 for a CLOAD, so when you AND against 0, you always get 0. If this was CLOAD?, nothing would happen as a result of this.
2C67-2C68Jump to 2C8AH if CLOAD? was selected but the bytes don’t match
2C69LD (HL),E 73At this point either CLOAD? was selected and the bytes match, or CLOAD was selected. Either way, save the character we read from the tape (held in Register E) to the location of the memory pointer in HL
2C6A-2C6CCALL 196CH
CALL REASONCD 6C 19Make sure there is more room, and toss a ?OM ERROR if there isn’t.
2C6DLD A,(HL) 7ELoad Register A with the character at the location of the memory pointer in HL
2C6EOR A B7Check to see if the byte just read in Register A is equal to zero
2C6FINC HL 23Bump the value of the memory pointer in HL
2C70-2C71Loop if the byte in Register A isn’t equal to zero (meaning that it isn’t end of program or end of statement)
2C72-2C74CALL 022CH CALL BCASINCD 2C 02Call the BLINK ASTERISK routine at 022CH which alternatively displays and clears an asterisk in the upper right hand corner of the video display
2C75-2C76Do that loop until three zeros in a row have been read from the cassette recorder
2C77-2C79LD (40F9H),HL LD (VARTAB),HL 22 F9 40By 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 OKCASSLD HL,1929H LD HL,REDDY 21 29 19Load HL with the starting address of the BASIC READY message
2C75-2C76Do that loop until three zeros in a row have been read from the cassette recorder
2C83-2C85LD HL,(40A4H) LD HL,(TXTTAB) 2A A4 40Load 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).
2C86PUSH HL E5Save the start of the BASIC program pointer in HL to the STACK. FINI will need this value there.
LD HL,2CA5H LD HL,NOOKCS 21 A5 2CLoad HL with the starting address of the BAD message
2C8D-2C8FCALL 28A7H CALL STROUTCD A7 28Call the WRITE MESSAGE routine at 28A7H to print the message pointed to by HL.
NOTE:
- The routine at 28A7 displays the message pointed to by HL on current system output device (usually video).
- The string to be displayed must be terminated by a byte of machine zeros or a carriage return code 0D.
- If terminated with a carriage return, control is returned to the caller after taking the DOS exit at 41D0H (JP 5B99H).
2C90-2C92JP 1A18 JP STPRDYC3 18 1AJUMP to STPRDY to pop NEWSTT from the STACK and then fall into the READY routine
LD B,03H 06 03Load Register B with the number of zeros to be found to stop the search
CALL 0235H CALL CASINCD 35 02Calls 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)
2C9BOR A B7Check to see if the character in Register A is equal to zero
2C9E-2C9FLoop until three zeros in a row have been read from the cassette recorder
2CA0-2CA2CALL 0296H CALL CSRDON + 3CD 96 02Calls 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)
2CA5-2CA9 – MESSAGE STORAGE LOCATION – “NOOKCS”
2CA5-2CA9 NOOKCS“BAD” + 0DH + 00H 42The BAD message is stored here
2CAA-2CB0 – LEVEL II BASIC PEEK ROUTINE – “PEEK”
The original ROM source code says that PEEK only accepts positive numbers up to 32767 and POKE will only take an address up to 32767. Negative numbers can be used to refer to locations higher than 32767, the correspondence is given by subtracting 65536 from locations higher than 32767 or by specifying a positive number up to 65535
On entry, ACCumulator to have the peek location, and on exit ACCumulator to have the peeked value.
2CAA-2CAC PEEKCALL 0A7FH CALL FRCINTCD 7F 0ACall 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)
2CADLD A,(HL) 7ELoad Register A with the value at the location of the memory pointer in HL
2CAE-2CB0JP 27F8H JP SNGFLTC3 F8 27Go save the 8-bit value in Register A as the current result in ACCumulator
2CB1-2CBC – LEVEL II BASIC POKE ROUTINE – “POKE”
2CB1-2CB3 POKECALL 2B02H CALL GETIN2CD 02 2BGo evaluate the expression at the location of the current BASIC program pointer in HL and return with the integer result in DE
2CB4PUSH DE D5Save the address the user wants to POKE to (held in DE) to the STACK
2CB5-2CB6Since the character at the location of the current BASIC program pointer in HL must be a , , call the COMPARE SYMBOL routine at RST 08H.
NOTE: The RST 08H routine compares the symbol in the input string pointed to by HL Register to the value in the location following the RST 08 call.- If there is a match, control is returned to the next execution address (i.e, the RST 08H instruction + 2) with the next symbol in the A Register and HL incremented by one.
- If the two characters do not match, a syntax error message is given and control returns to the Input Phase).
2CB7-2CB9CALL 2B1CH CALL GETBYTCD 1C 2BGOSUB 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
2CBAPOP DE D1Get the address the user wants to POKE to from the STACK and put it in DE
2CBBLD (DE),A 12Save the value the user wanted to poke (held in Register A) in the location that the user wants to POKE to (held in DE)
2CBCRET C9RETurn 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
Vernon Hester has reported an error in the PRINT USING routine. A PRINT USING statement with a negative sign at the end of the field prints a negative sign after negative numbers and prints a space for positive numbers. However, if the field specifiers in the string also has two asterisks at the beginning of the field, the ROM prints an asterisk instead of a space after a positive number.
Example: PRINT USING “**####-“;1234 will display **1234* instead of **1234 SPACE
CALL 2338H CALL FRMCHKCD 38 23Go evaluate the string expression at the location of the current BASIC program pointer in HL
2CC0-2CC2CALL 0AF4H CALL CHKSTRCD F4 0AGo make sure the expression that was just evaluated was a string
2CC3-2CC4Since 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).
2CC5EX DE,HL EBSwap DE and HL so that DE now holds the current BASIC program pointer
2CC6-2CC8LD HL,(4121H) LD HL,(FACLO) 2A 21 41Load HL with the USING string’s VARPTR
LD A,(40DEH) LD A,(FLGINP) 3A DE 40Load Register A with the value of the READ/INPUT flag, which is being used here to track if we printed out a value on the prior scan.
2CCEOR A B7Check to see if that flag indivates that we did, or did not, print out a value last time.
2CCF-2CD0If we did not print out a value last time, we have an error, so JUMP down to 2CDDH
2CD1POP DE D1Restore the pointer to the “USING” string decription from the STACK into DE
2CD2EX DE,HL EBSwap 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.
PUSH HL E5Save the pointer to the “USING” string descriptor (i.e., the USING string’s VARPTR) in HL to the STACK
2CD4XOR A AFZero Register A and all the flags.
2CD5-2CD7LD (40DEH),A LD (FLGINP),A 32 DE 40Clear the flag we are using to see if we printed the values or not.
2CD8CP D BATurn 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.
2CD9PUSH AF F5Save the flag indicating if the value list has ended or not to the STACK
2CDAPUSH DE D5Save the pointer into the value list to the STACK
2CDBLD B,(HL) 46Load Register B with the USING string’s length
2CDCOR B B0Check to see if the USING string’s length in Register B is equal to zero
2CE0INC HL 23Bump the pointer to the USING string’s data in HL by 1
2CE1LD C,(HL) 4ELoad Register C with the LSB of the USING string’s address at the location of the USING string’s VARPTR in HL
2CE2INC HL 23Bump the value of the USING string’s VARPTR in HL
2CE3LD H,(HL) 66Load Register H with the MSB of the USING string’s address at the location of the USING string’s VARPTR in HL
2CE4LD L,C 69Load Register L with the LSB of the USING string’s address in Register C
2CE8PUSH HL E5Save the pointer to the USING string pointer in HL to the top of the STACK
2CE9-2CEALD C,02H 0E 02Since the \\ string field length is two plus number of enclosed spaces, add two
LD A,(HL) 7ELoad Register A with the character at the location of the USING string pointer in HL
2CECINC HL 23Bump the value of the USING string data pointer in HL
2CED-2CEECP 25H CP CSTRNG FE 25Check to see if the character in Register A is a %, which acts as a field terminator. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
2CEF-2CF1JP Z,2E17H JP Z,ISSTRFCA 17 2EIf it is a “%” then JUMP to 2E17H to evaluate a string and print
2CF2-2CF3CP 20H FE 20Check to see if the character in Register A is a ” “, which acts as a field extender. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
2CF4-2CF5If the character is not a field extender, then it isn’t a string field, so JUMP down a few opcodes to 2CF9H
2CF6INC C 0CIncrement the field width (tracked in in Register C)
2CF7-2CF8Decrement 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 NOSTRFPOP HL E1Restore the pointer to the “USING” string’s data into Register Pair HL
2CFALD B,E 43Load Register B with the USING string’s length
2CFB-2CFCLD A,25H LD A,CSTRNG 3E 25Restore 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
CALL 2E49H CALL PLSPRTCD 49 2EIf a + came before the character, make sure to print it
2D00-2D02CALL 032AH CALL OUTDOCD 2A 03Once that has been printed, now we print the character in Register A since we know it isn’t part of a field
XOR A AFWe 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
2D04LD E,A 5FZero Register E
2D05LD D,A 57Zero Register D
CALL 2E49H CALL PLSPRTCD 49 2EGo print a leading + if necessary (i.e., to allow for multiple plusses)
2D09LD D,A 57Set 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.
2D0ALD A,(HL) 7ELoad Register A with the next field description character in the USING string
2D0BINC HL 23Bump the value of the USING string pointer in HL
2D0C-2D0DCP 21H CP “!” FE 21Check 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.
2D11-2D12CP 23H CP “#” FE 23Check 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.
2D15DEC B 05Since every other possibility is actually a two character field, decrement the value of the string’s length in Register B onem ore time
2D16-2D18JP Z,2DFEH JP Z,REUSINCA FE 2DIf 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-2D1ACP 2BH CP “+” FE 2BCheck 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-2D1CLD A,08H 3E 08Set 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
2D1FDEC HL 2BDecrement the value of the USING string pointer so we can re-get the character.
2D20LD A,(HL) 7ELoad Register A with the (current) character at the location of the USING string pointer in HL
2D21INC HL 23Bump the value of the USING string pointer in HL
2D22-2D23CP 2EH CP “.” FE 2ECheck to see if the character in Register A is a . (i.e., a numeric field with trailing digits). If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
2D24-2D25Jump if the character in Register A is a . to scan with Register E holding the number of digits before the “.” as 0
2D26-2D27CP 25H CP CSTRNG FE 25Check to see if the character in Register A is a % (i.e., a really big string field). If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
2D28-2D29Jump to see if it is really a string field if the character in Register A is a %
2D2ACP (HL) BECheck to see if the next character matches the current character in the the USING string. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
2D2B-2D2CIf the NZ flag is set, then we can’t have a $$ or a ** , so all remaining possibilities are exhausted, so JUMP to NEWUCH
2D2D-2D2ECP 24H CP “$” FE 24Check 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.
2D31-2D32CP 2AH CP “*” FE 2ACheck to see if the double character is a ** . If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
2D33-2D34If 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
2D35LD A,B 78Prepare 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-2D37CP 02H FE 02Check 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.
2D38INC HL 23Bump the value of the USING string pointer in HL
2D39-2D3AJump to 2D3EH if the USING string’s length in Register A isn’t at least two
2D3BLD A,(HL) 7ELoad Register A with the character at the location of the USING string pointer in HL
2D3C-2D3DCP 24H CP “$” FE 24Check 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.
2D40-2D41If we did not ultimately get a **$ then JUMP (noting we do NOT set the dollar sign flag)
2D42DEC B 05Decrement the value of the USING string’s length to take the $ into account
2D43INC E 1CBump the field width tracker to account for the floating dollar sign
2D44-2D45CP 0AFH FE AFZ-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.
2D46-2D47ADD A,10H C6 10Mask Register A to set the bit for a floating dollar sign flag.
2D48INC HL 23Bump the value of the USING string pointer in HL to go past the special characters
2D4AADD A,D 82Combine the bits in Register D into the flag tracker
2D4BLD D,A 57Preserve the modified flag tracker into Register D.
2D4D-2D4ELD C,00H 0E 00Set the number of digits to the right of the decimal point (tracked in Register C) to 0
2D4FDEC B 05Check to see if there are any more characters by decrementing the value of the string’s length in Register B
2D50-2D51If 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.
2D52LD A,(HL) 7ELoad Register A with the next character at the location of the USING string pointer in HL
2D53INC HL 23Bump the value of the USING string pointer in HL
2D54-2D55CP 2EH CP “.” FE 2ECheck to see if the character in Register A is a . (i.e., a trailing digit). If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
2D56-2D57If yes, then need to use a special scan loop to scan after the decimal point, so JUMP to AFTDOT
2D58-2D59CP 23H CP “#” FE 23Check to see if the character in Register A is a # (i.e., a leading digit). If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
2D5A-2DIf yes, increment the count and keep scanning via a JUMP to NUMNUM
2D5C-2D5DCP 2CH CP “,” FE 2CCheck to see if the character in Register A is a , . If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
2D5E-2D5FIf there is no comma, then JUMP to FINNUM because there are no more leading digits and we need to check for “^^^”
2D60LD A,D 7AIf we are here, then a comma was requested. Turn on the COMMA bit
2D61-2D62OR 40H F6 40Mask the flag in Register A for ,
2D63LD D,A 57Load Register D with the value of the flag in Register A
2D66 – Part of the PRINT USING Routine – “DOTNUM”
Jumped here when a “.” is seen in the USING string. THis means that we are starting a numeric field ONLY if it is followed by a “#”
2D66 DOTNUMLD A,(HL) 7ELoad Register A with the next character of the USING string
2D67-2D68CP 23H FE 23Check to see if the character in Register A is a # (i.e., a numeric field following a “.”). If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
2D69-2D6ALD A,2EH LD A,”.” 3E 2ELoad Register A with a decimal point
2D6B-2D6CIf it isn’t a “.” then JUMP AWAY to NEWUCH with A holding a “.” so that a “.” will get printed
2D6D-2D6ELD C,01H 0E 01If it was a “.” then we have a numeric field to process. First, set C with the number of characters to the right of the decimal point
2D6FINC HL 23Bump the value of the USING string pointer in HL
INC C 0CBump the number of digits to the right of the decimal point (tracked in Register C)
2D71DEC B 05Decrement the value of the USING STRING’s length to test to see if there are more characters
2D72-2D73If the USING string length is now ZERO, JUMP to ENDNUS to stop scanning
2D74LD A,(HL) 7ELoad Register A with the character at the location of the USING string pointer in HL
2D75INC HL 23Bump the value of the USING string pointer in HL
2D76-2D77CP 23H FE 23Check to see if the character in Register A is a # ; meaning that there are more digits after the decimal point. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
2D78-2D79If 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
PUSH DE D5Save the value of the flag (tracked in D) and the number of leading digits (tracked in E) to the STACK
2D7B-2D7DLD DE,2D97H LD DE,NOTSCI 11 97 2DLoad DE with the return address in case this is not a scientific notation
2D7EPUSH DE D5Save the value of the return address in DE to the STACK
2D7F
2D80LD D,H
LD E,L 54Let DE = HL in case we need to rememer HL
2D81-2D82CP 5BH FE 5BCheck 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.
2D83RET NZ C0Return if the character in Register A isn’t an up arrow
CP (HL) BECheck 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.
2D85RET NZ C0Return 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)
2D87CP (HL) BECheck 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.
2D88RET NZ C0Return 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)
2D8ACP (HL) BECheck 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.
2D8BRET NZ C0Return 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)
INC HL 23Bump the value of the USING string pointer in HL. If we are here we have a #.^^^^ format
2D8DLD A,B 78Now 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-2D8FSUB 04H D6 04Check to see if there are at least 4 characters left in the USING string
2D90RET C D8Return to 2D97 if there aren’t at least four characters left in the USING string
POP DE D1If there are at least 4 characters left, then clean up the STACK by removing the NOTSCI return address
2D92POP DE D1Get the flag and the count of the characters to the left of the decimal point from the STACK and put it in DE
2D93LD B,A 47Load Register B with the new USING string’s length in Register A
2D94INC D 14Set the exponential notation flag (tracked in Register D)
2D95INC HL 23Bump the value of the USING string pointer in HL
2D96JP Z,0D1EBH CA EB D1Z-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,HL EB(Ignored if passing through) Restore the old HL into HL
2D98POP DE D1(Ignored if passing through) Restore the flags into Register D and the number of leading digits into Register E
LD A,D 7AWe 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
2D9ADEC HL 2BDecrement the value of the USING string pointer in HL
2D9BINC E 1CBump the number of characters to the left of the decimal point in Register E to take into account the leading plus
2D9C-2D9DAND 08H E6 08Mask Register A to NOT check for a trailing sign
2D9E-2D9FIf that AND leaves us with a NZ, then we are all done with the field, so JUMP to ENDNUM
2DA0DEC E 1DOtherwise, 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
2DA1LD A,B 78Check to see if there are more characters by first loading Register A with the USING string’s length from Register B
2DA2OR A B7Check to see if this is the end of the USING string
2DA3-2DA4If we are out of characters, then we are all done, so JUMP to ENDNUM
2DA5LD A,(HL) 7EIf there ARE more characters, then fill Register A with the character at the location of the USING string pointer in HL
2DA6-2DA7SUB 2DH SUB “-“ D6 2DCheck to see if the character in Register A is a – (i.e., a trailing minus)
2DAA-2DABCP 0FEH CP “+” – “-“ FE FECheck 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.
2DAE-2DAFLD A,08H 3E 08If we are here then we did have a trailing “+” so first set the flag for a POSITIVE “+”
2DB2ADD A,D 82Combine the value of the flag in Register D with the value of the flag in Register A
2DB3LD D,A 57Load Register D with the current flags
2DB4DEC B 05Decrement the value of the USING string’s length in Register B by 1 to account for the trailing sign
2DB5 – Part of the PRINT USING Routine – “ENDNUM”
Jump point for when we figure out that we are at the end of a string of digits within a USING string
2DB5 ENDNUMPOP HL E1Get the value of the current BASIC program pointer from the STACK and put it in HL
2DB6POP AF F1Load Register A with the flag that tells us whether there are more values to process in the value list.
2DB7-2DB8If there are no more values in the value list to process, then JUMP to FLDFIN because we are done with the PRINT
2DB9PUSH BC C5Save 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
2DBAPUSH DE D5Save the flags (held in D) and the number of leading digits (held in E) to the STACK
2DBB-2DBDCALL 2337H CALL FRMEVLCD 37 23Read 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
2DBEPOP DE D1Restore the flags (held in D) and the number of leading digits (held in E) from the STACK
2DBFPOP BC C1Restore 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
2DC0PUSH BC C5Save 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
2DC1PUSH HL E5Save the value of the current BASIC program pointer in HL to the STACK
2DC2LD B,E 43Set Register B to hold the number of leading digits (i.e., the number of characters to the left of the decimal point)
2DC3LD A,B 78We 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
2DC4ADD A,C 81Then 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-2DC6CP 19H FE 19Check to see if the total number of characters in Register A is greater than 24. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
2DC7-2DC9JP NC,1E4AH JP NC,FCERRD2 4A 1EDisplay a FC ERROR message if the total number of digits is greater than 24
2DCALD A,D 7ALoad Register A with the flags (held in Register D)
2DCB-2DCCOR 80H F6 80Turn on the “USING” bit in the flags
2DCD-2DCFCALL 0FBEH CALL PUFOUTCD BE 0FPrepare to print by calling the FLOATING TO ASCII routine at 0FBEH (whcih converts a single or double precision number in ACCumulator to its ASCII equivalent which will be stored at the buffer pointed to by HL using the format codes in the A, B, and C registers
2DD0-2DD2CALL 28A7H CALL STROUTCD A7 28Call the WRITE MESSAGE routine at 28A7H to print the message pointed to by HL.
NOTE:
- The routine at 28A7 displays the message pointed to by HL on current system output device (usually video).
- The string to be displayed must be terminated by a byte of machine zeros or a carriage return code 0D.
- If terminated with a carriage return, control is returned to the caller after taking the DOS exit at 41D0H (JP 5B99H).
POP HL E1Top of a loop. Get the value of the current BASIC program pointer from the STACK and put it in HL
2DD4DEC HL 2BDecrement the value of the current BASIC program pointer in HL so we can test to see what the terminator was
2DD5We 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.
2DD6SCF 37Set the Carry flag to indicate that a CRLF is desired
2DD7-2DD8If 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-2DDBLD (40DEH),A LD (FLGINP),A 32 DE 40Set the flag that the value HAS been printed!
2DDC-2DDDCP 3BH CP “;” FE 3BCheck 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.
2DE0-2DE1CP 2CH CP “,” FE 2CCheck to see if the character at the location of the current BASIC program pointer in Register A is a comma. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
2DE2-2DE4JP NZ,1997H JP NZ,SNERRC2 97 19If 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.
POP BC C1Restore the number of characters remaining to be procesed in the USING string into Register B
2DE7EX DE,HL EBSwap DE and HL so that DE will point to the location of the current BASIC program pointer. We don’t care about HL.
2DE8POP HL E1Restore the position in the USING string from the STACK and put it in HL
2DE9PUSH HL E5Save the position in the USING string (held in HL) to the STACK
2DEAPUSH AF F5Save the flag that indicates whether or not the value list has terminated to the STACK
2DEBPUSH DE D5Save 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.
2DECLD A,(HL) 7ELoad Register A with the USING string’s length at the location of the USING string’s VARPTR in HL
2DEDSUB B 90Subtract the number of characers which were already scanned
2DEEINC HL 23Bump the pointer to the “USING” strings string data
2DEFLD C,(HL) 4ELoad Register C with the LSB of the USING string’s address at the location of the USING string’s VARPTR in HL
2DF0INC HL 23Bump the value of the USING string’s VARPTR in HL
2DF1LD H,(HL) 66Load Register H with the MSB of the USING string’s address at the location of the USING string’s VARPTR in HL
2DF2LD L,C 69Load Register L with the LSB of the USING string’s address in Register C
2DF3-2DF4LD D,00H 16 00Zero Register D so that Register Pair DE can be a 16 bit offset of whatever is held in A.
2DF5LD E,A 5FLoad Register E with the USING string’s offset in Register A
2DF6ADD HL,DE 19Add 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
2DF7LD A,B 78Load Register A with the number of characters left to scan
2DF8OR A B7Check to see if this is the end of the USING string
2DF9-2DFBJP NZ,2D03H JP NZ,PRCCHRC2 03 2DIf there are still more string characters to scan, JUMP to PRCCHR to do so
2DFE-2E00 – Part of the PRINT USING Routine – “REUSIN”
We will wind up here when we are done processing a numeric field
2E01-2E03CALL 032AH CALL OUTDOCD 2A 03Go send the FINAL character (held in Register A) to the current output device
POP HL E1Get the value of the current BASIC program pointer from the STACK and put it in HL
2E05POP AF F1Restore the flag which indicates whether or not the value list has ended into Register A
2E06-2E08JP NZ,2CCBH JP NZ,REUSSTC2 CB 2CIf the value list has NOT ended, JUMP back to REUSST to reuse the USING string
CALL C,20FEH CALL C,CRDODC FE 20If 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
2E0CEX (SP),HL E3Swap (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
2E10POP HL E1Get the value of the current BASIC program pointer from the STACK and put it in HL
2E14-2E15 – Part of the PRINT USING Routine – “SMSTRF”
We will wind up here when the “!” indicating a single character string field has been scanned
2E16-2E17LD A,0F1H 3E F1Z-80 Trick. By putting a 3E in front of the F1 (which is POP AF , to clear the STACK) that POP AF gets skipped if flowing down in the code
POP AF F1(Skipped if passing down) Clear the STACK *dumping the HL that was being saved in case it turned out that this wasn’t actually a string)
2E18DEC B 05Decrement the USING string character count (tracked in Register B)
2E1CPOP HL E1Get the value of the current BASIC program pointer from the STACK and put it in HL
2E1DPOP AF F1Get the flag which indicates whether there are more values in the value list into Register A
2E1E-2E1FIf there are no more values in the value list, then we are done so JUMP back to 2E09H
2E20PUSH BC C5Save the number of characters still to be scanned from the USING string (tracked in B) to the STACK
2E21-2E23CALL 2337H CALL FRMEVLCD 37 23Read 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
2E27POP BC C1Restore the field width (a/k/a the number of characters to be printed) into Register C
2E28PUSH BC C5Save the USING string’s length and the number of characters to be printed in BC to the STACK
2E29PUSH HL E5Save the value of the current BASIC program pointer in HL to the STACK
2E2A-2E2CLD HL,(4121H) LD HL,(FACLO) 2A 21 41Load HL with the string’s VARPTR in ACCumulator
2E2DLD B,C 41Load Register B with field width (a/k/a the number of characters to be printed)
2E2E-2E2FLD C,00H 0E 00Zero Register C so that we can use the LEFT$ routine
2E30PUSH BC C5Save the length of the string to be printed in Register B to the STACK (as we will need that for space padding)
2E31-2E33CALL 2A68H CALL LEFTUSCD 68 2ATruncate the string to B characters via a call to the LEFT$ routine
2E37-2E39LD HL,(4121H) LD HL,(FACLO) 2A 21 41Load HL with the string’s VARPTR in ACCumulator so we can see if we need to pad the string
2E3APOP AF F1Get the field width (a/k/a the length of the string to be printed) from the STACK and put it in Register A
2E3BSUB (HL) 96Determine 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
2E3CLD B,A 47Save the amount of padding needed into Register B
2E3D-2E3ELD A,20H 3E 20Load Register A with a SPACE
2E3FINC B 04Bump 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.
2E41-2E43JP Z,2DD3H JP Z,FNSTRFCA D3 2DIf all of the spaces have been printed, Jump back to 2DD3H to see if the value list ended and to resume scanning
2E49 – Part of the PRINT USING Routine – “PLSPRT”
When a “+” is detected in the “USING” string and a numeric field follows, a bit in Register D should be set, otherwise + should be printed. Since deciding whether a numeric field follows is very difficult, the bit is always set in Register D. At the point it is decided a character is not part of a numeric field, this routine is called to see if the bit in Register D is set, which means a plus preceded the character and should be printed
2E49 PLSPRTPUSH AF F5Save the current character (held in Register A) to the STACK
2E4ALD A,D 7AWe need to test the PLUS BIT in D, so first load Register A with the value in Register D
2E4BOR A B7Check 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-2E4DLD A,2BH LD A,”+” 3E 2BPrepare to print the + by loading Register A with a +
2E4E-2E50CALL NZ,032AH CALL NZ,OUTDOC4 2A 03If the bit was set (i.e., A was non-zero), then send a + to the current output device
2E51POP AF F1Get the current character from the STACK and put it in Register A
2E52RET C9RETurn 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
LD (409AH),A LD (ERRFLG),A 32 9A 40Reset the EDIT flag.
Note: 409AH holds the ERROR/RESUME flag
2E56-2E58LD HL,(40EAH) LD HL,(ERRLIN) 2A EA 40Load HL with the line number to be edited.
Note: 40EAH-40EBH holds the line number with error
2E59OR H B4OR Register A with the MSB of the error line number in Register H
2E5AAND L A5Combine 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
2E5BINC A 3CBump 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
2E5CEX DE,HL EBSwap DE and HL so that DE now holds the line number to edit.
2E5DRET Z C8If 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
2E60-2E62 EDITCALL 1E4FH CALL LINSPCCD 4F 1EGet the first line number by calling 1E4F – returns in in DE
2E63RET NZ C0If the zero flag got set, there was no line number, so return
2E66-2E68LD (40ECH),HL LD (DOT),HL 22 EC 40Save 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
2E69EX DE,HL EBLoad HL with the line number to be edited
2E6A-2E6CCALL 1B2CH CALL FNDLINCD 2C 1BFind 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
2E70
2E71LD H,B
LD L,C 60At this point, the line number has been found. Let HL=BC so that HL also points to the location in RAM of the line number being edited
2E72
2E73INC HL
INC HL 23Bump the value of the memory pointer in HL twice to now point to the first byte of the line.
2E74LD C,(HL) 4ELoad Register C with first byte of the line number being edited
2E75INC HL 23Bump the value of the memory pointer in HL to point to the second byte of the line being edited
2E76LD B,(HL) 46Load Register B with second byte of the line number being edited
2E77INC HL 23Bump the value of the memory pointer in HL to now point to the first byte of the actual line
2E78PUSH BC C5Save the line number to the STACK
2E79-2E7BCALL 2B7EH CALL BUFLINCD 7E 2BGOSUB to 2B7EH move the BASIC line at the location of the memory pointer in HL into a memory buffer and untokenize the BASIC line
2E7D INLEDPUSH HL E5Save the value of the line number in HL to the STACK
2E7E-2E80CALL 0FAFH CALL LINPRTCD AF 0FConvert the line number to ASCII and print it out by calling the HL TO ASCII routine at 0FAFH (which converts the value in the HL (assumed to be an integer) to ASCII and display it at the current cursor position on the video screen)
2E81-2E82LD A,20H 3E 20Load Register A with a space
2E86-2E88LD HL,(40A7H) LD HL,(BUFPNT) 2A A7 40Load HL with the starting address of the expanded version of the current line from the input buffer.
Note: 40A7H-40A8H holds the input Buffer pointer
2E89-2E8ALD A,0EH 3E 0ELoad Register A with the “turn on the cursor” character
2E8EPUSH HL E5Save the value of the input buffer pointer (in HL) to the STACK
2E8F-2E90LD C,FFH 0E FFLoad Register C with the number of characters examined so far with FFH because the next line is going to INC it by 1 to make it 0
2E92LD A,(HL) 7ELoad Register A with the character at the location of the input buffer pointer in HL
2E93OR A B7Check to see if the character in Register A is an end of the BASIC line character
2E94INC HL 23Bump the value of the input buffer pointer in HL
2E95-2E96Loop back to 2E91H until the end of the BASIC line has been found
2E97POP HL E1At this point, C will be the maximum number of characters in the line at issue. Put the start of the expanded buffer into HL
2E98LD B,A 47Set the current position in the BASIC line being edited (tracked by Register B) to ZERO
2E99-2E9A DISPEDLD D,00H 16 00Assume the repetition count for the upcoming command (tracked by Register D) is zero
2D9E-2E9F DISPSUB 30H 20 15We need to test to see if the character was alphabetic or alphanumeric so we subtract 30H from it
2EA2-2EA3CP 0AH FE 0ACheck 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.
2EA6LD E,A 5FLoad Register E with the binary value of the character in Register A
2EA7LD A,D 7APut the repetition value into Register A
2EA8RLCA 07Multiply the value in Register A by two (so now A has multiplied by 2)
2EA9RLCA 07Multiply the value in Register A by two (so now A has multiplied by 4)
2EAAADD A,D 82Add the value in Register D to the value in Register A (so now A has multiplied by 5)
2EABRLCA 07Multiply the value in Register A by two (so now A has multiplied by 10). Now the “ones place” is empty.
2EACADD A,E 83Add the value in Register E to the value in Register A in the “ones place”
2EADLD D,A 57Load Register D with the value in Register A
2EB0H – LEVEL II BASIC EDIT ROUTINE – “NOTDGI”
While getting user command input within an edit, we wind up here if the user enters a non-numeric character (i.e., the actual command, and not just the repetition number which precedes it)
2EB0 NOTDGIPUSH HL E5Save the value of the input buffer pointer in HL to the STACK
2EB1-2EB3LD HL,2E99H LD HL,DISPED 21 99 2ELoad HL with the return address of 2E99H
2EB4EX (SP),HL E3Exchange the value of the return address in HL with the value of the input buffer pointer to the STACK
2EB5DEC D 15We 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
2EB6INC D 14… and then incrementing the numeric value in Register D to set the flags
2EB7-2EB9JP NZ,2EBBH JP NZ,NTZERDC2 BB 2EIf we had a received a repetition count already, then JUMP to 2EBBH
2EBAINC D 14Otherwise, set the repetition count (held in Register D) to be one
CP 0D8H FE D8Check to see if the character in Register A is a BACKSPACE character. If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
2EBD-2EBFJP Z,2FD2H JP Z,DELEDCA D2 2FIf the character in Register A is a BACKSPACE character, JUMP to DELED
2EC0-2EC1CP 0DDH FE DDCheck to see if the character in Register A is a CARRIAGE RETURN . If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
2EC2-2EC4JP Z,2FE0H JP Z,CREDCA E0 2FIf the character in Register A is a CARRIAGE RETURN , JUMP to CRED
2EC5-2EC6CP 0F0H FE F0Check 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.
That’s it for non-alphabetic instructions, so we need to need to convert a lower case command to upper case
2EC9-2ECACP 31H FE 31Check 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.
2ECD-2ECESUB 20H D6 20Convert the lowercase character in Register A to uppercase
CP 21H FE 21Check 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.
2ED4-2ED5CP 1CH FE 1CCheck 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.
2ED9-2EDACP 23H FE 23Check 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.
2EDD-2EDECP 19H FE 19Check 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.
2EE2-2EE3CP 14H FE 14Check 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.
2EE7-2EE8CP 13H FE 13Check 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.
2EEC-2EEDCP 15H FE 15Check 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.
2EF1-2EF2CP 28H FE 28Check 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.
2EF6-2EF7CP 1BH FE 1BCheck 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.
2EFA-2EFBCP 18H FE 18Check to see if the character in Register A is an H . If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
2EFC-2EFEJP Z,2F75H JP Z,HEDCA 75 2FJump if the character in Register A is an H (i.e., HACK off the rest of the line and then enter INSERT mode)
2EFF-2F00CP 11H FE 11Check 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.
2F01RET NZ C0Return if the character in Register A isn’t an A
2F02 – EDIT Command – Cancel and Restore Logic.
2F02POP BC C1Clean up the STACK (i.e., remove the DISPI return address)
2F03POP DE D1Get 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 SPEDLD A,(HL) 7ELoad Register A with the character at the location of the input buffer pointer in HL
2F0BOR A B7Check to see if the character in Register A is an end of the BASIC line character
2F0CRET Z C8Return if the character in Register A is an end of the BASIC line character
2F0DINC B 04Bump the character position in Register B
2F11INC HL 23Bump the value of the pointer in HL
2F12DEC D 15Decrement the number of times to perform the operation in Register D
2F15RET C9RETurn to CALLer
2F16 – EDIT Command – KILL Logic – “KED” .
2F17-2F19LD HL,2F5FH LD HL,TYPSLH 21 5F 2FLoad HL with the return address of 2F5FH (which will print the final !
2F1AEX (SP),HL E3Exchange the value of the return address in HL with the value of the input buffer pointer to the STACK
2F1BSCF 37Set the KILL/SEARCH flag for KILL since CARRY flag signals KILL
2F1D-2F1FCALL 0384H CALL INCHRCD 84 03Go scan the keyboard for the character the user wants to SEARCH for
2F20LD E,A 5FSave the character the user wants to SEARCH for into Register E
2F21POP AF F1Get the KILL/SEARCH flag from the STACK
2F22PUSH AF F5Save the KILL/SEARCH flag to the STACK
2F23-2F25CALL C,2F5FH CALL C,TYPSLHDC 5F 2FIf KILL (because the CARRY flag was set) then GOSUB to 2F5FH to print a !
LD A,(HL) 7ELoad Register A with the character at the location of the input buffer pointer in HL
2F27OR A B7Check to see if the character in Register A is an end of the BASIC line character
2F28-2F2AJP Z,2F3EH JP Z,POPARTCA 3E 2FJump down to 2F3EH if the character in Register A is an end of the BASIC line character
2F2EPOP AF F1Get the KILL/SEARCH flag from the STACK
2F2FPUSH AF F5Save the KILL/SEARCH flag to the STACK
2F30-2F32CALL C,2FA1H CALL C,DELCHRDC A1 2FIf the CARRY flag is set, that means we are in KILL mode so GOSUB to 2FA1H to delete the character from the input buffer
2F33-2F34Jump to 2F37H if KILL. Note, we do not move the HL pointer in this case because DELCHR already moved it.
2F35INC HL 23If we are here, it must be SEARCH! So bump to the next character
2F36INC B 04Bump the value of the character position in Register B
LD A,(HL) 7ERegardless of whether we are SEARCH or KILL, load Register A with the character at the location of the current input buffer pointer in HL
2F38CP E BBCheck 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.
2F3BDEC D 15Decrement the number of times to perform the operation in Register D (as initially specified by the user by entering a number before the command)
2F3FRET C9RETurn to CALLer
2F40 – EDIT Command – LIST Logic – “LED” .
CALL 2B75H CALL LISPRTCD 75 2BSince 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
2F46POP BC C1Clear off the RETURN address to DISPED
2F47-2F49JP 2E7CH JP LLEDC3 7C 2EJump to 2E7CH (to display the current line number and await the next EDIT command)
2F4A – EDIT Command – DELETE Logic – “DED”
LD A,(HL) 7ELoad Register A with the character at the location of the input buffer pointer in HL
2F4BOR A B7Check to see if the character in Register A is an end of the BASIC line character
2F5CRET Z 15Return if the character in Register A is an end of the BASIC line character
LD A,(HL) 7ELoad Register A with the character at the location of the input buffer pointer in HL
2F53OR A B7Check to see if the character in Register A is an end of the BASIC line character
2F54-2F5BJump to 2F5FH if the character in Register A is an end of the BASIC line character
2F5CDEC D 15Decrement the number of times to perform the operation in Register D (as initially specified by the user by entering a number before the command)
2F64RET C9RETurn to CALLer
2F65 – EDIT Command – CHANGE Logic – “CED” .
2F65 CEDLD A,(HL) 7ELoad Register A with the character at the location of the input buffer pointer in HL
2F66OR A B7Check to see if the character in Register A is an end of the BASIC line character
2F67RET Z C8Return if the character in Register A is an end of the BASIC line character
CALL 0384H CALL INCHRCD 84 03Go get the character to put in the input buffer from the keyboard
2F6BLD (HL),A 77Save the character in Register A at the memory location of the input buffer pointer in HL
2F6FINC HL 23Bump the value of the input buffer pointer in HL
2F70INC B 04Bump the character position in Register B
2F71DEC D 15Decrement the number of times to perform the operation in Register D (as initially specified by the user by entering a number before the command)
2F74RET C9RETurn to CALLer
2F75 – EDIT Command – HACK/INSERT Logic – “HED”
2F75-2F76 HEDLD (HL),00H 36 00Set the line end to be the current position.
2F77LD C,B 48Load Register C with the character position in Register B which will now be the line length
LD D,0FFH 16 FFPrepare for the next CALL to find the end of the line by loading Register D with the number of times to perform the operation
2F80OR A B7Check to see if a key was pressed
2F84-2F85CP 08H FE 08Check to see if the character in Register A is a backspace character . If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
2F86-2F87Jump to 2F92H if the character in Register A is a backspace character
2F88-2F89CP 0DH FE 0DCheck to see if the character in Register A is a carriage return . If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
2F8A-2F8CJP Z,2FE0H JP Z,CREDCA E0 2FJump to 2FE0H if the character in Register A is a carriage return
2F8D-2F8ECP 1BH FE 1BCheck 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.
2F8FRET Z C8Return if the character in Register A is shift up arrow
2F92 – EDIT Command – BACKSPACE CURSOR Logic – “TYPARW” .
2F94 TYPAR1DEC B 05Decrement the character position in Register B
2F95INC B 04Bump the character position in Register B
2F96-2F97If this is the first character of the BASIC line Jump forward to 2FB7H
2F9BDEC HL 2BDecrement the value of the input buffer pointer in HL
2F9CDEC B 05Decrement the character position in Register B
2F9D-2F9FLD DE,2F7DH LD DE,IED 11 7D 2FLoad DE with a return address of 2F7DH
2FA0PUSH DE D5Save the value of the return address in DE to the STACK
2FA1 – LEVEL II BASIC EDIT ROUTINE – “DELCHR”
This subroutine will delete the character pointed to by Register Pair HL and will correct Register C
2FA1 DELCHRPUSH HL E5Save the value of the input buffer pointer in HL to the STACK
2FA2DEC C 0DDecrement the character position in Register C
LD A,(HL) 7ELoad Register A with the character at the location of the input buffer pointer in HL
2FA4OR A B7Check to see if the character in Register A is an end of the BASIC line character
2FA5SCF 37Set the Carry flag to signal that DELCHR was called
2FA6-2FA8JP Z,0890H JP Z,POPHRTCA 90 08If the character in Register A is an end of the BASIC line character then we are done compressing so Jump to 0890H
2FA9INC HL 23Bump the value of the input buffer pointer in HL
2FAALD A,(HL) 7ELoad Register A with the character at the location of the input buffer pointer in HL
2FABDEC HL 2BDecrement the value of the input buffer pointer in HL
2FACLD (HL),A 77Save the character in Register A at the location of the current input buffer pointer in HL
2FADINC HL 23Bump the value of the input buffer pointer in HL
2FB0 – EDIT Command – ADD A CHARACTER Logic – “NTARRW” .
2FB1LD A,C 79Load Register A with the number of characters in the input buffer (i.e., the length of the line) in Register C
2FB2-2FB3CP FFH CP BUFLEN FE FFWe 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.
Jump forward to 2FB9H if the maximum BASIC line length hasn’t been reached
2FB6POP AF F1Get the character to be inserted from the STACK and put it in Register A
SUB B 90Subtract 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
2FBAINC C 0CBump the number of characters in the input buffer in Register C
2FBBINC B 04Bump the character position in Register B
2FBCPUSH BC C5Save the character position and the number of characters in the input buffer in BC to the STACK
2FBDEX DE,HL EBLoad DE with the input buffer pointer in HL
2FBELD L,A 6FLoad Register L with the number of bytes to move
2FBF-2FC0LD H,00H 26 00Zero Register H so that the number of bytes to move can be done in a 16 bit Register Pair.
2FC1ADD HL,DE 19Add the value of the input buffer pointer in DE to the character count in HL
2FC2LD B,H 44Load Register B with the MSB of the end of the BASIC line pointer in Register H
2FC3LD C,L 4DLoad Register C with the LSB of the end of the BASIC line pointer in Register L
2FC4INC HL 23Bump the value of the end of the BASIC line pointer in HL
2FC8POP BC C1Get the character position and the number of characters in the input buffer from the STACK and put it in BC
2FC9POP AF F1Get the character to be inserted from the STACK and put it in Register A
2FCALD (HL),A 77Save the character in Register A at the location of the current input buffer pointer in HL
2FCEINC HL 23Bump the value of the input buffer pointer in HL
2FD2 – EDIT Command – BACKSPACE Logic – “DELED” .
LD A,B 78Top 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
2FD3OR A B7Check to see if this is the start of the BASIC line
2FD4RET Z C8Return if this is the start of the BASIC line
2FD6DEC HL 2BDecrement the value of the buffer pointer in HL
2FD7-2FD8LD A,08H 3E 08Load Register A with a backspace the cursor character
2FDCDEC D 15Decrement the number of times to perform the operation in Register D
2FDFRET C9RETurn to CALLer
CALL 2B75H CALL LISPRTCD 75 2BSince 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
2FE6POP BC C1Clean up the STACK (to remove the DISPED return address)
2FE7POP DE D1Get the BASIC line number (in binary) from the STACK and put it in DE
2FE8LD A,D 7ALoad Register A with the MSB of the BASIC line number in Register D
2FE9AND E A3Combine the LSB of the BASIC line number in Register E with the MSB of the BASIC line number in Register A
2FEAINC A 3CBump the combined BASIC line number in Register A
LD HL,(40A7H) LD HL,(BUFPNT) 2A A7 40Load HL with the starting address of the input buffer.
Note: 40A7H-40A8H holds the input Buffer pointer
2FEEDEC HL 2BDecrement the value of the input buffer pointer in HL
2FEFRET Z C8Return if this is the Level II BASIC command mode
SCF 37Set the Carry flag to to fool the INSERT code; this flags the line number has having been seen
2FF1INC HL 23Bump the value of the input buffer pointer in HL
2FF2PUSH AF F5Save the command mode flag in AF to the STACK
2FF6 – EDIT Command – QUIT Logic – “QED” .
2FF6 QEDPOP BC C1Get rid of the DISPED return address
2FF7POP DE D1Get the line number off of the stack
2FFB-2FFFNOP 00THE END OF THE LEVEL II BASIC ROMS
2FFB-2FFFNOP 00Nothing here
*2FFB-2FFCSBC A,0C3HIn ROM v1.2 this is just garbage
On entry, HL=address of LEFT$$, the STACK = string address, STACK+1 = n, and DE = code string address.
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.
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).
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).
The original ROM source explains that we need to do some fancy footwork here to handle the case where the two strings are stored next to each other.
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.
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).
“GETINT”
This evaluates an expression and leaves the result in DE as an integer.
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.
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).
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.
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.
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.
This routine sets the output device flag to PRINTER and then flows through to the LIST command.
Note: 409CH holds the current output device flag: -1=cassette, 0=video and 1=printer
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.
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.
Note: 40ECH-40EDH holds EDIT line number
Note: 40A7H-40A8H holds the input Buffer pointer
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 41C1H.
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.
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.
Note: 40A7H-40A8H holds the input Buffer pointer
2B83
LD C,L 44
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!
DEC BC
DEC BC
DEC BC 0B
INC D
INC D
INC D 14
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.
2BD2
LD E,L 54
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.
- Note: 40F9H-40FAH holds the starting address of the simple variable storage area.
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.
- Note: 40F9H-40FAH holds the starting address of the simple variable storage area.
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.
- Note: 40A4H-40A5H holds the starting address of BASIC program text also known as the PROGRAM STATEMENT TABLE (PST).
- Note: 40F9H-40FAH holds the starting address of the simple variable storage area.
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.
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.
- 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.
CALL REASONCD 6C 19
- Note: 40F9H-40FAH holds the starting address of the simple variable storage area.
- Note: 40A4H-40A5H holds the starting address of BASIC program text also known as the PROGRAM STATEMENT TABLE (PST).
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).
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.
2CB1-2CBC – LEVEL II BASIC POKE ROUTINE – “POKE”
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).
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
Vernon Hester has reported an error in the PRINT USING routine. A PRINT USING statement with a negative sign at the end of the field prints a negative sign after negative numbers and prints a space for positive numbers. However, if the field specifiers in the string also has two asterisks at the beginning of the field, the ROM prints an asterisk instead of a space after a positive number.
Example: PRINT USING “**####-“;1234 will display **1234* instead of **1234 SPACE
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).
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.
At this point we need to print the character held in Register A since it wasn’t part of any field
Now we parse all the 2 character USING fields.
2D66 – Part of the PRINT USING Routine – “DOTNUM”
Jumped here when a “.” is seen in the USING string. THis means that we are starting a numeric field ONLY if it is followed by a “#”
2D7A – Part of the PRINT USING Routine – “FINNUM”
Now we move on to check the “^^^^” that indicates scientific notation
2D80
LD E,L 54
2DB5 – Part of the PRINT USING Routine – “ENDNUM”
Jump point for when we figure out that we are at the end of a string of digits within a USING string
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).
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.
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.
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.
2DFE-2E00 – Part of the PRINT USING Routine – “REUSIN”
We will wind up here when we are done processing a numeric field
2E14-2E15 – Part of the PRINT USING Routine – “SMSTRF”
We will wind up here when the “!” indicating a single character string field has been scanned
This loop will print all the spaces needed and then jump to 2DD3H.
2E49 – Part of the PRINT USING Routine – “PLSPRT”
When a “+” is detected in the “USING” string and a numeric field follows, a bit in Register D should be set, otherwise + should be printed. Since deciding whether a numeric field follows is very difficult, the bit is always set in Register D. At the point it is decided a character is not part of a numeric field, this routine is called to see if the bit in Register D is set, which means a plus preceded the character and should be printed
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
Note: 409AH holds the ERROR/RESUME flag
Note: 40EAH-40EBH holds the line number with error
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
Note: 40ECH-40EDH holds EDIT/LIST line number
2E71
LD L,C 60
2E73
INC HL 23
Note: 40A7H-40A8H holds the input Buffer pointer
2EB0H – LEVEL II BASIC EDIT ROUTINE – “NOTDGI”
While getting user command input within an edit, we wind up here if the user enters a non-numeric character (i.e., the actual command, and not just the repetition number which precedes it)
That’s it for non-alphabetic instructions, so we need to need to convert a lower case command to upper case
2F02 – EDIT Command – Cancel and Restore Logic.
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 SPEDLD A,(HL) 7ELoad Register A with the character at the location of the input buffer pointer in HL
2F0BOR A B7Check to see if the character in Register A is an end of the BASIC line character
2F0CRET Z C8Return if the character in Register A is an end of the BASIC line character
2F0DINC B 04Bump the character position in Register B
2F11INC HL 23Bump the value of the pointer in HL
2F12DEC D 15Decrement the number of times to perform the operation in Register D
2F15RET C9RETurn to CALLer
2F16 – EDIT Command – KILL Logic – “KED” .
2F17-2F19LD HL,2F5FH LD HL,TYPSLH 21 5F 2FLoad HL with the return address of 2F5FH (which will print the final !
2F1AEX (SP),HL E3Exchange the value of the return address in HL with the value of the input buffer pointer to the STACK
2F1BSCF 37Set the KILL/SEARCH flag for KILL since CARRY flag signals KILL
2F1D-2F1FCALL 0384H CALL INCHRCD 84 03Go scan the keyboard for the character the user wants to SEARCH for
2F20LD E,A 5FSave the character the user wants to SEARCH for into Register E
2F21POP AF F1Get the KILL/SEARCH flag from the STACK
2F22PUSH AF F5Save the KILL/SEARCH flag to the STACK
2F23-2F25CALL C,2F5FH CALL C,TYPSLHDC 5F 2FIf KILL (because the CARRY flag was set) then GOSUB to 2F5FH to print a !
LD A,(HL) 7ELoad Register A with the character at the location of the input buffer pointer in HL
2F27OR A B7Check to see if the character in Register A is an end of the BASIC line character
2F28-2F2AJP Z,2F3EH JP Z,POPARTCA 3E 2FJump down to 2F3EH if the character in Register A is an end of the BASIC line character
2F2EPOP AF F1Get the KILL/SEARCH flag from the STACK
2F2FPUSH AF F5Save the KILL/SEARCH flag to the STACK
2F30-2F32CALL C,2FA1H CALL C,DELCHRDC A1 2FIf the CARRY flag is set, that means we are in KILL mode so GOSUB to 2FA1H to delete the character from the input buffer
2F33-2F34Jump to 2F37H if KILL. Note, we do not move the HL pointer in this case because DELCHR already moved it.
2F35INC HL 23If we are here, it must be SEARCH! So bump to the next character
2F36INC B 04Bump the value of the character position in Register B
LD A,(HL) 7ERegardless of whether we are SEARCH or KILL, load Register A with the character at the location of the current input buffer pointer in HL
2F38CP E BBCheck 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.
2F3BDEC D 15Decrement the number of times to perform the operation in Register D (as initially specified by the user by entering a number before the command)
2F3FRET C9RETurn to CALLer
2F40 – EDIT Command – LIST Logic – “LED” .
CALL 2B75H CALL LISPRTCD 75 2BSince 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
2F46POP BC C1Clear off the RETURN address to DISPED
2F47-2F49JP 2E7CH JP LLEDC3 7C 2EJump to 2E7CH (to display the current line number and await the next EDIT command)
2F4A – EDIT Command – DELETE Logic – “DED”
LD A,(HL) 7ELoad Register A with the character at the location of the input buffer pointer in HL
2F4BOR A B7Check to see if the character in Register A is an end of the BASIC line character
2F5CRET Z 15Return if the character in Register A is an end of the BASIC line character
LD A,(HL) 7ELoad Register A with the character at the location of the input buffer pointer in HL
2F53OR A B7Check to see if the character in Register A is an end of the BASIC line character
2F54-2F5BJump to 2F5FH if the character in Register A is an end of the BASIC line character
2F5CDEC D 15Decrement the number of times to perform the operation in Register D (as initially specified by the user by entering a number before the command)
2F64RET C9RETurn to CALLer
2F65 – EDIT Command – CHANGE Logic – “CED” .
2F65 CEDLD A,(HL) 7ELoad Register A with the character at the location of the input buffer pointer in HL
2F66OR A B7Check to see if the character in Register A is an end of the BASIC line character
2F67RET Z C8Return if the character in Register A is an end of the BASIC line character
CALL 0384H CALL INCHRCD 84 03Go get the character to put in the input buffer from the keyboard
2F6BLD (HL),A 77Save the character in Register A at the memory location of the input buffer pointer in HL
2F6FINC HL 23Bump the value of the input buffer pointer in HL
2F70INC B 04Bump the character position in Register B
2F71DEC D 15Decrement the number of times to perform the operation in Register D (as initially specified by the user by entering a number before the command)
2F74RET C9RETurn to CALLer
2F75 – EDIT Command – HACK/INSERT Logic – “HED”
2F75-2F76 HEDLD (HL),00H 36 00Set the line end to be the current position.
2F77LD C,B 48Load Register C with the character position in Register B which will now be the line length
LD D,0FFH 16 FFPrepare for the next CALL to find the end of the line by loading Register D with the number of times to perform the operation
2F80OR A B7Check to see if a key was pressed
2F84-2F85CP 08H FE 08Check to see if the character in Register A is a backspace character . If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
2F86-2F87Jump to 2F92H if the character in Register A is a backspace character
2F88-2F89CP 0DH FE 0DCheck to see if the character in Register A is a carriage return . If they match, the Z FLAG is set, and otherwise the NZ FLAG is set. If A < the checked value, then the C FLAG is set. If A >= the checked value, the NC FLAG is set.
2F8A-2F8CJP Z,2FE0H JP Z,CREDCA E0 2FJump to 2FE0H if the character in Register A is a carriage return
2F8D-2F8ECP 1BH FE 1BCheck 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.
2F8FRET Z C8Return if the character in Register A is shift up arrow
2F92 – EDIT Command – BACKSPACE CURSOR Logic – “TYPARW” .
2F94 TYPAR1DEC B 05Decrement the character position in Register B
2F95INC B 04Bump the character position in Register B
2F96-2F97If this is the first character of the BASIC line Jump forward to 2FB7H
2F9BDEC HL 2BDecrement the value of the input buffer pointer in HL
2F9CDEC B 05Decrement the character position in Register B
2F9D-2F9FLD DE,2F7DH LD DE,IED 11 7D 2FLoad DE with a return address of 2F7DH
2FA0PUSH DE D5Save the value of the return address in DE to the STACK
2FA1 – LEVEL II BASIC EDIT ROUTINE – “DELCHR”
This subroutine will delete the character pointed to by Register Pair HL and will correct Register C
2FA1 DELCHRPUSH HL E5Save the value of the input buffer pointer in HL to the STACK
2FA2DEC C 0DDecrement the character position in Register C
LD A,(HL) 7ELoad Register A with the character at the location of the input buffer pointer in HL
2FA4OR A B7Check to see if the character in Register A is an end of the BASIC line character
2FA5SCF 37Set the Carry flag to signal that DELCHR was called
2FA6-2FA8JP Z,0890H JP Z,POPHRTCA 90 08If the character in Register A is an end of the BASIC line character then we are done compressing so Jump to 0890H
2FA9INC HL 23Bump the value of the input buffer pointer in HL
2FAALD A,(HL) 7ELoad Register A with the character at the location of the input buffer pointer in HL
2FABDEC HL 2BDecrement the value of the input buffer pointer in HL
2FACLD (HL),A 77Save the character in Register A at the location of the current input buffer pointer in HL
2FADINC HL 23Bump the value of the input buffer pointer in HL
2FB0 – EDIT Command – ADD A CHARACTER Logic – “NTARRW” .
2FB1LD A,C 79Load Register A with the number of characters in the input buffer (i.e., the length of the line) in Register C
2FB2-2FB3CP FFH CP BUFLEN FE FFWe 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.
Jump forward to 2FB9H if the maximum BASIC line length hasn’t been reached
2FB6POP AF F1Get the character to be inserted from the STACK and put it in Register A
SUB B 90Subtract 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
2FBAINC C 0CBump the number of characters in the input buffer in Register C
2FBBINC B 04Bump the character position in Register B
2FBCPUSH BC C5Save the character position and the number of characters in the input buffer in BC to the STACK
2FBDEX DE,HL EBLoad DE with the input buffer pointer in HL
2FBELD L,A 6FLoad Register L with the number of bytes to move
2FBF-2FC0LD H,00H 26 00Zero Register H so that the number of bytes to move can be done in a 16 bit Register Pair.
2FC1ADD HL,DE 19Add the value of the input buffer pointer in DE to the character count in HL
2FC2LD B,H 44Load Register B with the MSB of the end of the BASIC line pointer in Register H
2FC3LD C,L 4DLoad Register C with the LSB of the end of the BASIC line pointer in Register L
2FC4INC HL 23Bump the value of the end of the BASIC line pointer in HL
2FC8POP BC C1Get the character position and the number of characters in the input buffer from the STACK and put it in BC
2FC9POP AF F1Get the character to be inserted from the STACK and put it in Register A
2FCALD (HL),A 77Save the character in Register A at the location of the current input buffer pointer in HL
2FCEINC HL 23Bump the value of the input buffer pointer in HL
2FD2 – EDIT Command – BACKSPACE Logic – “DELED” .
LD A,B 78Top 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
2FD3OR A B7Check to see if this is the start of the BASIC line
2FD4RET Z C8Return if this is the start of the BASIC line
2FD6DEC HL 2BDecrement the value of the buffer pointer in HL
2FD7-2FD8LD A,08H 3E 08Load Register A with a backspace the cursor character
2FDCDEC D 15Decrement the number of times to perform the operation in Register D
2FDFRET C9RETurn to CALLer
CALL 2B75H CALL LISPRTCD 75 2BSince 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
2FE6POP BC C1Clean up the STACK (to remove the DISPED return address)
2FE7POP DE D1Get the BASIC line number (in binary) from the STACK and put it in DE
2FE8LD A,D 7ALoad Register A with the MSB of the BASIC line number in Register D
2FE9AND E A3Combine the LSB of the BASIC line number in Register E with the MSB of the BASIC line number in Register A
2FEAINC A 3CBump the combined BASIC line number in Register A
LD HL,(40A7H) LD HL,(BUFPNT) 2A A7 40Load HL with the starting address of the input buffer.
Note: 40A7H-40A8H holds the input Buffer pointer
2FEEDEC HL 2BDecrement the value of the input buffer pointer in HL
2FEFRET Z C8Return if this is the Level II BASIC command mode
SCF 37Set the Carry flag to to fool the INSERT code; this flags the line number has having been seen
2FF1INC HL 23Bump the value of the input buffer pointer in HL
2FF2PUSH AF F5Save the command mode flag in AF to the STACK
2FF6 – EDIT Command – QUIT Logic – “QED” .
2FF6 QEDPOP BC C1Get rid of the DISPED return address
2FF7POP DE D1Get the line number off of the stack
2FFB-2FFFNOP 00THE END OF THE LEVEL II BASIC ROMS
2FFB-2FFFNOP 00Nothing here
*2FFB-2FFCSBC A,0C3HIn ROM v1.2 this is just garbage
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
2F92 – EDIT Command – BACKSPACE CURSOR Logic – “TYPARW” .
2FA1 – LEVEL II BASIC EDIT ROUTINE – “DELCHR”
This subroutine will delete the character pointed to by Register Pair HL and will correct Register C
2FB0 – EDIT Command – ADD A CHARACTER Logic – “NTARRW” .
2FD2 – EDIT Command – BACKSPACE Logic – “DELED” .
Note: 40A7H-40A8H holds the input Buffer pointer