Model I ROM Explained – Part 2

Page Customization:

Display OPCodes
Display Labels



1001-1002
If we do NOT need to do an asterisk fill in the ASCII string, JUMP to FOTZS1.
1003
LD A,B78
If we’re here, then we do need to do the asterisk fill, so first lets see what the sign was. Load Register A with the character at the location of the input buffer pointer in Register B
1004
CP CB9
Check to see if the character at the location of the input buffer pointer in Register A is a SPACE. The Z FLAG will be set if it was a SPACE
1005-1006
LD C,2AHLD C,”*”0E 2A
Load Register C with a the fill character, which, in this case, will be a *
1007-1008
If the character at the location of the input buffer pointer in Register A isn’t SPACE then JUMP to FOTS1 to change the SPACE where the sign would be into a *.
1009
LD B,C41
Load Register B with the * character in Register C
100A
 ↳ FOTZS1
LD (HL),C71
Fill the zero or the sign with the filler character held in Register C at the location of the input buffer pointer in Register Pair HL
100B
We need the next character from the buffer. Using CHRGET is, however, a RAM saving method since there is no SPACE to skip, so the RST 10H really just does INC HL and LD A,(HL)
100C-100D
If the character at the location of the input buffer pointer in Register Pair HL is the end of the input buffer character (00H) then we are done with the number. In this casse, we need to back up and put in a ZERO, so JUMP to FOTZS4. CHRGET would have set the ZERO FLAG on any 00H or :, but there are no : going to be found.
100E-100F
CP 45HCP “E”FE 45
Check to see if the character at the location of the input buffer pointer in Register A is an E
1010-1011
If the character is an E we need to put a 0 in the floating point nontation with the C format 0, so JUMP to FOTZS4 to put into that ZERO.
1012-1013
CP 44HCP “D”FE 44
Check to see if the character at the location of the input buffer pointer in Register A is a D
1014-1015
If the character is an D we need to put a 0 in the floating point nontation with the C format 0, so JUMP to FOTZS4 to put into that ZERO.
1016-1017
CP 30HCP “0”FE 30
Check to see if the character at the location of the input buffer pointer in Register A is a 0
1018-1019
If the character is a 0 then we need to suppress it, so JUMP to FOTZS1.
101A-101B
CP 2CHCP “,”FE 2C
Check to see if the character at the location of the input buffer pointer in Register A is a ,
101C-101D
If the character is a , then we need to suppress it, so JUMP to FOTZS1.
101E-101F
CP 2EHCP “.”FE 2E
Check to see if the character at the location of the input buffer pointer in Register A is a .
1020-1021
If we do not have a ., then JUMP to FOTZS2
1022
 ↳ FOTZS4
DEC HL2B
If we are here then we need to back up the string and put a 0 before it. First, step back one location in the string
1023-1024
LD (HL),30HLD (HL),”0″36 30
Save a 0 at the location of the input buffer pointer in Register Pair HL
1025
 ↳ FOTZS2
LD A,E7B
Next we need to check to see if we need a floating dollar sign. First, load the format specs into Register A
1026-1027
AND 10HAND 0001 0000E6 10
Check to see if a $ is to be included in the ASCII string
1028-1029
If the Z FLAG is set, then we don’t have a dollar sign, so skip the next 2 instructions (which puts in a $) if a $ isn’t to be included in the ASCII string
102A
DEC HL2B
Need to add a $, so first we decrement the value of the input buffer pointer in Register Pair HL …
102B-102C
LD (HL),24HLD (HL),”$”36 24
… and then put a $ there
102D
 ↳ FOTZS3
LD A,E7B
Next we need to check to see if we need a trailing sign. First, load the format specs into Register A
102E-102F
AND 04HAND 0000 0100E6 04
Turn off every bit except Bit 2 (by ANDing against 00000100). If Bit 2 was on, then NZ will be set. If Bit 2 was off, then Z will be set. So this checks to see if the sign is to follow the ASCII string
1030
RET NZC0
If the sign isn’t to follow the ASCII string, then we are done so RETurn
1031
DEC HL2B
Decrement the value of the input buffer pointer in Register Pair HL
1032
LD (HL),B70
Save the sign (in Register B) to the location of the input buffer pointer in Register Pair HL
1033
RETC9
RETurn to CALLer

1034 – LEVEL II BASIC MATH ROUTINE – “FOUINI”

Initially set up the format specs and put in a SPACE for the sign of a positive number. This routine gets called by the FLOATING to ASCII Conversion Routine (at 0FBEH) and by the BINARY to ASCII Conversion Routine (at 0FAFH)
1034-1036
 ↳ FOUINI
LD (40D8H),ALD (TEMP3),A32 D8 40
Save the format specification (in Register A) to 40D8H.
Note: 40D8H-40D9H holds the temporary storage location
1037-1039
LD HL,4130HLD HL,FBUFFR+121 30 41
Set up a pointer into FBUFFR, starting at FBUFFR+1 just in case the number will overflow its field, in which case there is still room in FBUFFR for the % character.
103A-103B
LD (HL),” “36 20
Save a SPACE at the location of the input buffer pointer in Register Pair HL
103C
RETC9
RETurn to CALLer

103D – LEVEL II BASIC MATH ROUTINE – “FOUFRV”

This routine gets called by the FLOATING to ASCII Conversion Routine (0FBEH-0FC0H) if the value being converted is either Single Precision or Double Precision. This will print a single or double precision number in free format
103D-103E
 ↳ FOUFRV
CP 05HFE 05
Set the Carry flag according to whether the current value in ACCumulator is single precision or double precision (Carry set if double precision)
103F
PUSH HLE5
Save the pointer to the buffer (held in Register Pair HL) to the STACK
OK, this is fun. The next instructions are supposed to set Register D to be the counter for the number of digits to display. There is no agreement on what the next two instructions do:

“Microsoft BASIC Decoded & Other Mysteries” says it turns 04 (SP) and 08 (SP) into 08 (SP) and 10 (DP) into 09 (SP) and 0B (DP)

“Model III ROM Commented” says it turns D into 07 (SP) and 17 (DP)

The original ROM Source Code comment says it turns D into 04 to 06 (SP) and 10 to 20 (DP)
1040-1041
SBC A,00HDE 00
Adjust the value of the number type in Register A. It will be 04H if SINGLE PRECISION and it will be 08H if DOUBLE precision
1042
RLA17
Multiply the value of the number type in Register A by two, so now A will be 08H if SINGLE precision and 0AH if DOUBLE precision
1043
LD D,A57
Load Register D with the adjusted value of the number type in Register A
1044
INC D14
Bump the value of the number type in Register D (so D will be 09H if SINGLE precision and 0BH if DOUBLE precision)
1045-1047
Go scale (normalize) the current value in ACCumulator so that all the significant digits will be in the integer portion (i.e., 99,999 <= X <= 999,999). Returns wihth A being the number of times the DOUBLE precision value was scaled up or down
1048-104A
LD BC,0300H01 00 03
Load Register B to be the decimal point count of 3 (as we will assume it will come in E Notation), and Register C to be the comma count (currently 0).
104B
ADD A,D82
Test to see if we are going to actually need E Notation by first adding the value in Register D to the value in Register A
104C-104E
If D is less than .01 then we will need E Notation, so JUMP to FOFRS1
104F
INC D14
Now we need to see if the number is too big. Bump the value in Register D
1050
CP DBA
Compare the bumped B to Register A
1051-1052
If the number is too big (i.e., greater than 10^D-1), JUMP to FOFRS1
1053
INC A3C
If we are here, then we are able to display the number in fixed point notation, so we must bump the number of decimal point count
1054
LD B,A47
Load Register B with the decimal point count (stored in Register A)
1055-1056
LD A,02H3E 02
Set up for fixed point output. Fixed point notation has no exponent, so loading Register A with a two so that the next instruction will turn A (which is tracking the exponent) to 0.
1057-1058
 ↳ FOFRS1
SUB A,02HD6 02
Compute the exponent value (which will be a zero if we were passing through), so now D-2 will be added to it
1059
POP HLE1
Get the pointer to the string buffer from the STACK and put it in Register Pair HL
105A
PUSH AFF5
Save the exponent value (currently in Register A) to the STACK
105B-105D
GOSUB to FOUTED to test to see if the number is .01 < number < .1 for purposes of putting a comma or decimal point in the input buffer if necessary
105E-105F
LD (HL),30HLD (HL),”0″36 30
If the number is within that range, then add a 0 at the location of the buffer pointer in Register Pair HL
1060-1062
If there was no scaling, GOSUB to 09C9H to bump HL and return
1063-1065
Next we need to convert the number to decimal digits by a GOSUB to FOUTCV which will convert the binary value in ACCumulator to ASCII, the result being stored in the input buffer pointer
The FOFRS2 routine will suppress trailing zeroes.
1066
 ↳ FOFRS2
DEC HL2B
Backspace to the last character by decrementing the value of the input buffer pointer in Register Pair HL
1067
LD A,(HL)7E
Fetch the last character (at the location of the input buffer pointer in Register Pair HL)
1068-1069
CP 30HCP “0”FE 30
Check to see if the value in Register A is a 0
106A-106B
If it is a zero, then we want to suppress it, so loop back to FOFRS2 to decrement again and keep suppressing ending zeroes.
At this point, all trailing zeroes are now gone and HL points to the last non-zero character.
106C-106D
CP 2EHCP “.”FE 2E
Check to see if the last character in the buffer (now that all ending zeroes have been supressed) is is a .
106E-1070
If its NOT a decimal point, GOSUB to bump the value of the input buffer pointer in Register Pair HL. Otherwise, HL is now sitting at the decimal point to suppress that character too.
1071
POP AFF1
Restore the exponent from the STACK into Register A
1072-10731
If the exponent is zero then we are done, so jump to 1093H. Otherwise, pass down to FOFLDN.

1074 – LEVEL II BASIC MATH ROUTINE – “FOFLDN”

This routine will put the exponent and a D or E into the buffer. On entry, Register A holds the exponent and it is assumed that all FLAGs are set correctly.
1074
 ↳ FOFLDN
PUSH AFF5
Save the exponent (stored in A) to the STACK
1075
Determine the precision by checking the value of the current number type flag. In this case, this is a really cool trick. The purpose is to load a bit into the CARRY flag if we are going to display an E instead of a D. We start off with 1/2 of the ascii value for the “D”, then, in 1 instruction, multiply it by 2 and add in the carry bit. So if the CARRY FLAG is off, then it is a “D” and if the CARRY FLAG is on, then it is an “E”
1076-1077
LD A,22H3E 22
Load Register A with the starting value for a D or E character. In this case, A is set for 1/2 of the ASCII code for D
1078
ADC A,A8F
Multiply the value of the character in Register A by two and add in the value of the Carry flag from the number type flag test. This will result with A it being a D if the value is SINGLE precision and an E if the value is DOUBLE precision
1079
LD (HL),A77
Save the exponent designation (the D or E in Register A) at the location of the input buffer pointer in Register Pair HL
107A
INC HL23
Bump the value of the buffer pointer in Register Pair HL, which is the first position of the exponent in the buffer
107B
POP AFF1
Get the value of the exponent from the STACK and put it in Register A
107C-107D
LD (HL),2BHLD (HL),”+”36 2B
Save a + at the location of the input buffer pointer in Register Pair HL. This is done to save bytes. Instead of testing for + or – and then putting in the appropriate character, a + is put in, and then it is overwritten if a should be there.
107E-1080
If the exponent is positive, then the + we just put into the buffer (and HL is still pointing to that location) is good, so skip the next 3 instructions (by jumping to 1085H) if the exponent is positive
1081-1082
LD (HL),2DHLD (HL),”-“36 2D
Save a (which is 2DH) at the location of the input buffer pointer in Register Pair HL, thus overwriting the initially placed + in that same location
1083
CPL2F
If we are here then we have a negative exponent (or we would have jumped to 1085H back in 107EH), so convert the negative exponent to positive by reversing the value of the exponent in Register A
1084
INC A3C
We also need to bump the value of the exponent in Register A by 1 when switching from negative to positive. We then pass through and rejoin where we would have jumped if the number had been positive.

1085 – LEVEL II BASIC MATH ROUTINE – “FOUCE1” and “FOUCE2”

This routine will calculate the two digit exponent.
1085-1086
 ↳ FOUCE1
LD B,2FHLD B,”0″-106 2F
At this point, the exponent is positive. Next step is to load Register B with a 0 minus one. This is because the next instruction, which is the top of a loop, bumps it by one.
1087
 ↳ FOUCE2
INC B04
Top of a loop. Bump the value of the ASCII character in Register B. This is the start of a 3 Opcode routine to divide by 10 using compound subtraction
1088-1089
SUB A,0AHD6 0A
Subtract ten from the value of the exponent in Register A
108A-108B
Loop until the value of the exponent in Register A is less than ten. B holds the quotient (e.g., the number of times the subtraction had to occur to get to a remainder less than 10)
108C-108D
ADD A,3AHC6 3A
Since A is holding the remainder of the ‘divide-by-10’ routine above, add 3AH to it so that it will be an ASCII digit + 10
108E
INC HL23
Bump the value of the buffer pointer in Register Pair HL
108F
LD (HL),B70
Save the ASCII character in Register B (which is the first digit of the exponent in ASCII – the 10’s digit) at the location of the input buffer pointer in Register Pair HL
1090
INC HL23
Bump the value of the buffer pointer in Register Pair HL
1091
LD (HL),A77
Save the value of the ASCII character in Register A (which is the second digit of the exponent in ASCII – the 1’s digit) at the location of the input buffer pointer in Register Pair HL
1092
 ↳ FOUTZR
INC HL23
Bump the value of the buffer pointer in Register Pair HL

1093 – LEVEL II BASIC MATH ROUTINE – “FOUTDN”

This routine will print a free format zero.
1093-1094
 ↳ FOUTDN
LD (HL),00H36 00
Save an end of the ASCII string character (designated as 00H) at the location of the input buffer pointer in Register Pair HL
1095
EX DE,HLEB
Since the FFXFLV routine will need the buffer pointer in DE instead of HL, swap those registers
1096-1098
LD HL,4130HLD HL,FBUFFR+121 30 41
Load Register Pair HL with the starting address of the buffer pointer.
Note: 4130H-4149H holds an internal print buffer
1099
RETC9
DONE! RETurn to CALLer

109A- LEVEL II BASIC MATH ROUTINE – “FOUTFX”

This routine will print a number in fixed format.
109A
 ↳ FOUTFX
INC HL23
Bump the value of the buffer pointer in Register Pair HL
109B
PUSH BCC5
Save the field length specifiers (B has the number of #‘s before the current vale of the input buffer pointer and C has the number of #’s after) to the STACK
109C-109D
CP 04HFE 04
Check to see if the current number type in ACCumulator is single or double precision
109E
LD A,D7A
Load Register A with the format specifiers (held in Register D)
109F-10A1
If the current value in ACCumulator is either single precision or double precision then JUMP away to FOUFXV. If its an integer we will pass through.
10A2
RRA1F
Rotate Register A so that we can check to see if this has to be printed in floating format or not. RRA rotates Register A right one bit, with Bit 0 going to CARRY and CARRY going to Bit 7.
10A3-10A5
If we need to print it in floating point (exponential) notation, JUMP TO FFXIFL.
If we are here then we are going to print an integer in fixed format/fixed point notation.
10A6-10A8
LD BC,0603H01 03 06
Load Register B to a decimal counte of 6 and Load Register C with a comma count of 3
10A9-10AB
Go check to see if commas are needed. If no comma is needed, set C to zero
10AC
POP DED1
Restore the field lengths (the number of #’s to the left and right of the decimal point) from the STACK into Register DE
10AD
LD A,D7A
Load Register A with the number of digits requested to the left of the decimal point in Register D
10AE-10AF
SUB A,05HD6 05
Since the maximim number of digits allowed for an integer to the left of the decimal point is 5, subtract 5 from the number of digits to the left of the decimal point requested. This will test to see if we have to print extra spaces because the field is too big.
10B0-10B2
If the field is too big, and we have to print extra spaces, we GOSUB to FOTZER to put in zeroes which will later be converted to either SPACE or * by FOUTZS
10B3-10B5
Convert the number to decimal digits by GOSUBing to the INTEGER TO ASCII routine at 1232F (which converts the integer in ACCumulator to ASCII and stores the ASCII string in the buffer pointed to in HL)
10B6
 ↳ FOUTTD
LD A,E7B
Next we need to test to see if we need a decimal point. First, load Register A with the number of digits to the right of the decimal point requested (which is stored in Register E)
10B7
OR AB7
Check to see if there are any digits to the right of the decimal point requested and set the status flags accordingly
10B8-10BA
If the Z FLAG is set, then we do NOT need a decimal point, and need to backspace over it, so GOSUB to DCXHRT to decrement the value of the buffer pointer in Register Pair HL
10BB
DEC A3D
Next we need to test to see how many trailing zeroes we need to print. Decrement the number of digits to the right of the decimal point in Register A.
10BC-10BE
If the POSITIVE flag is set, then print the trailing zeroes via GOSUB to 1269H

10BF – LEVEL II BASIC MATH ROUTINE – “FOUTTS”

This routine will finish up the printing of a fixed format number.
10BF
 ↳ FOUTTS
PUSH HLE5
Save the current buffer pointer (stored in Register Pair HL) to the STACK. We then pss through to the FOUTTS routine to finish up the number.
10C0-10C2
Go edit the ASCII string in the input buffer to suppress any zeroes, if needed.
10C3
POP HLE1
Get the saved buffer pointer value from the STACK and put it in Register Pair HL
10C4-10C5
If the Z FLAG is set, then we do NOT have a trailing sign, so we JUMP away to 10C8H
10C6
LD (HL),B70
So now we know a sign does follow the value so we save sign (held in Register B) at the location of the buffer pointer in Register Pair HL
10C7
INC HL23
Bump the value of the input buffer pointer in Register Pair HL
10C8-10C9
 ↳ FFXIX1
LD (HL),00H36 00
Terminate the buffer by saving an end of the ASCII string character (=00H) at the location of the input buffer pointer in Register Pair HL
Now we need to check to see if the fixed format/fixed point number overflowed its field length. The location if the decimal point needs to be in TEMP2.
10CA-10CC
LD HL,412FHLD HL,FBUFFR21 2F 41
Load Register Pair HL with the starting address of the input buffer pointer (which is 412FH) minus 1 (because the first instruction of the following common code is add 1 to HL)
10CD
 ↳ FOUBE1
INC HL23
Bump the value of the buffer pointer in Register Pair HL
10CE-10D0
 ↳ FOUBE5
LD A,(40F3H)LD A,(TEMP2)3A F3 40
Load Register A with the LSB of the address of the decimal point for the ASCII string. Why just the LSB? FBUFFR is only 35 bytes long, so we only need to check the LSB to see if the field is big enough.
10D1
SUB A,L95
First, subtract the LSB of the input buffer pointer address in Register L from the value in Register A to see how much space we have taken up
10D2
SUB A,D92
Next, set the flags by subtract the number of digits to the left of the decimal point in Register D from the adjusted value in Register A to determine if we have taken the right amount of space. Z FLAG will mean we did!
10D3
RET ZC8
If we have taken the right amount of space, then we are done, so we RETurn
10D4
LD A,(HL)7E
If we are here, then we took too much space. How do we know it is too much instead of just “different”? Well, we started checking from the beginning of the buffer, and the field must be small enough to fit into the buffer. With this, we need to fetch the next character from the buffer into Register A
10D5-10D6
CP 20HCP ” “FE 20
Check to see if the character at the location of the buffer pointer in Register A is a space, meaning we can just ignore the character to make the field shorter
10D7-10D8
If it is a space, then LOOP back to FOUBE1 to ignore it
10D9-10DA
CP 2AHCP “*”FE 2A
Check to see if the character at the location of the input buffer pointer in Register A is a *, meaning we can just ignore the character to make the field shorter
10DD
DEC HL2B
Since we want to ignore *‘s we decrement the value of the input buffer pointer in Register Pair HL so it will get re-tested
10DE
PUSH HLE5
Save the value of the buffer pointer in Register Pair HL to the STACK

10DF – LEVEL II BASIC MATH ROUTINE – “FOUBE2”

In this routine, we check to see if we can ignore the leading zero before a decimal point. We can do this if if we see the following: (in order)
+,-a sign (either “-” or “+”)[optional]
$a dollar sign[optional]
0a zero[mandatory]
.a decimal point[mandatory]
0-9another digit[mandatory]

If we see a leading zero, it must be the one before a decimal point or else FOUTZS would have akready suppressed it. In that case, we just INC HL over the character following the zero, and not have to check for the decimal point explicitly.
10DF
 ↳ FOUBE2
PUSH AFF5
Save the the current character (which is the value in Register Pair AF) to the STACK. This also saves the ZERO FLAG.
10E0-10E2
LD BC,10DFHLD BC,FOUBE201 DF 10
Load Register Pair BC with the return address for use in case we have a , a +, or a $
10E3
PUSH BCC5
Save the return address in Register Pair BC to the STACK
10E4
Since we need to bump the current input buffer pointer in Register Pair HL 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.
10E5-10E6
CP 2DHCP “-“FE 2D
Check to see if the character at the location of the input buffer pointer in Register A is a
10E7
RET ZC8
Return (to 10DFH) if the character at the location of the input buffer pointer in Register A is a
10E8-10E9
CP 2BHCP “+”FE 2B
Check to see if the character at the location of the input buffer pointer in Register A is a +
10EA
RET ZC8
Return (to 10DFH) if the character at the location of the input buffer pointer in Register A is a +
10EB-10EC
CP 24HCP “$”FE 24
Check to see if the character at the location of the input buffer pointer in Register A is a $
10ED
RET ZC8
Return (to 10DFH) if the character at the location of the input buffer pointer in Register A is a $
10EE
POP BCC1
We don’t need a shortcut to jump to 10DFH anymore, so let’s get rid of the now unneeded return address from the STACK
10EF-10F0
CP 30HCP “0”FE 30
Check to see if the character at the location of the input buffer pointer in Register A is a 0
10F1-10F2
If the character at the location of the input buffer pointer in Register A isn’t a 0 then we can no longer just get rid of the characters, so JUMP to FOUBE4 to continue
10F3
INC HL23
Bump the value of the input buffer pointer in Register Pair HL so that we skip over the decimal point to the next character
10F4
Since we need to bump the current input buffer pointer in Register Pair HL 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.
10F5-10F6
If the character after the decimal point is not a digit then we can’t shorten the field anymore, so JUMP to FOUBE4
10F7
DEC HL2B
If we didn’t jump away, then we can shorten the field by one, so DECrement the value of the buffer pointer in Register Pair HL to backspace
10F8
LD BC,772BH01 2B 77
Z-80 Trick! The byte at this memory location, 01H, is there to turn the real instruction that follows in 10F9H into a harmless LD BC,xxxx. This way, if you are processing straight down in order, it skips the next command at 10F9H (in this case a DEC HL) because it wasn’t a command, it was a hex number to be loaded into BC! Instead, if you jump to 10F9H, you skip this byte and it is an DEC HL

10F9 – LEVEL II BASIC MATH ROUTINE – “FOUBE3”

If we can get rid of the zero, we put the characters on the STACK back into the buffer one position in front of where they originally were.

Note that the maximum number of STACK levels this uses is three — one for the last entry flag, one for a possible sign, and one for a possible dollar sign.

We don’t have to worry about the first character being in the buffer twice because the pointer when FOUT exits will be pointing to the second occurance.
10F9
 ↳ FOUBE3
DEC HL2B
If passing through, this instruction won’t get executed. If JUMPed to, decrement the value of the buffer pointer in Register Pair HL (we needed that Z-80 trick to avoid a double backspace if passing through)
10FA
LD (HL),A77
If passing through, this instruction won’t get executed. If JUMPed to, save the character in Register A at the location of the input buffer pointer in Register Pair HL
10FB
POP AFF1
Get the character from the STACK and put it in Register Pair AF
10FC-10FD
If the Z FLAG is set, then we LOOP back to FOUBE3 to put the character back into the buffer
10FE
POP BCC1
Restore the buffer pointer from the top of the STACK into Register Pair BC
10FF-1101
LOOP back to 10CEH to see if the field is NOW small enough.

1102 – LEVEL II BASIC MATH ROUTINE – “FOUBE4”

If the number is too big for the field, we wind up here to deal with that.
1102
 ↳ FOUBE4
POP AFF1
Restore the character from the STACK and put it in Register Pair AF
1103-1104
If the Z FLAG is set, then LOOP back 1 instruction to leave the number in the buffer alone
1105
POP HLE1
Get the starting address of the field from the STACK and put it in Register Pair HL. This will be the pointer to the beginning of the number – 1
1106-1107
LD (HL),25HLD (HL),”%”36 25
Show that we have overflowed the field by putting a % character at the front.
1108
RETC9
All done! RETurn to CALLer

1109 – LEVEL II BASIC MATH ROUTINE – “FOUFXV”

This is where the PRINT USING routine will print a single or double precision number in a fixed format
1109
 ↳ FOUFXV
PUSH HLE5
Save the buffer pointer in Register Pair HL to the STACK
110A
RRA1F
Rotate Register A so that the “fixed notation” or “floating notation” flag bit moves into the CARRY FLAG for testing. RRA rotates Register A right one bit, with Bit 0 going to CARRY and CARRY going to Bit 7.
110B-110D
If the CARRY FLAG was set, then we know we are printing the number in “E” notation, so JUMP to FFXFLV
110E-110F
If the Z FLAG was set, the we have a SINGLE PRECISION number to print, so JUMP to FFXSFC to do that
If we are here, then we are printing a DOUBLE PRECISION number in fixed format/fixed point notation
1110-1112
LD DE,1384HLD DE,FFXDXM11 84 13
Load Register Pair DE with the address of the DOUBLE PRECISION value to be compared to the current value in ACCumulator. Register Pair DE points to a double precision constant equal to 1D16
1113-1115
Since we can’t print a number which is greater than 10^16 in fixed format, GOSUB to compare the double precision constant pointed to by Register Pair DE (which is 1Dl6) to the double precision value in ACCumulator
1116-1117
LD D,10H16 10
Load Register D with the maximum length of a double precision value (which is 16 in decimal)
1118-111A
If the M FLAG is set, then the number in the ACCumulator is small enough to print (i.e., less than or equal to 1Dl6), so JUMP to 1132H

111B – LEVEL II BASIC MATH ROUTINE – “FFXSDO”

This routine will print a number which is greaster than 10^16 in free format with a percent sign
111B
 ↳ FFXSDO
POP HLE1
Get the current buffer pointer from the STACK and put it in Register Pair HL
111C
POP BCC1
Get the field specifier from the STACK and put it in Register Pair BC, resulting in B containing the number of #‘s before and C containing the number of #‘s after
111D-111F
Print the number in free format via a GOSUB to FOUT (which will convert a double precision value in ACCumulator to an ASCII string)
1120
DEC HL2B
Decrement the input buffer pointer in Register Pair HL to point in front of the number
1121-1122
LD (HL),25HLD (HL),”%”36 25
Save a % character at the location of the input buffer pointer in Register Pair HL
1123
RETC9
All done! RETurn to CALLer

1124 – LEVEL II BASIC MATH ROUTINE – “FFXSFX”

This routine will print a SINGLE PRECISION number in fixed format/fixed point notation
1124-1126
 ↳ FFXSFX
LD BC,B60EH01 0E B6
Load Register Pair BC/DE with 1E16
1127-1129
LD DE,1BCAH11 CA 1B
Register Pairs BC and DE now hold a single precision constant equal to 1×10^16
112A-112C
Call the SINGLE PRECISION COMPARISON routine at routine at 0A0CH which algebraically compares the single precision value in BC/DE to the single precision value ACCumulator.
The results are stored in A as follows:
If ACCumulator = BCDEA=00
If ACCumulator > BCDEA=01
If ACCumulator < BCDEA=FF
112D-112F
If the P FLAG is set then the number is too big, so we need to JUMP to FFXSDO to print it in free format with a % overflow symbol
1130-1131
LD D,06H16 06
Now we know that the SINGLE precision value in ACCumulator is less than 1×10^16. Load Register D with the maximum length of a single precision value (which is 6) and then fall through to the FFXSDC routine

1124 – LEVEL II BASIC MATH ROUTINE – “FFXSDC”

This routine will print a SINGLE PRECISION or DOUBLE PRECISION number in fixed format/fixed point notation
1132-1134
 ↳ FFXSDC
GOSUB to SIGN to see if we have a ZERO in the ACCumulator
1135-1137
If we do NOT have a ZERO, then GOSUB to FOUTNV to normalize the number so that all digits to be printed are located in the initeger part
1138
POP HLE1
Get the buffer pointer from the STACK and put it in Register Pair HL
1139
POP BCC1
Get the value from the STACK and put it in Register Pair BC, resulting in B containing the number of #‘s before and C containing the number of #‘s after
113A-113C
If the exponent is negative, JUMP to FFXXVS to handle that
This routine will print a number that has no fractional digits
113D
PUSH BCC5
Save the value in Register Pair BC (B was the number of #‘s before and C is the number of #‘s after) to the STACK
113E
LD E,A5F
Load Register E with the exponent
If the field length is higher than the number of characters we actually have, we are going to need to put in that number of leading zeroes.
113F
LD A,B78
Load Register A with the number of digits before the decimal point requested
1140
SUB A,D92
Subtract the maximum length for the current number type in Register D (which is 6) from the number of digits requested in Register A
1141
SUB A,E93
Subtract the number of times the current value in ACCumulator was divided in Register E from the adjusted value in Register A
1142-1144
If B-D-E is still POSITIVE, then we have to fill with some zeroes so GOSUB to 1269H to put leading zeros into the input buffer if necessary
1145-1147
Next, set up the decimal point and comma counts via a GOSUB to DOUTCD
1148-114A
Then, convert the number to decimal digits via a GOSUB to FOUTCV to convert the integer portion of the current value in ACCumulator to an ASCII string
114B
OR EB3
Merge in the number of digits after the number, if the field is big enough of course.
114C-114E
If there are number to be put there (i.e., merging in E leaves a number greater than Zero), then GOSUB to FOTZEC to put trailing zeros into the input buffer if necessary
114F
OR EB3
Check to see if commas or the decimal point is needed
1150-1152
Go put commas and the decimal point into the input buffer if necessary
1153
POP DED1
Retrieve the field length specs from the STACK and put it in Register Pair DE
1154-1156
Jump to 10B6H to check the size, run zero suppression, and convert the fractional portion of the number to ASCII to finish up

1157 – LEVEL II BASIC MATH ROUTINE – “FFXXVS”

This routine will print a SINGLE PRECISION or DOUBLE PREVISION number that has fractional digits
1157
 ↳ FFXXVS
LD E,A5F
Preserve the exponent into Register E
1158
LD A,C79
Prepare to divide by 10 the right number of times so that the result will be rounded correctly and have the correct number of significant digits. First, load Register A with the number of digits requested to the right of the decimal point
1159
OR AB7
Check to see if any digits to the right of the decimal point was requested
115A-115C
Go decrement the number of digits requested to the right of the decimal point if necessary
115D
ADD A,E83
Add the number of times the current value was multiplied in Register E to the number of digits to the right of the decimal point requested in Register A
115E-1160
If the value in ACCumulator must be scaled down then skip the next instruction, as we want a ZERO FLAG only if the result was not negative
1161
XOR AAF
Zero Register A
1162
 ↳ FFXXV8
PUSH BCC5
Save the field specifications held in Register Pair BC (B was the number of #‘s before and C is the number of #‘s after) to the STACK
1163
PUSH AFF5
Save the the scale count (held in Register Pair AF) to the STACK
1164-1166
 ↳ FFXXV2
Top of a divide loop. GOSUB to 0F18H to divide the value in ACCumulator by ten, A times, if necessary
1167-1169
Loop until the value in ACCumulator is properly adjusted. When this is done, A will hold the number of times it was divided by 10
116A
POP BCC1
Get the original scale count from the STACK and put it in Register Pair BC
116B
LD A,E7B
We now need to test as to whether the number has integer digits or not. First, load Register A with the number of times the value in ACCumulator was multiplied in Register E
116C
SUB A,B90
Subtract the value in Register B from the value in Register A
116D
POP BCC1
Get the value from the STACK and put it in Register Pair BC, resulting in B containing the number of #‘s before and C containing the number of #‘s after
116E
LD E,A5F
Calculate the number of decimal places before the number ends by first loading Register E with the adjusted scale factor value in Register A …
116F
ADD A,D82
… and then adding the length of the maximum size for the current value in Register D to the adjusted scale factor value in Register A. This will set the sign flag
1170
LD A,B78
Load Register A with the number of #‘s before (stored in B)
1171-1173
Jump to 117FH if there are no digits to the left of the decimal point
This routine will print numbers with integer digits, and will print some leading zeroes if the field is bigger than the number of digits we need to print.
1174
SUB A,D92
We now know there are leading digits so, subtract the maximum length for the current value in Register D (6 for SINGLE precision and 10 for DOUBLE precision) from the adjusted value in Register A
1175
SUB A,E93
Then, subtract the adjusted scale value in Register E from the adjusted value in Register A
1176-1178
If that subtraction leads to a positive number, go put leading zeros into the input buffer
1179
PUSH BCC5
Save the field specs held in Register Pair BC (B was the number of #‘s before and C is the number of #‘s after) to the STACK
117A-117C
GOSUB to set up BC for decimal point and comma counters
117D-117E
Jump to 1190H to convert the digits before the decimal point and trim the number

117F – LEVEL II BASIC MATH ROUTINE – “FFXXV3”

This routine will print a number without integer digits.
117F-1181
 ↳ FFXXV3
Go put leading zeros (as needed) into the input buffer
1182
LD A,C79
Load Register A with the number of bytes requested to the right of the decimal point (in Register C) because C is about to get wiped
1183-1185
GOSUB to 1294H to put a decimal point into the input buffer
1186
LD C,A4F
Reload Register C with the number of digits requested to the right of the decimal point in Register A
1187
XOR AAF
Next we need to calculate how many zeroes to put between the decimal point and the first digit, so start by zeroing Register A
1188
SUB A,D92
Then – subtract the maximum length for the current value in Register D from the value in Register A
1189
SUB A,E93
Then – subtract the value in Register E from the adjusted value in Register A
118A-118C
GOSUB to put that many zeroes into the buffer
118D
PUSH BCC5
Save the value in Register Pair BC (B is the exponent and C is the number of #‘s after) to the STACK
118E
LD B,A47
Load Register B (i.e., the decimal place count) with the value in Register A (which is 0)
118F
LD C,A4F
Load Register C (i..e, the comma count) with the value in Register A (which is 0)
1190-1192
 ↳ FFXXV6
GOSUB to 12A4H to convert the integer portion of the SINGLE precision value in ACCumulator to an ASCII string. These will be the decimal digits.
1193
POP BCC1
Get the number of #‘s before and number of #‘s after and put it back in Register Pair BC
1194
OR CB1
Check to see if we need to print any zeroes after the last digit (i.e., if there are any digits to the right of the decimal point requested) and set the status accordingly
1195-1196
If the NZ FLAG is set, then there are digits to the right of the decimal point to fill, so JUMP to 119AH to do that
1197-1199
LD HL,(40F3H)LD HL,(TEMP2)2A F3 40
Now we know that there are no digits to the right of the decimal point. Load Register Pair HL with the position of the decimal point (which is stored in 40F3H).
Note: 40F3H-40F4H is a temporary storage location

119A – LEVEL II BASIC MATH ROUTINE – “FFXXV7”

This routine will print trailing zeroes.
119A
 ↳ FFXXV7
ADD A,E83
Add the value in Register E to the value in Register A to get the number of digits before the decimal point
119B
DEC A3D
Decrement the adjusted value in Register A
119C-119E
If dropping A by 1 still results in a positive number, GOSUB 1269H to put that number of zeros into the input buffer
119F
LD D,B50
Load Register D with the number of digits to the left of the decimal point requested (from Register B)
11A0-11A2
Jump to 10BFH to finish up

11A3 – LEVEL II BASIC MATH ROUTINE – “FFXIFL”

This routine will print an integer in fixed format/floating point notation.
11A3
 ↳ FFXIFL
PUSH HLE5
Save the current position of the buffer (in Register Pair HL) to the STACK
11A4
PUSH DED5
Generally save Register Pair DE to be POPped after the CALL. DE currently holds the format specs
11A5-11A7
GOSUB 0ACCH to convert the integer value in ACCumulator to a SINGLE precision value
11A8
POP DED1
Restore DE from the STACK
11A9
XOR AAF
Zero Register A, clear the status flags. This will denote to the next routine that we are printing a number as a SINGLE PRECISION number, and then fall into the FFXFLV routine

11AA – LEVEL II BASIC MATH ROUTINE – “FFXFLV”

This routine will print a SINGLE or DOUBLE PRECISION number in fixed format/floating point notation.
11AA-11AC
 ↳ FFXFLV
If we have a SINGLE PRECISION number (because the Z FLAG is set), Jump to 11B0H to set the flags appropriately
11AD-11AE
LD E,10H1E 10
We know we have a DOUBLE PRECISION so load Register E with the maximum length of a double precision value (which is 16)
11AF-11B2
LD BC,1E06H01 1E 06
Z-80 Trick! If passing through then this just modifies the Register Pair BC. However, if JUMPing to 11B0, a LD E,06H occurs, changing E
11B0-11B1
 ↳ FFXSFL
LD E,06H1E 06
Load Register E with the maximum length of a single precision value (which is 6)
11B2-11B4
GOSUB 0955H to check to see if we have a zero in the ACCumulator
11B5
SCF37
Set the Carry flag to determine if we are printing a zero or not. This works because FOUTNV exits with the NC FLAG set
11B6-11B8
If we do not have a zero, then we need to normalize the number so that all digits to be printed are in the integer portion, so GOSUB to 1201H to scale the current value in ACCumulator
11B9
POP HLE1
Get the buffer position from the STACK and put it in Register Pair HL
11BA
POP BCC1
Get the number of #‘s before and the number of #‘s after from the STACK and put it in Register Pair BC
11BB
PUSH AFF5
Save the exponent in Register Pair AF to the STACK
11BC
LD A,C79
We need to calculate how many significant digits we must print, so load Register A with the number of digits to the right of the decimal point requested (stored in Register C)
11BD
OR AB7
Set the status so we can see if there are any digits to the right of the decimal point requested through a zero register
11BE
PUSH AFF5
Save the original trailing digit count (in Register Pair AF) to the STACK
11BF-11C1
If the trail count is not zero, then GOSUB to 0F16H to decrement the number of digits requested to the right of the decimal point in Register A
11C2
ADD A,B80
Add the number of digits requested for the left of the decimal point in Register B to the number of digits requested to the right of the decimal point in Register A
11C3
LD C,A4F
Load Register C with the total digit count (held in Register A)
11C4
LD A,D7A
Load Register A with the value of the edit flag in Register D
11C5-11C6
AND 04HAND 0000 0100E6 04
Check to see if the sign follows the ASCII string (i.e., is a “trailing” sign)
11C7-11C8
CP 01HFE 01
Set the Carry flag according to the sign following the ASCII string test (it will be No Carry if a sign follows, and will be CARRY if A=0)
11C9
SBC A,A9F
If we have a trailing sign, this will set Register D to 0. Otherwise, D will be FFH if we don’t have a trailing sign.
11CA
LD D,A57
Load Register D with those results
11CB
ADD A,C81
Add the value in Register C to the value in Register A so as to set the number of significant digits to print
11CC
LD C,A4F
Load Register C with the adjusted value in Register A
11CD
SUB A,E93
If the number of significant digits to print is less than E, then we have to get rid of some numbers! Subtract the value in Register E from the adjusted value in Register A so that A will now contain the number of times to divide by 10
11CE
PUSH AFF5
Save the divisor count (from Register Pair AF) to the STACK. This is the result of the comparison of the number of significant digits and the number of digits we will actually print.
11CF
PUSH BCC5
Save the “B” field spec and the number of significant digits (from Register Pair BC) to the STACK
11D0-11D2
 ↳ FFXLV1
GOSUB 0F18H to divide the current value in ACCumulator by ten, Register A number of times
11D3-11D5
Loop back 1 instruction (divide by 10) until the division has been completed
11D6
POP BCC1
Retrieve the “B” field spec and the number of significant digits from the STACK back into Register Pair BC
11D7
POP AFF1
Get the number of trailing zeroes to print from the STACK and put it in Register Pair A
11D8
PUSH BCC5
Save the “B” field spec and the number of significant digits (from Register Pair BC) to the STACK
11D9
PUSH AFF5
Save the number of trailing zeroes to print to the STACK
11DA-11DC
Skip the next instruction (i.e., jump to 11DEH) if there are any trailing zeroes
11DD
XOR AAF
Zero Register A and all status flags
11DE
 ↳ FFXLV3
CPL2F
Make the trailing zero count posivite by inverting the value in Register A
11DF
INC A3C
Bump the value in Register A so that it will be positive
11E0
ADD A,B80
Set the decimal place count by adding the number of digits requested to the left of the decimal point in Register B to the adjusted value in Register A
11E1
INC A3C
Bump the adjusted value in Register A
11E2
ADD A,D82
Take into account if the sign is trailing by adding the value of the maximum length for the current number type in Register D (6 for single precision, 16 fo double precision) to the adjusted value in Register A
11E3
LD B,A47
Copy Register A into Register B so that B holds the number of digits before the decimal point
11E4-11E5
LD C,00H0E 00
Set the comma count to zero by loading Register C with zero (so that there are no commas)
11E6-11E8
GOSUB to 12A4H to convert the current value in ACCumulator to decimal digits
11E9
POP AFF1
Get the number of #’s before from the STACK and put it in Register Pair AF
11EA-11EC
GOSUB 1271H to put zeros into the trailing input buffer
11ED
POP BCC1
Get the number of #’s before and the number of #‘s after from the STACK and put it in Register Pair BC
11EE
POP AFF1
Get the C count (numbers before the decimal point) from the STACK and put it in Register Pair A and restore the FLAGS
11EF-11F1
If C = 0 then the last character was a decimal point, so ignore it via a GOSUB to 092FH to decrement the input buffer pointer in Register Pair HL if there are none
11F2
POP AFF1
Get the exponent back from from the STACK and put it in Register Pair AF
11F3-11F4
If the number is zero, then the exponent is zero, so JUMP to 11F8H (to add the exponent) if the carry flag was set
11F5
ADD A,E83
Otherwise, we need to scale the number – so first add the value in Register E to the value in Register A
11F6
SUB A,B90
Subtract the number of digits to the left of the decimal point requested in Register B from the adjusted value in Register A
11F7
SUB A,D92
Subtract the value in Register D from the value in Register A to get the size of the exponent
11F8
 ↳ FFXLV2
PUSH BCC5
Save the “B” field spec to the STACK
11F9-11FB
Put the exponent into the buffer via a GOSUB to 1074H to figure the value of the exponent for the current value in ACCumulator
11FC
EX DE,HLEB
Swap DE and HL so that the pointer to the end of the buffer is put into Register Pair HL just in case we have a trailing sign we need to add.
11FD
POP DED1
Restore the “B” field spec into Register D in case we need to put on a trailing sign.
11FE-1200
Jump to 10BFH to put on the trailing sign and finish up

1201 – Test the magnitude of SP and DP numbers, and clear the times the value was scaled – “FOUTNV”

This routine will scale (normalize) the number in the accumulator so that all the digits are in the integer part (i.e., between 99,999 and 999,999). The signed base 10 exponent is returned in Register A. Registers D and E are unchanged.
1201
 ↳ FOUTNV
PUSH DED5
Save the value in Register Pair DE to the STACK. We are going to pop this back at the end of the routine.
1202
XOR AAF
Zero Register A, which will be the exponent
1203
PUSH AFF5
Save the exponent in Register Pair A to the STACK
1204
We need to check the value of the current number type flag, so we call the TEST DATA MODE routine at RST 20H.
NOTE: The RST 20H routine determines the type of the current value in ACCumulator and returns a combination of STATUS flags and unique numeric values in the A Register according to the data mode flag (40AFH). The results are returned as follows:
  • Integer = NZ/C/M/E and A is -1
  • String = Z/C/P/E and A is 0
  • Single Precision = NZ/C/P/O and A is 1
  • and Double Precision is NZ/NC/P/E and A is 5.
1205-1207
If that test shows we have a SINGLE PRECISION number (through getting a Parity-Odd flag), jump to 1222H to handle. Otherwise, pass through
1208-120A
 ↳ FORBIG
LD A,(4124H)LD A,(FAC)3A 24 41
At this point we know we have a DOUBLE precision value. Load Register A with the value of the exponent for the double precision value in ACCumulator
120B-120C
CP 91HFE 91
Check to see if the double precision value in ACCumulator uses is less than 1D5 (i.e., the integer portion of the double precision value)
120D-120F
If the double precision value in ACCumulator is not less than 1D5, then ship over the following multiplcation code and go to FOUNDB.
1210-1212
LD DE,1364HLD DE,TENTEN11 64 13
Load Register Pair DE with 1D10
1213-1215
LD HL,4127HLD HL,ARGLO21 27 41
In praration for VMOVE and DMULT, point HL to REG2
1216-1218
GOSUB to 09D3H to move the double precision constant into REG2
1219-121B
GOSUB to 0DA1H to call the DOUBLE PRECISION MULTIPLY routine at 0DA1H (which multiplies the double precision value in ACCumulator by the value in REG 2. The product is left in ACCumulator)
121C
POP AFF1
Retrieve the original exponent from the STACK into Register A
121D-121E
SUB A,0AHD6 0A
Subtract ten from the value in Register A to do a proper offset for an exponent
121F
PUSH AFF5
Save the adjusted exponent (held in Register A) to the STACK
1220-1221
Force it to be bigger via a JUMP to 1208H so as to loop until the integer portion exceeds 2e16

1222 – LEVEL II BASIC MATH ROUTINE – “FOUNDB”

There is a big bug in this routine which was fixed in v1.2 of the ROM. The fixing of that bug caused a renumbering from 1228H-124CH. The numbering here will show both.
1222-1224
 ↳ FOUNDB
Check to see if the number in the ACCumulator is too big or too small via a GOSUB to 124FH to compare the current value in ACCumulator to 999999.5
1225
 ↳ FOUNV1
In order to determine if the ACCumulator is big enough, we need to know what kind of value we have in the ACCumulator so 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.
1226-1228
If that test shows we have a DOUBLE PRECISION or a STRING, jump to 1234H
*1226-1228
In ROM 1.2 this is a big bug fix. Now if the shows we do NOT have a STRING, jump to 1233H
The next two instructions load BCDE with 99999.95 so as to check to see if the number in FAC is too big.
1229-122B
*1228-122A
LD BC,9143H01 43 91
Load Register Pair BC with the exponent and the MSB of a single precision constant
122C-122E
*122B-122D
LD DE,4FF9H11 F9 4F
Load Register Pair DE with the NMSB and the LSB of a single precision constant. Register Pairs BC and DE are now equal to a single precision constant of 99,999.945
122F-1231
*122E-1230
GOSUB to routine at 0A0CH which algebraically compares the single precision value in BC/DE to the single precision value ACCumulator.
The results are stored in A as follows:
If ACCumulator = BCDEA=00
If ACCumulator > BCDEA=01
If ACCumulator < BCDEA=FF
1232-1233
Jump down two instructions to 123AH to test the results of the comparison
*1231-1232
Jump down two instructions to 123AH to test the results of the comparison
1234-1236
 ↳ FOUNV4

*1233-1235
LD DE,136CHLD DE,FOUTDL11 6C 13
Load Register Pair DE with the starting address of a double precision constant equal to 999,999,999,999,999.95
1237-1239
*1236-1238
Go compare the double precision constant pointed to by Register Pair DE to the double precision value in ACCumulator to see if the number is still too small
123A-123C
 ↳ FOUNV5

1239-123B
If the number isn’t too small anymore then we are done so JUMP to 124CH
*1239-123B
 ↳ FOUNV5
JP P,124BH
If the number isn’t too small anymore then we are done so JUMP to 124BH
123D
*123C
POP AFF1
If we are here then the number is still too small so we will need to multiply it by 10. Get the value of the scaled counter from the STACK and put it in Register Pair AF
123E-1240
*123D-123F
GOSUB to 0F0BH to multiply the current value in ACCumulator by ten
1241
*1240
PUSH AFF5
Save the exponent value (the negative of the number of times the value was multiplied) in Register Pair AF to the STACK.
1242-1243
1241-1242
Keep looping back to see if the number is big enough (i.e., between 999,999 and 99,999)
1244
*1243
POP AFF1
At this point, the ACCumulator is too big. First, fetch the exponent (i.e., the scaled count) from the STACK and put it in Register A
1245-1247
1244-1246
GOSUB to 0F18H to divide the current value in ACCumulator by ten
1248
1247
PUSH AFF5
Save the exponent to the STACK. A is the count of the number of times it was divided
1249-124B
*1248-124A
We need to see if the ACCumulator is small enough so GOSUB to 124FH to loop until the value in ACCumulator is < 999,999
124C
 ↳ FOUNV3

*124B
POP AFF1
At this point, we are done scaling, so restore the exponent into Register A. A = + times divided or – times multiplied
124D
124C
POP DED1
Restore DE from where it was preserved at the top of this routine
N/A
*124D
OR A
In ROM v1.2 sets the status flags. This also realigns the memory addresses from changes to v1.2 ROM
124E
RETC9
RETurn to CALLer

124F – LEVEL II BASIC MATH ROUTINE – “FOUNVC”

This routine will see if the number in the ACCumulator is small enough yet
124F
 ↳ FOUNVC
We need to check the value of the current number type flag, so we call the TEST DATA MODE routine at RST 20H.
NOTE: The RST 20H routine determines the type of the current value in ACCumulator and returns a combination of STATUS flags and unique numeric values in the A Register according to the data mode flag (40AFH). The results are returned as follows:
  • Integer = NZ/C/M/E and A is -1
  • String = Z/C/P/E and A is 0
  • Single Precision = NZ/C/P/O and A is 1
  • and Double Precision is NZ/NC/P/E and A is 5.
1250-1252
If that test shows we have a DOUBLE PRECISION number, jump to 125EH
The next two instructions load BCDE with 999999.5 to see if the number in the FAC is too large.
1253-1255
LD BC,9474H01 74 94
Now that we know we have a single precision number, load Register Pair BC with the exponent and the MSB of a single precision constant
1256-1258
LD DE,23F8H11 F8 23
Load Register Pair DE with the NMSB and the LSB of a single precision constant. Register Pairs BC and DE are now equal to a single precision constant of 999,999.5
1259-125B
Call the SINGLE PRECISION COMPARISON routine at routine at 0A0CH which algebraically compares the single precision value in BC/DE to the single precision value ACCumulator.
The results are stored in A as follows:
If ACCumulator = BCDEA=00
If ACCumulator > BCDEA=01
If ACCumulator < BCDEA=FF
125C-125D
Jump to 1264H to test the result of the comparison
125E-1260
 ↳ FONVC1
LD DE,1374HLD DE,FOUTDU11 74 13
If we are here, then we have a DOUBLE PRECISION number to deal with, so start by loading Register Pair DE with the starting address of a double precision constant equal to 9,999,999,999,999,999.5
1261-1263
Check to see if the number is too big via a GOSUB to 0A49H to compare the double precision constant pointed to by Register Pair DE to the double precision value in ACCumulator
1264
 ↳ FONVC2
POP HLE1
Get the return address from the STACK and put it in Register Pair HL so we can go to 1244H
1265-1267
If the P FLAG is set, then the number is still too big (i.e., the number in the ACCumulator has more than 6 digits in the integer portion), so JUMP to 1244H
*1265-1267
In ROM v1.2 the ROM addresses had moved 1 byte
1268
JP (HL)E9
If the number isn’t too big, then just RETurn by JUMPing to (HL)

1269H – LEVEL II BASIC MATH ROUTINE – “FOTZER”

This routine puts leading zeroes into the input buffer. The count is held in Register A and it can be zero, but the Z FLAG needs to be set in that case. Only (HL) and Register A are affected.
1269
 ↳ FOTZER
OR AB7
This is the entry point from FFXXV3 where the flags have not yet been set, so set the flags, particularly the Z FLAG
126A
 ↳ FOTZR1
RET ZC8
Top of a loop. If the number of 0’s we need to display is zero, then just RETurn
126B
DEC A3D
Decrement the value in Register A to show that an ASCII zero was moved to the print buffer
126C-126D
LD (HL),30HLD (HL),”0″36 30
Save a 0 at the location of the input buffer pointer in Register Pair HL
126E
INC HL23
Bump the input buffer pointer in Register Pair HL
126F-1270
Jump back to 126AH until the number in Register A of ASCII zeroes were moved

1271 – LEVEL II BASIC MATH ROUTINE – “FOTZNC”

This routine will put zeroes in the buffer along with commans or a decimal point in the middle. The count is held in Register A and it can be zero, but the Z FLAG needs to be set in that case. Registers B (decimal point count) and C (comma count) are updated accordingly. Everything but DE is affected.
1271-1272
 ↳ FOTZNC
So long as we are adding zeroes, Jump to 1277H
1273
 ↳ FOTZRC
RET ZC8
Top of a loop. If there are no more zeroes to add, RETurn
1274-1276
Check to see if we need to insert a comma or a decimal prior to the zero at the current positiuon via a GOSUB to FOUTED
1277-1278
 ↳ FOTZEC
LD (HL),30HLD (HL),”0″36 30
Save a 0 at the location of the input buffer pointer in Register Pair HL
1279
INC HL23
Bump the input buffer pointer in Register Pair HL
127A
DEC A3D
Decrement the counter of trailing zeroes to add in Register A
127B-127C
Loop back and keep looping until the number of zeroes to add is 0.

127D – LEVEL II BASIC MATH ROUTINE – “FOUTCD”

This routine will put a possible comma count into Register C and will zero Register C if we are not using commas in the specification.
127D
 ↳ FOUTCD
LD A,E7B
The next bunch of math is to set up the decimal point count. First, load Register A with the value in Register E so that A holds the decimal point countcount of the times the value was scaled up or down
127E
ADD A,D82
Add the number of digits to print (from Register D) to the value in Register A
127F
INC A3C
Bump the adjusted value in Register A so now A holds the number of digits before the decimal point
1280
LD B,A47
Load Register B with the leading digit count (from Register A)
1281
INC A3C
Next, we are going to set up the comma count. First bump the value in Register A so not A holds the leading digits + 2
1282-1283
 ↳ FOTCD1
SUB A,03HD6 03
Subtract three from the adjusted value in Register A which, when combined with the next instruction as a loop, divides modulo 3
1284-1285
Loop back 1 instruction until the value in Register A is -1, -2, or -3
1286-1287
ADD A,05HC6 05
Add 5 (which is 3 back plus 2 more for scaling) to A to get a positive remainder. This will give 4, 3, or 2 as the comma count
1288
LD C,A4F
Save the possible comma count into Register A
1289-128B
 ↳ FOUICC
LD A,(40D8H)LD A,(TEMP3)3A D8 40
Load Register A with the format specs from the temporary storage location
128C-128D
AND 40HAND 0100 0000E6 40
Mask against 0100 0000 to isolate the comma bit to see if commas are requested
128E
RET NZC0
If the NZ FLAG is set then we are using commas, so just RETurn
128F
LD C,A4F
If we are here, then we aren’t using commas, so Zero the comma counter in Register C
1290
RETC9
RETurn to CALLer

1291 – LEVEL II BASIC MATH ROUTINE – “FOUTED”

This routine will put decimal points and commas in their correct places. This subroutine should be called before the next digit is put in the buffer. Register B = the decimal point count and Register C = the comma count.

The counts tell how many more digits have to go in before the comma ;or decimal point go in.

The comma or decimal point then goes before the last digit in the count. For example, if the decimal point should come after the first digit, the decimal point count should be 2.
1291
 ↳ FOUTED
DEC B05
First we need to test to see if it is time to put in a decimal point. To do this, we DECrement the decimal point counter in Register B to see if the zero flag sets or not
1292-1293
If the decimal point position hasn’t been reached then JUMP to FOUED1 to see if a comma needs to go there.
1294-1295
 ↳ FOUTDP
LD (HL),2EHLD (HL),”.”36 2E
If we are here, then the decimal point time has come. Save a decimal point at the location of the input buffer pointer in Register Pair HL
1296-1298
LD (40F3H),HLLD (TEMP2),HL22 F3 40
Save the address of the decimal point position (held in Register Pair HL).
Note: 40F3H-40F4H is a temporary storage location
1299
INC HL23
Bump the buffer pointer in Register Pair HL
129A
LD C,B48
We just put in a decimal point, so we KNOW we don’t need to put a comma here, so ZERO out the comma counter
129B
RETC9
RETurn to CALLer

129C – LEVEL II BASIC MATH ROUTINE – “FOUED1”

Part of the above routine, jumped here to test to see if a comma needs to be placed at (HL).
129C
 ↳ FOUED1
DEC C0D
First, we need to test to see if it is time to put in a comma by DECrementing the comma counter in Register C
129D
RET NZC0
If the NZ FLAG is set, then we are not putting in a comma, so RETurn
129E-129F
LD (HL),2CHLD (HL),”,”36 2C
If didn’t jump out, then we need a comma here so put a comma (which is ASCII code 2CH) at the location of the input buffer pointer in Register Pair HL
12A0
INC HL23
Bump the input buffer pointer (to account for the new comma) in Register Pair HL
12A1-12A2
LD C,03H0E 03
Reset the comma counter by setting it to 3 (since commas come after units of 3 numbers)
12A3
RETC9
RETurn to CALLer

12A4 – LEVEL II BASIC MATH ROUTINE – “FOUTCV”

This routine will convert a SINGLE PRECISION or a DOUBLE PRECISION number that has been normalized to decimal digits. The decimal point count is in Register B and the comma count is in Register C. (HL) points to where the first digit will go. Routine will exit with A=0.
12A4
 ↳ FOUTCV
PUSH DED5
Generally preserve Register Pair DE. This will get POPped when the subroutine is done.
12A5
We need to check the value of the current number type flag, so we call the TEST DATA MODE routine at RST 20H.
NOTE: The RST 20H routine determines the type of the current value in ACCumulator and returns a combination of STATUS flags and unique numeric values in the A Register according to the data mode flag (40AFH). The results are returned as follows:
  • Integer = NZ/C/M/E and A is -1
  • String = Z/C/P/E and A is 0
  • Single Precision = NZ/C/P/O and A is 1
  • and Double Precision is NZ/NC/P/E and A is 5.
12A6-12A8
If we have a single precision number (by the Parity Odd flag being set) JUMP to 12EAH to convert a SINGLE precision number into its INTEGER equivalent)
12A9
PUSH BCC5
Now that we know we have a DOUBLE PRECISION number, save decimal/comma count (in Register Pair BC) to the STACK
12AA
PUSH HLE5
Save the buffer address (in Register Pair HL) to the STACK
12AB-12AD
GOSUB to 09FCH to mmove the double precision value in ACCumulator to REG2
12AE-12B0
LD HL,137CHLD HL,DHALF21 7C 13
Load Register Pair HL with the starting address of a double precision constant equal to 0.5D0
12B1-12B3
GOSUB to 09F7H to move 0.5D0 to the ACCumulator
12B4-12B6
Call the DOUBLE PRECISION ADD function (which adds the double precision value in REG 2 to the value in ACCumulator (which is the constant 0.5D0). Result is left in ACCumulator)
12B7
XOR AAF
Zero Register A and clear the status flags; particularly the CARRY FLAG
12B8-12BA
Isolate the integer part of the double precision number via a GOSUB to 0B7BH
12BB
POP HLE1
Restore the buffer address from the STACK and put it in Register Pair HL
12BC
POP BCC1
Restore the decimal and comma counters from the STACK and put it in Register Pair BC
12BD-12BF
LD DE,138CHLD DE,FODTBL11 8C 13
Load Register Pair DE with the starting address of a series of double precision constants (i.e., a table of powers of 10 from 1.0x10E15 – 1.0x10E6) for the binary to ASCII conversion
12C0-12C1
LD A,0AH3E 0A
We are going to want to convert ten digits, so load Register A with the number of times to divide the double precision value in ACCumulator by a power of 10
Top of a loop to convert the next digit. It is executed “A” times.
12C2-12C4
 ↳ FOUCD1
Check to see if we need to put in a decimal point or a comma at the location pointed to by HL via a GOSUB to 1291H
12C5
PUSH BCC5
Save the count of digits before the decimal point and the count of digts after the decimal point (stored in Register Pair BC) to the STACK
12C6
PUSH AFF5
Save the number of digits to process / division count (stored in Register Pair A) to the STACK
12C7
PUSH HLE5
Save the current buffer address (stored in Register Pair HL) to the STACK
12C8
PUSH DED5
Save the address of the power of 10 table (stored in Register Pair DE) to the STACK
12C9-12CA
LD B,2FHLD B,”0″-106 2F
Load Register B (which will be the quotient in ASCII for each division) with the ASCII value for a zero character minus one since the loop which follows starts by INCrementing the value
12CB
 ↳ FOUCD2
INC B04
Top of a loop. Bump the ASCII value for the digit in Register B so as to start with ASCII “0”
12CC
POP HLE1
Get the address of the power of 10 table (i.e., the divisor) from the STACK and put it in Register Pair HL and
12CD
PUSH HLE5
…. put it right back into the STACK so that it can be restored during the loop
12CE-12D0
GOSUB to 0D48H to subtract the double precision value pointed to by Register Pair HL from the double precision value in REG l. This is to divide the current integer value by of a power of 10 starting at 10e15 working its way down to 10e6 in a loop until the remainder is less than the current power)
12D1-12D2
Jump back to do another subtraction and keep looping until the Carry flag gets set by the subtraction (meaning that the remainder is now less than the current power)
12D3
POP HLE1
If we are here because the C FLAG fired, then we have subtracted once too many times. So we need to un-subtract once. To do that we first need to get the address of the power table from the STACK and put it in Register Pair HL
12D4-12D6
GOSUB to 0D36H to add the double precision value pointed to by Register Pair HL (which is the table of powers of 10) to the double precision remainder in ACCumulator to make it a positive value. Return with the correct remainder in ACCumulator
12D7
EX DE,HLEB
Swap DE and HL so that th eopoert of ten pointer is now in DE.
12D8
POP HLE1
Get the current buffer address from the STACK and put it in Register Pair HL
12D9
LD (HL),B70
Save the ASCII value for the digit in Register B at the location of the input buffer pointer (stored in Register Pair HL)
12DA
INC HL23
Bump the buffer pointer in Register Pair HL since we have just put a digit there
12DB
POP AFF1
Get the loop counter back into Register A
12DC
POP BCC1
Get the decimal point and comma counter from the STACK and put it in Register Pair BC
12DD
DEC A3D
Decrement the loop counter value in Register A (we are going to loop 10 times)
12DE-12DF
Loop 10 times until the ASCII string has been figured
12E0
PUSH BCC5
At this point, we have finished printing the last digit, so now we want to convert the remaining digits using single precision routines (which are faster). First, save the decimal and comma counters (stored in Register Pair BC) to the STACK
12E1
PUSH HLE5
Save the input buffer pointer (stored in Register Pair HL) to the STACK
12E2-12E4
LD HL,411DHLD HL,DFACLO21 1D 41
Point HL to the remaining digits for processing as a single precision number
12E5-12E7
Move the numbers that are left to ACCumulator via a GOSUB to MOVRM
12E8-12E9
Jump to 12F6H to convert that last half to ASCII

12EA – LEVEL II BASIC MATH ROUTINE – “FOUTCS”

This routine is to convert a SINGLE precision value to an INTEGER which will be the decimal digits. Divide the integer equivalent by 100,000 and 10,000. Use the code at 1335H to convert the last 1000 to ASCII.
12EA
 ↳ FOUTCS
PUSH BCC5
Save the decimal/comma count (in Register Pair BC) to the STACK
12EB
PUSH HLE5
Save the buffer pointer (stored in Register Pair HL) to the STACK
12EC-12EE
Round the number to the nearest integer via a GOSUB to 0708H which will add a single precision value of 0.5 to the single precision value in ACCumulator. The result is stored in BC/DE
12EF
INC A3C
When a number is positive and non-zero, a FADDH call to round will always exit with the HIGH ORDER of 0 in Register A. So we add 1 to force A to be non-zero.
12F0-12F2
GOSUB to 0AFBH to convert the positive single precision value in ACCumulator to an integer. The result is stored in C/D/E
12F3-12F5
Save the C/D/E number into the ACCumulator via a GOSUB to MOVFR
12F6
 ↳ FOUCDC
POP HLE1
Get the current buffer pointer value from the STACK and put it in Register Pair HL
12F7
POP BCC1
Get the decimal/comma count value from the STACK and put it in Register Pair BC
12F8
XOR AAF
Clear the CARRY FLAG, which is our flag to calculate two digits
12F9-12FB
LD DE,13D2HLD DE,FOSTBL11 D2 13
Load Register Pair DE with the starting address for a series of integer values (in this case, 100,000) and then fall through to FOUCS1

12FC – LEVEL II BASIC MATH ROUTINE – “FOUCS1”

This routine is to calculate the next digit of the number.
12FC
 ↳ FOUCS1
CCF3F
Complement the Carry flag, which tracks when we are done with the division loop of 12FC-1327H
12FD-12FF
Check to see if we need to put a decimal point or a comma before the current number via GOSUB to FOUTED
1300
PUSH BCC5
Save the decimal and comma counter (stored in Register Pair BC) to the STACK
1301
PUSH AFF5
Save the carry flag (which acts as our digit count for the count of the number of times through this loop) to the STACK
1302
PUSH HLE5
Save the current buffer pointer value (stored in Register Pair HL) to the STACK
1303
PUSH DED5
Save the power of 10 table pointer (stored in Register Pair DE) to the STACK
1304-1306
Loads the SINGLE PRECISION value in ACCumulator into Register Pair BC/DE via A GOSUB to MOVRF.
1307
POP HLE1
Get the power of 10 table address (the integer value for 100,000) from the STACK and put it in Register Pair HL
1308-1309
LD B,2FHLD B,”0″-106 2F
Set B to be the next digit to print. Since the next step INCremenets B, we need to start off with B one too low.

130A – LEVEL II BASIC MATH ROUTINE – “FOUCS2”

This routine divides the integer portion of the current value by 100,000 using compound subtraction. The quotient is kept in Register B as an ASCII value.
130A
 ↳ FOUCS2
INC B04
Bump the ASCII value from the digit in Register B to increase the ASCII value from 0 and upward
130B
LD A,E7B
Load Register A with the Low Order/LSB of the single precision value in Register E
130C
SUB (HL)96
Subtract the value at the location of the memory pointer in Register Pair HL (the LSB of 100,000) from the value of the LSB of the single precision value in Register A
130D
LD E,A5F
Load Register E with the adjusted LSB of the single precision value in Register A
130E
INC HL23
Bump the value of the memory pointer in Register Pair HL to the next digit of 100,000
130F
LD A,D7A
Load Register A with the Middle Order/NMSB of the single precision value in Register D
1310
SBC A,(HL)9E
Subtract the value at the location of the memory pointer in Register Pair HL (the middle byte of 100,000) from the value of the NMSB of the single precision value in Register A
1311
LD D,A57
Load Register D with the adjusted NMSB of the single precision value in Register A
1312
INC HL23
Bump the value of the memory pointer in Register Pair HL to the MSB of 100,000
1313
LD A,C79
Load Register A with the High Order/MSB of the single precision value in Register C
1314
SBC A,(HL)9E
Subtract the value at the location of the memory pointer in Register Pair HL from the value of the MSB of 100,000 (a single precision value in Register A)
1315
LD C,A4F
Load Register C with the adjusted MSB of the single precision value in Register A
1316
DEC HL2B
Decrement the value of the memory pointer in Register Pair HL to the NMSB of 100,000
1317
DEC HL2B
Decrement the value of the memory pointer in Register Pair HL again, now to the LSB of 100,000
1318-1319
Loop until the ASCII value for the digit under 100,000 has been figured
131A-131C
We need to add 100,000 to C/D/E and make it positive so we GOSUB to 07B7H to add the value at the location of the memory pointer in Register Pair HL to the value in Register Pairs BC and DE
131D
INC HL23
Bump the value of the memory pointer in Register Pair HL to now point to the 10,000 constant
131E-1320
Save the remainder as a current value by GOSUB to 09B4H (which moves the SINGLE PRECISION value in DC/DE into ACCumulator)
1321
EX DE,HLEB
Load Register Pair DE with the address of the next value to divide the current value in ACCumulator by (which is the constant of 10,000)
1322
POP HLE1
Get the value of the memory pointer from the STACK and put it in Register Pair HL
1323
LD (HL),B70
Save the ASCII value for the digit in Register B at the location of the input buffer pointer in Register Pair HL
1324
INC HL23
Bump the value of the input buffer pointer in Register Pair HL
1325
POP AFF1
Get the carry flag from the STACK and put it in Register Pair AF
1326
POP BCC1
Get the value from the STACK and put it in Register Pair BC so it can be saved later
1327-1328
If the carry flag is set, then reset it and loop the dividing by 10,000 until the integer portion is found
1329
INC DE13
If we fall through to here, we have divided the integer part of the single precision variable by 100,000 and then by 10,000 with the remainder being positive and saved as the current value. With this we bump the value of the memory pointer in Register Pair DE
132A
INC DE13
and again bump the value of the memory pointer in Register Pair DE, so now DE points to the constant 1,000
132B-132C
LD A,04H3E 04
Load Register A with the number of digits for the ASCII string to be figured
132D-132E
Jump to 1335H to convert the remainder to 4 ASCII digits. Note that the CARRY FLAG will be off.

132F – This routine will convert an INTEGER to ASCII – “FOUTCI”

This routine converts an integer into decimal digits by dividing the integer portion of the current value by 100,000 using compound subtraction. The quotient is kept in Register B as an ASCII value and A=0 on exit.
132F
 ↳ FOUTCI
PUSH DED5
Generally preserve DE. This will be POPped just before the RETurn
1330-1332
LD DE,13D8HLD DE,FOITBL11 D8 13
Load Register Pair DE with the starting address of the descending powers of 10 starting at 10,000
1333-1334
LD A,05H3E 05
Load Register A with the number of digits for the ASCII string to be built (i.e., 5 since the maximum positive integer is 32768)
1335-1337
 ↳ FOUCI1
Top of the big loop. Check to see if a decimal point or comma needs to be placed before the digit being processed via a GOSUB to FOUTED
1338
PUSH BCC5
Save the decimal and comma counter (stored in Register Pair BC) to the STACK
1339
PUSH AFF5
Save the number of digits-to-process counter (stored in Register A) to the STACK
133A
PUSH HLE5
Save the address of the power table (stored in Register Pair HL) to the STACK
133B
EX DE,HLEB
Load Register Pair HL with the starting address of the descending powers of 10 starting at 10,000 (stored in Register Pair DE)
133C
LD C,(HL)4E
Load Register C with the LSB for the power of 10 stored in Register Pair HL
133D
INC HL23
Bump the value of the memory pointer in Register Pair HL to be the MDB of the power of 10
133E
LD B,(HL)46
Load Register B with the MSB for the integer value at the location of the memory pointer in Register Pair HL
133F
PUSH BCC5
Save the integer value of the power of 10 in Register Pair BC to the STACK
1340
INC HL23
Bump the value of the memory pointer in Register Pair HL to the next value in the power of 10 table
1341
EX (SP),HLE3
Swap (SP) and HL so that the pointer to the power of 10 table is in the STACK and the power of ten is in HL
1342
EX DE,HLEB
Put the power of ten into DE
1343-1345
LD HL,(4121H)LD HL,(FACLO)2A 21 41
Load Register Pair HL with the integer value in ACCumulator
1346-1347
LD B,2FHLD B,”0″ – 106 2F
Since we are about to start a loop which starts with an INC, compensate by loading Register B with the ASCII value for a zero character minus one
This loop divides the current value by a power of 10 starting at 10,000 and working down to 10. The remainder frome ach division is added to the division and the sum becomes the dividend for the next division until done. The quotient is +2FH (which is the ASCII equivalent of a quotient).
1348
 ↳ FOUCI2
INC B04
Bump the ASCII value for the digit in Register B (so it starts at 0 and moves up each loop)
1349
LD A,L7D
Load Register A with the LSB of the integer value in Register L
134A
SUB E93
Subtract the value of the LSB of the integer value in Register E from the value of the LSB of the integer value in Register A
134B
LD L,A6F
Load Register L with the adjusted value of the LSB of the integer value in Register A
134C
LD A,H7C
Load Register A with the value of the MSB of the integer value in Register H
134D
SBC A,D9A
Subtract the MSB of the integer value in Register D from the value of the MSB of the integer value in Register A
134E
LD H,A67
Load Register H with the adjusted value of the MSB of the integer value in Register A
134F-1350
If the quotient (stored in HL) >= the current power of 10 (stored in DE) then we need to loop back to 1348H
1351
ADD HL,DE19
The problem with using the CARRY FLAG as a trigger is that it triggers once you have already gone too far. So we need to go back 1. To do this, add the remainder (stored as an integer in Register Pair DE) to the quotient (stored in Register Pair HL as an integer)
1352-1354
LD (4121H),HLLD (FACLO),HL22 21 41
Save the integer remainder (stored in Register Pair HL) in ACCumulator
1355
POP DED1
Get the address of the next power of 10 from the STACK and put it in Register Pair DE
1356
POP HLE1
Get the memory pointer for the buffer from the STACK and put it in Register Pair HL
1357
LD (HL),B70
Save the ASCII value for the digit (from Register B that tracked the number of divisions) to the location of the output buffer pointer (stored in Register Pair HL)
1358
INC HL23
Bump the value of the buffer pointer in Register Pair HL since we just filled that spot with an ASCII value
1359
POP AFF1
Get the number of digits to convert (i.e., the digit counter) from the STACK and put it in A
135A
POP BCC1
Get the decimal/comma counts from the STACK and put it into Register Pair BC
135B
DEC A3D
Decrement the value of the counter in Register A (which is a countdown from 5)
135C-135D
If the counter of the number of digits (from 5) is still not zero, jump back to 1335H until all of the digits have been figured
135E-1360
So now all the digits have been calculated in ASCII, so GOSUB 1291H to put a decimal point or comma into the input buffer if necessary
1361
LD (HL),A77
Save a zero (the value in Register A which hit zero when the loop from 5 finished) to the input buffer, pointed to by Register Pair HL. Note that we do not advance HL, so we can overwrite this trailing zero if necessary.
1362
POP DED1
Get the value from the STACK (which was whatever value was in DE when this routine started) and put it in Register Pair DE
1363
RETC9
RETurn to CALLer with A=0

1364-136B – DOUBLE PRECISION CONSTANT STORAGE LOCATION – “TENTEN”

1364-136B
 ↳ TENTEN
00 00 00 00 F9 02 15 A2
A double precision constant equal to 10000000000 is stored here

136C-1373 – DOUBLE PRECISION CONSTANT STORAGE LOCATION – “FOUTDL”

136C-1373
 ↳ FOUTDL
FD FF 9F 31 A9 5F 63 B2
A double precision constant equal to 999,999,999,999,999.95 is stored here

1374-137B – DOUBLE PRECISION CONSTANT STORAGE LOCATION – “FOUTDU”

1374-137B
 ↳ FOUTDU
FE FF 03 BF C9 1B 0E B6
A double precision constant equal to 9,999,999,999,999,999.5 is stored here

137C-1383 – DOUBLE PRECISION CONSTANT STORAGE LOCATION – “DHALF”

137C-137F
 ↳ DHALF
00 00 00 00
A double precision constant equal to 0.5D0 is stored here.
BYTE SAVING NOTE: Referencing 1380H, which is half-way through this double precision value of .5, results in a single precision value of 0.5
1380-1383
 ↳ FHALF
00 00 00 80
A double precision constant equal to 0.5E0 is stored here.
BYTE SAVING NOTE: Referencing 1380H, which is half-way through this double precision value of .5, results in a single precision value of 0.5

1384-138B – DOUBLE PRECISION CONSTANT STORAGE LOCATION – “FFXDXM”

1384-138B
 ↳ FFXDXM
00 00 04 BF C9 1B 0E B6
A double precision constant equal to 1D16

138C-13D1 – DOUBLE PRECISION INTEGER CONSTANT STORAGE LOCATION – “FODTBL”

138C-1392
 ↳ FODTBL
00 80 C6 A5 7E 8D 03
1D15
1393-1399
00 40 7A 10 F3 5A 00
1D14
139A-13A0
00 A0 72 4E 18 09 00
1D13
13A1-13A7
00 10 A5 D5 E8 00 00
1D12
13A1-13A7
00 10 A5 D5 E8 00 00
1D11
13A8-13AE
00 E8 76 48 17 00 00
1D10
13AF-13B5
00 E4 0B 54 02 00 00
1D9
13B6-13BC
00 CA 9A 3B 00 00 00
1D8
13BD-13C3
00 E1 F4 05 00 00 00
1D7
13C4-13CA
80 96 98 00 00 00 00
1D6
13CB-13D1
40 42 0F 00 00 00 00
1D5

13D2-13D9 – SINGLE PRECISION POWER OF TEN TABLE LOCATION – “FOSTBL

13D2-13D4
 ↳ FOSTBL
A0 86 01
1E5
13D5-13D7
10 27 00
1E4

13D8 – SINGLE PRECISION POWER OF TEN TABLE LOCATION – “FOITBL

13D8-13D9
 ↳ FOITBL
10 27
10,000
13DA-13DB
E8 03
1,000
13DC-13DD
64 00
100
13DE-13DF
0A 00
10
13E0-13E1
01 00
1

13E2-13E6 – LEVEL II BASIC MATH ROUTINE – “PSHNEG”

13E2-13E4
 ↳ PSHNEG
LD HL,0982HLD HL,NEG21 82 09
Load Register Pair HL with the address of the routine for conversion of floating point numbers from negative to positive
13E5
EX (SP),HLE3
Exchange the value of that routines jump address to the STACK with the value of the return address in Register Pair HL
135E-1360
So now all the digits have been calculated in ASCII, so GOSUB 1291H to put a decimal point or comma into the input buffer if necessary

13E7-13F1 – LEVEL II BASIC SQR(n) – “SQR”

This routine computes the square root of any value in ACCumulator. It processes it by raising n to the power of 0.5. The root is left in ACCumulator as a single precision value. Single-precision values only should be used
13E7-13F1
 ↳ SQR
GOSUB 09A4 which moves the SINGLE PRECISION value in ACCumulator to the STACK (stored in LSB/MSB/Exponent order)
13EA-13EC
LD HL,1380HLD HL,FHALF21 80 13
Load Register Pair HL with the starting address of a single precision constant equal to 0.5 (which will be the exponent)
13ED-13EF
GOSUB 09B1H (which moves a SINGLE PRECISION number pointed to by HL to ACCumulator)
13F0-13F1
Jump to the EXP(n) routine at 13F5H (which will be using a .5 exponent to do the square root) skipping 13F2H since the exponent is already single precision

13F2-1478H LEVEL II BASIC X to the Y Power (X^Y) ROUTINE – “FPWRQ”

A call to 13F2H raises the single precision value which has been saved to the STACK to the power specified in ACCumulator. The result will be returned in ACCumulator. The method of computation is e ** (y ln x).
13F2-13F4
 ↳ FPWRQ
Make sure that the exponent is single precision by GOSUB to 0AB1H which is the CONVERT TO SINGLE PRECISION routine at 0AB1H (which converts the contents of ACCumulator from integer or double precision into single precision)
13F5
 ↳ FPWRT
POP BCC1
Get the MSB of the single precision value from the STACK and put it in Register Pair BC
13F6
POP DED1
Get the NMSB and the LSB of the single precision value from the STACK and put it in Register Pair DE

13F7 – LEVEL II BASIC Exponentiation routine – “FPWR”

This routine handles the exponentiation routine of X^Y. To do so, first Y is checked for 0 and, if so, then the answer is simply 1. Then we check X for 0 and, if so, then the answer is simply 0.

If neither of those scenarios is the case, then must check to see if X is positive and, if not, check to see if Y is negative and if it is even or odd.

If Y is negative, the we negate it to avoid the LOG routine giving a ?FC ERROR when we call it.

If X is negative and Y is odd, the NEG routine is pushed to the STACK as the exit rouine so that the result will be negative.

The actual math here is X^Y = EXP(Y*LOG(X)).
13F7-13F9
 ↳ FPWR
First, check Y to see if Y is zero via a GOSUB 0955H to check the sign for the single precision value in ACCumulator (the exponent)
13FA
LD A,B78
Next, check to see if X is zero by first loading Register A with the MSB of the number to be raised (stored as a single precision value in Register B)
13FB-13FC
If it is zero then we already know our ansder which is, mathematically, a 1 so JUMP to the EXP(n) routine at 1439H
13FD-13FF
After knowing that X isn’t 0, we must check the sign of Y. If it is positive, then JUMP to POSEXP to skip the next 2 opcodes (which check to see if zero is involved) if the exponent (the single precision value in ACCumulator) is positive
1400
OR AB7
Check to see if this is a ZERO raised to the minus power.
1401-1403
If it is 0 raised to a minus power, display a ?/0 ERROR message since the single precision value in ACCumulator is negative and the single precision value in Register Pairs BC and DE is equal to zero.
/0 ERROR entry point
1404
 ↳ POSEXP
OR AB7
ANOTHER check to see if the value to be raised (i.e., the single precision value in Register Pairs BC and DE) is equal to zero
1405-1407
If the value to be raised (i.e., the single precision value in Register Pairs BC and DE) is equal to zero, then we already know the result will be zero, so JUMP to ZERO0.
1408
PUSH DED5
At this point we know that none of the values are zero, and we are raising the number to a positive power. Save the value to be raised (the NMSB and the LSB of the single precision value in Register Pair DE) to the STACK
1409
PUSH BCC5
Save the exponent and the MSB of the single precision value in Register Pair BC to the STACK
140A
LD A,C79
Now we want to check the sign of X. First, load Register A with the value of the MSB of the single precision value to be raised (which is stored in Register C)
140B-140C
OR 7FHF6 7F
Turn the Z FLAG off by ORing against 7FH (0111 1111) in Register A
140D-140F
Load the Y (the power) into BC/DE by GOSUB to 09BF which loads the SINGLE PRECISION value in ACCumulator (the exponent) into Register Pair BC/DE
1410-1412
If X is positive, then jump down to FPWR1 as we have nothing advanced to process
1413
PUSH DED5
Otherwise, we need to do some more math. Save the Y value to the STACK first by saving the NMSB and the LSB of the exponent (the single precision value in Register Pair DE) to the STACK
1414
PUSH BCC5
and then Save the exponent and the LSB of the single precision value in Register Pair BC to the STACK
1415-1417
Check to see if the Y is an integer via a GOSUB to 0B40H to figure the integer portion of the exponent (i.e., the single precision value in ACCumulator) into A with the truncated floating point portion into ACCumulator
1418
POP BCC1
Restore the exponent and the MSB of the Y value from the STACK and put it in Register Pair BC
1419
POP DED1
Restore the NMSB and the LSB of the Y value from the STACK and put it in Register Pair DE
141A
PUSH AFF5
Save the LSB of the integer to the STACK for even and odd information
141B-141D
Make sure we have an integer by GOSUBing to FCOMP which will compare the original exponent to the truncated one by GOSUB to routine at 0A0CH which algebraically compares the single precision value in BC/DE to the single precision value ACCumulator.
The results are stored in A as follows:
If ACCumulator = BCDEA=00
If ACCumulator > BCDEA=01
If ACCumulator < BCDEA=FF
141E
POP HLE1
Get the exponent as an integer from the STACK and put it in Register H. This will help us determine if it is even or odd.
141F
LD A,H7C
Load Register A with the exponent as an integer (as stored in Register H)
1420
RRA1F
Rotate that exponent right by one, so we can tell if it is even or odd. If the exponent (as an integer) is odd, set the CARRY FLAG. RRA rotates Register A right one bit, with Bit 0 going to CARRY and CARRY going to Bit 7.
1421
 ↳ FPWR1
POP HLE1
Prepare to get the X back into the ACCumulator by fetching the number from the top of the STACK into Register Pair HL
1422-1424
LD (4123H),HLLD (FAC-1),HL22 23 41
Save the HIGH ORDERs of X to the ACCumulator
1425
POP HLE1
Get the LOW ORDERS of X from the STACK and put it in Register Pair HL
1426-1428
LD (4121H),HLLD (FACLO),HL22 21 41
Save the rest of the exponent (i.e., as stored in Register Pair HL as the NMSB and the LSB of the single precision value) in ACCumulator
1429-142B
If the exponent is odd then we need to negate the final result, so GOSUB to 13E2H to PUSH the address of the NEG routine into the STACK
142C-142E
If the exponent is an integer and the base is negative, GOSUB to 0983H to invert the value of the exponent
142F
PUSH DED5
Save the NMSB and the LSB of the Y/exponent (i.e., the single precision value in Register Pair DE) to the STACK
1430
PUSH BCC5
Save the MSB of the Y/exponent (i.e., the single precision value in Register Pair BC) to the STACK
1431-1433
Now we want to compute EXP(Y*LOG(X)) so we CALL the LOG(N) routine at 0809H (which computes the natural log (base E) of the single precision value in ACCumulator. The result is returned as a single precision value in ACCumulator. Can give an ILLEGAL FUNCTION CALL erro if a negative base is raised to a power with a fraction)
1434
POP BCC1
Get the exponent and the MSB of the single precision value from the STACK and put it in Register Pair BC
1435
POP DED1
Get the NMSB and the LSB of the single precision from the STACK and put it in Register Pair DE
1436-1438
We need to multiply the ln(value) * the exponent so we have to GOSUB to 0847H to SINGLE PRECISION MULTIPLY routine (which multiplies the current value in ACCumulator by the value in (BC/DE). The product is left in ACCumulator

1439 – LEVEL II ROM EXP ROUTINE.

Single-precision only. (ACCumulator = EXP(REG1)).

To process this function we first save the original argument and multiply the ACCumulator by log2(e). The result of that is then used to determine if we will get overflow, since exp(x)=2^(x*log2(e)) where log2(e)=log(e) base 2.

We then save the integer part of this to scale the answer at the end, since 2^y=2^int(y)*2^(y-int(y)) and 2^int(y) is easy to compute.

So in the end we compute 2^(x*log2(e)-int(x*log2(e))) by p(ln(2)*(int(x*log2(e))+1)-x) where p is an approximation polynomial.

The result is then scaled by the power of 2 we previously saved.

A call to 1439H raises E (natural base) to the value in ACCumulator which must be a single precision value. The result will be returned in ACCumulator as a single precision number.
1439-143B
 ↳ EXP
Save the argument via a GOSUB to 09A4 to move the SINGLE PRECISION value in ACCumulator (the exponent) to the STACK (stored in LSB/MSB/Exponent order)
143C-143E
LD BC,8138H01 38 81
Next we want to do a LOG(E) in base 2, so load Register Pair BC with the exponent and MSB of a single precision constant
143F-1441
LD DE,AA3BH11 3B AA
Load Register Pair DE with the NMSB and the LSB of a single precision constant. Register Pairs BC and DE are now equal to a single precision constant of 1.442695 (which is approximately 2 + ln 2)
1442-1444
We next want to calculate INT(ARG/LN(2)) = INT(ARG*LOG2(E)). So we will need to multiply the exponent value by 2 ln 2 so we call the SINGLE PRECISION MULTIPLY routine at 0847H (which multiplies the current value in ACCumulator by the value in (BC/DE). The product is left in ACCumulator
1445-1447
LD A,(4124H)LD A,(FAC)3A 24 41
Load Register A with the result of the math just done (i.e., which was multiplying the exponent value by 2 ln 2) which was stored in ACCumulator.
1448-1449
CP 88HFE 88
Next we want to see if ABS(ACCumulator) is >= 128 (i.e., if the integer portion of the single precision value in ACCumulator uses more than 7 bits of precision) by comparing it against a mask of 1000 1000
144A-144C
If the single precision value in ACCumulator uses more than 7 bits of precision for its integer portion then it is too big and we need to JUMP to MLDVEX to deal with that.
144D-144F
So now that we know the integer portion is not too big, but we need to see if the argument is too big as well so we GOSUB to 0B40H to get the integer portion of the value in ACCumulator and return with it in Register A
1450-1451
ADD A,80HC6 80
Adjust the value in Register A by masking it against 1000 0000
1452-1453
ADD A,02HC6 02
Adjust the value in Register A by adding 2 more. We will either get an overflow (C FLAG) or we wont (NC FLAG)
1454-1456
If (exponent * 2 ln 2) is => 126 (meaning when 2 was added it it, it overflowed with a 128), jump to 0931H
1457
PUSH AFF5
So now neither has overflowed, so save the scale factor +82H (as stored in Register Pair AF) to the STACK
1458-145A
LD HL,07F8HLD HL,FONE21 F8 07
Load Register Pair HL with a single precision constant equal to 1.0 (as found at 1458H)
145B-145D
Go add the single precision constant 1.0 (as pointed to by Register Pair HL) to the current value in ACCumulator which is EXP * 2 ln 2
145E-1460
Need to multiply that by ln 2, so GOSUB to 0841H to multiply (1 + [EXP * 2 ln 2]) (as stored in ACCumulator) by 0.693147
1461
POP AFF1
Get the scale factor (as stored in the STACK) and put it in Register Pair AF
1462
POP BCC1
Get the original exponent into BC/DE in 2 steps fist get the exponent and the MSB of the single precision value from the STACK and put it in Register Pair BC
1463
POP DED1
and then get the NMSB and the LSB of the single precision value from the STACK and put it in Register Pair DE
1464
PUSH AFF5
Put the scale factor (the integerized EXP * 2 ln 2) as stored in Register Pair AF onto the STACK
1465-1467
Now we need to subtract the original exponent from the integerized exponent so we GOSUB to 0713H which is the SINGLE PRECISION SUBTRACT routine (which subtracts the single precision value in BC/DE from the single precision value in ACCumulator. The difference is left in ACCumulator)
1468-146A
To force that difference to be a positive number we GOSUB to 0982H which makes the current single precision value in ACCumulator positive
146B-146D
LD HL,1479HLD HL,EXPCON21 79 14
Load Register Pair HL with the starting address for a series of 8 coefficients so as to enable us to evaluate the approximation polynomial in the next instruction
146E-1470
GOSUB to 14A9H to do that series of computations
1471-1473
LD DE,0000H11 00 00
We want to make sure that FMULT will check for an exponent overflow at the end of this routine, so we can’t just add it to the exponent. Rather, we will multiply it by 2^(B-1) so that FMULT will check. So first, load the integerized equivalent of EXP * 2 lnt 2 into BC/DE so first we load Register Pair DE with zero …
1474
POP BCC1
… and then get the value from the STACK and put it in Register Pair BC
1475
LD C,D4A
Load Register C with zero (since Register D was filled with a zero in 1471H)
1476-1478
We need to multiply by the sum from the series and return so we jump to 0847H which is the the SINGLE PRECISION MULTIPLY routine at 0847H (which multiplies the current value in ACCumulator by the value in (BC/DE). The product is left in ACCumulator

1479-1499 – SINGLE PRECISION CONSTANT STORAGE LOCATION
This represents 1/6, -1/5, 1/4, -1/3, 1/2, -1, and 1 – “EXPCON”

1479
 ↳ EXPCON
09
The number of single precision constants (9) which follow are stored here
147A-147D
40 2E 94 74
A single precision constant equal to -0.00014171607 (-1.413165 * 10e-4) is stored here
147E-1481
70 4F 2E 77
A single precision constant equal to 0.00132988204 (1.32988 * 10e-3, roughly -1/6) is stored here
1482-1485
6E 02 88 7A
A single precision constant equal to -0.00830136052 (-8.30136 * 10e-3, roughly -1/5) is stored here
1486-1489
E7 A0 2A 7C
A single precision constant equal to 0.04165735095 (roughly 1/4) is stored here
148A-148D
50 AA AA 7E
A single precision constant equal to -0.16666531543 (roughly -1/3) is stored here
148E-1491
FF FF 7F 7F
A single precision constant equal to 0.49999996981 (roughly 1/2) is stored here
1492-1495
00 00 80 81
A single precision constant equal to -1.0 is stored here
1496-1499
00 00 00 81
A single precision constant equal to 1.0 is stored here

149A-14C8 – LEVEL II BASIC MATH ROUTINE – “POLYX”

This is a general purpose summation routine which computes the series C0*X+C1*X^3+C2*X^5+C3*X^7+…+C(N)*X^(2*N+1) for I=0 to N when entered at 149AH If entered at 14A9H the series changes to SUM ((((x*c0+c1)x*c2)x+c3)x+.cN. On entry, the x is held in BC/DE and HL points to a list containing the number of terms followed by the coefficients.

The pointer to degree+1 is in (HL) and the constants should follow the egree, stored in reverse order. X is in the ACCumulator.
149A-149C
 ↳ POLYX
Save X to the STACK via a GOSUB to 09A4 to which move the SINGLE PRECISION value in ACCumulator to the STACK (stored in LSB/MSB/Exponent order)
149D-149F
LD DE,0C32HLD DE,FMULTT11 32 0C
Load Register Pair DE with the return address of the FMULTT routine …
14A0
PUSH DED5
… and push it to the STACK, so that once this routine ends, it will be multiplied by X
14A1
PUSH HLE5
Save pointer to the constant (as stored in Register Pair HL) to the STACK
14A2-14A4
We need to square X, so we do that in the next two steps. First, GOSUB to 09BFH which loads the SINGLE PRECISION value in ACCumulator into Register Pair BC/DE
14A5-14A7
Since ACCumulator and BC/DE now hold the same number, you can square that by a GOSUB to 0847H which is the SINGLE PRECISION MULTIPLY routine (which multiplies the current value in ACCumulator by the value in (BC/DE). The product is left in ACCumulator)
14A8
POP HLE1
Restore the consatnt pointer from the STACK and put it in Register Pair HL, and then fall through into the POLY routine

14A9 – LEVEL II BASIC MATH ROUTINE – “POLY”

General polynomial evaluator routine. Pointer to degree+1 is in (HL), and that gets updated through the computation. The Constants follow the degree and should be stored in reverse order. The ACCumulator has the X. The formula is c0+c1*x+c2*x^2+c3*x^3+…+c(n-1)*x^(n-1)+c(n)*x^n
14A9-14AB
 ↳ POLY
Save the “X” to the STACK. We need to move either x or x**2 (depending on the routine entry point) to the STACK so we GOSUB to 09A4 which moves the SINGLE PRECISION value in ACCumulator to the STACK (stored in LSB/MSB/Exponent order)
14AC
LD A,(HL)7E
Fetch the degree (i.e., the number of values to be figured at the location of the memory pointer in Register Pair HL) into Register A
14AD
INC HL23
Bump the value of the memory pointer in Register Pair HL so that it points to the first constant/coefficient
14AE-14B0
Now load that constant/coefficient (stored in HL) and move it to ACCumulator by GOSUB to 09B1H (which moves a SINGLE PRECISION number pointed to by HL to ACCumulator)
14B1
LD B,0F106 F1
Z-80 Trick! If passing through, this will simply alter Register B and the next instruction of POP AF will not be processed.
14B2
 ↳ POLY1
POP AFF1
Get the degree (count of coefficients left) from the STACK and put it in Register A
14B3
POP BCC1
Get the value of “X” from the STACK and put it in Register Pair BC/DE – Step 1 and …
14B4
POP DED1
… Step 2
14B5
DEC A3D
Count 1 of the terms as computed by decrementing the counter in Register A
14B6
RET ZC8
If that decrement results in a zero (meaning the series of computations has been completed) return out of the subroutine
14B7-14B8
PUSH DE
PUSH BCD5
Save the NMSB and the LSB of “X” from DE to the STACK and save the MSB of “X” from BC to the STACK
14B9
PUSH AFF5
Save counter of the remaining degrees (terms to compute) as tracked by Register A into the STACK
14BA
PUSH HLE5
Save the value of the memory pointer to the next constant/coefficient (stored in Register Pair HL) to the STACK
14BB-14BD
Compute C(I)*x by GOSUB to 0847H which is the SINGLE PRECISION MULTIPLY routine (which multiplies the current value in ACCumulator by the value in (BC/DE). The product is left in ACCumulator
14BE
POP HLE1
Restore the coefficient table address (from the STACK) to Register Pair HL
14BF-14C1
Get the next coefficient from HL into BC/DE by GOSUB to 09C2H (which loads a SINGLE PRECISION value pointed to by Register Pair HL into Register Pairs BC and DE)
14C2
PUSH HLE5
Save the next coefficient (stored in Register Pair HL) to the STACK
14C3-14C5
Compute C(I)*x+C(I+1) by GOSUB to 0716H which is the SINGLE PRECISION ADD routine (which adds the single precision value in (BC/DE) to the single precision value in ACCumulator. The sum is left in ACCumulator)
14C6
POP HLE1
Restore the coefficient table address (from the STACK) to Register Pair HL
14C7-14C8
Jump back to 14B2H to continue the series. ACCumulator contains the current term

14C9-1540 – LEVEL II BASIC RND(n) ROUTINE – “RND”.

If the passed argument is 0, the last random number generated is returned. If the argument is < 0, a new sequence of random numbers is started using the argument.

To form the next random number in the sequence, we multiply the previous random number by a random constant, and add in another random constant. Then the HIGH ORDER and LOW ORDER bytes are switched, the exponent is put where it will be shifted in by normal, and the exponent in the ACCUMULATOR is set to 80H so the result will be less than 1. This is then normalized and saved for the next time.

The reason we switch the HIGH ORDER and LOW ORDER bytes is so we have a random chance of getting a number less than or greater than .5

Integer, single or double-precision. Output will be single-precision. (ACC=RND (ACC))

A call to 14C9H Generates a random number between 0 and 1, or 1 and n depending on the parameter passed in ACCumulator, The random value is returned in ACCumulator as an integer with the mode flag set. The parameter passed will determine the range of the random number returned. A parameter of 0 will return an interger between 0 and 1. A parameter greater than 0 will have any fraction portion truncated and will cause a value between 1 and the integer portion of the parameter to be returned.
14C9-14CB
 ↳ RND
First convert the argument to an integer via a GOSUB to 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)
14CC
LD A,H7C
Load Register A with the value of the MSB for the integer value in Register H
14CD
OR AB7
Check to see if the integer value in Register Pair HL is negative
14CE-14D0
Since we won’t accept a negative number, display a ?FC ERROR message if the integer value in Register Pair HL is negative
14D1
OR LB5
Combine the MSB and LSB and set status flags so we can see if the integer value in Register Pair HL is equal to zero
14D2-14D4
If it is zero, we don’t need the rest of the below which functions to generate RND(n) so we just jump to 14F0H (which generates RND(0), which is a number between 0 and 1)
14D5
PUSH HLE5
Since it wasn’t zero, we need to save the argument (as stored in Register Pair HL) to the STACK
14D6-14D8
Generate a random number between 0 and 1 via a call to GOSUB to 14F0H (which generates RND(0)) and return with the single precision result in ACCumulator
14D9-14DB
Move the random number we just generated into BC/DE via a GOSUB to 09BFH which loads the SINGLE PRECISION value in ACCumulator into Register Pair BC/DE
14DC
EX DE,HLEB
Swap some registers so that the random number is now in B/C/H/L
14DD
EX (SP),HLE3
Swap (SP) and HL so that the LOW ORDER bytes of the random number are at the top of the STACK, and HL now holds the integer argument
14DE
PUSH BCC5
Save the HIGH ORDER bytes of the random number value to the STACK
14DF-14E1
Convert the original x of RND(x) to single precision by GOSUB to 0ACFH which converts the integer value in Register Pair HL to single precision and return with the result in ACCumulator
14E2-14E3
POP BC
POP DEC1
Restore the RND(0) value from the STACK and put it into Register Pair BC/DE
14E4-14E6
Multiply the RND(0) value (currently in BC/DE) by the n of RND(n) (currently in ACCumulator) by GOSUB to 0847H which is the SINGLE PRECISION MULTIPLY routine (which multiplies the current value in ACCumulator by the value in (BC/DE). The product is left in ACCumulator
14E7-14E9
LD HL,07F8HLD HL,FONE21 F8 07
Load Register Pair HL with the starting address of a single precision constant equal to 1.0
14EA-14EC
Increase the random number by one by GOSUB to 070BH which adds the single precision constant pointed to by Register Pair HL (which is 1.0) to the single precision value in ACCumulator (which is the random number). Return with the single precision result in ACCumulator
14ED-14EF
With the random number now in ACCumulator, jump to 0B40H (which will convert it to an integer and RETurn to the subroutine caller, thus exiting out of this routine)

14F0 – This routine calculates RND(0) – “RND0”.

14F0-14F2
LD HL,4090HLD HL,MULTR21 90 40
Load Register Pair HL with the starting address for a multiplier table used for figuring random numbers
14F3
PUSH HLE5
Save the starting address for the table used for figuring random numbers (stored in HL) to the STACK
14F4-14F6
LD DE,0000H11 00 00
Load Register Pair DE with zero (which will be the NMLSB and LSB of the starting value)
14F7
LD C,E4B
Load Register C with zero (C will be the MSB of the starting value). Now C/D/E is zero.
14F8-14F9
LD H,03H26 03
Load Register H with the counter value for the multiplication loop (which will be 3)
14FA-14FB
 ↳ RNDO0
LD L,08H2E 08
Load Register L with a counter value of 8 bits
14FC
 ↳ RND1
EX DE,HLEB
Swap DE and HL so that the counters are now in DE and the NMSB and the LSB of the random number is in Register Pair HL
14FD
ADD HL,HL29
Multiply the NMSB and the LSB of the random number in Register Pair HL by two
14FE
EX DE,HLEB
Exchange the newly doubled NMSB and the LSB of the random number to DE and the counters to Register Pair HL
14FF
LD A,C79
Next we want to shift the HIGH ORDER byte (Register C), so first load Register A with the MSB of the random number in Register C
1500
RLA17
Multiply the HIGH ORDER byte of the random number in Register A by two
1501
LD C,A4F
Load Register C with the adjusted MSB of the random number in Register A
1502
EX (SP),HLE3
Swap (SP) and HL so that the counters are now at the top of the STACK and the pointer to the multiplier is in Register Pair HL
1503
LD A,(HL)7E
Fetch a multiplier from the the table value (held at the location of the memory pointer in Register Pair HL) into Register A
1504
RLCA07
Rotate the bits of Register A
1505
LD (HL),A77
Save the doubled value (stored in Register A) at the location of the memory pointer in Register Pair HL
1506
EX (SP),HLE3
Swap (SP) and HL so that the counters are now in HL and the pointer to the multiplication table is at the top of the STACK
1507-1509
If that rotation set a NC FLAG, JUMP forward to 1516H
150A
PUSH HLE5
Save the counter values in Register Pair HL to the STACK
150B-150D
LD HL,(40AAH)LD HL,(RNDX)2A AA 40
Load Register Pair HL with the NMSB and the LSB of the random number seed.
Note: 40AAH-40ADH holds the random number seed
150E
ADD HL,DE19
Add the NMSB and the LSB of the random number in Register Pair DE to the NMSB and the LSB of the random number seed in Register Pair HL
150F
EX DE,HLEB
Load Register Pair DE with the adjusted NMSB and LSB of the random number in Register Pair HL
1510-1512
LD A,(40ACH)LD A,(RNDX+2)3A AC 40
Load Register A with the MSB of the random number seed
1513
ADC A,C89
Add the MSB of the random number in Register C to the MSB of the random number seed in Register A
1514
LD C,A4F
Load Register C with the adjusted MSB of the random number in Register A
1515
POP HLE1
Get the counter values from the STACK and put it in Register Pair HL
1516
 ↳ RND2
DEC L2D
Decrement the loop counter in Register L
1517-1519
Loop back to 14FCH until the above has been done eight times
151A
EX (SP),HLE3
Swap (SP) and HL so that HL will now point to the table of multipliers
151B
INC HL23
Bump to the next table of multipliers value
151C
EX (SP),HLE3
Exchange the bumped pointer to the table value in Register Pair HL with the counter value to the STACK
151D
DEC H25
Decrement the counter value of the outer loop (in Register H) to see if there are more bytes to deal with
151E-1520
Loop back to 14FAH three times until the random number has been figured
1521
POP HLE1
Clear the flag table address from the STACK. The fact that it is going into HL is not important
1522-1524
LD HL,B065H21 65 B0
Load Register Pair HL with the value to re-seed the random number seed
1525
ADD HL,DE19
Add the seed (from Register Pair HL) to the NMSB and the LSB of the random number in Register Pair DE
1526-1528
LD (40AAH),HLLD (RNDX),HL22 AA 40
Save the adjusted value in Register Pair HL as the NMSB and the LSB of the random number seed.
Note: 40AAH-40ADH holds the random number seed
1529-152B
Go set the current number type to single precision
152C-152D
LD A,05H3E 05
Load Register A with a 5
152E
ADC A,C89
Add 5 (the value held in A) and the MSB of the random number in Register C
152F-1531
LD (40ACH),ALD (RNDX+2),A32 AC 40
Save the adjusted value in Register A as the MSB of the random number seed, so now the result is in A/H/L
1532
EX DE,HLEB
Swap DE and HL so that the result is now in A/D/E
1533-1534
LD B,80H06 80
Load Register B with a value for the sign flag and the exponent (i.e, 1000 0000)
1535-1537
LD HL,4125HLD HL,FAC+121 25 41
Load Register Pair HL with the address for the sign value storage location.
Note: 4125H-4126H is used by floating point routines
1538
LD (HL),B70
Save the sign result (1000 0000) in Register B at the location of the memory pointer in Register Pair HL
1539
DEC HL2B
Decrement to exponent (held in Register Pair HL)
153A
LD (HL),B70
Set the exponent to (1000 0000) so that the value will be < 1
153B
LD C,A4F
Now we just want to normalize C/D/E. First, load Register C with the value of the MSB for the single precision random number in Register A
153C-153D
LD B,00H06 00
Zero the value of any overflow in Register B
153E-1540
Jump to 0765H which will normalize the value and then jump to 14D9H unless RND(0) was called in which case return to caller

1541-1546 – LEVEL II BASIC COS
ROUTINE – “COS”.

Single-precision only.(ACCumulator = COS(ACCumulator)). A call to 1541H computes the cosine for an angle given in radians. The angle must be a floating point value in ACCumulator; the cosine will be returned in ACCumulator as a floating point value.

The formula being used is COS(X) = SIN(X+PI/2)
1541-1543
 ↳ COS
LD HL,158BHLD HL,PI221 8B 15
Load Register Pair HL with the starting address of a single precision constant equal to 1.57079637029 (which is pi / 2)
1544-1546
GOSUB to 070BH to add 1.57079637029 (stored in HL) to the single precision value in ACCumulator and then pass through to the SIN() routine which is next

1547-158A – LEVEL II BASIC SIN ROUTINE – “SIN”

Single-precision only.(ACCumulator = SIN(ACCumulator)).

A call to 1549H returns the sine as a single precision value in ACCumulator. The sine must be given in radians in ACCumulator.

The actual calculation routine is:
  1. Assume X <= 360 degrees.
  2. Recompute x as x=x/360 so that x=< 1.
  3. If x <= 90 degrees go to step 7.
  4. If x <= 180 degrees then x=0.5-x and then go to step 7.
  5. If x <= 270 degrees then x=0.5-x.
  6. Recompute x as x=x-1.0.
  7. Compute SIN using the power series.
1547-1549H
“SIN”
First we want to divide the ACCumulator by 2*PI. First, GOSUB to 09A4 which moves the SINGLE PRECISION value in ACCumulator (the x in a SIN(x) call) to the STACK (stored in LSB/MSB/Exponent order)
154A-154C
LD BC,8349H01 49 83
Load Register Pair BC with the exponent and the MSB of a single precision constant
154D-154F
LD DE,0FDBH11 DB 0F
Load Register Pair DE with the NMSB and the LSB of a single precision constant. Register Pairs BC and DE now hold a single precision constant equal to 6.2831855 (which is pi * 2)
1550-1552
Move 2 x pi value (held in DC/BE) into ACCumulator by GOSUB to 09B4H (which moves the SINGLE PRECISION value in DC/DE into ACCumulator)
1553-1554
POP BC
POP DEC1
Put the x from a SIN(x) call into BC/DE
1555-1557
To divide the x from a SIN(x) call (held in BC/DE) by pi*2 (held in ACCumulator) we must GOSUB 80A2H to divide the single precision value in Register Pairs BC and DE by the single precision value in ACCumulator. Return with the single precision result in ACCumulator
1558-155A
Move that value (x / 2*pi) from ACCumulator to the STACK by GOSUB to 09A4H which moves the SINGLE PRECISION value in ACCumulator to the STACK (stored in LSB/MSB/Exponent order)
155B-155D
Go figure the integer portion for the single precision value in ACCumulator by calling 0B40H. We need to do this so we can isolate the remainder
155E,155F
POP BC
POP DEC1
Put the quotient and remainder of x/2*pi into BC/DE
1560-1562
To get the remainder we need to subtract the integer portion from the full portion so we GOSUB 0713H (the SINGLE PRECISION SUBTRACT routine) to subtract the single precision value in BC/DE (the entire result) from the single precision value in ACCumulator (the integer part of the result). The difference is left in ACCumulator)
1563-1564
LD HL,158FHLD HL,FR421 8F 15
Load Register Pair HL with the starting address of a single precision constant equal to 0.25
1566-1568
Next in calculating a SIN we would need to subtract .25 (held in HL) from the fractional part (held in ACCumulator) so as to see if it is <= to 90 degrees. To do this we GOSUB 0710H to subtract the single precision value in ACCumulator from the single precision constant pointed to by Register Pair HL. Return with the result in ACCumulator
1569-156B
Go check the sign of the result of that (.25 – fractional part) subtraction which is held in ACCumulator
156C
SCF37
Set the Carry flag
156D-156F
Jump to 1577H if the single precision value in ACCumulator is positive (meaning it is < than 90 degrees)
1570-1572
If we are here, it is => 90 degrees, so we need to add .5 to the single precision value in ACCumulator. Return with the result in ACCumulator
1573-1575
Go check the sign for the single precision value in ACCumulator which basically checks to see if it is > 0.75 (meaning < 270 degrees)
1576
OR AB7
Test the value of the sign test in Register A
1577
 ↳ SIN1
PUSH AFF5
Save the sign indicator (+ or -1) in Register Pair AF to the STACK
1578-157A
If it is positive, make it negative by GOSUB to 0982H
157B-157D
LD HL,158FHLD HL,FR421 8F 15
Load Register Pair HL with the starting address of a single precision constant equal to 0.25
157E-1580
Add .25 (stored in HL) to the current value in ACCumulator by GOSUB to 070BH (result is saved in ACCumulator)
1581
POP AFF1
Get the sign reversal flag from the STACK and put it in Register Pair AF
1582-1584
Set the sign of the x term according to the quadrant by GOSUB to 0982H if if the Carry flag wasn’t set from above
1585-1587
LD HL,1593HLD HL,SINCON21 93 15
Load Register Pair HL with 1593H (which is the starting address for a series of single precision values for a set of computations)
1588-158A
Go to 149AH to compute the series and then RETURN

158B-158E – SINGLE PRECISION CONSTANT STORAGE LOCATION – “PI2”

158B-158EH
 ↳ PI2
DB 0F 49 81DB 0F
A single precision constant equal to 1.57079637029 is stored here

158F-1592 – SINGLE PRECISION CONSTANT STORAGE LOCATION – “FR4”

158F-1592H
 ↳ FR4
00 00 00 7F
A single precision constant equal to 0.25 is stored here

1593-15A7 – SINGLE PRECISION CONSTANTS STORAGE LOCATION – “SINCON”

1593
 ↳ SINCON
05H
The number of single precision constants (05) which follows is stored here. These are the coefficients used in the power series to compute SIN(x)
1594-1597H
BAH D7H 1EH 86H
A single precision constant equal to 39.7106704708 is stored here
1598-159BH
64H 26H 99H 87H
A single precision constant equal to -76.5749816893 is stored here
159C-159FH
58H 34H 23H 87H
A single precision constant equal to 81.6022338865 is stored here
15A0-15A3H
E0H 6DH A5H 86H
A single precision constant equal to -41.3416748045 is stored here
15A4-15A7H
DAH 0FH 49H 83H
A single precision constant equal to 6.28318500497 is stored here

15A8-15BC – LEVEL II BASIC TAN(n) ROUTINE – “TAN”

Single-precision only.(ACCumulator = TAN(ACCumulator)).
A call to 15A8H computes the tangent of an angle in radians. The angle must be specified as a single precision value in ACCumulator. The tangent will be left in ACCumulator.
Uses the fact that TAN(x) = SIN(x) / COS(x)
15A8-15AA
 ↳ TAN
Save the argument via a GOSUB to 09A4 which moves the SINGLE PRECISION value in ACCumulator to the STACK (stored in LSB/MSB/Exponent order)
15AB-15AD
Call the SIN(n) routine at 1547H (which returns the sine as a single precision value in ACCumulator. The sine must be given in radians in ACCumulator
15AE,15AF
POP BC
POP HLC1
Get the original exponent and value from the STACK and put it in Register Pair BC/HL
15B0-15B2
Call 09A4 which moves the SIN(x) single precision value (stored in REG) 1 to the STACK (stored in LSB/MSB/Exponent order)
15B3
EX DE,HLEB
Load Register Pair DE with the NMSB and the LSB of the single precision value in Register Pair HL
15B4-15B6H 
Call 09B4H (which moves the original value in BC/DE into ACCumulator)
15B7-15B9
Call the COSINE routine at 1541H (which computes the cosine for an angle given in radians. The angle must be a floating point value; the cosine will be returned in ACCumulator as a floating point value
15BA-15BC
Jump to 08A0H to compute SIN(n) / COS(n) and return the value as TAN(n)

15BD-15E2 – LEVEL II BASIC ATN(n) ROUTINE – “ATN”.

Single-precision only.(ACCumulator = ATN(ACCumulator)).
A call to 15BD returns the angle in radians, for the floating point tangent value in ACCumulator. The angle will be left as a single precision value in ACCumulator.

The method of computation used in this routine is:
  1. Test the sign of the tangent to see if a negative angle is in the 2nd or 4th quadrant. Set the flag to force the result to positive on exit. If the value is negative, invert the sign.
  2. Test magnitude of tangent. If it is < 1 go to step 3. Otherwise, compute its reciprocal and put the return address on the STACK that will calculate pi/2 – series value.
  3. Evaluate the series: (((x^2*c0+c1) x^2+c2) . c8)x
  4. If the flag from step 1 is not set, then invert the sign of the series result.
  5. If the original value is < 1 then return to the caller. Otherwise, compute pi/2-value from step 4 and then return.
15BD-15BF
 ↳ ATN
Go check the sign of argument (i.e., the single precision value in the ACCumulator)
15C0-15C2
If the single precision value in ACCumulator is negative then put a return address of 13E2H to the STACK
15C3-15C5
Go convert the negative number in ACCumulator to positive if necessary
15C6-15C8
LD A,(4124H)LD A,(FAC)3A 24 41
We next want to see if the ACCumulator is > 1, so load Register A with the exponent of the tangent (which is a single precision value in ACCumulator)
15C9-15CA
CP 81HFE 81
Check to see if the the exponent of the tangent (which is a single precision value in ACCumulator) is less than one
15CB-15CC
Jump to forward 15D9H if the carry flag is set (i.e., the single precision value in ACCumulator is less than one)
15CD-15CF
LD BC,8100H01 00 81
Load Register Pair BC with an exponent and a MSB for a single precision value
15D0
LD D,C51
Zero the NMSB of the single precision value in Register D
15D1
LD E,C59
Zero the LSB of the single precision value in Register E
15D2-15D4
GOSUB 082AH to get the reciprocal of the tangent. This routine divides the single precision value in ACCumulator into the single precision constant in Register Pairs BC and DE
15D5-15D7
LD HL,0710HLD HL,FSUBS21 10 07
Load Register Pair HL with a return address of 0710H (which is the subtract routine to be called once the series is calculated)
15D8
PUSH HLE5
Save the value of the return address in Register Pair HL to the STACK
15D9-15DB
 ↳ ATN2
LD HL,15E3HLD HL,ATNCON21 E3 15
Load Register Pair HL with the starting address for a series of single precision numbers for a set of computations
15DC-15DE
Go do the set of computations
15DF-15E1
LD HL,158BHLD HL,PI221 8B 15
Load Register Pair HL with the starting address of a single precision constant equal to 1.57079637029 (which is pi/2)
15E2
RETC9
Return. The return address was set to 0710H above, which will then subtract the last term from pi/2 and then return

15E3-1607 – SINGLE PRECISION CONSTANTS STORAGE LOCATION – “ATNCON”

15E3
 ↳ ATNCON
09
The number of single precision constants (9) which follows is stored here
15E4-15E7
4A D7 3B 78
A single precision constant equal to 0.00286622549 is stored here
15E8-15EB
02 6E 84 7B
A single precision constant equal to -0.01616573699 is stored here
15EC-15EF
FE C1 2F 7C
A single precision constant equal to 0.04290961441 is stored here
15F0-15F3
74 31 9A 3D
A single precision constant equal to 0.07528963666 is stored here
15F4-15F7
84 3D 5A 7D
A single precision constant equal to 0.10656264407 is stored here
15F8-15FB
C8 7F 91 7E
A single precision constant equal to -0.14208900905 is stored here
15FC-15FF
E4 BB 4C 7E
A single precision constant equal to 0.19993549561 is stored here
1600-1603
6C AA AA 7F
A single precision constant equal to -0.33333146561 is stored here
1604-1607
00 00 00 01
A single precision constant equal to 1.0 is stored here

1608-18C8 – LIST OF BASIC RESERVED WORDS, TOKENS, AND ENTRY LOCATIONS AS FOLLOWS:

The original ROM source code makes an interesting note about the order of these reserved words. Some reserved words are contained in other reserved words, which will cause a problem. They given examples of:
  • IF J=F OR T=5 will process a FOR
  • INP is part of INPUT
  • IF T OR Q THEN will process a TO
SO, the smaller word always has to appear later in the reserved word table.
ABSD90977|ANDD225FD
ASCF62A0F|ATNE415BD
AUTOB72008|CDBLF10ADB
CHR$(F72A1F|CINTEF0A7F
CLEARB81E7A|CLOADB92C1F
CLOSEA64185|CLS8401C9
CMD854173|CONTB31DE4
COSEl1541|CSAVEBA2BF5
CSNGF00ABl|CVDE8415E
CVIE64152|CVSE74158
DATA881F05|DEFDD415B
DEFDBL9B1E09|DEFINT991E03
DEFSNG9A1E06|DEFSTR981E00
DELETEB62BC6|DIM8A2608
EDIT9D2E60|ELSE951F07
END801DAE|EOFE94161
ERLC224DD|ERRC324CF
ERROR9E1FF4|EXPE01439
FIELDA3417C|FIXF20B26
FNBE4155|FOR811CA1
FREDA27D4|GETA44174
GOSUB911EB1|GOTO5D1EC2
IF8F2039|INKEY$C9019D
INPDB2AEF|INPUT89219A
INSTRC5419D|INTD80B37
KILLAA4191|LEFT$F82A61
LENF32A03|LET8C1F21
LINE9C41A3|LISTB42B2E
LLISTB52B29|LOADA74188
LOCEA4164|LOFEB4167
LOGDF0809|LPRINTAF2067
LSETAB4197|MEMC827C9
MERGEA8418B|MID$FA2A9A
MKD$EE4170|NAMEA9418E
NEWBB1B49H|NEXT8722B6
NOTCB25C4|ONA11FC6
OPENA24179|ORD325F7
OUTAO2AFB|PEEKE52CAA
POINTC60132|POKEB12CB1
POSDC27F5|PRINTB2206F
PUTA54182|RANDOM8601D3
READ8B21EF|REM931F07
RESET820138|RESTORE901D91
RESUME9F1FAFH|RETURN921EDEH
RIGHT$F92A91|RNDDE14C9
RSETAC419A|RUN8E1EA3
SAVEAD41A0|SET830135
SGND7098A|SINE21547
SQRCD13E7|STEPcc2B01
STOP941DA9|STR$F42836
STRING$C42A2F|SYSTEMAE02B2
TAB(BC2137|TANE315A8
THENCA|TIME$C74176
TOBD|TROFF971DF8
TRON961DF8|USINGBF2CBD
USRC127FE|VALFF2AC5
VARPTRC024EB|+CD249F
CE2532|*CF
/D0|?D1
>D4|=D5
<D6|&26
FB3A93

18C9-18F6 – STORAGE LOCATION FOR LEVEL II BASIC ERROR MESSAGES – “ERRTAB”

18C9
“NF”
NEXT without FOR Error Message (Error 00H)
18CB
“SN”
Syntax Error Error Message (Error 02H)
18CD
“RG”
RETURN without GOSUB Error Message (Error 04H)
18CF
“OD”
Out of DATA) Error Message (Error 06H)
18D1
“FC”
Illegal Function Call Error Message (Error 08H)
18D3
“OV”
Overflow Error Message (Error 0AH)
18D5
“OM”
Out of Memory Error Message (Error 0CH)
18D7
“UL”
Underfined Line Number Error Message (Error 0EH)
18D9
“BS”
Subscript out of Range Error Message (Error 10H)
18DB
“DD”
Redimensioned Array Error Message (Error 12H)
18DD
“/0”
Division by Zero Error Message (Error 14H)
18DF
“ID”>
Illegal Direct Operation Error Message (Error 16H)
18E1
“TM”
Type Mismatch Error Message (Error 18H)
18E3
“OS”
Out of String Message (Error 1AH)
18E5
“LS”
Out of Memory Error Message (Error 1CH)
18E7
“ST”
String Too Long Error Message (Error 1EH)
18E9
“CN”
Can’t Continue Error Message (Error 20H)
18EB
“NR”
No RESUME Error Message (Error 22H)
18ED
“RW”
RESUME Without Error Error Message (Error 24H)
18EF
“UE”
Unprintable Error Error Message (Error 26H)
18F1
“HO”
Missing Operand Error Message (Error 28H)
18F3
“FD”
Bad file Data Error Message (Error 2AH)
18F5
“L3”
Disk BASIC Command Error Message (Error 2CH)

18F7-1904 – STORAGE LOCATION FOR THE SINGLE PRECISION DIVISION ROUTINE
This code is moved from 18F7-191DH to 4080H-40A5H during non-disk initial setup.

18F7
SUB 00HD6 00
Subtract the LSB
18F9
LD L,A6F
Restore the value to L
18FA
LD A,H7C
Get the middle byte
18FB
SBC A,00HDE 00
Subtract the middle byte
18FD
LD H,A67
Move the difference to H
18FE
LD A,B78
Get the MSB
18FF
SBC A,00HDE 00
Subtract the MSB
1901
LD B,A47
Move it back to A
1902
LD A,00H3E 00
Clear A
1904
RETC9
RETurn to CALLer

1905-191C – STORAGE LOCATION FOR VALUES PLACED IN RAM UPON INITIALIZATION.

This code is moved to 408E during non-disk initial setup.

191D-1923 – MESSAGE STORAGE LOCATION – “ERR”

191D-1923
 ↳ ERR
“Error” + 00H20 45
The word “ERROR”
1924-1928
 ↳ INTX
” in ” + 00H
The word ” IN “

1929-192F – MESSAGE STORAGE LOCATION – “REDDY”

1929-192F
 ↳ REDDY
“READY” + 0DH + 00H
The Level II BASIC READY message is stored here

1930-1935 – MESSAGE STORAGE LOCATION – “BRKTXT”

1930-1935
 ↳ BNKTXT
“Break” + 00H
The Level II BASIC BREAK message is stored here

1936-1954 – SCAN STACK ROUTINE – “FNDFOR”

This routine is called with DE as the address of the NEXT index. It scans the STACK backwards looking for a FOR push. If one is found, it gets the address of the index and compares with the DE that was in place when this routine was called. If it is equal, then it exits with A=0 and HL=Address of the variable. If it is not equal it will keep scanning until no FOR push is found and then exit with A<>0.

According to the original ROM source, this routine is part of the general storage management routines, and if designed to find a FOR entry on the STACK with the variable pointer passed in Register Pair DE.
1936-1938
 ↳ FNDFOR
LD HL,0004H21 04 00
Load Register Pair HL with 4 so that we can backspace
1939
ADD HL,SP39
Add the 4 (held in HL) to the current value of the STACK pointer. HL will hold the current STACK pointer, the STACK point will bump forward 4
193A
 ↳ LOOPER
LD A,(HL)7E
Load Register A with the value held at the current STACK point MINUS 4. This is to enable seeing what type of data is on the STACK
193B
INC HL23
Bump the value of the memory pointer in Register Pair HL so as to backspace one more byte in case a FOR token is located
193C-193D
CP 81HFE 81
Check to see if the value in Register A (which is the current STACK pointer – 4) is a FOR token to make sure that the item in the STACK was associated with a FOR loop
193E
RET NZC0
If the item isn’t associated with a FOR statement (as the value in Register A isn’t a FOR token), exit out of this routine. This returns with A being non-zero because there was no FOR push
193F
LD C,(HL)4E
If we are here, then the entry on the STACK is associated with a FOR statement. Load Register C with the LSB of the FOR‘s variable address
1940
INC HL23
Bump the value of the memory pointer in Register Pair HL so as to backspace the current STACK pointer by yet another byte
1941
LD B,(HL)46
Load Register B with the MSB of the FOR‘s variable address
1942
INC HL23
Bump the value of the memory pointer in Register Pair HL so now HL will be the address of the FOR variable on the STACK
1943
PUSH HLE5
Save the value in Register Pair HL (which is the address of the FOR variable) to the STACK
1944
LD L,C69
Load Register L with the LSB of the FOR variable’s address in Register C
1945
LD H,B60
Load Register H with the MSB of the FOR variable’s address in Register B
1946-1947
LD A,D
OR E7A
Z-80 Trick to check a Register Pair (in this case DE) for zero. Load D into A and then OR that against E. If both D and E are zero, then A will be zero. This sets up to handle a NEXT statement that doesn’t have a variable argument
1948
EX DE,HLEB
Exchange the variable address in Register Pair HL with the variable address in Register Pair DE so that DE will now hold the address of the FOR variable from the STACK. This is to ensure that we return with DE pointing to the variable
1949-194A
Skip the next 2 opcodes if the variable address in Register Pair DE was equal to zero, meaning that DE was not, in fact, pointing to the variable as we needed it to be
194B
EX DE,HLEB
Exchange the variable address in Register Pair HL with the variable address in Register Pair DE so that HL will now have the address of the FOR variable from the STACK
194C
This routine was entered with DE being the address of the NEXT index, so we need to compare that against the index from the STACK. To do this, we RST 18 to see if the variable address in HL is the same as in DE, so we call the COMPARE DE:HL routine, which numerically compares DE and HL. Will not work for signed integers (except positive ones). Uses the A-register only. The result of the comparison is returned in the status Register as: CARRY SET=HL<DE; NO CARRY=HL>DE; NZ=Unequal; Z=Equal)
194D-194F
 ↳ POPGOF
LD BC,000EH
LD BC,FORSIZ01 0E 00
Load Register Pair BC with the value to backspace (i.e., erase) the FOR token (which is 10)
1950
POP HLE1
Get the memory pointer from the STACK of the sign of the increment flag and put it in Register Pair HL
1951
RET ZC8
If the variable in the FOR block matched the NEXT index block, then RETURN with HL pointing to the bottom of the entry
1952
ADD HL,BC09
If it didn’t match, execute that 10 byte stepback in BC for the next possible FOR push
1953-1954
At this point, we should be pointing to the start of the NEXT entry, so JUMP to keep looking until the appropriate FOR block has been located

1955-1962 – DATA MOVEMENT ROUTINE – “BLTU”

This routine moves a variable into another area specified by the caller. On entry BC is set as the end address of the list to move (which is the upper limit); DE is set as the start address of the list to move; and HL is the end of the area to move it to.

According to the original ROM source, this routine is part of the general storage management routines, and if designed to make space by shoving everything forward and to check to make sure a reasonable amount of space remains between the top of the STACK and the highest location transferred to. On Entry, HL should be the destination of the high address, DE should be the low address to be transferred there, and BC should be the high address to be transferred there. On exit, HL=DE=Low BC=The location LOW was moved to.
1955-1957
 ↳ BLTU
GOSUB to 196CH to make sure there’s enough room in memory for the string area and make sure the STACK won’t be overrun
1958
 ↳ BLTUC
PUSH BCC5
The next 3 instructions are really just to exchange HL and BC. First, save the end address of the list to move (stored in BC) to the STACK
1959
EX (SP),HLE3
Save the end address of the list to move (stored in the STACK now) to Register Pair HL
195A
POP BCC1
Get the end address of the move from the STACK and put it in Register Pair BC
195B
 ↳ BLTLOP
Check is we are done by checking to see if the memory pointer in HL is the same as the memory pointer in DE (to see if the move is finished), so we call the COMPARE DE:HL routine, which numerically compares DE and HL. Will not work for signed integers (except positive ones). Uses the A-register only. The result of the comparison is returned in the status Register as: CARRY SET=HL<DE; NO CARRY=HL>DE; NZ=Unequal; Z=Equal)
195C
LD A,(HL)7E
Get a byte from the source list to transfer and put it in Register A
195D
LD (BC),A02
Transfer it by saving the byte into wherever BC is pointing
195E
RET ZC8
Return if finished with the move (i.e., the memory pointer in Register Pair HL is the same as the value of the memory pointer in Register Pair DE)
195F
DEC BC0B
Decrement the source address (in Register Pair BC)
1960
DEC HL2B
Decrement the destination address (in Register Pair HL)
1961-1962
Loop until the entire block was moved

1963-197D – MEMORY CHECK ROUTINE – “GETSTK”

This routine computes the amount of space between HL and the end of memory at FFC6. On entry, Register C should hold the number of desired bytes.

According to the original ROM source, this routine is part of the general storage management routines, and if designed to make sure that a certain number of locations remain available for the STACK. To use this routine, Register C needs to hold the number of two byte entries needed, and then do a CALL GETSTK. This routine must be called by any reoutine which puts an arbitrary amount of stuff into the STACK (such as a recursive routine like FRMEVL). It is also called by routines such as GOSUB and FOR which make permanent entries in the STACK.
1963
 ↳ GETSTK
PUSH HLE5
Save the value in Register Pair HL to the STACK
1964-1966
LD HL,(40FDH)LD HL,(STREND)2A FD 40
Load Register Pair HL with the starting address of free memory (which is stored at 40FDH).
Note: 40FDH-40FEH holds Free memory pointer
1967-1968
LD B,00H06 00
Load Register B with zero
1969
ADD HL,BC09
Add 2 times the number of bytes required to start of free area (held in Register Pair BC) to the value in Register Pair HL
196A
ADD HL,BC09
Add the value in Register Pair BC to the value in Register Pair HL leaving HL to now contain the end of the free area
196B-196C
LD A,0E5H3E E5
Z-80 Trick! See the general explanation at 10F8H
196C
 ↳ REASON
PUSH HLE5
Now we check t omake sure there is at least “NUMLEV” bytes between the address and the top of the STACK. First, save the new free area pointer (which is the start) to the STACK
196D-196E
LD A,C6H
LD A,256-(2*NUMLEV)3E C6
Load Register A with C6H (which is the the LSB of FFC6H; the top of memory)
196F
SUB L95
Subtract the LSB of the value of the new memory pointer in Register L from the value in Register A
1970
LD L,A6F
Load Register L with the adjusted value in Register A (i.e., the free memory pointer resulting from subtracting the new starting address)
1971-1972
LD A,FFH3E FF
Load Register A with the MSB of the top of memory
1973
SBC A,H9C
Subtract the MSB of the new memory pointer in Register H from the value in Register A. If the free space list exceeds 7FFC6 then the Carry flag gets set, meaning memory overflowed
1974-1975
If the CARRY flag is set then HL was simply too big. So we need to display a ?OM ERROR since we are out of memory
1976
LD H,A67
Next we need to determine if the free space list has overflowed the STACK area so first we load Register H with the adjusted value in Register A
1977
ADD HL,SP39
Add the value of the STACK pointer to the adjusted value in Register Pair HL. If we are OK, the CARRY FLAG will be set
1978
POP HLE1
Restore the original HL on entry back into Register Pair HL
1979
RET CD8
If the carry flag is set, then we have no overflow – so RETURN to CALLer

197A-197B – ?OM ERROR ENTRY POINT – “OMERR”

197A-197B
 ↳ OMERR
LD E,0CHLD E,ERROM1E 0C
Load Register E with the ?OM ERROR
197C-197D
Display an ?OM ERROR message

197E-1AF7 – LEVEL II BASIC COMMAND MODE ERROR HANDLING – “PRGEND”

197E-1980
 ↳ PRGEND
LD HL,(40A2H)LD HL,(CURLIN)2A A2 40
Load Register Pair HL with the value of the current BASIC line number.
Note: 40A2H-40A3H holds the current BASIC line number
1981
LD A,H7C
Test to see if this was a direct command instead a line number by first loading Register A with the MSB of the current BASIC line number in Register H
1982
AND LA5
Combine the LSB of the current BASIC line number in Register L with the MSB of the current line number in Register A
1983
INC A3C
Bump the value of the combined BASIC line number in Register A. If the current line is FFFFH then we have not started execution of a BASIC program yet (meaning we are still in the inputting phase)
1984-1985
Jump to 198EH if Level II BASIC is still in the command mode (rather than being in execution mode)
1986-1988
LD A,(40F2H)LD A,(ONEFLG)3A F2 40
Load Register A with the error override flag (i.e., if there is an ON ERROR GOTO active)
1989
OR AB7
Check to see if the error flag is set
198A-198B
LD E,22HLD E,ERRNR1E 22
Load Register E with a ?NR ERROR code
198C-198D
Jump to 19A2H if the error flag is set (meaning there was no RESUME address)
198E-1990
 ↳ ENDCNJ
Otherwise, jump to 1DC1H (to END) because there was an error in the input phase
1991-1993
 ↳ DATSNE
LD HL,(40DAH)LD HL,(DATLIN)2A DA 40
Load Register Pair HL with the DATA line number (which is stored at 16602).
Note: 40DAH-40DBH holds DATA line number
1994-1996
LD (40A2H),HLLD (CURLIN),HL22 A2 40
Make the DATA line number into the CURRENT line number by saving it in Register Pair HL.
Note: 40A2H-40A3H holds the current BASIC line number
1997-1998
 ↳ SNERR
LD E,02HLD E,ERRSN1E 02
Load Register E with a ?SN ERROR code.
SN ERROR entry point
The next few instructions are all Z-80 tricks to allow Register E to hold its value while passing through them all.
1999-199B
 ↳ DV0ERR
LD BC,141EH01 1E 14
Z-80 Trick. JUMPing here will load BC but skip the reload of Register E as follows
199A-199B
LD E,14HLD E,ERRDV001 1E 14
Load Register E with a ?/0 ERROR code
199C-199E
 ↳ NFERR
LD BC,001EH01 1E 00
Z-80 Trick. JUMPing here will load BC but skip the reload of Register E as follows
199D-199E
LD E,00HLD E,ERRNF1E 00
Load Register E with a ?NF ERROR code.
?NF ERROR entry point
199F-19A1
 ↳ REERR
LD BC,241EHLD E,ERRRE01 1E 24
Z-80 Trick. JUMPing here will load BC but skip the reload of Register E as follows
19A0-19A1
LD E,24HLD E,ERRRE1E 24
Load Register E with a ?RW ERROR code.
?RW ERROR entry point
19A2-19A4
 ↳ ERROR
LD HL,(40A2H)LD HL,(CURLIN)2A A2 40
Load Register Pair HL with the value of the current BASIC line number which has the error. Note: 40A2H-40A3H holds the current BASIC line number
19A5-19A7
LD (40EAH),HLLD (ERRLIN),HL22 EA 40
Save the value of the current BASIC line number with the error into the RAM Location which tracks the ERL variable.
Note: 40EAH-40EBH holds Line number with error
19A8-19AA
LD (40ECH),HLLD (DOT),HL22 EC 40
Save the value of the current BASIC line number with the error into the RAM location used for EDIT or LIST
19AB-19AD
 ↳ ERRESM
LD BC,19B4HLD BC,ERRMOR01 B4 19
Load Register Pair BC with the return address of 19B4H which is the continuation address after a reinitialization
19AE-19B0
 ↳ ERESET
LD HL,(40E8H)LD HL,(SAVSTK)2A E8 40
Load Register Pair HL with the value of the STACK pointer (which is stored at 40E8H).
Note: 40E8H-40E9H holds STACK pointer pointer
19B1-19B3
Jump to 1B9AH to reinitialize the system variables, including reinitializing the STACK to the location now held in SAVSTK

19B4 – LEVEL II BASIC COMMAND MODE ERROR HANDLING – “ERRMOR”

19B4
 ↳ ERRMOR
POP BCC1
Discard the entry at the top of the STACK (which is the FNDFOR Stopper)
19B5
LD A,E7B
Load Register A with the value of the error code in Register E
19B6
LD C,E4B
Load Register C with the value of the error code in Register E, as we will need to restore it later as well
19B7-19B9
LD (409AH),ALD (ERRFLG),A32 9A 40
Save the value of the error code (from in Register A) into 409AH.
Note: 409AH holds the RESUME flag
19BA-19BC
LD HL,(40E6H)LD (SAVTXT),A2A E6 40
Load Register Pair HL with the value of the current BASIC program pointer (which is stored in 40E6H) (i.e., the address of the last byte executed in the current line).
Note: 40E6H-40E7H holds the temporary storage location
19BD-19BF
LD (40EEH),HLLD (ERRTXT),HL22 EE 40
Save the value of the current BASIC program pointer (which is stored in 40EEH) in Register Pair HL.
Note: 40EEH-40EFH is used by RESUME
19C0
EX DE,HLEB
Load Register Pair DE with the value of the current BASIC program pointer in Register Pair HL so that the SAVTXT is preserved in Register Pair DE
19C1-19C3
LD HL,(40EAH)LD HL,(ERRLIN)2A EA 40
Load Register Pair HL with the line number where the error occurred.
Note: 40EAH-40EBH holds Line number with error
19C4,19C4
LD A,H
AND L7C
Z-80 Trick to test if HL is zero or not – If H AND L are 0, then they are each zero
19C6
INC A3C
Bump the value of the combined current BASIC line number. If the line with the error was a direct command, this would have been FFFF, so the INC A will then set the ZERO flag if it was direct
19C7-19C8
If this was a direct command (and ZERO FLAG is set), then we do not want to modify OLDTXT or OLDLIN, so jump to 19D0H
19C9-19CB
LD (40F5H),HLLD (OLDLIN),HL22 F5 40
Let OLDLIN = ERRLIN by saving the value of the current BASIC line number in Register Pair HL to (40F5H).
Note: 40F5H-40F6H holds the last line number executed
19CC
EX DE,HLEB
Get bacK SAVTXT by swapping HL and DE
19CD-19CF
LD (40F7H),HLLD (OLDTXT),HL22 F7 40
Let OLDTXT = SAVTXT by saving the value of the current BASIC program pointer in Register Pair HL.
Note: 40F7H-40F8H holds Last byte executed
19D0-19D2
 ↳ NTMDCN
LD HL,(40F0H)LD HL,(ONELIN)2A F0 40
See if we are trapping errors by first loading Register Pair HL with the current ON ERROR address.
Note: 40F0H-40F1H is used by ON ERROR
19D3,19D4
LD A,H
OR L7C
Z-80 Trick to test if HL is zero or not – If H OR L are 0, then they are each zero
19D5
EX DE,HLEB
Load Register Pair DE with the ON ERROR address to go to if there’s an error which is currently in Register Pair HL
19D6-19D8
LD HL,40F2HLD HL,ONEFLG21 F2 40
Load Register Pair HL with the address of the error flag (which is 40F2H).
Note: 40F2H holds Error flag
19D9-19DA
Jump to 19E3H (to error out) if we aren’t otherwise trapping errors (because there isn’t an ON ERROR address)
19DB
AND (HL)A6
Since Register A is currently non-zero (or we would have jumped away in the prior instruction), combining that number with with the ONEFLG will result in either a 0 or non-zero based on whether whether the flag was already set
19DC-19DD
If the NZ FLAG is set, then it was already set, so JUMP to 19E3H (to error out)
19DE
DEC (HL)35
Force an error
19DF
EX DE,HLEB
Load Register Pair HL with the ON ERROR line address pointer held in Register Pair DE
19E0-19E2
Jump to 1D36H to make that happen

19E3 – LEVEL II BASIC COMMAND MODE ERROR HANDLING – “NOTRAP”

19E3
 ↳ NOTRAP
XOR AAF
Zero Register A
19E4
LD (HL),A77
Reset ONMEFLG. Clear the error override flag by save a zero (from Register A) as the current error flag at the location of the memory pointer in Register Pair HL
19E5
LD E,C59
Restore the error code (which was tucked away in Register C at 19B6H) into Register E
19E6-19E8
We need to position the video to the next line, so go display a carriage return on the video display if necessary
19E9-19EB
LD HL,18C9HLD HL,ERRTAB21 C9 18
Load Register Pair HL with the starting address for the table of error messages
19E6-19E8
Check to see if DOS should be handling this
19EF
LD D,A57
Since we are non-DOS, we continue by loading Register D with zero
19F0-19F1
LD A,3FHLD A,”?”3E 3F
Load Register A with a ?
19F2-19F4
GOSUB to 032AH to display the question mark in Register A
19F5
ADD HL,DE19
Add the value of the error code in Register Pair DE to the starting address of the table of error messages in Register Pair HL
19F6
LD A,(HL)7E
Load Register A with the first character of the error message at the location of the table pointer in Register Pair HL
19F7-19F9
GOSUB to 032AH to display the first character of the error message in Register A
19FA
Error codes are 2 characters so we need to set the second character of the error in Register A, 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.
19FB-19FD
GOSUB to 032AH to display the second character of the error message in Register A
19FE-1A00
LD HL,191DHLD HL,ERR21 1D 19
Load Register Pair HL with 191DH which is the starting address of the word “ERROR” message
1A01
PUSH HLE5
Save the starting address of the word “ERROR” (held in HL) to the STACK
1A02-1A04
LD HL,(40EAH)LD HL,(ERRLIN)2A EA 40
Load Register Pair HL with the value of the BASIC line number causing the error.
Note: 40EAH-40EBH holds Line number with error
1A05
EX (SP),HLE3
Exchange the value of the current BASIC line number in Register Pair HL with the starting address of the Level II BASIC ERROR message to the STACK
1A06
 ↳ ERRFIN
GOSUB to 28A7 to display the entire word ERROR on screen
1A09
POP HLE1
Get the value of the BASIC line number with the error from the STACK and put it in Register Pair HL
1A0A-1A0C
LD DE,FFFEHLD DE,0 + 6553411 FE FF
Load Register Pair DE with FFFEH.

This basically reserves the line number 65534 as a trigger for the next few steps
1A0D
Now we need to compare the BASIC line number causing the error (held in HL) with FFFEH (held in DE) so as to see if we are in the initialization routine, so we call the COMPARE DE:HL routine, which numerically compares DE and HL. Will not work for signed integers (except positive ones). Uses the A-register only. The result of the comparison is returned in the status Register as: CARRY SET=HL<DE; NO CARRY=HL>DE; NZ=Unequal; Z=Equal)
1A0E-1A10
Jump to 0674H if we are in the initialization routine because the error line number was FFFEH
1A11
LD A,H7C
Next, let’s see if we were in direct mode (i.e., entered from the command line). Load Register A with the MSB of the current BASIC line number in Register H
1A12
AND LA5
Combine the LSB of the current BASIC line number in Register L with the MSB of the current BASIC line number in Register A
1A13
INC A3C
Bump the combined value of the current BASIC line number in Register A to test to see if the line number is 00H (meaning command mode)
1A14-1A16
GOSUB to 0FA7H to display the current BASIC line number in Register Pair HL if Level II BASIC isn’t in the command mode
The original ROM has this note: The following code is for “LIST” command stopping and for returning from a failed “CVER” and to correct a direct GOSUB which does input.
1A17
LD A,0C1H3E C1
Z-80 Trick! If passing through from the above routine, then A will loaded and the instruction at 1A18 will be skipped.
1A18
 ↳ STPRDY
POP BCC1
Get the value from the STACK and put it in Register Pair BC
1A19-1A1BH
“READY”
Go set the current output device to the video display.
Re-entry into BASIC command mode entry point. (see 6CCH also)
1A1C-1A1EH
CALL 41ACHCALL PRGFINCD AC 41
1A1F-1A21
Go turn off the cassette recorder
1A22-1A24
Go display a carriage return if necessary
1A25-1A27
LD HL,1929HLD HL,REDDY21 29 19
Load Register Pair HL with the starting address of word “READY”
1A28-1A2A
 ↳ REPINI
Display the word “READY”
1A2B-1A2D
LD A,(409AH)LD A,(ERRFLG)3A 9A 40
Load Register A with the value of the current error code
1A2E-1A2F
SUB 02HD6 02
Check to see if the current error code is a ?SN ERROR code by subtracting 2 from the error code, resulting in a zero if its a SN ERROR and any other number if it isn’t
1A30-1A32
If the current error code is a SN ERROR code, then automatically enter EDIT mode on that line via this CALL

1A33 – MAIN LEVEL II BASIC INTERPRETER ENTRY – “MAIN”

If the jump here was from an AUTO call, (40E4H) will have the increment number, (40E1H) will be 0 if no AUTO and non-zero if AUTO, and (40E2H) will have the starting line number.
1A33-1A35
 ↳ MAIN
LD HL,FFFFH21 FF FF
Load Register Pair HL with the command mode line number
1A36-1A38
LD (40A2H),HLLD (CURLIN),HL22 A2 40
Set CURLIN up for direct command mode by saving FFFFH as the current BASIC line number.
Note: 40A2H-40A3H holds the current BASIC line number
1A39-1A3B
LD A,(40E1H)LD A,(AUTFLG)3A E1 40
Load Register A with the value of the AUTO flag. It will be zero if not in AUTO, and anything else if in AUTO
1A3C
OR AB7
Check to see if in the AUTO mode
1A3D-1A3E
Jump to 1A76H if not in the AUTO mode
1A3F-1A41
LD HL,(40E2H)LD HL,(AUTLIN)2A E2 40
We are in AUTO mode so load Register Pair HL with the current AUTO line number.
Note: 40E2H-40E3H holds Current BASIC line number
1A42
PUSH HLE5
Save the current AUTO line number (stored in Register Pair HL) to the STACK
1A43-1A45
Display the current AUTO line number on the screen via a GOSUB to 0FAFH to call the HL TO ASCII routine at 0FAFH (which converts the value in the HL Register Pair (assumed to be an integer) to ASCII
1A46
POP DED1
Get the current AUTO line number from the STACK and put it in Register Pair DE
1A47
PUSH DED5
Save the current AUTO line number in Register Pair DE to the STACK
1A48-1A4A
See if the line number already exists by CALLing 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
1A4B-1A4C
LD A,2AH3E 2A
Load Register A with a * (which will be code for a matching line number)
1A4D-1A4E
If the call to 1B2CH shows a matching line number was found in the BASIC program (by returning a C), skip the next instruction so that Register A keeps the *
1A4F-1A50
LD A,20HLD A,” “3E 20
If we are here, then there was no matching line number so we need to change the next character from a * (which is loaded into Register A which but is not applicable) to a SPACE
1A51-1A53
 ↳ AUTELN
Go display the character in Register A on the video display (which will be a “*” if a matching line number was found)
1A54-1A56
GOSUB to 0361H to read a line into the buffer
1A57
POP DED1
Get the current line number from the STACK and put it in Register Pair DE
1A58-1A59
Skip the next 3 opcodes if the BREAK key wasn’t pressed
1A5A
 ↳ AUTRES
XOR AAF
The BREAK key was pressed so we need to zero Register A to clear the AUTO increment flag
1A5B-1A5D
LD (40E1H),ALD (AUTFLG),A32 E1 40
Save the value in Register A as the current AUTO flag (to turn off AUTO)
1A5E-1A5F
Jump to the normal command mode “READY” routine at 1A19H

1A60H – Part of the AUTO command – “AUTGOD”

1A60-1A62
 ↳ AUTGOD
LD HL,(40E4H)LD HL,(AUTINC)2A E4 40
Load Register Pair HL with the value of the AUTO increment.
Note: 40E4H-40E5H holds AUTO increment
1A63
ADD HL,DE19
Since we didn’t BREAK out of the routine we need to keep processing the AUTO so we add the value of the AUTO line number in Register Pair DE with the AUTO increment value in Register Pair HL
1A64-1A65
If that addition to the next AUTO line number causes an overflow (by triggering the Carry flag), jump to 1A5AH which is the same as if the BREAK key was hit
1A66
PUSH DED5
Save the current AUTO line number in Register Pair DE to the STACK
1A67-1A69
LD DE,FFF9H11 F9 FF
Load Register Pair DE with the maximum BASIC line number of FFF9H (=65529).

There is an explanation at 1E5AH as to why 65529 is the highest possible line number (vs 65535 which would make more sense)
1A6A
Now we need to compare the adjusted AUTO line number (in HL) with the maximum BASIC line number (in DE), so we call the COMPARE DE:HL routine, which numerically compares DE and HL. Will not work for signed integers (except positive ones). Uses the A-register only. The result of the comparison is returned in the status Register as: CARRY SET=HL<DE; NO CARRY=HL>DE; NZ=Unequal; Z=Equal)
1A6B
POP DED1
Get the current AUTO line number from the STACK and put it in Register Pair DE
1A6C-1A6D
If the adjusted AUTO line number in Register Pair HL is too large, jump to 1A5AH which is the same as if the BREAK key was hit
1A6E-1A70
LD (40E2H),HLLD (AUTLIN),HL22 E2 40
Save the adjusted AUTO line number in Register Pair HL as the current AUTO line number.
Note: 40E2H-40E3H holds Current BASIC line number
1A71-1A72
OR 0FFHF6 FF
Set all non-zero condition codes by ORing Register A with FFH
1A73-1A75
Jump to the EDIT routine to save the current BASIC line

1A76H – Part of the AUTO command – “NTAUTO”

1A76-1A77
 ↳ NTAUTO
LD A,3EHLD A,”>”3E 3E
Load Register A with a > symbol (i.e., the prompt that follows READY)
1A78-1A7A
Go display the Level II BASIC prompt in Register A on the video display
1A7B-1A7D
GOSUB to 0361H to accept input. HL will hold the buffer address for that input
1A7E-1A80
Jump to 1A33H if the BREAK key was pressed
1A81
Since we need to bump the current input buffer pointer in Register Pair HL until it points to the first 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.
1A82
INC A3C
Bump the value of the character in Register A. This sets the status flags but saves the carry flag
1A83
DEC A3D
Decrement the value of the character in Register A so we can test for an end of statement
1A84-1A86
Jump to 1A33H if we have an end of statement or a blank statement
1A87
PUSH AFF5
Save the value in Register Pair AF to the STACK (including the carry flag)
1A88-1A8A
Call the ASCII TO INTEGER routine at 1E5AH which converts the ASCII string pointed to by HL to an integer deposited into DE. If the routine finds a non-numeric character, the conversion is stopped
1A8B
 ↳ BAKSP
DEC HL2B
Top of a loop. Decrement the value of the input buffer pointer in Register Pair HL so that it will point to the previous character
1A8C
LD A,(HL)7E
Fetch the character at the location of the input buffer pointer in Register Pair HL
1A8D-1A8E
CP 20HCP ” “FE 20
Check to see if the character at the location of the input buffer pointer in Register A is a SPACE
1A8F-1A90
Loop back to 1A8BH if the character at the location of the input buffer pointer in Register A is a space
1A91
INC HL23
Now HL points to the last non-space character, so we need to advance one — Bump the value of the input buffer pointer in Register Pair HL so that it points to the first character following a line number
1A92
LD A,(HL)7E
Load Register A with that character
1A93-1A94
CP 20HCP ” “FE 20
Check to see if the character at the location of the input buffer pointer in Register A is a space
1A95-1A97
If it is a space then skip it by a GOSUB to 09C9H which bumps the value of the input buffer pointer in Register Pair HL if necessary
1A98
 ↳ EDENT
PUSH DED5
Save the BASIC line number in Register Pair DE (which was converted from ASCII to an integer in 1A88H through a call to 1E5AH) to the STACK
1A99-1A9B
Tokenize the input via a GOSUB to 1BC0H. BC will equal the length of the encoded statement when its done
1A9C
POP DED1
Restore the BASIC line number (which is an integer) from the STACK
1A9D
POP AFF1
Get the carry flag (from the 1A81H character fetch) and put it in Register Pair AF to aid in determining if there even was a line number
1A9E-1AA0
LD (40E6H),HLLD (SAVTXT),HL22 E6 40
Save the input buffer pointer in Register Pair HL t the temporary storage area for use in RESUMEing a direct statement.
Note: 40E6H-40E7H holds the temporary storage location
1A99-1A9B
Check to see if DOS should be taking this over
1AA4-1AA6
If NC is set then this was a direct statement, so JUMP to 1D5AH as there wasn’t a line number with the input
1AA7
PUSH DED5
Save the BASIC line number (as an integer stored in Register Pair DE) to the STACK
1AA8
PUSH BCC5
Save the length (i.e., character count) of the tokenized input (stored in Register Pair BC) to the STACK
1AA9
XOR AAF
Zero Register A
1AAA-1AAC
LD (40DDH),ALD (BFKLFL),A32 DD 40
Save the value in Register A (which is a 00H) as the input flag.
Note: 40DDH holds the BUFFER KILLED flag
1AAD
Since we need find the first token, we have to bump the current input buffer pointer in Register Pair HL until it points to the next character by calling 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.
1AAE
OR AB7
Set the flags
1AAF
PUSH AFF5
Save the status flag to the STACK
1AB0
EX DE,HLEB
Load Register Pair HL with the integer value of the BASIC line number (held in Register Pair DE)
1AB1-1AB3
LD (40ECH),HLLD (DOT),HL22 EC 40
Save the integer value of the line number (held in Register Pair HL) to 40ECH.
Note: 40ECH-40EDH holds EDIT line number
1AB4
EX DE,HLEB
Exchange the value of the input buffer pointer in Register Pair DE with the integer value of the BASIC line number in Register Pair HL. This will fill DE with the line number for the search routine in the next instruction
1AB5-1AB7
Call 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
1AB8
 ↳ LEXIST
PUSH BCC5
Save the address of the line number in the BASIC program (if it exists) in Register Pair BC to the STACK
1AB9-1ABB
Delete the line since there wasn’t a matching line number in the BASIC program. The GOSUB to 2BE4H will move the closest line number up in memory to make room for another line
1ABC
 ↳ NODEL
POP DED1
REstore the pointer to the place to insert the line from the STACK into Register Pair DE
1ABD
POP AFF1
Restore the status from the 1AADH token scan into Register Pair AF to see if the line had anything on it
1ABE
PUSH DED5
Save the integer address of the BASIC line number where we need to start fixing links to the STACK
1ABF-1AC0
Jump to 1AE8H if there was a matching line number in the BASIC program; otherwise we move on and a new line has to be added as follows
1AC1
POP DED1
Clear the STACK from the start of the fix links
1AC2-1AC4
LD HL,(40F9H)LD HL,(VARTAB)2A F9 40
Load Register Pair HL with the end of the BASIC program pointer.
Note: 40F9H-40FAH holds the starting address of the simple variable storage area
1AC5
EX (SP),HLE3
Exchange the length of the tokenized input to the STACK with the end of the BASIC program pointer (VARTAB) in Register Pair HL
1AC6
POP BCC1
Get the end of the BASIC program pointer (VARTAB) from the STACK and put it in Register Pair BC
1AC7
ADD HL,BC09
Add the end of the BASIC program pointer in Register Pair BC to the value of the length of the tokenized input in Register Pair HL
1AC8
PUSH HLE5
Save the adjusted end of the BASIC program pointer (VARTAB) in Register Pair HL to the STACK
1AC9-1ACB
Go check to see if there is enough room in memory for the new BASIC line by GOSUB to 1955H
1ACC
POP HLE1
Get the new end of the BASIC program pointer from the STACK and put it in Register Pair HL
1ACD-1ACF
LD (40F9H),HLLD (VARTAB),HL22 F9 40
Save the new end of the BASIC program pointer in Register Pair HL.
Note: 40F9H-40FAH holds the starting address of the simple variable storage area
1AD0
EX DE,HLEB
Load Register Pair HL with the address of the BASIC line
1AD1
LD (HL),H74
Save the MSB of the address of the BASIC line in Register H
1AD2
POP DED1
Get the value of the BASIC line number from the STACK and put it in Register Pair DE
1AD3
PUSH HLE5
Save the value of the memory pointer in Register Pair HL to the STACK. This will be the place to start to fix links
1AD4
INC HL23
Bump the value of the memory pointer in Register Pair HL (which bumps it to the LSB of the line number entry). This is so that the ROM doesn’t think that this link is the end of the program
1AD5
INC HL23
Bump the value of the memory pointer in Register Pair HL (which bumps it to the MSB of the line number entry)
1AD6
LD (HL),E73
Save the LSB of the BASIC line number in Register E at the location of the memory pointer in Register Pair HL
1AD7
INC HL23
Bump the value of the line number memory pointer in Register Pair HL
1AD8
LD (HL),D72
Save the MSB of the BASIC line number in Register D at the location of the memory pointer in Register Pair HL. At this point DE should have the binary value for the new line number
1AD9
INC HL23
Bump the value of the BASIC line number in Register Pair HL
1ADA
EX DE,HLEB
Load Register Pair DE with first data byte address following the line number (held in Register Pair HL)
1ADB-1ADD
LD HL,(40A7H)LD HL,(BUFPNT)2A A7 40
Load Register Pair HL with the value of the tokenized input pointer
Note: 40A7H-40A8H holds Input Buffer pointer
1ADE
EX DE,HLEB
Exchange the value of the memory pointer in Register Pair DE with the value of the tokenized input pointer in Register Pair HL
1ADF
DEC DE1B
Decrement the value of the tokenized input buffer pointer in Register Pair DE
1AE0
DEC DE1B
Decrement the value of the tokenized input buffer pointer in Register Pair DE
1AE1
 ↳ MLOOPR
LD A,(DE)1A
Top of a loop to transfer the line. Load Register A with the value at the location of the tokenized input buffer pointer in Register Pair DE
1AE2
LD (HL),A77
Save the value in Register A at the location of the memory pointer in Register Pair HL
1AE3
INC HL23
Bump the store address (held in Register Pair HL)
1AE4
INC DE13
Bump the fetch address (held in Register Pair DE)
1AE5
OR AB7
Check to see if the character in Register A is an end of the line character
1AE6-1AE7
Since a 0 will mark the end of the line, so long as NZ is set we need to keep looping, so loop backup until the whole of the new BASIC line has been stored in memory
1AE8
 ↳ FINI
POP DED1
Get the address of the line in the program table from the STACK and put it in Register Pair DE. This would be the start of link fixing area
1AE9-1AEB
Go fix/update line pointers for all lines following the new line
1AEC-1AEA
Check to see if DOS should be handling something
1AEF-1AF1
Do a clear, set up the STACK, and update all the BASIC line pointers
1AF2-1AF4
Check to see if DOS should be handling something
1AF5-1AF7
Go get the input again

1AF8-1B0F – LINE POINTERS ROUTINE – “LINKER”

This routine fixes the line pointers in a BASIC program. This is useful, for instance for a renumber program which has to move BASIC program lines from one location in memory to an other, which means that the line pointers would no longer be valid. This routine will fix them. Registers A, HL and DE are used.
1AF8-1AFA
 ↳ LINKER
LD HL,(40A4H)LD HL,(TXTTAB)2A A4 40
Load Register Pair HL with the start of the BASIC program pointer (called the PST).
Note: 40A4H-40A5H holds the starting address of BASIC program text also known as the PROGRAM STATEMENT TABLE (PST)
1AFB
EX DE,HLEB
Move the PST address to DE
A note in the original rom source code says that CHEAD goes through the program storage area in RAM and fixes up all the links. The end of each line is found by searching for a zero. The double zero link is used to detect the end of the program.
1AFC,1AFD
 ↳ CHEAD
LD H,D
LD L,E62
LET HL = DE
1AFE
LD A,(HL)7E
Load Register A with the value at the location of the memory pointer in Register Pair HL so that we can see if we are at the end of a chain
1AFF
INC HL23
Bump the value of the memory pointer in Register Pair HL
1B00
OR (HL)B6
Since the first 2 bytes of each line contains the address of the next line, a 0000H would signify the end byte. With this, check to see if the character at the location of the memory pointer in Register Pair HL is an end of the BASIC program character
1B01
RET ZC8
Return if done
If we are here, we did not get a 00 end of program, so we continue
1B02
INC HL23
We need HL to be the start of the text. Since HL is the ‘beginning of statment pointer’, we need to skip over the 3rd and 4th bytes, so bump the value of the memory pointer in Register Pair HL
1B03
INC HL23
Bump the value of the memory pointer in Register Pair HL
1B04
INC HL23
Bump the value of the memory pointer in Register Pair HL
1B05
XOR AAF
Zero Register A and clear the flags
1B06
 ↳ CZLOOP
CP (HL)BE
Top of a loop. Check to see if the character at the location of the memory pointer in Register HL is an end of the BASIC line character
1B07
INC HL23
Bump the value of the memory pointer in Register Pair HL
1B08-1B09
Loop until the end of the BASIC line character is found
1B0A
EX DE,HLEB
Exchange the starting address of the current BASIC line in Register Pair DE with the starting address of the next BASIC line in Register Pair HL
1B0B
LD (HL),E73
Save the LSB of the next BASIC line’s starting address in Register E at the location of the memory pointer in Register Pair HL
1B0C
INC HL23
Bump the value of the memory pointer in Register Pair HL
1B0D
LD (HL),D72
Save the MSB of the next BASIC line’s starting address in Register D at the location of the memory pointer in Register Pair HL
1B0E-1B0F
Loop until the end of the program has been found

1B10-1B48 – EVALUATE LINE NUMBERS – “SCNLINE”

This is called by LIST and DELETE. It converts the starting and ending linbers (X-Y) to binary and saves the ending line number on the STACK. Then the code locates the program table address for the starting line. The routine leaves the address of the starting line in BC and the ending line number in the STACK.

According to the original ROM source, SCNLIN scans a line range of the form of #-# or #- or -# or blank, and then finds the first line in the range.
1B10-1B12
 ↳ SCNLIN
LD DE,0000H11 00 00
Load Register Pair DE (which will be the list found value) with zero
1B13
PUSH DED5
Save the initial assumption of start-of-list to the STACK
1B14-1B15
If we are finished (i.e., there aren’t any line numbers to be evaluated), and the Z FLAG is therefore set, then jump to 1B1FH so list it all
1B16
POP DED1
Get the line number from the STACK and put it in Register Pair DE
1B17-1B19
Go evaluate the line number at the location of the current BASIC program pointer in Register Pair HL and return with the line number’s binary value in Register Pair DE
1B1A
PUSH DED5
Save the first line number’s value (stored in Register Pair DE) to the STACK
1B1B-1B1C
Jump if there isn’t a second line number to be evaluated given (i.e, LIST 3000-)
1B1D-1B1E
RST 08H CEHCF CE
If we are here, there is a second line number. That that would have to be preceded by a at the location of the current BASIC program pointer in Register Pair HL, call the COMPARE SYMBOL routine which comparess the symbol in the input string pointed to by HL Register to the value in the location following the RST 08 call. If there is a match, control is returned to address of the RST 08 instruction 2 with the next symbol in in Register A 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)
1B1F-1B21
 ↳ ALLLST
LD DE,FFFAH11 FA FF
Load Register Pair DE with the maximum end of range of FFAFH as the second line number, as FFAH is the last permitted line number. Note: FFFFH means that the BASIC instruction being interpreted was entered from the command line instead of being part of a program
1B22-1B24
Go evaluate the second line number at the location of the current BASIC program pointer in Register Pair HL and return with the line number’s binary value in Register Pair DE. Will return with Z flag set if it was a number
1B25-1B27
Go to the Level II BASIC error routine and display a ?SN ERROR message if the data which followed the token wasn’t a line number
1B28
 ↳ SNGLIN
EX DE,HLEB
Set HL to be the FINAL line number by Loading Register Pair HL with the value of the second line number in Register Pair DE and load Register Pair DE with the value of the current BASIC program pointer in Register Pair HL
1B29
POP DED1
Get the value of the FIRST line number from the STACK and put it in Register Pair DE
1B2A
 ↳ FNDLN1
EX (SP),HLE3
Exchange the return address to the STACK with the value of the second line number in Register Pair HL
1B2B
PUSH HLE5
Save the value of the return address in Register Pair HL to the STACK so we can properly exit later

1B2CH – SEARCH FOR A LINE NUMBER – “FNDLIN”

According to the original ROM source, the FNDLIN routine searches the program text for the line whose line number is held in Register Pair DE. DE is preserved. There are three possible returns:
  • If there is no line in the program which is greater than the one sought, then Z/NC and HL=BC.
  • If the line which was searched for was actually found, Z and BC=the link field in the line and HL=the link field in the next line.
  • If the line was not found, but there is still more lines in the program, NZ/NC, BC=the line in the porgram greater than the one searched for, and HL = the link field in the next line.
This routine searches a BASIC program for a BASIC line with a line number matching the value in the DE Register Pair. To use this routine, the required line number must be placed in the DE Register Pair. When a match is found, this routine sets the carry flag; the BC Register Pair points to the start of the required line, and the HL Register points to the start of the next line. HL, AF and BC are used.

This is the the SEARCH FOR LINE NUMBER routine at 1B2C, which searches the Program Statement Table (PST) for a BASIC statement with the line number specified in the DE Register Pair. All registers are used. The exit conditions are:
  • C/Z=Line Found and BC is the starting address of the line in the PST and HL is the address following;
  • NC/Z=Line not found or too large and HL/BC will have the address of the next available PST location; and
  • NC/NZ=Line not found and BC=Address of the first line number greater than the one specified and HL will be the address of the following line.
1B2C-1B2E
 ↳ FNDLIN
LD HL,(40A4H)LD HL,(TXTTAB)2A A4 40
Load Register Pair HL with the value of 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)
1B2F,1B30
 ↳ LOOP
LD B,H
LD C,L44
LET BC = HL so that BC will also hold the address of the current line in the PST
1B31
LD A,(HL)7E
Load Register A with the first byte of the word pointer (held in Register Pair HL)
1B32
INC HL23
Bump the value of the memory pointer in Register Pair HL to the MSB of the address of the next line
1B33
OR (HL)B6
Combine the first byte of the word pointer with the second byte of the word pointer with the result in Register A and set the status flags
1B34
DEC HL2B
Restore HL to the start of the current line
1B35
RET ZC8
Return if this is the end of PST (=the end of the BASIC program)
1B36
INC HL23
It’s not the end so we need HL to point the line number for the current line which means it must advance by 2. Bump the value of the memory pointer in Register Pair HL
1B37
INC HL23
Bump the value of the memory pointer in Register Pair HL
1B38
LD A,(HL)7E
Load Register A with the LSB of the current BASIC line number at the location of the memory pointer in Register Pair HL
1B39
INC HL23
Bump the value of the memory pointer in Register Pair HL to point to the MSB of the current BASIC line number
1B3A
LD H,(HL)66
Load Register H with the MSB of the current BASIC line number at the location of the memory pointer in Register Pair HL
1B3B
LD L,A6F
Load Register L with the LSB of the current BASIC line number in Register A. HL should now hold the line number in the PST
1B3C
Now we need to compare the value of the current BASIC line number in HL and the first line number (in DE), so we call the COMPARE DE:HL routine, which numerically compares DE and HL. Will not work for signed integers (except positive ones). Uses the A-register only. The result of the comparison is returned in the status Register as: CARRY SET=HL<DE; NO CARRY=HL>DE; NZ=Unequal; Z=Equal)
1B3D
LD H,B60
Next we need to set HL to the start of the line before the current one, and that is held in BC
1B3E
LD L,C69
Load Register L with the LSB of the memory pointer in Register C
1B3F
LD A,(HL)7E
Load Register A with the value at the location of the memory pointer in Register Pair HL
1B40
INC HL23
Bump the value of the memory pointer in Register Pair HL
1B41
LD H,(HL)66
Load Register H with the MSB of the next BASIC line pointer at the location of the memory pointer in Register Pair HL
1B42
LD L,A6F
Load Register L with the LSB of the next BASIC line pointer in Register A to form the address of the next line in HL
1B43
CCF3F
Complement the value of the Carry flag. The carry will be set if the current line number is < the value in DE. This will clear the Carry flag.
1B44
RET ZC8
Return if the first line number in Register Pair DE is the same as the current BASIC line number. The line numbers match, so exit C, Z, BC=address of the current line, and HL=address of the next line
1B45
CCF3F
We have no match, so complement (reverse) the Carry flag and exit
1B46
RET NCD0
if the first line number in Register Pair DE is less than the current BASIC line number. BC will be the address of the current line and HL will be the address of the next line
1B47-1B48
Loop until the location of the line number has been found in the BASIC program

1B49-1B5C – LEVEL II BASIC NEW ROUTINE – “SCRATH”

1B49
 ↳ SCRATH
RET NZC0
Go to the Level II BASIC error routine and display a ?SN ERROR message if there is any input following the NEW token
1B4A-1B4C
Call the CLEAR SCREEN routine at 01C9 (which cleanrts the screen, changes to 64 characters, and homes the screen)
1B4D-1B4F
 ↳ SCRTCH
LD HL,(40A4H)LD HL,(TXTTAB)2A A4 40
Load Register Pair HL with the start of the PST (the start of the BASIC program).
Note: 40A4H-40A5H holds the starting address of BASIC program text also known as the PROGRAM STATEMENT TABLE (PST)
1B50-1B52
GOSUB to the TROFF routine at 1DF8H (which just loads A with a zero for TROFF, and puts that 0 into 411BH)
1B53-1B55
LD (40E1H),ALD (AUTFLG),A32 E1 40
Reset the AUTO flag by putting a zero (which is in A due to the GOSUB to the TROFF statement in the above instruction) into 40E1H
1B56
LD (HL),A77
We need to initialize the PST, and the way to do that is to zero the first two bytes so . save a zero at the location of the memory pointer in Register Pair HL
1B57
INC HL23
. bump the value of the memory pointer in Register Pair HL
1B58
LD (HL),A77
. and save a zero at the location of the memory pointer in Register Pair HL
1B59
INC HL23
Bump the value of the memory pointer in Register Pair HL
1B5A-1B5C
LD (40F9H),HLLD (VARTAB),HL22 F9 40
Save the value in Register Pair HL at 40F9H to initialize the start of the variable list table as the end of the PST.
Note: 40F9H-40FAH holds the starting address of the simple variable storage area

1B5D-1BB2 – LEVEL II BASIC RUN ROUTINE – “RUNC”

This routine does a lot of variable resets and other things that are common to NEW as well, so NEW just does the special NEW stuff and than passes right through to here to reset the rest.

To use a ROM call to RUN a BASIC program, starting with its first line, execute the following instructions:
   LD HL,1D1EH
   PUSH HL
   JP 1B5DH.
1B5D-1B5F
 ↳ RUNC
LD HL,(40A4H)LD HL,(TXTTAB)2A A4 40
Load Register Pair HL with the PST (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)
1B60
DEC HL2B
Decrement the value in Register Pair HL to backspace

1B61H – Subroutine which initializes a lot of stuff – “CLEARC”

Initialize he variable and array space by resetting ARYTAB (which is the end of the the simple variable spac) and STREND (which is the end of the array storage). It then falls into STKINI which resets the STACK. HL is preserved.
1B61-1B63
 ↳ CLEARC
LD (40DFH),HLLD (TEMP),HL22 DF 40
Save the adjusted value in Register Pair HL into 40DFH.
Note: 40DFH-40E0H is used by DOS
1B64-1B65
LD B,1AH06 1A
Load Register B with the number of variable names to be initialized (which is 26)
1B66-1B68
LD HL,4101HLD HL,DEFTBL21 01 41
Load Register Pair HL with the starting address of the variable declaration table (which is 4101H).
Note: 4101H-411AH holds Variable Declaration Table
1B69-1B6A
 ↳ LOPDFT
LD (HL),04H36 04
Top of a DJNZ loop. Set the variable at the location of the memory pointer in Register Pair HL to a single precision variable
1B6B
INC HL23
Bump the value of the memory pointer in Register Pair HL to the next variable
1B6C-1B6D
Loop until all 26 variables have been set to single precision
1B6E
XOR AAF
Zero Register A
1B6F-1B71
LD (40F2H),ALD (ONEFLG),A32 F2 40
Save the value in Register A (which is a zero) as the current value of the RESUME flag to say that there is no error for RESUME to handle.
Note: 40F2H holds Error flag
1B72
LD L,A6F
Zero Register L
1B73
LD H,A67
Zero Register H
1B74-1B76
LD (40F0H),HLLD (ONELIN),HL22 F0 40
Save a zero (held in Register Pair HL) as the current ON ERROR address.
Note: 40F0H-40F1H is used by ON ERROR
1B77-1B79
LD (40F7H),HLLD (OLDTXT),HL22 F7 40
Save a zero (held in Register Pair HL) as the current BREAK, STOP, or END address.
Note: 40F7H-40F8H holds Last byte executed
1B7A-1B7C
LD HL,(40B1H)LD HL,(MEMSIZ)2A B1 40
Load Register Pair HL with the top of the memory pointer held in 40B1H.
Note: 40B1H-40B2H holds MEMORY SIZE? pointer
1B7D-1B7F
LD (40D6H),HLLD (FRETOP),HL22 D6 40
Save the top of memory pointer (held in Register Pair HL) as the next available address in the string space pointer.
Note: 40D6H-40D7H holds the next available location in string space pointer
1B80-1B82
Go do a RESTORE (which will mess with DE and HL)
1B83-1B85
LD HL,(40F9H)LD HL,(VARTAB)2A F9 40
Load Register Pair HL with the end of the BASIC program pointer.
Note: 40F9H-40FAH holds the starting address of the simple variable storage area
1B86-1B88
LD (40FBH),HLLD (ARYTAB),HL22 FB 40
Save the value in Register Pair HL as the new simple variables pointer. 40FBH-40FCH holds the starting address of the BASIC array variable storage area
1B89-1B8B
LD (40FDH),HLLD (STREND),HL22 FD 40
Save the value in Register Pair HL as the new array variables pointer.
Note: 40FDH-40FEH holds Free memory pointer
1B80-1B82
Go do a RESTORE (which will mess with DE and HL)

1B8F – Subroutine which initializes a lot of stuff – “STKINI”

According to the notes in the original ROM source code, this routine resets the STACK point, which will also destroy all GOSUBs and FORs. String temporaries are freed, SUBFLG is reset, CONT is forbidden, and a dummy entry is put on the STACK, so that FNDFOR will always find a NON-“FOR” entry at the bottom of the STACK. A will be reset to 0 and Register Pair DE is preserved.
1B8F
 ↳ STKINI
POP BCC1
Get the return address from the STACK because we are about to change the STACK pointer
1B90-1B92
LD HL,(40A0H)LD HL,(STKTOP)2A A0 40
Load Register Pair HL with the start of string space pointer (which is also the end of RAM). 40A0H-40A1H holds the start of string space pointer
1B93
DEC HL2B
Decrement the value of the memory pointer in Register Pair HL
1B94
DEC HL2B
Decrement the value of the memory pointer in Register Pair HL (so now HL has the start of the string space pointer – 2) so that there is now room for a FNDFOR stopper value to be put on the STACK
1B95-1B97
LD (40E8H),HLLD (SAVSTK),HL22 E8 40
Save the string space pointer – 2 (in Register Pair HL) as the STACK pointer
Note: 40E8H-40E9H holds STACK pointer pointer
1B98
INC HL23
Bump the value of the memory pointer in Register Pair HL
1B99
INC HL23
Bump the value of the memory pointer in Register Pair HL so it is back to being the start of the string space pointer
1B9A
 ↳ STKERR
LD SP,HLF9
Initialize the STACK by loading the STACK pointer with the start of the string space pointer (held in Register Pair HL)
1B9B-1B9D
LD HL,40B5HLD HL,TEMPST21 B5 40
Load Register Pair HL with the start of the string work area (which is 40B5H).
Note: 40B5H-40D2H holds Temporary string work area
1B9E-1BA0
LD (40B3H),HLLD (TEMPPT),HL22 B3 40
Initialize the string temporaries by saving the value in Register Pair HL as the next available location in the string work area pointer.
Note: 40B3H-40B4H holds the next available location in the temporary string work area pointer
1BA1-1BA3
GOSUB 038BH to set the current output device to the video display
1BA4-1BA6
Go turn off the cassette recorder
1BA7
XOR AAF
Zero Register A
1BA8
LD H,A67
Zero Register H
1BA9
LD L,A6F
Zero Register L
1BAA-1BAC
 ↳ WASDIR
LD (40DCH),ALD (SUBFLG),A32 DC 40
Clear the FOR statement flag.
Note: 40DCH holds FOR flag
1BAD
PUSH HLE5
Save the value in Register Pair HL to the STACK to deal with FOR and GOSUB
1BAE
PUSH BCC5
Save the value in Register Pair BC (which is the RETURN ADDRESS) back on the STACK
1BAF-1BB1
 ↳ GTMPRT
LD HL,(40DFH)LD HL,(TEMP)2A DF 40
Restore Register Pair HL so it is preserved
1BB2
RETC9
RETurn to CALLer

1BB3-1BBF – KEYBOARD INPUT ROUTINE – “QINLIN”

This is the last of the general purpose input routines. This routine functions identically to the 0361H routine with the exception that it prints a ? on the screen (like INPUT does with BASIC) before allowing input from the keyboard.
1BB3-1BB4
 ↳ QINLIN
LD A,3FHLD A,”?”3E 3F
Load Register A with a ?
1BB5-1BB7
Go display the ? (stored in Register A) on the video display
1BB8-1BB9
LD A,20H3E 20
Load Register A with a SPACE
1BBA-1BBC
Go display the space in Register A on the video display
1BBD-1BBF
Jump to the keyboard input routine at 0361H. Note that this skips the “CRUNCHING” of tokens

1BC0-1C8F – TOKENIZE INPUT ROUTINE – “CRUNCH”

The original ROM source code says that this routine translates all “reserved words” into single bytes with the MSB on. This saves space and time by allowing for table dispatch during execution, and, as such, all statements appear together in the ; reserved word list in the same ; order they appear in in STMDSP.
1BC0
 ↳ CRUNCH
XOR AAF
Zero Register A
1BC1-1BC3
LD (40B0H),ALD (DORES),A32 B0 40
Save the value in Register A as the current value of the tokenization flag.
Note: 40B0H holds the temporary storage location
1BC4
LD C,A4F
Zero Register C
1BC5
EX DE,HLEB
Load Register Pair DE with the address of the first character after the line number (as stored in Register Pair HL)
1BC6-1BC8
LD HL,(40A7H)LD HL,(BUFPNT)2A A7 40
Load Register Pair HL with the starting address of the input buffer.
Note: 40A7H-40A8H holds Input Buffer pointer
1BC9
DEC HL2B
We need to backspace twice so … decrement the value of the input buffer pointer in Register Pair HL
1BCA
DEC HL2B
… and again decrement the value of the input buffer pointer in Register Pair HL
1BCB
EX DE,HLEB
Exchange the string address – 2 from HL into DE, and the current input string address from DE into HL
1BCC
 ↳ KLOOP
LD A,(HL)7E
Load Register A with the character at the current location in the buffer (in Register Pair HL)
1BCD-1BCE
CP 20HFE 20
Check to see if that character in Register A is a SPACE that we would want to keep
1BCF-1BD1
If that character is a SPACE we would want to keep, Jump to 1C5BH to “STUFF” it into the destination line
1BD2
LD B,A47
Copy the current character into Register B
1BD3-1BD4
CP 22HFE 22
Check to see if the current character is a
1BD5-1BD7
If the current character is a , Jump to 1C77H to will move the entire field between the quotes into the a code string
1BD8
OR AB7
Now we want to check to see if the current character is an END OF LINE, so we need to set up the status flags
1BD9-1BDB
If the current character is an END OF LINE then we are done, so jump to 1C7DH
1BDC-1BDE
LD A,(40B0H)LD A,(DORES)3A B0 40
Load Register A with the value of the tokenization flag for DATA.
Note: 40B0H holds the temporary storage location
1BDF
OR AB7
Check to see if a DATA statement is being processed
1BE0
LD A,(HL)7E
Re-fetch the current character (from the memory location of the input buffer pointer in Register Pair HL) and put it into Register A
1BE1-1BE3
Jump to 1C5BH if a DATA statement is being processed, as we don’t want to crunch that
1BE4-1BE5
CP 3FHFE 3F
Check to see if the character in Register A is a ? (meaning a PRINT statement)
1BE6-1BE7
LD A,B2HLD A,$PRINT3E B2
Load Register A with a PRINT token
1BE8-1BEA
If we have a ? then make believe it is a “PRINT” token, and jump to 1C5BH to STUFF it into the destination line
1BEB
LD A,(HL)7E
Re-fetch the current character (from the memory location of the input buffer pointer in Register Pair HL) and put it into Register A
1BEC-1BED
CP 30HFE 30
Since the crunching routine is slow, these next instructions look for characters that will not need crunching. First, check to see if the character in Register A is less than a zero character (alpha numeric)
1BEE-1BEF
Jump to 1BF5H if the character in Register A is less than a zero character, meaning it is not a digit or letter
1BF0-1BF1
CP 3CHFE 3C
Next, check to see if the character in Register A is less than < character (which is a test to see if it is 09, :, ;, <, constant or special character
1BF2-1BF4
Jump to 1C5BH if the character in Register A is 09, :, ;, <, constant or special character
1BF5
 ↳ MUSTCR
PUSH DED5
Save the value of the input buffer pointer in Register Pair DE to the STACK
1BF6-1BF8
LD DE,164FHLD D,RESLST-111 4F 16
Load Register Pair DE with the starting address of the reserved words list, minus 1 (since the first instruction in the LOPSKP routine is to INC the value)
1BF9
PUSH BCC5
Save the character count (held in Register Pair BC) to the STACK
1BFA-1BFC
LD BC,1C3DHLD BC,NOTRES01 3D 1C
Load Register Pair BC with a return address after matching the reserved word list
1BFD
PUSH BCC5
Save the return address in Register Pair BC to the STACK
1BFE-1BFF
LD B,7FH06 7F
Load Register B with a value to initialize the reserved words counter
1C00
LD A,(HL)7E
Load Register A with the character at the location of the input buffer pointer in Register Pair HL
1C01-1C02
CP 61HCP “A”+20HFE 61
Check to see if the character in Register A is lower-case
1C03-1C04
Jump to 1C0CH if the character in Register A isn’t lowercase
1C05-1C06
CP 7BHCP “Z”+21HFE 7B
Check to see if the character in Register A is within the lower-case range
1C07-1C08
Jump down 2 instructions to 1C0CH if the character in Register A isn’t lowercase
1C09-1C0A
AND 5FHAND 0101 1111E6 5F
Covert the lowercase character in Register A to upper-case
1C0B
LD (HL),A77
Replace the current character in the input buffer (tracked by Register Pair HL) with the adjusted character (held in Register A)
1C0C
 ↳ TRYAGA
LD C,(HL)4E
Load Register C with the character at the location of the input buffer pointer in Register Pair HL
1C0D
EX DE,HLEB
Exchange DE and HL so that DE will now hold the input buffer pointer (TXTPTR) and HL will hold the reserved words list pointer (“RESLST”)
1C0E
 ↳ LOPSKP
INC HL23
Bump the value of the reserved words list pointer to the next reserved word and put that in Register Pair HL
1C0F
OR (HL)B6
We need to find the start of a reserved word which is done by searching the list for a character with its MSB bit on. So first, check to see if bit 7 of the character at the location of the reserved words list pointer in Register Pair HL is set
1C10-1C12
Jump to 1C0EH if the character at the location of the reserved words list pointer in Register Pair HL doesn’t have bit 7 set
If we are here, the the character in the reserved word list had its MSB on, and is a reserved word.
1C13
INC B04
Bump the reserved words counter being tracked in Register B
1C14
LD A,(HL)7E
Load Register A with the character at the location of the reserved words list pointer in Register Pair HL
1C15-1C16
AND 7FHAND 0111 1111E6 7F
Reset the MSB (i.e., Bit 7 aka the Sign Bit) of the character in Register A
1C17
RET ZC8
If that set the Z FLAG then we are at the end of ther reserved word list, so, if so RETurn to CALLer
1C18
CP CB9
Check to see if the character in Register C is the same as the character at the location of the reserved words list pointer in Register A
1C19-1C1A
Jump to 1C0EH if the characters don’t match
1C1B
EX DE,HLEB
Exchange the value of the reserved words list pointer (“RESLST”) in Register Pair HL with the value of the input buffer pointer (“TXTPTR”) in Register Pair DE
1C1C
PUSH HLE5
Save the value of the input buffer pointer to the STACK in case it turns out that this isn’t a match after all
1C1D
 ↳ LOPPSI
INC DE13
Top of a loop. Bump the value of the reserved words list pointer (held in Register Pair DE) to the next character of the reserved word being checked
1C1E
LD A,(DE)1A
Load Register A with the character at the location of the reserved words list pointer in Register Pair DE
1C1F
OR AB7
Check to see if Bit 7 of the character in Register A is set, meaning we just hit a different reserved word
1C20-1C22
If Bit 7 of that character was set, and we are at a new reserved word, then we have finished matching, so jump to 1C39H
If we are here then we are in the middle of checking against the reserved word list, and we are still in the middle of a reserved word that might be a potential match.
1C23
LD C,A4F
Load Register C with the current reserved word list character (held in Register A)
1C24
LD A,B78
Load Register A with the value of the reserved words counter in Register B
The GOTO reserved word is the only one which allows for spaces to be inside it, so . if we find that we have GO so far, we will call the RST 10H to strip out any intevening spaces before continuing.
1C25-1C26
CP 8DHCP $GOTOFE 8D
Check to see if the current reserved word being checked is GOTO
1C27-1C28
Skip the next 2 instructions if the current reserved word being checked isn’t GOTO
1C29
Since we need to skip spaces we need to bump the current input buffer pointer in Register Pair HL 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.
1C2A
DEC HL2B
Decrement the value of the input buffer pointer in Register Pair HL because the next instruction increments it
1C2B
 ↳ NTGOTO
INC HL23
Bump the value of the input buffer pointer in Register Pair HL to point to the next character
1C2C
LD A,(HL)7E
Load Register A with the next character at the location of the input buffer pointer in Register Pair HL
1C2D-1C2E
CP 61HCP “A”+20HFE 61
Check to see if the character in Register A is lower-case
1C2F-1C30
If the character in Register A isn’t lowercase, skip the next instruction
1C31-1C32
AND 5FHAND 0101 1111E6 5F
AND the character in Register A against 0101 1111 to get rid of the lowercase bit and make it uppercase
1C33
 ↳ NOTLW1
CP CB9
Check to see if the character in Register A (the input element) matches the character in Register C (the next letter in the reserved word list)
1C34-1C35
If that character is ALSO a match, loop back to 1C1DH to keep checking that reserved word
1C36
POP HLE1
If we are here, then the matching process failed, so we need to get back the original input buffer pointer into HL and move on to the next reserved word
1C37-1C38
Jump back to 1C0CH to process the next reserved word against the character at the input buffer
1C39
 ↳ FOUND
LD C,B48
Load Register C with the value of the reserved words counter in Register B
1C3A
POP AFF1
Clear the old TXTPTR text pointer from the STACK (disposing of the HL push from 1C1CH)
1C3B
EX DE,HLEB
Exchange the TXTPTR and RESPTR because the NOTRES routine starts with the same instruction flipping them back
1C3C
RETC9
RETurn to CALLer (which, by the way, will just pass through, the the RET was reprogrammed to be the next instruction)

1C3D – Part of the tokeninzing routine – “NOTRES”

1C3D
 ↳ NOTRES
EX DE,HLEB
Exchange the reserved words list pointer in Register Pair HL with the input buffer pointer in Register Pair DE
1C3E
LD A,C79
Load Register A with the value of the reserved words counter in Register C
1C3F
POP BCC1
Restore the character count into Register Pair BC
1C40
POP DED1
Restore the “STUFF” pointer into Register Pair DE
1C41
EX DE,HLEB
Exchange DE and HL so that DE will now hold the input buffer pointer (TXTPTR) and HL will hold the “STUFF” pointer
The ELSE token needs to be treated differently as it is a reserved word which is followed by a reserved word. To deal with this, we put in a fake colon!
1C42-1C43
CP 95HFE 95
Check to see if the token in Register A is an ELSE token
1C44-1C45
LD (HL),3AHLD (HL),”:”36 3A
Save a colon at the “STUFF” pointer location (held in Register Pair HL)
1C46-1C47
If the token in Register A isn’t an ELSE token, skip the next two instructions
1C48
INC C0C
Bump the value of the crunched character counter
1C49
INC HL23
Bump the value of the “STUFF” pointer (held in Register Pair HL)
The token needs to be treated differently as it doesn’t require a colon. To deal with this, we put in a fake colon!
1C4A-1C4B
 ↳ CKSNGQ
CP 0FBHCP SNGQTKFE FB
Next we check to see if the token in Register A is a token
1C4C-1C4D
Jump to 1C5AH if the token in Register A isn’t a
1C4E-1C4F
LD (HL),3AHLD (HL),”:”36 3A
Save a “:” at the “STUFF” pointer (held in Register Pair HL)
1C50
INC HL23
Bump the value of the “STUFF” pointer (held in Register Pair HL) because we just inserted a :
1C51-1C52
LD B,93HLD B,$REM06 93
Load Register B with a REM token
1C53
LD (HL),B70
Save the REM token in Register B at the location of the input buffer pointer in Register Pair HL
1C54
INC HL23
Bump the value of the “STUFF” pointer (held in Register Pair HL) because we just inserted a REM token
1C55
EX DE,HLEB
Exchange DE and HL so that DE will now hold the “STUFF” pointer and HL will hold the input buffer pointer
1C56
INC C0C
Bump the character counter in Register C
1C57
INC C0C
Bump the character counter in Register C
1C58-1C59
Jump to 1C77H to move all the rest of the text of the line to the “STUFF” buffer

1C5A – Part of the tokeninzing routine – “NTSNGT” and “STUFFH”

1C5A
 ↳ NTSNGT
EX DE,HLEB
Exchange DE and HL so that DE will now hold the “STUFF” pointer
1C5B
 ↳ STUFFH
INC HL23
Bump the value of the input buffer pointer in Register Pair HL
1C5C
LD (DE),A12
Save the value of the token in Register A at the location of the input buffer pointer in Register Pair DE
1C5D
INC DE13
Bump the value of the “STUFF” pointer (held in Register Pair DE)
1C5E
INC C0C
Bump the value of the crunched character count
1C5F-1C60
SUB 3AHD6 3A
Check to see if the character in Register A is a : to flag a multi-statement line
1C61-1C62
If we found a “:” then skip the next two instructions
1C63-1C64
CP 4EHCP $DATAFE 4E
Check to see if the token in Register A is a DATA token
1C65-1C66
If the token in Register A isn’t a DATA token then skip the next instruction
1C67-1C69
 ↳ COLIS
LD (40B0H),ALD (DORES),A32 B0 40
Save the value in Register A as the tokenization flag for DATA.
Note: 40B0H holds the temporary storage location
1C6A-1C6B
 ↳ NODATT
SUB 59HD6 59
Check to see if the token in Register A is a REM token
1C6C-1C6E
Jump to 1BCCH if the token in Register A isn’t a REM token
1C6F
LD B,A47
Load Register B with a zero, since processing a REM doesn’t end with a :, only an END OF LINE (i.e., 0)
1C70
 ↳ STR1
LD A,(HL)7E
Top of a loop. Load Register A with the character at the location of the input buffer pointer in Register Pair HL
1C71
OR AB7
Check to see if the character in Register A is an END OF LINE delimiter of 0
1C72-1C73
Jump out of this loop to 1C7DH if the character in Register A is an END OF LINE delimeter
1C74
CP BB8
Check to see if the character in Register B matches the character in Register A
1C75-1C76
If they match, then we are completely done with gobbling the whole rest of line without checking, so Jump to 1C5BH
1C77
 ↳ STRNG
INC HL23
Bump the value of the input buffer pointer in Register Pair HL
1C78
LD (DE),A12
Save the character in Register A to the location of the “STUFF” pointer (in Register Pair DE)
1C79
INC C0C
Bump the value of the crunched character count
1C7A
INC DE13
Bump the value of the “STUFF” pointer (held in Register Pair DE)
1C7B-1C7C
Loop until an END OF LINE delimiter or a ending quote is found

1C7D – Part of the tokeninzing routine – Jumped here when an EOL is found – “CRDONE”

1C7D-1C7F
 ↳ CRDONE
LD HL,0005H21 05 00
We are going to need to add 5 bytes to the tokenized character count
1C80
LD B,H44
Load Register B with zero
1C81
ADD HL,BC09
Add 5 to the length of the tokenized character count so far
1C82,1C83
LD B,H
LD C,L44
Let BC = HL
1C84-1C86
LD HL,(40A7H)LD HL,(BUFPNT)2A A7 40
Load Register Pair HL with the start address of the input buffer.
Note: 40A7H-40A8H holds Input Buffer pointer
1C87
DEC HL2B
Decrement the value of the input buffer pointer in Register Pair HL
1C88
DEC HL2B
Decrement the value of the input buffer pointer in Register Pair HL
1C89
DEC HL2B
Decrement the value of the input buffer pointer in Register Pair HL
1C8A
LD (DE),A12
We need THREE zeroes at the end, so . zero the location of the input buffer pointer in Register Pair DE to denote END OF LINE
1C8B
INC DE13
Bump the value of the input buffer pointer in Register Pair DE
1C8C
LD (DE),A12
Zero the next two locations of the input buffer pointer in Register Pair DE to denote no further link (since this was a direct statement)
1C8D
INC DE13
Bump the value of the input buffer pointer in Register Pair DE
1C8E
LD (DE),A12
Zero the location of the input buffer pointer in Register Pair DE
1C8F
RETC9
RETURN t o CALLer since we are done with the CRUNCHing

1C90-1C95 – RST 0018H CODE – “DCOMPR”

The RST 18H code is located here. Unsigned compare (HL-DE), which numerically compares DE and HL. Will not work for signed integers (except positive ones). Uses the A-register only. The result of the comparison is returned in the status Register as: CARRY SET=HL<DE; NO CARRY=HL>DE; NZ=Unequal; Z=Equal).
1C90
 ↳ DCOMPR
LD A,H7C
Load Register A with the MSB of the value in Register H
1C91
SUB D92
Subtract the value of the MSB of the value in Register D from the MSB of the value in Register A
1C92
RET NZC0
Return if the MSB of the value in Register D doesn’t equal the MSB of the value in Register H
1C93
LD A,L7D
Load Register A with the LSB of the value in Register L
1C94
SUB E93
Subtract the LSB of the value in Register E from the LSB of the value in Register A
1C95
RETC9
RETurn to CALLer

1C96-1CA0 – RST 0008H CODE – “SYNCHR”

The RST 8H code is located here. This is the COMPARE SYMBOL routine which comparess the symbol in the input string pointed to by HL Register to the value in the location following the RST 08 call. If there is a match, control is returned to address of the RST 08 instruction 2 with the next symbol in in Register A 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).
1C96
 ↳ SYNCHR
LD A,(HL)7E
Load Register A with the character at the location of the current BASIC program pointer in Register Pair HL
1C97
EX (SP),HLE3
Save the return address of the routine by exchanging the value of the current BASIC program pointer in Register Pair HL with the value of the return address to the STACK
1C98
CP (HL)BE
Check to see if the character at the location following the RST 08H call (stored in Register Pair HL) is the same as the character in Register A
1C99
INC HL23
Bump the value of the return address in Register Pair HL
1C9A
EX (SP),HLE3
Restore the return address (meaning the RST 08H plus 1 byte plus 1 byte) to the STACK pointer
1C9B-1C9D
Jump to the RST 0010H code if the characters match
1C9E-1C90
If they don’t match, jump to the ?SN ERROR routine

1CA1-1D1D – Level II BASIC FOR ROUTINE – “FOR”

According to the comments to the actual ROM source code, the FOR entry in the STACK has 16 bytes, as follows:
  • 1 Byte – The FOR token
  • 2 Bytes – A pointer to the loop’s variable
  • 1 Byte – A byte reflecting the sign of the increment
  • 4 Bytes – The value of the STEP
  • 4 Bytes – The upper limit of the loop
  • 2 Bytes – The line number of the FOR statement
  • 2 Bytes – A text pointo into the FOR statement
1CA1-1CA2
 ↳ FOR
LD A,64H3E 64
Load Register A with the value for the FOR flag
1CA3-1CA5
LD (40DCH),ALD (SUBFLG),A32 DC 40
Save the value in Register A as the current value of the FOR flag.
Note: 40DCH holds FOR flag
1CA6-1CA8
GOSUB to the “LET” routine at 1F21H to read the variable, assign it the correct initial value, and store a pointer to the RAM variable location “TEMP”
1CA9
EX (SP),HLE3
Exchange the value of the current BASIC program pointer in Register Pair HL with the value to the STACK
1CAA-1CAC
Go check to see if there is a FOR statement to the STACK already using the same variable name (called the index)
1CAD
POP DED1
Get the current BASIC program pointer from the STACK (which should be the TO token and put it in Register Pair DE
1CAE-1CAF
If there isn’t a matching FOR statement to the STACK, skip the next 3 instructions (which are preparing for a NEXT WITHOUT FOR error) and jump to 1CB5H. If one is found, on exit HL will equal the starting address of the FOR push
1CB0
ADD HL,BC09
Add the value in Register Pair BC (which is the offset to the end of the STACK frame) to the value in Register Pair HL. In the case where we had a matching FOR, we elimiate the matchin entry as well as evertying after it by doing this addition. After this addition, we should be pointing to the end of the first FOR frame push
1CB1
LD SP,HLF9
Remove all the rest by resetting the STACK pointer to end of the first FOR frame push. This also frees up the STACK space and prepares for a NF error
1CB2-1CB4
LD (40E8H),HLLD (SAVSTK),HL22 E8 40
Save the value in Register Pair HL as the STACK pointer, get ready for a NF error.
Note: 40E8H-40E9H holds STACK pointer pointer
1CB5
 ↳ NOTOL
EX DE,HLEB
Exchange Register Pairs DE and HL, so that HL now points to the current BASIC program pointer and DE will be the STACK pointer address
1CB6-1CB7
LD C,08H0E 08
Load Register C with the 1/2 the amount of space (i.e. 16 bytes) needed for a FOR entry
1CB8-1CBA
Go check to see if there is enough memory (i.e., 16 bytes) left by calling 1963H (which is the MEMORY CHECK ROUTINE)
1CBB
PUSH HLE5
Save the value of the current BASIC program pointer (which is the code string address before the TO) in Register Pair HL to the STACK
1CBC-1CBE
Keep scanning the current BASIC program (pointer is in Register Pair HL) until it points to the end of the BASIC statement. HL should then point to the END OF LINE terminator
1CBF
EX (SP),HLE3
Exchange the adjusted value of the current BASIC program pointer in Register Pair HL with the value of the current BASIC program pointer to the STACK
1CC0
PUSH HLE5
Save the value of the current BASIC program pointer in Register Pair HL to the STACK. This should be pointing to the TO token
1CC1-1CC3
LD HL,(40A2H)LD HL,(CURLIN)2A A2 40
Load Register Pair HL with the value (in binary) of the current BASIC line number.
Note: 40A2H-40A3H holds the current BASIC line number
1CC4
EX (SP),HLE3
Exchange the value of the current BASIC line number in Register Pair HL with the value of the current BASIC program pointer to the STACK. Once again, HL will point to the current location in the BASIC program
1CC5-1CC6
RST 08H BDHRST 08H TOCF
Since the character at the location of the current BASIC program pointer in Register Pair HL must be TO token (BDH) so call the COMPARE SYMBOL routine which comparess the symbol in the input string pointed to by HL Register to the value in the location following the RST 08 call. If there is a match, control is returned to address of the RST 08 instruction 2 with the next symbol in in Register A 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)
1CC7
We need to check the value of the current number type flag, so we call the TEST DATA MODE routine at RST 20H.
NOTE: The RST 20H routine determines the type of the current value in ACCumulator and returns a combination of STATUS flags and unique numeric values in the A Register according to the data mode flag (40AFH). The results are returned as follows:
  • Integer = NZ/C/M/E and A is -1
  • String = Z/C/P/E and A is 0
  • Single Precision = NZ/C/P/O and A is 1
  • and Double Precision is NZ/NC/P/E and A is 5.
1CC8-1CCA
If that test shows we have a STRING, go to the Level II BASIC error routine and display a TM ERROR message
1CCB-1CCD
If that test shows we have a DOUBLE PRECISION number, go display a ?TM ERROR message
1CCE
PUSH AFF5
We have an integer, so let’s keep going and save the resulting integer value in Register Pair AF (the type flags) to the STACK
1CCF-1CD1
Go evaluate the expression at the location of the current BASIC program pointer in Register Pair HL (which should be the TO side) and return with the result in ACCumulator
1CD2
POP AFF1
Restore the index type flags from the from the STACK and put it in Register Pair AF
1CD3
PUSH HLE5
Save the value of the current BASIC program pointer (which is the code string after the TO pointer) in Register Pair HL to the STACK
1CD4-1CD6
If the flag is positive, then we have a SINGLE PRECISION “FOR” loop
1CD7-1CD9
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)
1CDA
EX (SP),HLE3
Exchange the integer value in Register Pair HL from that conversion (the current TO value) with the value of the current BASIC program pointer to the STACK
1CDB-1CCD
LD DE,0001H11 01 00
Load Register Pair DE with a default STEP value of 1
1CDE
LD A,(HL)7E
Fetch the next character from the current BASIC program line (pointer in Register Pair HL) into Register A
1CDF-1CE0
CP 0CCHCP STEPTKFE CC
Check to see if the character in Register A is a STEP token
1CE1-1CE3
So now we have a STEP token so we have to get the step value into DE. To do this, GOSUB to 2B01H to evaluate the expression at the location of the current BASIC program pointer in Register Pair HL and return with the integer value in Register Pair DE if the character in Register A is a STEP token
1CE4
PUSH DED5
Save the STEP index value (in Register Pair DE) to the STACK
1CE5
PUSH HLE5
Save the current BASIC program pointer (in Register Pair HL) to the STACK
1CE6
EX DE,HLEB
Exchange the STEP value (from DE) with the value of the current BASIC program pointer (in Register Pair HL). Now HL will have the value so the next call can test its size
1CE7-1CE9
GOSUB to 099EH to get the sign of the STEP value into A. It will be A=+1 if positive and A=-1 if negative
1CEA-1CEB
Jump down to 1D0EH to finish the entry by putting the sign of the STEP and the dummy entries into the STACK

1CECH – Part of the Level II BASIC FOR ROUTINE – “SNGFOR”

1CEC-1CEE
 ↳ SNGFOR
Need the TO value to be integer so GOSUB to the CONVERT TO SINGLE PRECISION routine at 0AB1H (which converts the contents of ACCumulator from integer or double precision into single precision)
1CEF-1CF1
Call 09BF which loads the SINGLE PRECISION value in ACCumulator (the TO value in integer) into Register Pair BC/DE
1CF2
POP HLE1
Get the value of the current BASIC program pointer from the STACK (which should be the end of the TO expression) and put it in Register Pair HL
1CF3,1CF4
PUSH BC
PUSH DEC5
Save all 4 bytes of the TO value to the STACK
1CF5-1CF7
LD BC,8100H01 00 81
Load Register Pair BC with the exponent and the MSB for a single precision constant
1CF8
LD D,C51
Zero the NMSB for the single precision constant in Register D
1CF9
LD E,D5A
Zero the LSB for the single precision constant in Register E. Register Pairs BC and DE now hold a single precision constant equal to one
1CFA
LD A,(HL)7E
Load Register A with the character at the location of the current BASIC program pointer in Register Pair HL
1CFB-1CFC
CP 0CCHFE CC
Check to see if the character in Register A is a STEP token
1CFD-1CFE
LD A,01H3E 01
Load Register A with the default STEP value (in this case, 1)
1CFF-1D00
Skip over the next unstructions by jumping down to 1D0FH if the character at the location of the current BASIC program pointer in Register A isn’t a STEP token
1D01-1D03
Go evaluate the expression at the location of the current BASIC program pointer (which is the STEP instruction and return with the result in ACCumulator
1D04
PUSH HLE5
Save the value of the current BASIC program pointer in Register Pair HL to the STACK
1D05-1D07
Convert the STEP value to single precision by calling the CONVERT TO SINGLE PRECISION routine at 0AB1H (which converts the contents of ACCumulator from integer or double precision into single precision)
1D08-1D0A
Load the STEP value into BC/DE by calling 09BF which loads the SINGLE PRECISION value in ACCumulator into Register Pair BC/DE
1D0B-1D0D
Go get the sign for the STEP increment value (held in ACCumulator) into Register A. A will be +1 if positive, and -1 if negative
1D0E
 ↳ STPSGN
POP HLE1
Get the value of the current BASIC program pointer from the STACK and put it in Register Pair HL
1D0F
 ↳ ONEON
PUSH BCC5
Save the exponent and the NMSB for the single precision value in Register Pair BC to the STACK
1D10
PUSH DED5
Save the NMSB and the LSB for the single precision value in Register Pair DE to the STACK
1D11
LD C,A4F
Load Register C with the sign value for the STEP value in Register A
1D12
We need to check the value of the current number type flag, so we call the TEST DATA MODE routine at RST 20H.
NOTE: The RST 20H routine determines the type of the current value in ACCumulator and returns a combination of STATUS flags and unique numeric values in the A Register according to the data mode flag (40AFH). The results are returned as follows:
  • Integer = NZ/C/M/E and A is -1
  • String = Z/C/P/E and A is 0
  • Single Precision = NZ/C/P/O and A is 1
  • and Double Precision is NZ/NC/P/E and A is 5.
1D13
LD B,A47
Load Register B with type-adjusted and sign value of the number type flag test in Register A
1D14
PUSH BCC5
Save the type-adjusted and sign value in Register Pair BC to the STACK
1D15
PUSH HLE5
Save the value of the current BASIC program pointer in Register Pair HL to the STACK
1D16-1D18
LD HL,(40DFH)LD HL,(TEMP)2A DF 40
Load Register B with a FOR x=y token
1D19
EX (SP),HLE3
Put the pointer to the variable onto the STACK and restore the pointer to the BASIC program line being examined into HL
1D1A-1D1B
 ↳ NXTCON
LD B,81HLD B,$FOR06 81
Load Register B with the FOR token
1D1C
PUSH BCC5
Save the FOR and token and the sign of the STEP increment BC to the STACK
1D1D
INC SP33
Since a token only takes one byte of space, bump the value of the STACK pointer to leave a one byte gap. By continuing onward, we will wind up continuing the execution of the code string

1D1E-1D77 – LEVEL II BASIC INTERPRETER – “NEWSTT”

According to the original ROM source code, this is where we go for a new statement. The character on the BASIC program line pointed to by Register Pair HL should be either a “:” or an END OF LINE. The address of this routine is left on the STACK so that when a statement is executed and done, the RETurn comes back here.
1D1E-1D20
 ↳ NEWSTT
Go check to see if a key has been pressed
1D21
OR AB7
Set the flags. If a key was hit, test for SHIFT+@
1D22-1D24
GOSUB to 1DA0H if the key pressed was a SHIFT+@. This will save the address of the last byte executed in the current line
1D25-1D27
LD (40E6H),HLLD (SAVTXT),HL22 E6 40
Save the value of the current BASIC program pointer. This would be used by CONT, INPUT, CLEAR, and PRINT USING
Note: 40E6H-40E7H holds the temporary storage location
1D28-1D2B
LD (40E8H),SPLD (SAVSTK),SPED 73 E8 40
Save the value of the STACK pointer.
Note: 40E8H-40E9H holds STACK pointer pointer
1D2C
LD A,(HL)7E
Load Register A with the value at the location of the current BASIC program pointer in Register Pair HL (which SHOULD be the character which terminated the last statement)
1D2D-1D2E
CP 3AHFE 3A
Check to see if the character in Register A is a :
1D2F-1D30
If the character is a :, jump to 1D5AH since that means this is a brand new statement on this line
1D31
OR AB7
There wasn’t a colon, so the only valid thing we can find now is an END OF LINE character (i.e., a NULL). This will check to see if the character in Register A is an end of the BASIC line character
1D32-1D34
Go to the Level II BASIC error routine and display a ?SN ERROR message if the character in Register A isn’t an end of the BASIC line character since COLON and NULL are the only two valid characters
1D35
INC HL23
So now we know that we have another line number to check, so bump the value of the current BASIC program pointer in Register Pair HL
1D36
 ↳ GONE4
LD A,(HL)7E
Load Register A with the LSB of the next BASIC line pointer at the location of the current BASIC program pointer in Register Pair HL
1D37
INC HL23
Bump the value of the current BASIC program pointer in Register Pair HL
1D38
OR (HL)B6
Check to see if the next BASIC line pointer is equal to zero
1D39-1D3B
If that OR matched, then we had two NULL NULL, meaning END OF PROGRAM, so JUMP to 197EH since we are at the end of the BASIC program
1D3C
INC HL23
If we are here, it was not the end of the BASIC program so we need to bump the value of the current BASIC program pointer in Register Pair HL
1D3D
LD E,(HL)5E
Load Register E with the LSB of the BASIC line number at the location of the current BASIC program pointer in Register Pair HL
1D3E
INC HL23
Bump the value of the current BASIC program pointer in Register Pair HL
1D3F
LD D,(HL)56
Load Register D with the MSB of the BASIC line number at the location of the current BASIC program pointer in Register Pair HL
1D40
EX DE,HLEB
Exchange the value of the BASIC line number in Register Pair DE with the value of the current BASIC program pointer in Register Pair HL. HL will now hold the line number
1D41-1D43
LD (40A2H),HLLD (CURLIN),HL22 A2 40
Save the value of the BASIC line number in Register Pair HL into the memory location devoted to tracking that sort of thing
Honor a TRON by showing the line number if it is in effect.
1D44-1D46
LD A,(411BH)LD A,(TRCFLG)3A 1B 41
Before we move on, we need to honor a TRON, if its in effect so first we load Register A with the value of the TRON flag.
Note: 411BH holds TRON/TROFF flag
1D47
OR AB7
Check for TRON. NZ means that TRACE is on
1D48-1D49
Jump out of this routine to 1D59H if TROFF
1D4A
PUSH DED5
If we are here, we have to process the code to show the “<nnnn>” of a TRON. First, save the value of the current BASIC program pointer in Register Pair DE to the STACK
1D4B-1D4C
LD A,3CH3E 3C
Load Register A with a <
1D4D-1D4F
Go display the < that preceeds the line number in TRON output
1D50-1D52
Call the HL TO ASCII routine at 0FAFH (which converts the value in the HL Register Pair (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
1D53-1D54
LD A,3EH3E 3E
Load Register A with a >
1D55-1D57
Go display the > that follows the line number in TRON output
1D58
POP DED1
Get the value of the current BASIC program pointer from the STACK and put it in Register Pair DE
That finishes the TRON routine where we display <nnnn> if it is in effect.
1D59
 ↳ NOTTRC
EX DE,HLEB
Load Register Pair HL with the value of the current BASIC program pointer in Register Pair DE
1D5A
 ↳ GONE
We need to get the next token. We bump the current input buffer pointer in Register Pair HL 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.
1D5B-1D5D
LD DE,1D1EHLD DE,NEWSTT11 1E 1D
Load Register Pair DE with the return address to go to after executing one verb
1D5E
PUSH DED5
Save that return address in Register Pair DE to the STACK
1D5F
 ↳ GONE3
RET ZC8
Return (back to 1D1EH) if the character at the location of the current BASIC program pointer (in Register Pair HL) is an END OF LINE delimiter
1D60-1D61
 ↳ GONE2
SUB 80HSUB $ENDD6 80
Check to see if the character at the location of the current BASIC program pointer in Register A is a token. This is accomplished because tokens range from 80H-FBH so this would give an index of the current token. This is looking for an ON GOTO and ON GOSUB
1D62-1D64
If the C FLAG is set, then this must be a LET so jump to 1F21H
1D65-1D66
 ↳ NUMCMD
CP 3CHFE 3C
Check to see if the token in Register A is below the TAB( token
1D67-1D69
Jump out of here to 2AE7H if the token in Register A is greater than or equal to a TAB( token, meaning TAB( to MID$(
1D6A
RLCA07
Multiply the token value in Register A by two. This doubles the remainder of the routine address offset
1D6B
LD C,A4F
Load the adjusted token value in Register C from Register A
1D6C-1D6D
LD B,00H06 00
Load Register B with zero so that BC now holds “00” and (2 x the token)
1D6E
EX DE,HLEB
Load Register Pair DE with the value of the current BASIC program pointer in Register Pair HL
1D6F-1D71
LD HL,1822HLD HL,STMDSP21 22 18
Load Register Pair HL with the list of BASIC execution addresses (called the Statement Dispatch Table in the original ROM source code)
1D72
ADD HL,BC09
Add the value of the token offset in Register Pair BC to the starting address of the list of BASIC execution addresses in Register Pair HL
1D73
LD C,(HL)4E
Load Register C with the LSB of the execution address at the location of the memory pointer in Register Pair HL
1D74
INC HL23
Bump the value of the memory pointer in Register Pair HL
1D75
LD B,(HL)46
Load Register B with the MSB of the execution address at the location of the memory pointer in Register Pair HL
1D76
PUSH BCC5
Save the value of the execution address in Register Pair BC to the STACK
1D77
EX DE,HLEB
Load Register Pair HL with the value of the current BASIC program pointer in Register Pair DE (i.e., restore the code string address)

1D78-1D90 – RST 0010H CODE – “CHRGTR”

The RST 10H code is located here. This is the EXAMINE NEXT SYMBOL routine which loads the next character from the string pointed to by the HL Register set into the A-register and clears the CARRY flag if it is alphabetic, or sets it if is alphanumeric. Blanks and control codes 09 and OB are ignored causing the following character to be loaded and tested. The HL Register will be incremented before loading any character therfore on the first call the HL Register should contain the string address minus one. The string must be terminated by a byte of zeros).
1D78
 ↳ CHRGTR
INC HL23
Bump the value of the current BASIC program pointer in Register Pair HL to the next character
1D79
 ↳ CHRGT2
LD A,(HL)7E
Load Register A with the value of the character at the location of the current BASIC program pointer in Register Pair HL
1D7A-1D7B
CP 3AHFE 3A
Check to see if the character at the location of the current BASIC program pointer in Register A is greater than or equal to a :
1D7C
RET NCD0
Return if the character at the location of the current BASIC program pointer in Register A is greater than or equal to a : (meaning :, ;, < . Y, Z
1D7D-1D7E
 ↳ CHRCON
CP 20HCP ” “FE 20
Check to see if the character at the location of the current BASIC program pointer in Register A is a SPACE
1D7F-1D81
Loop if the character at the location of the current BASIC program pointer in Register A is a SPACE
1D82-1D83
CP 0BHFE 0B
Check to see if the character at the location of the current BASIC program pointer in Register A is greater than or equal to 0BH (meaning it is not a control code)
1D84-1D85
Jump if the character at the location of the current BASIC program pointer in Register A if greater than or equal to 0BH
1D86-1D87
CP 09HFE 09
Check to see if the character at the location of the current BASIC program pointer in Register A is greater than or equal to 09H (meaning a line feed or tab)
1D88-1D8A
Loop back up to get the next character if if the character at the location of the current BASIC program pointer in Register A is greater than or equal to 09H
1D8B-1D8C
 ↳ NOTLFT
CP 30HCP “0”FE 30
Check to see if the character at the location of the current BASIC program pointer in Register A is greater than or equal to a zero character
1D8D
CCF3F
Set the carry flag if that ASCII character is numeric (i.e., greater than or equal to 30H)
1D8E
INC A3C
Clear the CARRY FLAG if it is not numeric (i.e., it is less than 30)
1D8F
DEC A3D
Set the status flags (except for the CARRY FLAG) according to the character at hand
1D90
RETC9
RETurn to CALLer

1D91-1D9A – LEVEL II BASIC RESTORE ROUTINE – “RESTORE”

1D91
 ↳ RESTORE
EX DE,HLEB
Save the contents of HL by loading its contents into DE
1D92-1D94
LD HL,(40A4H)LD HL,(TXTTAB)2A A4 40
Load Register Pair 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)
1D95
DEC HL2B
Backspace from the start of the BASIC program pointer, so that it is now TXTTAB – 1
1D96-1D98
 ↳ RESFIN
LD (40FFH),HLLD (DATPTR),HL22 FF 40
Save the start of the program pointer -1 into 40FFH.
Note: 40FFH-4100H holds READ pointer
1D99
EX DE,HLEB
Restore the poiner to the current character on the BASIC program line being examined back into Register Pair HL
1D9A
RETC9
RETurn to CALLer

1D9B-1DAD – SCAN KEYBOARD ROUTINE – “ISCNTC”

1D9B-1D9D
 ↳ ISCNTC
Go scan the keyboard
1D9E
OR AB7
Check to see if a key was pressed
1D9F
RET ZC8
Return if a key wasn’t pressed
1DA0-1DA1
 ↳ CNTCCN
CP 60HFE 60
Check to see if the key pressed in Register A is a SHIFT+@
1DA2-1DA4
If you got a SHIFT+@ we now need to honor that by waiting for yet another key to be pressed
1DA5-1DA7
LD (4099H),ALD (CHARC),A32 99 40
Save the key pressed in Register A as the value of the last key pressed.
Note: 4099H holds the Last key pressed
1DA8
DEC A3D
Check to see if the BREAK key was pressed

1DA9-1DAD – STOP ROUTINE – “STOP”

1DA9
 ↳ STOP
RET NZC0
Return if the BREAK key wasn’t pressed.
This is the STOP entry point
1DAA
INC A3C
Readjust the value of the key pressed in Register A
1DAB-1DAD
Jump into the applicable portion of the code that processes END

1DAE-1DE3 – LEVEL II BASIC END ROUTINE – “END”

1DAE
 ↳ END

RET NZC0
Return and display a ?SN ERROR message if there is anything following the END token -or- if we did not get a BREAK
1DAF
PUSH AFF5
Save all the condition codes and the value in Register Pair AF to the STACK
1DB0-1DB2
Jump into DOS to see if it wants to do anything here
1DB3
POP AFF1
Restore the condition codes and Register A
1DB4-1DB6
 ↳ CONSTP
LD (40E6H),HLLD (SAVTXT),HL22 E6 40
Save the value of the current BASIC program pointer in Register Pair HL. This will be for a CONTinue.
Note: 40E6H-40E7H holds the temporary storage location
1DB7-1DB9
LD HL,40B5HLD HL,TEMPST21 B5 40
We next want to reset the String temp pointer, so load Register Pair HL with the starting address of the temporary string work area.
Note: 40B5H-40D2H holds Temporary string work area
1DBA-1DBC
LD (40B3H),HLLD (TEMPPT),HL22 B3 40
Save the value in Register Pair HL as the new temporary string work area pointer.
Note: 40B3H-40B4H holds the next available location in the temporary string work area pointer
1DBD-1DBFH
LD HL,FFF6H21 F6 FF
Z-80 space saving trick. If passing down from the prior instruction, the line is run and the next OR FFH line is NOT!
1DBE-1DBF
 ↳ STPEND
OR FFHF6 FF
Force A to be non-zero so as to force the printing of the BREAK message
1DC0
POP BCC1
Clears out the NEWSTT return address from the STACK, as we won’t be returning
1DC1-1DC3
 ↳ ENDCON
LD HL,(40A2H)LD HL,(CURLIN)2A A2 40
Load Register Pair HL with the value of the current BASIC line number in binary.
Note: 40A2H-40A3H holds the current BASIC line number
1DC4
PUSH HLE5
Save the value of the current BASIC line number (in binary) in Register Pair HL to the STACK
1DC5
PUSH AFF5
Save the value in Register Pair AF to the STACK. A will be 0 if it is an END and A will be a 1 if it is a STOP. If A is 0 then it should NOT print the BREAK message
1DC6
LD A,L7D
These 3 instructions test to see if we are in command mode by testing for an uninitialized line (meaning a line number of FFFF). First, load Register A with the LSB of the current BASIC line number in Register L
1DC7
AND HA4
Combine the MSB of the current BASIC line number in Register H with the LSB of the current BASIC line number in Register A
1DC8
INC A3C
Bump the combined value of the current BASIC line number in Register A
1DC9-1DCA
Increasing FFFF by 1 would flip the Z flag on, meaning there was no line number. If there was no line number, skip the next 3 instructions and go to 1DD4H
If we are here, then there was a line number, so we need to set some locations to enable a CONT command to work.
1DCB-1DCD
LD (40F5H),HLLD (OLDLIN),HL22 F5 40
Save the line number we ended on in Register Pair HL.
Note: 40F5H-40F6H holds the last line number executed
1DCE-1DD0
LD HL,(40E6H)LD HL,(SAVTXT)2A E6 40
Load Register Pair HL with the value of the current BASIC program pointer .
Note: 40E6H-40E7H holds the temporary storage location
1DD1-1DD3
LD (40F7H),HLLD (OLDTXT),HL22 F7 40
Save the value of the current BASIC program pointer in Register Pair HL.
Note: 40F7H-40F8H holds Last byte executed
1DD4-1DD6
 ↳ DIRIS
Go set the current output device to the video display
1DD7-1DD9
Go display a carriage return if necessary
1DDA
POP AFF1
Restore A so we can see if this is an END (where A=0) or a STOP (where A=1)
1DDB-1DDD
LD HL,1930HLD HL,BRKTXT21 30 19
Load Register Pair HL with the starting address of the BREAK message
1DDE-1DE0
Jump to 1A06H if it was a BREAK or a STOP that halted program execution
1DE1-1DE3
At this point it was either due to an END statement or an error while in command mode so jump to 1A18H (note: This uses a Z-80 trick as 1A18H is in the middle of a 2 Opcode instruction starting at 1A17H)

1DE4-1DF6 – LEVEL II BASIC CONT ROUTINE – “CONT”

1DE4-1DE6
 ↳ CONT
LD HL,(40F7H)LD HL,(OLDTXT)2A F7 40
Load Register Pair HL with the value of the continuation address. A stored text pointer of 0000 is set up by STKINI if there is nothing to CONTinue
Note: 40F7H-40F8H holds Last byte executed
1DE7
LD A,H7C
Load Register A with the MSB of the continuation address in Register H
1DE8
OR LB5
Combine the LSB of the continuation address in Register L with the MSB of the continuation address in Register A. If there was nothing in HL, this would trigger a Z flag. There should be nothing in the HL flag if there was a STOP, END, hitting ENTER in response to an INPUT request, and hitting BREAK
1DE9-1DEA
 ↳ RESERR
LD E,20HLD E,ERRCN1E 20
Load Register E with a ?CN ERROR code
1DEB-1DED
Go to the ?CN ERROR routine if CONT isn't possible (meaning the line number was zero)
1DEE
EX DE,HLEB
If we are here, there was a valid return line number, so load Register Pair DE with the value of the continuation line number in Register Pair HL
1DEF-1DF1
LD HL,(40F5H)LD HL,(OLDLIN)2A F5 40
Load HL with the value of the last BASIC line number executed.
Note: 40F5H-40F6H holds the last line number executed
1DF2-1DF4
LD (40A2H),HLLD (CURLIN),HL22 A2 40
Save the last line number executed in Register Pair HL (which had the error) as the current BASIC line number.
Note: 40A2H-40A3H holds the current BASIC line number
1DF5
EX DE,HLEB
Swap so that HL will be the address of the continuation line
1DF6
RETC9
Return (continue running but from the CONT line number)

1DF7-1DF8 - TRON ENTRY POINT - "TON"

Turns TRON feature on. Causes line numbers for each BASIC statement executed to be displayed. Uses Register A.
1DF7-1DF8
 ↳ TON
LD A,0AFH3E AF
Load Register A with a nonzero value. Note that this value was chosen simply because this is also a Z-80 trick. If 1DF8 is jumped into, that is XOR A which will set A to zero instead of this value

1DF8 - TROFF ENTRY POINT - "TOFF"

1DF8
 ↳ TOFF
XOR AAF
Z-80 trick. This command is only visible if jumped to. This zeros Register A
The following code is common to both TRON and TROFF.
1DF9-1DFB
LD (411BH),ALD (TRCFLG),A32 1B 41
Save the value in Register A as the current value of the TRON/TROFF flag.
Note: 411BH holds TRON/TROFF flag
1DFC
RETC9
RETurn to CALLer

1DFD-1DFF - DISK ROUTINE NOT USED BY LEVEL II BASIC - "POPAHT".

1DFD
 ↳ POPAHT
POP AF
1DFEE1
POP HL
Restore the pointer to the BASIC program line being parsed into Register Pair HL
1DFF
RET

1E00-1E02 - DEFSTR ENTRY POINT - "DEFSTR"

1E00-1E01
 ↳ DEFSTR
1E 03
LD E,03H
Load Register E with the DEFSTR string number type flag (03H)
1E02-1E04
LD BC,021EH01 1E 02
Z-80 Trick! If this line is found via pass through, the BC is just loaded with this number, and then others, until it hits 1E0BH with E still holding 3

1E03-1E05 - DEFINT ENTRY POINT - "DEFINT"

1E03-1E04
 ↳ DEFINT
LD E,02H1E 02
Load Register E with the DEFINT integer number type flag (02H)
1E05
LD BC,041EH01 1E 04
Z-80 Trick! If this line is found via pass through, the BC is just loaded with this number, and then others, until it hits 1E0BH with E still holding 2

1E06-1E08 - DEFSNG ENTRY POINT - "DEFREA"

1E06-1E07
 ↳ DEFREA
LD E,04H1E 04
Load Register E with the DEFSNG single precision number type flag (04H)
1E08
LD BC,081EH01 1E 08
Z-80 Trick! If this line is found via pass through, the BC is just loaded with this number, and then others, until it hits 1E0BH with E still holding 4

1E09-1E0A - DEFDBL ENTRY POINT - "DEFDBL"

1E09-1E0A
 ↳ DEFDBL
LD E,08H1E 08
Load Register E with the DEFDBL double precision number type flag (08H)

1E0B-1E3C - COMMON CODE SHARED BY DEFSTR/DEFINT/DEFSNG/DEFDBL - "DEFCON".

All of those can either have a - for a range of values or be separated by ,. This code needs to figure out the variables that followed the DEF??? instruction and then set the variable type (which is currently sitting in Register E) in the variable table
1E0B-1E0D
 ↳ DEFCON
A call to 1E3DH checks the value at memory location (HL), which would be the current BASIC program pointer, to see if it is a letter. If its not, CARRY is set. If it is, CARRY is clear
1E0E-1E10
LD BC,1997HLD BC,SNERR01 97 19
Load Register Pair BC with a return address which will return to the ?SN ERROR routine
1E11
PUSH BCC5
Save the ?SN ERROR address (in Register Pair BC) to the STACK
1E12
RET CD8
Return if the character at the location of the current BASIC program pointer in Register A isn't alphabetic (meaning that DEF??? wasn't followed by a letter)
1E13-1E14
SUB 41HD6 41
Subtract 41H from the letter's value in Register A so that it will be in the range of 0-25
1E15
LD C,A4F
Load Register C with the offset (i.e., adjusted value in Register A)
1E16
LD B,A47
Load Register B with the same, under the assumption that it will get updated at some point
1E17
Since 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.
1E18-1E19
CP 0CEHCP MINUTKFE CE
Check to see if the character at the location of the current BASIC program pointer in Register A is a -
1E1A-1E1B
If it's not a - we know this isn't a range, so jump to 1E25H because we don't need to get any more variables
1E1C
If we are here, then we know the DEF??? has a range, so we need another character. We 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.
1E1D-1E1F
A call to 1E3DH checks the value at memory location (HL), which would be the current BASIC program pointer, to see if it is a letter. If its not, CARRY is set. If it is, CARRY is clear
1E20
RET CD8
Return with a ?SN ERROR if the character at the location of the current BASIC program pointer in Register A isn't alphabetic
1E21-1E22
SUB 41HD6 41
Subtract 41H from the letter's value in Register A so that it will be in the range of 0-25
1E23
LD B,A47
Overwrite Register B with the offset for the end of range letter variable
1E24
Since 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.
1E25
 ↳ NOTRNG
LD A,B78
Load Register A with the value of the second letter in Register B
1E26
SUB C91
Subtract the value of the first letter in Register C from the value of the second letter in Register A
1E27
RET CD8
If the varible names are not in ascending order (the one in C is earlier than the one in A), the CARRY FLAG will ahve been set, so RETurn to a ?SN ERROR
1E28
INC A3C
Bump the value in Register A so that it holds the number of variable names to be changed
1E29
EX (SP),HLE3
Save the pointer to the next character to be parsed in the BASIC program to the STACK, and clear the error address
1E2A-1E2C
LD HL,4101HLD HL,DEFTBL21 01 41
Load Register Pair HL with the starting address of the variable declaration table.
Note: 4101H-411AH holds Variable Declaration Table
1E2D-1E2E
LD B,00H06 00
Load Register B with zero so that the starting offset in Register C can be utilized in 16 bit math
1E2F
ADD HL,BC09
Make HL point to the first entry in the variable table to be modified by adding the value of the first letter in Register Pair BC to the value of the starting address of the variable declaration table in Register Pair HL
1E30
 ↳ LPDCHG
LD (HL),E73
Top of a loop. E was set on entry to string, integer, single precision, or double precision as applicable. Save the number type flag in Register E at the location of the memory pointer in Register Pair HL
1E31
INC HL23
Bump the value of the memory pointer in Register Pair HL
1E32
DEC A3D
Decrement the count of the number of variables to be changed in Register A so as to track the number of changes remaining to be made
1E33-1E34
Loop until all of the variables in the DEFxxx range have been changed
1E35
POP HLE1
Restore the pointer to the BASIC program line being processed into Register Pair HL
1E36
LD A,(HL)7E
Fetch the last character in the BASIC program line being processed into Register A
1E37-1E38
CP 2CHFE 2C
Check to see if the character at the location of the current BASIC program pointer in Register A is a ,
1E39
RET NZC0
Return if the character at the location of the current BASIC program pointer in Register A isn't a ,
1E3A
Since 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.
1E3B-1E3C
Loop until done with all the variables

1E3D-1E44 - EXAMINE VARIABLE - "ISLET"

This routine tests the value pointed to by the HL Register Pair and sets the C FLAG if it is an ASCII letter value; and otherwise the NC FLAG is set.
1E3D
 ↳ ISLET
LD A,(HL)7E
Load Register A with the character at the location of the current BASIC program pointer in Register Pair HL
1E3E-1E3F
 ↳ ISLET2
CP 41HCP "A"FE 41
Check to see if the character at the location of the current BASIC program pointer in Register A is less than an "A"
1E40
RET CD8
Return early if the character at the location of the current BASIC program pointer in Register A is less than an A
1E41-1E42
CP 5BHCP "Z"+1FE 5B
Check to see if the character at the location of the current BASIC program pointer in Register A is greater than a "Z"
1E43
CCF3F
Complement the value of the Carry flag. On exit this routine will have the Carry flag set if the character at the location of the current BASIC program pointer in Register A isn't alphabetic and will have the Carry flag cleared if the character at the location of the current BASIC program pointer in Register A is alphabetic
1E44
RETC9
RETurn to CALLer

1E45-1E4E - EXAMINE VARIABLE - "INTIDX"

This is called when evaluating a subscript for a variable reference. It will evaluate if the value is positive or negative.

According to the original ROM source code, this routine reads a formula from the current position and turns it into a positive integer, with the result put into Register Pair DE. Negative arguments are not allowed. On exit, Register Pair HL wil point to the terminating character of the formula on the BASIC program line being examined.
1E45
 ↳ INTIDX
Get the next symbol from the input. 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.
1E46-1E48
 ↳ INTID2
Go evaluate the expression at the current location of the BASIC program pointer in Register Pair HL and return with the integer result in Register Pair DE and the condition codes set based on the high order of the result
1E49
RET PF0
Return if the integer result in Register Pair DE is positive. If it is negative, flow down to the ?FC ERROR

1E4A - ?FC ERROR entry point - "FCERR"

1E4A-1E4B
 ↳ FCERR

LD E,08H1E 08
Load Register E with an ?FC ERROR code
1E4C-1E4E
Display a ?FC ERROR message. If this is from a pass through, the error wll show if the integer result in Register Pair DE is negative

1E4F-1E79 - Line Number Conversion Routine 1 - "LINSPC"

According to the original ROM source code, LINSPC and LINGET are identical except t hat LINSPC also permits the use of a "." to act as the current line number. Otherwise, They read the line number from the current position in the BASIC program. Possible line numbers are 00000-65529. On exit, DE holds the line number, and HL is updated to point to the terminating character, and Register A will contain the terminating character with the FLAGs set based on Register A's value.
1E4F
 ↳ LINSPC
LD A,(HL)7E
Load Register A with the character at the location of the current BASIC program pointer in Register Pair HL
1E50-1E51
CP 2EHCP "."FE 2E
Check to see if the character at the location of the current BASIC program pointer in Register A is a .
1E52
EX DE,HLEB
Load Register Pair DE with the value of the current BASIC program pointer in Register Pair HL
1E53-1E55
LD HL,(40ECH)LD HL,(DOT)2A EC 40
Load Register Pair HL with the current BASIC line number.
Note: 40ECH-40EDH holds current line number
1E56
EX DE,HLEB
Exchange the value of the current BASIC program pointer in Register Pair DE with the current BASIC line number in Register Pair HL
1E57-1E59
Jump to the RST 10H (EXAMINE NEXT SYMBOL) routine if the character at the location of the current BASIC program pointer in Register A is a .

1E5A - Line Number Conversion Routine 2 - "LINGET"

Converts numeric ASCII string pointed to by the HL Register Pair, to HEX and places the result in the DE Register Pair. After execution HL points to the delimiter and the A Register contains the delimiter value. The Z flag is set if the delimiter equals 00 or 3A. Z is reset if any other delimiter is used. If there is no string at the location pointed to by HL the routine will return a MO ERROR (missing operand). If the result in the DE Register Pair exceeds FFFFH an OV ERROR (overflow) results.
1E5A
 ↳ LINGET
DEC HL2B
Backspace HL (the current BASIC program pointer) to the current character
1E5B-1E5D
 ↳ LINGT2
LD DE,0000H11 00 00
Since Register Pair DE will be the "accumulator" for the result, start it off at zero
1E5E
 ↳ MORLIN
Top of a loop. Re-process that previous character through a RST 10H call.

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.
1E5F
RET NCD0
Return if the character at the location of the current BASIC program pointer in Register A isn't numeric
1E60
PUSH HLE5
Save the value of the current BASIC program pointer in Register Pair HL to the STACK
1E61
PUSH AFF5
Save the value in Register Pair AF (which is the digit plus flags resulting from the RST 10H call) to the STACK
1E62-1E64
LD HL,1998H21 98 19
Load Register Pair HL with 6552.

Why 6552? Well, since the Z-80 has no multiply function, checking for any possible arbitrary number would require 4 branches for each step in the 'add to itself until it hits * 10' plus another 4 when adding the last digit. The TRS-80 ROM didn't have that kind of room, nor the time to do all that, so they needed a cheat and that cheat was to let it go as high 65529. After all, 6552 + 1 more digit can NEVER exceed 65535, but 6553 + 1 digit sure can!

So with this trick, the ROM just needs to first check the number against 6552, which, when multiplied by 10, and adding one more digit, will never exceed 65529 (because 9 is the highest one number can go).

By using this trick, only 1 comparison is needed (is it greater or less than 6552) . at the cost of 4 usable line numbers/memory size setting in the 6553x range.

Wait, you say. 65535-65529 is 6 numbers, so why do you say 4. Well, another shortcut the ROM uses is that it assumes anything at line number 65535 is being entered in direct mode (i.e., no line number; just a command), so 65535 couldn't be a line number. Similarly, in 1A09, 65534 is reserved to trigger the BASIC interpreter to jump to the initial powerup routine in the ROM (i.e., a reboot) so you couldn't use that line number either
1E65
Now we need to check to see if the integer value in DE is greater than 6552, so we call the COMPARE DE:HL routine, which numerically compares DE and HL. Will not work for signed integers (except positive ones). Uses the A-register only. The result of the comparison is returned in the status Register as: CARRY SET=HL<DE; NO CARRY=HL>DE; NZ=Unequal; Z=Equal)
1E66-1E68
Go to the Level II BASIC error routine and display a SN ERROR message if the value in Register Pair DE is greater than 6552
Now we need HL = DE * 10
1E69
LD H,D62
Load Register H with the MSB of the integer total in Register D.

This is so we can multiply HL (which should hold the number 6552) by 10
1E6A
LD L,E6B
Load Register L with the LSB of the integer total in Register E.

This is so we can multiply HL (which should hold the number 6552) by 10
1E6B
ADD HL,DE19
Multiply the integer value in Register Pair HL by two
1E6C
ADD HL,HL29
Add HL to itself, which is the same as multiplying the integer value in Register Pair HL by two. The integer result in Register Pair HL is now equal to the integer value in Register Pair DE times four
1E6D
ADD HL,DE19
Add the integer value in Register Pair DE to the integer value in Register Pair HL. The integer result in Register Pair HL is now equal to the integer value in Register Pair DE times five
1E6E
ADD HL,HL29
Add HL to itself, which is the same as multiplying the integer value in Register Pair HL by two. The integer result in Register Pair HL is now equal to the integer value in Register Pair DE times ten. Now HL is 65520
1E6F
POP AFF1
Put the last ASCII digit (from the STACK) into AF
1E70-1E71
SUB 30HSUB "0"D6 30
Convert the ASCII digit in Register A to binary
1E72
LD E,A5F
Load Register E with the binary value of the character in Register A
1E73-1E74
LD D,00H16 00
Load Register D with zero so that DE will be 0000 through 0009 (the binary equivalent of the digit)
1E75
ADD HL,DE19
Add the binary value of the character in Register Pair DE to the integer value in Register Pair HL

As noted above, adding in any digit can only result in HL going to 65529
1E76
EX DE,HLEB
Swap DE and HL. This will have the effect of setting DE to be 10(base 10) * DE + A
1E77
POP HLE1
Restore the pointer to the next digit (from the STACK) into HL
1E78-1E79
Loop until the ASCII to binary conversion has been completed

1E7A-1EA0 - LEVEL II BASIC CLEAR ROUTINE - "CLEAR"

According to the original ROM source code, this will change the amount of string space allowed. If no formula is given, the amount of string space will remain unchanged. On entry, if the Z flag is set, there was no parameter present
1E7A-1E7C
 ↳ CLEAR
Jump to 1B61H (which will set all 26 variables to single precision) if there isn't a number of bytes specified to clear for string space
1E7D-1D7F
Go evaluate the number of bytes to be reserved for string space and return with the integer result in Register Pair DE
1E80
DEC HL2B
Decrement the current BASIC program pointer in Register Pair HL
1E81
Evaluate the next instruction through a RST 10H call. This will 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.
1E82
RET NZC0
Return out of the routine if the character at the location of the current BASIC program pointer isn't an end of the BASIC statement character
1E83
PUSH HLE5
Save the value of the current BASIC program pointer in Register Pair HL to the STACK
1E84-1E86
LD HL,(40B1H)LD HL,(MEMSIZ)2A B1 40
Load the top of memory pointer into Register Pair HL.
Note: 40B1H-40B2H holds MEMORY SIZE? pointer
1E87
LD A,L7D
Load Register A with the LSB of the top of memory pointer in Register L
1E88
SUB E93
Subtract the LSB of the number of bytes for string space in Register E from the LSB of the top of memory pointer in Register A
1E89
LD E,A5F
Load Register E with the LSB of the start of string space in Register A
1E8A
LD A,H7C
Load Register A with the MSB of the top of memory pointer in Register H
1E8B
SBC A,D9A
Subtract the MSB of the number of bytes for string space in Register D from the MSB of the top of memory pointer in Register A
1E8C
LD D,A57
Load Register D with the MSB of the start of string space pointer in Register A
1E8D-1E8F
If the CARRY flag was triggered there isn't enough memory for the amount of string space specified, so go show a ?OM ERROR message
1E90-1E92
LD HL,(40F9H)LD HL,(VARTAB)2A F9 40
Load Register Pair HL with the end of the BASIC program pointer.
Note: 40F9H-40FAH holds the starting address of the simple variable storage area
1E93-1E95
LD BC,0028H01 28 00
Load Register Pair BC with the least amount of space needed for BASIC program variables just so that we have some breathing room
1E96
ADD HL,BC09
Add the value in Register Pair BC to the end of BASIC program pointer in Register Pair HL
1E97
Now we need to check to the adjusted end of the BASIC program pointer (in HL) with the start of the string space pointer (in DE), so we call the COMPARE DE:HL routine, which numerically compares DE and HL. Will not work for signed integers (except positive ones). Uses the A-register only. The result of the comparison is returned in the status Register as: CARRY SET=HL<DE; NO CARRY=HL>DE; NZ=Unequal; Z=Equal)
1E98-1E9A
Display an ?OM ERROR message if the start of string space pointer in Register Pair DE is less than the adjusted end of the BASIC program pointer in Register Pair HL
1E9B
EX DE,HLEB
Put the new start of the string area address into HL
1E9C-1E9E
LD (40A0H),HLLD (STKTOP),HL22 A0 40
Load the start of string space pointer with HL. 40A0H-40A1H holds the start of string space pointer
1E9F
POP HLE1
Restore the code string pointer back into HL
1EA0-1EA2
Jump to 1B61H

1EA3-1EB0 - LEVEL II BASIC RUN ROUTINE - "RUN"

On entry, if the Z flag is set, there was no parameter present
1EA3-1EA5
 ↳ RUN
Jump to 1B5DH if there isn't a line number specified after the RUN token
1EA6-1EA9
GOSUB to 41C7H to see if DOS wants to do anything here - if so clean up the BASIC variables and pointer, set HL=TXTTAB-1 and RETurn to NEWSTT
1EA9-1EAB
Clean up, reset the STACK, CDATPTR, and variables. Only HL is preserved
1EAC-1EAE
LD BC,1D1EHLD BC,NEWSTT01 1E 1D
Load Register Pair BC with the continuation address in the execution driver
1EAF-1EB0
Put NEWSTT at the top of STACK (so that a RETurn will jump to it) and then pass through to the GOTO routine via a jump to 1EC1H to begin execution at the nnnn line

1EB1-1EC1 - LEVEL II BASIC GOSUB ROUTINE - "GOSUB"

According to the original ROM source code, the 5 byte GOSUB entry on the STACK is as follows:
  • LOW ADDRESS
    • 1 Byte - The GOSUB token.
    • 2 Bytes - The line number of the GOSUB statement.
    • 2 Bytes - A pointer to the text of the GOSUB in the BASIC program being executed.
  • HIGH ADDRESS
Can be used to execute the equivalent of a GOSUB statement from an assembly program. It allows a BASIC subroutine to be called from an assembly subroutine. After the BASIC subroutine executes, control returns to the next statement in the assembly program. All registers are used. On entry, the HL must contain an ASCII string with the starting line number of the subroutine.
1EB1-1EB2
 ↳ GOSUB
LD C,03H0E 03
Load Register B with half the number of bytes needed for the GOSUB push
1EB3-1EB5
Go make sure that there's enough memory for the GOSUB push
1EB6
POP BCC1
Get the NEWSTT return address from the STACK and put it in Register Pair BC
1EB7
PUSH HLE5
Save the value of the current BASIC program pointer in Register Pair HL to the STACK
1EB8
PUSH HLE5
Create a hole to be filled in later by once again saving the value of the current BASIC program pointer to the STACK
1EB9-1EBB
LD HL,(40A2H)LD HL,(CURLIN)2A A2 40
Load Register Pair HL with the value of the current BASIC line number in binary.
Note: 40A2H-40A3H holds the current BASIC line number
1EBC
EX (SP),HLE3
Put the binary value for the current line number into the hole in the STACK AND restore the code string pointer
1EBD-1EBE
LD A,91HLD A,$GOSUB3E 91
Load Register A with a GOSUB token
1EBF
PUSH AFF5
Save the GOSUB token (in Register Pair AF) to the STACK
1EC0
INC SP33
Bump the value of the STACK pointer since we just used one space for the GOSUB token
1EC1
 ↳ RUNC2
PUSH BCC5
Save the "NEWSTT" return address in Register Pair BC to the STACK, and now spill down to the GOTO routine

1EC2-1EDD - LEVEL II BASIC GOTO ROUTINE - "GOTO"

1EC2-1EC4
 ↳ GOTO
We need to put the line number to branch to into DE so we call ASCII TO INTEGER routine at 1E5A which converts the ASCII string pointed to by HL to an integer deposited into DE. If the routine finds a non-numerica character, the conversion is stopped
1EC5-1EC7
 ↳ GOTO2
Go bump the current BASIC program pointer in Register Pair HL until it points to the end of the current BASIC line
1EC8
PUSH HLE5
Save the value of the current BASIC program pointer in Register Pair HL to the STACK
1EC9-1ECB
LD HL,(40A2H)LD (CURLIN),HL2A A2 40
Load Register Pair HL with the binary equivalent of the last line number.
Note: 40A2H-40A3H holds the current BASIC line number
1ECC
Now we need to compare the value of the current BASIC line number (in HL) with the value of the line number to branch to (in DE), so we call the COMPARE DE:HL routine, which numerically compares DE and HL. Will not work for signed integers (except positive ones). Uses the A-register only. The result of the comparison is returned in the status Register as: CARRY SET=HL<DE; NO CARRY=HL>DE; NZ=Unequal; Z=Equal)
1ECD
POP HLE1
Get the value of the current BASIC program pointer from the STACK and put it in Register Pair HL
1ECE
INC HL23
Bump the value of the current BASIC program pointer in Register Pair HL so as to restore the code string address. DE holds the line number specified
1ECF-1ED1
If the line number to branch to (in Register Pair DE) is greater than the current BASIC line number then go find where the line number is located, starting with the current line
1ED2-1ED4
If the line number to branch to (in Register Pair DE) is less than the current BASIC line number, then go find where the line number is located by calling 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.
Yes, this is a second search that kicks in if the prior search (which started at the current line number) failed, as this one will start at the beginning of the program
1ED5,1ED6
LD H,B
LD L,C60
Let HL = BC (which is holding the address of the requested line number
1ED7
DEC HL2B
Decrement the value of the current BASIC program pointer in Register Pair HL to now point to the End of Line terminator from the previous line
1ED8
RET CD8
If a line number was found then the CARRY FLAG would have been set. If so, RETURN from this routine to the execution driver (to start execution at the new line number), otherwise pass through to the ?UL ERROR routine

1ED9-1EDD - LEVEL II BASIC ?UL ERROR ROUTINE - "USERR"

1ED9-1EDA
 ↳ USERR
LD E,0EHLD E,ERRUS1E 0E
Load Register E with an ?UL ERROR code
1EDB-1EDD
Since the line number wasn't found, display a ?UL ERROR message

1EDE-1E04 - LEVEL II BASIC RETURN ROUTINE - "RETURN"

Returns control to the BASIC statement following the last GOSUB call. An assembly program called by a BASIC subroutine may wish to return directly to the orginal caller without returning through the subroutine entry point. This exit can be used for that return. The return address to the STACK for the call to the assembly program must be cleared before returning via 1EDFH. On entry, if the Z flag is set, there was no parameter present.
1EDE
 ↳ RETURN
RET NZC0
Display a ?SN ERROR message if there is anything following the RETURN token
1EDF-1EE0
LD D,0FFH16 FF
Load Register D with FFH (a dummy address for the search routine to ensure that the variable pointer in Register Pair DE does not find a match)
1EE1-1EE3
Go past all the FOR entries in the STACK via this CALL which backspaces the STACK pointer by four and return with the value at the location of the STACK pointer in Register A
1EE4
LD SP,HLF9
Update the STACK by loading the STACK pointer with the new value in Register Pair HL
1EE5-1EE7HS
LD (40E8H),HLLD (SAVSTK),HL22 E8 40
Save the STACK pointer position in Register Pair HL.
Note: 40E8H-40E9H holds STACK pointer pointer
1EE8-1EE9
CP 91HCP $GOSUBFE 91
Check to see if the value in Register A is a GOSUB token
1EEA-1EEB
LD E,04HLD E,ERRRG1E 04
Load Register E with a ?RG ERROR code

1EEC - RG ERROR entry point.

1EEC-1EEE
Display a ?RG ERROR message if there isn't a GOSUB push to the STACK
1EEF
POP HLE1
Otherwise, get the line number that the GOSUB was from from the STACK and put it in Register Pair HL
1EF0-1EF2
LD (40A2H),HLLD (CURLIN),HL22 A2 40
Save the GOSUB line number in Register Pair HL as the current BASIC line number.
Note: 40A2H-40A3H holds the current BASIC line number
The next few instructions set up to see if there was GOSUB from the command line instead of insiude a program.
1EF3
INC HL23
Bump the value of the current BASIC line number in Register Pair HL
1EF4
LD A,H7C
Load Register A with the MSB of the adjusted current BASIC 1ine number in Register Pair HL
1EF5
OR LB5
Combine the LSB of the adjusted current BASIC line number in Register L with the adjusted MSB of the current BASIC line number in Register A. This is a test for an overflow or direct command mode
1EF6-1EF7
If the NZ FLAG is set, then this was NOT in direct command mode, so JUMP to 1EFF to do the RETURN
1EF8-1EFA
LD A,(40DDH)LD A,(BFKLFL)3A DD 40
If we are here, we may have a one liner! Load Register A with the command mode flag.
Note: 40DDH holds INPUT flag
1EFB
OR AB7
Set the flags
1EFC-1EFE
Jump to 1A18H if Level II BASIC, instead of doing a RETURN, since we are in direct command mode
1EFF-1F01
 ↳ GOBACK
LD HL,1D1EHLD HL,NEWSTT21 1E 1D
Load Register Pair HL with the return address of NEWSTT
1F02
EX (SP),HLE3
Put the "NEWSTT" return address into the top of the STACK and put the current location on the program line being parsed back into Register Pair HL
1F03-1F04
LD A,0E1H3E E1
Z-80 Trick! If passing through will just change Register A to this value, but NOT do a POP HL
1F04
 ↳ DATAH
POP HLE1
If this is jumped to, then process a POP HL, which would NOT be processed if this is passed through. If this line is processed, then its purpose is to restore the pointer to the current character on the BASIC program line being processed back into Register Pair HL

1F05-1F20 - SCAN ROUTINE - "DATA"

1F05
 ↳ DATA
LD BC,0E3AH01 3A 0E
This part of a Z-80 Trick. If this line is hit by passing through, then BC is simply changed and the next instruction at 1F07H is never executed
1F07-1F08
 ↳ REM
LD C,00H0E 00
Load Register C with zero
1F09-1F0A
LD B,00H06 00
Load Register B with zero, as the only terminator inside quotes or a REM is a NULL terminator
The notes in the original ROM source code explain that when a quote is seen, the second terminator is traded, so in a DATA statement a colon inside quotations will have no effect.

1F0B
 ↳ EXCHQT
LD A,C79
Top of a loop. Load Register A with the stop scan character in Register C
1F0C
LD C,B48
Load Register C with the stop scan character in Register B
1F0D
LD B,A47
Load Register B with the stop scan character in Register A
1F0E
 ↳ REMER
LD A,(HL)7E
Top of a loop. Load Register A with the character at the location of the current BASIC program pointer in Register Pair HL
1F0F
OR AB7
Check to see if the character at the location of the current BASIC program pointer in Register A is an END OF LINE terminator
1F10
RET ZC8
Return if the character at the location of the current BASIC program pointer in Register A is an END OF LINE terminator, because an END OF LINE terminator will stop everything, including quote things or a REM
1F11
CP BB8
Check to see if the character at the location of the current BASIC program pointer in Register A is the same as the stop scan character in Register B
1F12
RET ZC8
Return if the character at the location of the current BASIC program pointer in Register A is the same as the stop scan character in Register B
1F13
INC HL23
Bump the value of the current BASIC program pointer in Register Pair HL
1F14-1F15
CP 22HCP """FE 22
Check to see if the character at the location of the current BASIC program pointer in Register A is a quote
1F16-1F17
Loop back if the character at the location of the current BASIC program pointer in Register A is a quote, as we need to trade
The notes in the original ROM source code say that when an IF takes a false branch, it must find the appropriate ELSE to start execution at. "DATA" counts the number of IF's it sees so that the ELSE code can matche ELSE's with IF's. This count is kept in Register D.
1F18-1F19
SUB 8FHSUB $IFD6 8F
Check to see if the character at the location of the current BASIC program pointer in Register A is a IF token
1F1A-1F1B
Loop back to 1F0EH if the character at the location of the current BASIC program pointer in Register A isn't an IF token
1F1C
CP BB8
Since a REM cannot be SMASHed, we only increment Register D if Register B does not equal zero. So . Check to see if the character at the location of the current BASIC program pointer in Register A is the same as the character in Register B
1F1D
ADC A,D8A
As long as Regisister B is not zero, add the value in Register D to the value in Register A
1F1E
LD D,A57
Load Register D with the value in Register A
1F1F-1F20
Loop back to 1F0EH until scan is completed

1F21-1F6B - LEVEL II BASIC LET ROUTINE - "LET"

1F21-1F23
 ↳ LET
Call the FIND ADDRESS OF VARIABLE routine at 260DH which searches the Variable List Table for a variable name which matches the name in the string pointed to in HL, and return the address of that variable in DE (and if there is no variable, it creates it, zeroes it, and returns THAT location)
1F24-1F25
RST 08H D5HRST 08H EQULTKCF
Test if the variable name is followed by a =. Since the character at the location of the current BASIC program pointer in Register Pair HL must be an EQUAL sign (D5) so call the COMPARE SYMBOL routine which comparess the symbol in the input string pointed to by HL Register to the value in the location following the RST 08 call. If there is a match, control is returned to address of the RST 08 instruction 2 with the next symbol in in Register A 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)
1F26
EX DE,HLEB
Exchange the address of the variable in Register Pair DE with the value of the current BASIC program pointer in Register Pair HL
A note in the original ROM source code explains that the following sets up "TEMP" for the FOR command so when user-functions call REDINP, the "TEMP" doesn't get changed.
1F27-1F29
LD (40DFH),HLLD (TEMP),HL22 DF 40
Save the addres of the variable in Register Pair HL.
Note: 40DFH-40E0H is a common temporary storage area
1F2A
EX DE,HLEB
Exchange the value of the current BASIC program pointer in Register Pair DE with the address of the variable in Register Pair HL
1F2B
 ↳ REDINP
PUSH DED5
Save the address of the variable in Register Pair DE to the STACK
1F2C
We need to check the value of the current number type flag, so we call the TEST DATA MODE routine at RST 20H.
NOTE: The RST 20H routine determines the type of the current value in ACCumulator and returns a combination of STATUS flags and unique numeric values in the A Register according to the data mode flag (40AFH). The results are returned as follows:
  • Integer = NZ/C/M/E and A is -1
  • String = Z/C/P/E and A is 0
  • Single Precision = NZ/C/P/O and A is 1
  • and Double Precision is NZ/NC/P/E and A is 5.
1F2D
PUSH AFF5
Save the value in Register Pair AF to the STACK. A will be -1 for an integer, 0 for a string, 1 for single precision, and 5 for double precision
1F2E-1F30
 ↳ LETCN3
Go evaluate the expression at the location of the current BASIC program pointer in Register Pair HL and return with the result in ACCumulator
1F31
 ↳ LETCON
POP AFF1
Get the variable type of the variable into Register A
1F32
 ↳ LETCN2
EX (SP),HLE3
Exchange (SP) and HL so that the address of the variable is now held in Register Pair HL and the pointer to the current character in the BASIC program being processed goes to the top of the STACK
1F33-1F34
 ↳ INPCOM
ADD A,03HC6 03
Top of a loop. Adjust the value in Register A so that it will hold the correct number type flag (i.e., A will be 2 for integer, 3 for string, 4 for single precision, and 8 for double precision)
1F35-1F37
Go to 2819H to convert the result in ACCumulator to the same number type for the variable held in Register A
1F38-1F3A
Set Register Pair DE to equal the start position of good data in ACCumulator and call the GETYPE
1F3B
PUSH HLE5
Save the address of the variable in Register Pair HL to the STACK
1F3C-1F3D
If the result is anumber, JUMP to force it and copy
1F3E-1F40
LD HL,(4121H)LD HL,(FACLO)2A 21 41
Load Register Pair HL with the starting address of the string's VARPTR in ACCumulator
1F41
PUSH HLE5
Save the VARPTR for the string result in Register Pair HL to the STACK
1F42
INC HL23
Bump the value of the VARPTR for the string result in Register Pair HL
1F43
LD E,(HL)5E
Load Register E with the LSB of the address for the string at the location of the VARPTR for the string in Register Pair HL
1F44
INC HL23
Bump the value of the VARPTR for the string result in Register Pair HL
1F45
LD D,(HL)56
Load Register D with the MSB of the address for the string at the location of the VARPTR for the string in Register Pair HL
1F46-1F48
LD HL,(40A4H)LD HL,(TXTTAB)2A A4 40
Load Register Pair HL with the start of the BASIC program.
Note: 40A4H-40A5H holds the starting address of BASIC program text also known as the PROGRAM STATEMENT TABLE (PST)
1F49
Now we need to compare the start of the BASIC program area (in HL) with the address of the string result in DE, so we call the COMPARE DE:HL routine, which numerically compares DE and HL. Will not work for signed integers (except positive ones). Uses the A-register only. The result of the comparison is returned in the status Register as: CARRY SET=HL<DE; NO CARRY=HL>DE; NZ=Unequal; Z=Equal)
1F4A-1F4B
If the address of the string result in Register Pair DE is less than the start of the BASIC program area in Register Pair HL, then the data is really in the buffer, so JUMP to do the copy
1F4C-1F4E
LD HL,(40A0H)LD HL,(STKTOP)2A A0 40
We want to see if it points into string space, so load Register Pair HL with the start of the string space pointer. 40A0H-40A1H holds the start of string space pointer
1F4F
Now we need to compare the start of the string space pointer (in HL) with the address of the string result in DE, so we call the COMPARE DE:HL routine, which numerically compares DE and HL. Will not work for signed integers (except positive ones). Uses the A-register only. The result of the comparison is returned in the status Register as: CARRY SET=HL<DE; NO CARRY=HL>DE; NZ=Unequal; Z=Equal)
1F50
POP DED1
Get the VARPTR for the string result from the STACK and put it in Register Pair DE
1F51-1F52
If NC is set, then we have a literal, which we do not want to copy, so JUMP if the address of the string result in Register Pair DE was less than the start of the string space pointer in Register Pair HL
Next, we need to see if it is a variable by checking the descriptor. If it is not a variable, we do not want to copy it.
1F53-1F55
LD HL,(40F9H)LD HL,(VARTAB)2A F9 40
Load Register Pair HL with the simple variables pointer.
Note: 40F9H-40FAH holds the starting address of the simple variable storage area
1F56
Now we need to compare the address of the VARPTR for the string result in Register Pair DE with the simple variables pointer in Register Pair HL, so we call the COMPARE DE:HL routine, which numerically compares DE and HL. Will not work for signed integers (except positive ones). Uses the A-register only. The result of the comparison is returned in the status Register as: CARRY SET=HL<DE; NO CARRY=HL>DE; NZ=Unequal; Z=Equal)
1F57-1F58
Jump if the address of the VARPTR for the string result in Register Pair DE is less than the simple variables pointer in Register Pair HL
1F59-1F5AH
LD A,D1H3E D1
Z-80 Trick. If we are passing through to this location, then A will get changed and the next instruction (i.e., the POP DE) will not get executed
1F5A
 ↳ INBUFC
POP DED1
Get the VARPTR for the string result from the STACK and put it in Register Pair DE
1F5B-1F5D
Free up the TEMP without freeing up any string space
1F5E
EX DE,HLEB
Exchange the VARPTR for the string in Register Pair DE with the string's address in Register Pair HL, because the next instruction copies where HL points to
1F5F-1F61
Copy the variable in the string space OR strings with data in the buffer into string space
1F62-1F64
 ↳ DNTCPY
Free up the TEMP without freeing up any string space
1F65
EX (SP),HLE3
Exchange HL and (SP). HL will contain the place to store the VARPTR. (SP) will have nothing important
1F66-1F68
 ↳ COPNUM
Copy a descriptor or value to its proper location in memory
1F69
POP DED1
Get the top entry of the STACK. It is either garbage or information for a "FOR"
1F6A
POP HLE1
Get the value of the current BASIC program pointer from the STACK and put it in Register Pair HL
1F6B
RETC9
RETurn to CALLer

1F6C-1FAE - LEVEL II BASIC ERROR ON ROUTINE - "ONGOTO"

1F6C-1F6D
 ↳ ONGOTO
CP 9EHCP $ERRORFE 9E
Check to see if the character at the location of the current BASIC program pointer in Register A is an ERROR token (since this is supposed to be ON ERROR
1F6E-1F6F
Jump down to 1F95H if the character at the location of the current BASIC program pointer in Register A isn't an ERROR token
1F70
If we are here, we have ON ERROR but we do need to see what's next. Since 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.
1F71-1F72
RST 08H 8DHRST 08H $GOTOCF
The next valid character at the location of the current BASIC program pointer in Register Pair HL must be a GOTO token (=8DH) so call the COMPARE SYMBOL routine which comparess the symbol in the input string pointed to by HL Register to the value in the location following the RST 08 call. If there is a match, control is returned to address of the RST 08 instruction 2 with the next symbol in in Register A 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)
1F73-1F75
The next thing in the program line needs to be a line number, so convert the next constant into binary (with the result in DE). To do this, call the ASCII TO INTEGER routine at 1E5A which converts the ASCII string pointed to by HL to an integer deposited into DE. If the routine finds a non-numeric character, the conversion is stopped
1F76
LD A,D7A
We need to test to see if the line number in DE is a zero. So . load Register A with the MSB of the line number in Register D
1F77
OR EB3
Combine the LSB of the line number in Register E with the MSB of the line number in Register A to see if we have a zero as in ON ERROR GOTO 0
1F78-1F79
If we have an ON ERROR GOTO 0, we need to reset the error trap, so JUMP to 1F83H
1F7A-1F7C
Next we need to see if the line number actuall exists! Go find the location of the line number in Register Pair DE and return with the location of the line number in Register Pair BC
1F7D
1F7E
LD D,B
LD E,C50
Put the pointer to the line number (held in BC) into DE
1F7F
POP HLE1
Restore the location of the current position in the BASIC program being processed from the top of the STACK into Register Pair HL
1F80-1F82
If the NC FLAG is set, then the BASIC line number was not found, so we need to JUMP to display a ?UL ERROR
1F83
 ↳ RESTRP
EX DE,HLEB
Exchange DE and HL, so that HL will now hold the pointer to the line number and DE will hold the location of the current BASIC program pointer
1F84-1F86
LD (40F0H),HLLD (ONELIN),HL22 F0 40
Save the pointer to the line number held in in Register Pair HL.
Note: 40F0H-40F1H is used by ON ERROR
1F87
EX DE,HLEB
Exchange the value of the current BASIC program pointer in Register Pair DE with the location of the BASIC line in Register Pair HL
1F88
RET CD8
RETURN out of this routine to the execution driver if it was not ON ERROR GOTO 0000
1F89-1F8B
LD A,(40F2H)LD A,(ONEFLG)3A F2 40
Load Register A with the value of the error flag so we can see if we are in an ON . ERROR routine.
Note: 40F2H holds Error flag
1F8C
OR AB7
Check to see if the error flag is set
1F8D
RET ZC8
If the Z FLAG is set, then we are not in an ON . ERROR routine and we can just RETURN to CALLer because we have already disabled the trapping
1F8E-1F90
LD A,(409AH)LD A,(ERRFLG)3A 9A 40
Load Register A with the error code.
Note: 409AH holds the RESUME flag
1F91
LD E,A5F
Load Register E with the value of the error code in Register A
1F92-1F94
Force the error to occur via a JUMP to the Level II error routine and display the error message for the error code in Register E

1F95 - Still in the ON routine - "NTOERR"

We know it isn't ON ERROR. We now need to deal with the possibility that it was an ON n GOTO or ON n GOSUB.
1F95-1F97
 ↳ NTOERR
First we need to get the n so go evaluate the expression at the location of the current BASIC program pointer and return with the result in Register Pair DE
1F98
LD A,(HL)7E
Load Register A with the next character (which should be a token or terminator) at the location of the current BASIC program pointer in Register Pair HL
1F99
LD B,A47
Save that character into Register B
1F9A-1F9B
CP 91HCP $GOSUBFE 91
Check to see if the character at the location of the current BASIC program pointer in Register A is a GOSUB token
1F9C-1F9D
Skip the next 2 opcodes if the character at the location of current BASIC program pointer in Register A is a GOSUB token
1F9E-1F9F
RST 08H 8DHRST 08H $GOTOCF
Now let's test to see if the next character is the token for a GOTO, call the COMPARE SYMBOL routine which comparess the symbol in the input string pointed to by HL Register to the value in the location following the RST 08 call. If there is a match, control is returned to address of the RST 08 instruction 2 with the next symbol in in Register A 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)
1FA0
DEC HL2B
Decrement the value of the current BASIC program pointer in Register Pair HL to point to the GOTO token
1FA1
 ↳ ISGOSU
LD C,E4B
Load Register C with the character count of the expression after the ON token in Register E (i.e., the "n" from ON n GOTO
1FA2
 ↳ LOOPON
DEC C0D
Top of a loop. Decrement the line number counter in Register C to test to make sure there are enough skips
1FA3
LD A,B78
Load Register A with the token in Register B (which is either a GOSUB or GOTO token)
1FA4-1FA6
If we are done (i.e., C hit ZERO) then Jump to 1D60H
1FA7-1FA9
We need to slip over the line number so we GOSUB to 1E5BH to evaluate the line number at the location of the current BASIC program pointer and return with the result in Register Pair DE
1FAA-1FAB
CP 2CHCP ","FE 2C
Check to see if the character at the location of the current BASIC program pointer in Register A is a COMMA. If not, it is the ent of the statement
1FAC
RET NZC0
If the character at the location of the current BASIC program pointer in Register A isn't a , then we must be at the end of the line
1FAD-1FAE
Otherwise, keep grabbing and processing line numbers

1FAF-1FF3 - LEVEL II BASIC RESUME ROUTINE - "RESUME"

1FAF-1FB1
 ↳ RESUME
LD DE,40F2HLD DE,ONEFLG11 F2 40
Load Register Pair DE with the address of the Level II BASIC error flag.
Note: 40F2H holds Error flag
1FB2
LD A,(DE)1A
Load Register A with the error flag at the location of the memory pointer in Register Pair DE. It will be FF if there is an error, and a zero otherwise
1FB3
OR AB7
Check for an error
1FB4-1FB6
If we processed a RESUME but yet there was no error, then display an ?RW ERROR message
1FB7
INC A3C
Clear the error flag in Register A
1FB8-1FBA
LD (409AH),ALD (ERRFLG),A32 9A 40
Clear the error flag (by putting a 0 into 409AH) so that way if a BREAK is hit, it won't give an error
1FBB
LD (DE),A12
Reset the error flag at the location of the memory pointer in Register Pair DE
1FBC
LD A,(HL)7E
Load Register A with the character at the location of the current BASIC program pointer in Register Pair HL
1FBD-1FBE
CP 87HCP $NEXTFE 87
Check to see if the character at the location of the current BASIC program pointer in Register A is a NEXT token
1FBF-1FC0
Jump down to 1FCDH if the character at the location of the current BASIC program pointer in Register A is a NEXT token (as in RESUME NEXT
1FC1-1FC3
Get the binary equivalent of the line number into DE by calling the ASCII TO INTEGER routine at 1E5A which converts the ASCII string pointed to by HL to an integer deposited into DE. If the routine finds a non-numeric character, the conversion is stopped
1FC4
RET NZC0
Exit to the execution driver if there wasn't a line number at the location of the current BASIC program pointer
1FC5
1FC6
LD A,D7A
Prepare to test DE for Zero using the Z-80 trick of LD A,MSB and OR LSB
1FC7-1FC9
If the line number was NOT zero (i.e., it was RESUME nnnn), then JUMP there!
1FCA
INC A3C
Prepare to set a non-Zero condition code so that it will indicate RESUME 0
1FCB-1FCC
Jump to the RESUME 0 at 1FCFH

1FCDH - Part of the RESUME ROUTINE - "RESNXT"

1FCD
 ↳ RESNXT
Since 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.
1FCE
RET NZC0
Return if this is the end of the BASIC statement

1FCF - This is the RESUME 0 routine - "RESTXT"

1FCF-1FD1
 ↳ RESTXT
LD HL,(40EEH)LD HL,(ERRTXT)2A EE 40
Get the value of the current BASIC program pointer and put it in Register Pair HL.
Note: 40EEH-40EFH is used by RESUME
1FD2
EX DE,HLEB
Load Register Pair DE with the value of the current BASIC program pointer in Register Pair HL
1FD3-1FD5
LD HL,(40EAH)LD HL,(ERRLIN)2A EA 40
Load Register Pair HL with the current BASIC line number.
Note: 40EAH-40EBH holds Line number with error
1FD6-1FD8
LD (40A2H),HLLD (CURLIN),HL22 A2 40
Save the value of the current BASIC line number in Register Pair HL. This is where we will resume execution.
Note: 40A2H-40A3H holds the current BASIC line number
1FD9
EX DE,HLEB
Load Register Pair HL with the value of the current BASIC program pointer in Register Pair DE
1FDA
RET NZC0
Return to the execution driver if this is RESUME
1FDB
LD A,(HL)7E
Get the character at the location of the current BASIC program pointer in Register Pair HL and put it in Register A
1FDC
OR AB7
Check the character at the location of the current BASIC program pointer in Register A to see if its an end of the BASIC line character
1FDD-1FDE
If A was ZERO, then the character would be : or an end of the BASIC line character. Jump forward to 1FE3H if the character at the location of the current BASIC program pointer in Register A isn't an end of the BASIC line character or a ":"
1FDF
INC HL23
We need to skip the header, so we are going to move HL down 4 positions. Bump the value of the current BASIC program pointer in Register Pair HL to skip over the zero byte terminator
1FE0
INC HL23
Bump the value of the current BASIC program pointer in Register Pair HL to skip over the LSB of the pointer to the next statement
1FE1
INC HL23
Bump the value of the current BASIC program pointer in Register Pair HL to skip over the MSB of the pointer to the next statement
1FE2
INC HL23
Bump the value of the current BASIC program pointer in Register Pair HL to skip over the LSB of the line number in binary for the line following the error
1FE3
 ↳ NOTBGL
INC HL23
Bump the value of the current BASIC program pointer in Register Pair HL to skip over the MSB of the line number in binary for the line following the error so that it points to the start of the next statement
1FE4
LD A,D7A
Load Register A with the MSB of the line number with the error in Register D
1FE5
AND EA3
Combine the LSB of the line number with the error in Register E with the MSB of the line number with the error in Register A. This begins the test for the end of program marker
1FE6
INC A3C
Bump the combined value of the line number with the error in Register A. If this was a direct statement, rather than a program line, this will set the Z FLAG
1FE7-1FE9
Jump to NEWSTT and stop if this was part of a program (and not a direct command)
1FEA-1FEC
LD A,(40DDH)LD A,(BFKLFL)3A DD 40
Load Register A with the buffer kill flag
1FED
DEC A3D
Check to see if the command mode flag in Register A is set
1FEE-1FF0
Jump to 1DBEH if Level II BASIC is in the command mode because you cant CONTinue/RESUME if you are in command mode
1FF1-1FF3
Exit the routine by jumping to 1F05H to get the next statement

1FF4H-2007 - LEVEL II BASIC ERROR ROUTINE - "ERRORS"

This evaluates n for ERROR n
1FF4-1FF6
 ↳ ERRORS
Get the error code parameter which was passed by a GOSUB to 2B1CH which evaluates the expression at the location of the current BASIC program pointer in Register Pair HL and return with the result in A
1FF7
RET NZC0
Return if this isn't the end of the BASIC statement
1FF8
OR AB7
Set up to check to see if the error number in Register A is equal to zero
1FF9-1FFB
If the error code was zero, then that's an error in itself, so display an ?FC ERROR message
1FFC
DEC A3D
Subtract one from the error code in Register A
1FFD
ADD A,A87
Multiply the error code in Register A by two (so now A = 2(A-1))
1FFE
LD E,A5F
Load Register E with 2(A-1)
1FFF-2000
CP 2DHCP LSTERRFE 2D
Check to see if the error code in Register A is less than 45
2001-2002
Jump forward 1 instruction (i.e., skip the line that sets up for an error of ?UE ERROR) if the error code (in Register A) is in range (i.e., less than 45)