There is no difference between the early Model III ROM and the later Model III ROM in this range. The Model 4 ROM is also identical to the Model III ROM in this range.
1003LD A,BLoad register A with the character at the location of the input buffer pointer in register B.
1004CP CCheck to see if the character at the location of the input buffer pointer in register A is a space.
1005-1006LD C,2AHLoad register C with an * character.
1007-1008Skip the next opcode (which loads B with a *, if the character at the location of the input buffer pointer in register A isn’t a space.
1009LD B,CLoad register B with the * character in register C.
LD (HL),CSave the * character in register C at the location of the input buffer pointer in register pair HL.
100BRST 10HSince 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.
NOTE:- The RST 10H routine loads the next character from the string pointed to by the HL register into the A-register and clears the CARRY FLAG if it is alphabetic, or sets it if is alphanumeric.
- Blanks and control codes 09H and 0BH 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.
100C-100DJump down to 1022H if the character at the location of the input buffer pointer in register pair HL is the end of the input buffer character (00H).
100E-100FCP 45HCheck to see if the character at the location of the input buffer pointer in register A is an E.
1010-1011Jump down to 1022H if the character at the location of the input buffer pointer in register A is an E.
1012-1013CP 44HCheck to see if the character at the location of the input buffer pointer in register A is a D.
1014-1015Jump down to 1022H if the character at the location of the input buffer pointer in register A is a D.
1016-1017CP 30HCheck to see if the character at the location of the input buffer pointer in register A is a 0.
1018-1019Jump back to 100AH if the character at the location of the input buffer pointer in register A is a 0.
101A-101BCP 2CHCheck to see if the character at the location of the input buffer pointer in register A is a ,.
101C-101DJump back to 100AH if the character at the location of the input buffer pointer in register A is a ,.
101E-101FCP 2EHCheck to see if the character at the location of the input buffer pointer in register A is a ..
1020-1021Jump down to 1025H if the character at the location of the input buffer pointer in register A isn’t a ..
DEC HLNow we know we have an E, D, 0, ,, or . so we need to backspace it out by decrementing the value of the input buffer pointer in register pair HL.
1023-1024LD (HL),”0″Save a zero character (0) at the location of the input buffer pointer in register pair HL.
1026-1027AND 10HMASK A against 10H (Binary: 0001 0000) to leave only Bit 5 so as to check to see if a $ is to be included in the ASCII string.
1028-1029Skip the next 2 instructions (which put in a $) if a $ isn’t to be included in the ASCII string.
102ADEC HLNeed to add a $, so first we decrement the value of the input buffer pointer in register pair HL …
102B-102CLD (HL),24H… and then put a $ there.
102E-102FAND 04HCheck to see if the sign is to follow the ASCII string.
1030RET NZReturn if the sign isn’t to follow the ASCII string.
1031DEC HLDecrement the value of the input buffer pointer in register pair HL.
1032LD (HL),BSave the character in register B at the location of the input buffer pointer in register pair HL.
1033RETReturn.
1034 – LEVEL II BASIC MATH ROUTINE – “FOUINI”
This routine initializes the input buffer for an ASCII conversion. It is called by the FLOATING to ASCII Conversion Routine (at 0FBEH) and by the BINARY to ASCII Conversion Routine (at 0FAFH).
1034-1036LD (40D8H),ASave the value of the edit flag (stored at 40D8H) in register A.
NOTE: 40D8H-40D9H holds the temporary storage location.
1037-1039LD HL,4130HLoad register pair HL with the starting address of the input buffer (which is 4130H).
NOTE: 4130H-4149H holds Internal print buffer.
103A-103BLD (HL),20HSave a space at the location of the input buffer pointer in register pair HL.
103CRETReturn.
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-103ECP 05HSet the CARRY FLAG according to whether the current value in REG 1 is single precision or double precision (Carry set if double precision).
103FPUSH HLSave the value in register pair HL to the stack.
1040-1041SBC A,00HAdjust the value of the number type in register A. It will be 04H if SINGLE PRECISION and it will be 08H if DOUBLE precision.
1042RLAMultiply 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.
1043LD D,ALoad register D with the adjusted value of the number type in register A.
1044INC DBump the value of the number type in register D (so D will be 09H if SINGLE precision and 0BH if DOUBLE precision).
1045-1047GOSUB to 1201H to scale the current value in REG 1 to be 99,999 <= X <= 999,999. Returns wihth A being the number of times the DOUBLE precision value was scaled up or down.
1048-104ALD BC,0300HLoad register pair BC with 300H (Decimal: 768).
104BADD A,DAdd the value in register D to the value in register A.
104C-104EJump to 1057H if the number of digits in register A is too large (i.e., if scaled down more than 9 or 11 places).
104FINC DBump the value in register D (so D will be 0AH if SINGLE precision or 0CH if DOUBLE precision).
1050CP DCheck to see if the number of digits in register A is equal to the value in register D (meaning that the number wasn’t scaled at all).
NOTE: Results from a CP:- Z: A and * are the same
- NZ: A and * are NOT the same
- C: A < *
- NC: A => *
1051-1052If the number was scaled up or down (meaning that A and D are the same or A is greater than D), jump to 1057H.
1053INC ANow we know the number was scaled, so we must bump the number of digits in register A so that it holds the number of digits in the value.
1054LD B,ALoad register B with the number of digits in the value (stored in register A).
1055-1056LD A,02HLoad register A with a two because the next step (which is a common code jump point) will force the exponent to be zero.
1059POP HLGet the value from the stack (the Program Buffer) and put it in register pair HL.
105APUSH AFSave the exponent value (currently in register pair AF) to the stack.
105E-105FLD (HL),”0″Save a 0 character at the location of the input buffer pointer in register pair HL.
1060-1062If there was no scaling, GOSUB to 09C9H to bump the value of the input buffer pointer in register pair HL if necessary.
1063-1065Go convert the binary value in REG 1 to ASCII, the result being stored in the input buffer pointer.
1066DEC HLBackspace the last character by decrementing the value of the input buffer pointer in register pair HL.
1067LD A,(HL)Load register A with the value at the location of the input buffer pointer in register pair HL (which is the previous character).
1068-1069CP 30HCheck to see if the value in register A is a 0 (which is 30H).
106A-106BLoop until the character at the location of the input buffer pointer in register pair HL is not a zero character.
106C-106DCP “.”Check to see if the character at the location of the input buffer pointer in register A is a ..
NOTE: Results from a CP:- Z: A and * are the same
- NZ: A and * are NOT the same
- C: A < *
- NC: A => *
106E-1070If its NOT a decimal point, GOSUB to bump the value of the input buffer pointer in register pair HL.
1071POP AFGet the value from the stack (i.e., the exponent) and put it in register pair HL.
1075RST 20HWe 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 REG 1 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
- Double Precision is NZ/NC/P/E and A is 5.
1076-1077LD A,22HLoad register A with the starting value for a D or E character.
1078ADC A,AMultiply 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.
1079LD (HL),ASave the exponent designation (the D or E in register A) at the location of the input buffer pointer in register pair HL.
107AINC HLBump the value of the input buffer pointer in register pair HL, which is the first position of the exponent in the buffer.
107BPOP AFGet the value of the exponent from the stack and put it in register A.
107C-107DLD (HL),2BHSave a + (=2BH) at the location of the input buffer pointer in register pair HL.
1081-1082LD (HL),2DHSave a – (which is 2DH) at the location of the input buffer pointer in register pair HL.
1083CPLConvert the negative exponent to positive by reversing the value of the exponent in register A and …
1084INC A… bumping the value of the exponent in register A.
LD B,2FHAt this point, the exponent is positive. Next step is to load register B with a 0 minus one (which is a /).
1087INC BBump the value of the ASCII character in register B (so now it is an 0). This is the start of a 3 Opcode routine to divide by 10 using compound subtraction.
1088-1089SUB A,0AHSubtract ten from the value of the exponent in register A.
108A-108BLoop 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-108DADD A,3AHSince A is holding the remainder of the ‘divide-by-10’ routine above, add 3AH to it so that it will be an ASCII digit.
108EINC HLBump the value of the input buffer pointer in register pair HL.
108FLD (HL),BSave the ASCII character in register B (which is the first digit of the exponent in ASCII) at the location of the input buffer pointer in register pair HL.
1090INC HLBump the value of the input buffer pointer in register pair HL.
1091LD (HL),ASave the value of the ASCII character in register A (which is the second digit of the exponent in ASCII) at the location of the input buffer pointer in register pair HL.
1092INC HLBump the value of the input buffer pointer in register pair HL.
1093-1094LD (HL),00HSave an end of the ASCII string character (designated as 00H) at the location of the input buffer pointer in register pair HL.
1095EX DE,HLLoad register pair DE with the ending address of the input buffer pointer.
1096-1098LD HL,4130HLoad register pair HL with the starting address of the input buffer pointer.
NOTE: 4130H-4149H holds Internal print buffer.
1099RETReturn.
109BPUSH BCSave the value in register pair BC to the stack (currently B has the number of #‘s before the current vale of the input buffer pointer and C has the number of #’s after).
109C-109DCP 04HCheck to see if the current number type in REG 1 is single or double precision. Results:- If A=04H it sets the ZERO FLAG
- If A<04H then the CARRY FLAG will be set
- If A>=04H then the NO CARRY FLAG will be set
109ELD A,DLoad register A with the value of the edit flag in register D.
109F-10A1Jump to 1109H if the current value in REG 1 is either single precision or double precision (i.e., A>=04H since 4=Single precision and 8=Double precision
10A2RRARotate A right one bit to put the value of the exponential notation flag into the CARRY FLAG.
10A3-10A5JUMP to 11A3H if exponential notation is requested.
Alternative interpretation is Jump to 11A3H if the variable is a string; which will leave us now with only an integer value.
10A6 – This is where the PRINT USING routine will edit for INTEGER values.
10A6-10A8LD BC,0603HLoad register pair BC with a default value of 0603H (so that Register B has the number of leading digits of 6 and Register C has the comma counter of 3).
10A9-10ABGo check to see if commas are requested. If no comma is requested, set Register C to zero.
10ACPOP DEGet the value from the stack and put it in register pair DE. This will put the number of #’s to the left of the decimal point into D.
10ADLD A,DLoad register A with the number of digits requested to the left of the decimal point in register D.
10AE-10AFSUB A,05HSince 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.
10B0-10B2Go put leading zeros into the input buffer if the number of digits to the left of the decimal point requested is greater than the number of digits to the left of the decimal point for the maximum length of an integer value (meaning, the POSITIVE flag has been set).
10B3-10B5Call the INTEGER TO ASCII routine at 1232F (which converts the integer in REG 1 to ASCII and stores the ASCII string in the buffer pointed to in HL).
LD A,ELoad register A with the number of digits to the right of the decimal point requested (which is stored in register E).
10B7OR ACheck to see if there are any digits to the right of the decimal point requested and set the status flags accordingly.
10B8-10BAGo decrement the value of the input buffer pointer in register pair HL if there are no digits to the right of the decimal point requested.
10BBDEC ADecrement the number of digits to the right of the decimal point in register A. This tests to see if no count was given.
10BC-10BEIf the POSITIVE flag is set, gosub to 1269H to add trailing zeros to the ASCII string if necessary.
10C3POP HLGet the saved input buffer pointer value from the stack and put it in register pair HL.
10C6LD (HL),BSo now we know a sign does not follow the value so we save the character in register B (which should be a space) at the location of the input buffer pointer in register pair HL.
10C7INC HLBump the value of the input buffer pointer in register pair HL
10C8-10C9LD (HL),00HTerminate the buffer by saving an end of the ASCII string character (=00H) at the location of the input buffer pointer in register pair HL.
10CA-10CCLD HL,412FHLoad 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).
LD A,(40F3H)Load register A with the LSB of the address of the decimal point for the ASCII string.
NOTE: 40F3H-40F4H holds the temporary storage location.
10D1SUB A,LSubtract the LSB of the input buffer pointer address in register L from the value in register A.
10D2SUB A,DSubtract the number of digits to the left of the decimal point in register D from the adjusted value in register A.
10D3RET ZReturn if the input buffer pointer in register pair HL points to the start of the ASCII string.
10D4LD A,(HL)So now we know we are not at the start of the field, so we fetch the character at the location of the input buffer pointer in register pair HL into Register A.
10D5-10D6CP 20HCheck to see if the character at the location of the input buffer pointer in register A is a space (which is a blank).
10D7-10D8Jump back to 10CDH if the character at the location of the input buffer pointer in register pair HL is a space so that we keep looking until we are either at the start of the field, or a “+”, “-“, or “$” is found.
10D9-10DACP “*”Check to see if the character at the location of the input buffer pointer in register A is a *.
10DDDEC HLSince we want to ignore “*”‘s decrement the value of the input buffer pointer in register pair HL so it will get re-tested.
10DEPUSH HLSave the value of the input buffer pointer in register pair HL to the stack.
10DFPUSH AFSave the value in register pair AF (which is the current character) to the stack.
10E0-10E2LD BC,10DFHLoad register pair BC with the return address for use in case we have a –, a +, or a $.
10E3PUSH BCSave the return address in register pair BC to the stack.
10E4RST 10HSince 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.
NOTE:- The RST 10H routine loads the next character from the string pointed to by the HL register into the A-register and clears the CARRY FLAG if it is alphabetic, or sets it if is alphanumeric.
- Blanks and control codes 09H and 0BH 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.
10E5-10E6CP “-“Check to see if the character at the location of the input buffer pointer in register A is a –.
10E7RET ZReturn (to 10DFH) if the character at the location of the input buffer pointer in register A is a –.
10E8-10E9CP “+”Check to see if the character at the location of the input buffer pointer in register A is a +.
10EARET ZReturn (to 10DFH) if the character at the location of the input buffer pointer in register A is a +.
CP “$”Check to see if the character at the location of the input buffer pointer in register A is a $.
10EDRET ZReturn (to 10DFH) if the character at the location of the input buffer pointer in register A is a $.
POP BCWe don’t need a shortcut to jump to 10DFH anymore, so let’s get the real return address from the stack and put it in register pair BC.
10EF-10F0CP “0”Check to see if the character at the location of the input buffer pointer in register A is a 0.
10F1-10F2Jump to 1102H if the character at the location of the input buffer pointer in register A isn’t a 0.
10F3INC HLBump the value of the input buffer pointer in register pair HL so that we skip to the next character.
10F4RST 10HSince 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.
NOTE:- The RST 10H routine loads the next character from the string pointed to by the HL register into the A-register and clears the CARRY FLAG if it is alphabetic, or sets it if is alphanumeric.
- Blanks and control codes 09H and 0BH 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.
10F5-10F6Jump to 1102H if the character at the location of the input buffer pointer in register A isn’t a numeric character.
10F7DEC HLDecrement the value of the input buffer pointer in register pair HL to backspace to the last character examined.
01 2B 77Z-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.
10F9DEC HLDecrement the value of the input buffer pointer in register pair HL (we needed that Z-80 trick to avoid a double backspace in passing through).
10FALD (HL),ASave the character in register A at the location of the input buffer pointer in register pair HL.
10FBPOP AFGet the value from the stack and put it in register pair AF.
10FEPOP BCClear the stack.
POP AFRestore the character at the start of the field from the stack and put it in register pair AF.
1105POP HLGet the starting address of the field from the stack and put it in register pair HL.
1106-1107LD (HL),25HSave a % character at the location of the input buffer pointer in register pair HL (which is the starting address).
1108RETReturn.
1109 – This is where the PRINT USING routine will edit for FLOATING POINT values.
1109PUSH HLSave the current input buffer pointer in register pair HL to the stack.
110ARRARotate A right one bit, with Bit 0 going to the CARRY FLAG. This will allow us to test bit 0 of the edit flags to see if exponential notation is requested by the edit flag in register A.
110B-110DJump to 11AAH if exponential notation is requested by the edit flag in register A on a floating point number.
1110-1112LD DE,1384HLoad register pair DE with the address of the DOUBLE PRECISION value to be compared to the current value in REG 1. Register pair DE points to a double precision constant equal to 1el6.
1113-1115Go compare the double precision constant pointed to by register pair DE (which is 1el6) to the double precision value in REG 1.
1116-1117LD D,10HLoad register D with the maximum length of a double precision value (which is 16).
1118-111AJump to 1132H if the double precision value in REG 1 is less than or equal to 1el6.
POP HLSo now we know the double precision value in REG 1 exceeds 1×10^16. Get the current input buffer pointer from the stack and put it in register pair HL.
111CPOP BCGet 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.
111D-111FGo convert the double precision value in REG 1 to an ASCII string. The goal is to reenter the edit routine until the double precision value is less than 1×10^16.
1120DEC HLDecrement the input buffer pointer in register pair HL to get it back to the current position.
1121-1122LD (HL),”%”Save a % character at the location of the input buffer pointer in register pair HL.
1123RETReturn.
1124H – Continuation point if the current value in REG 1 is single precision.
1124-1126LD BC,B60EHLoad register pair BC with the exponent and the MSB of a single precision constant.
1127-1129LD DE,1BCAHLoad 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 1×10^16.
112A-112CCall the SINGLE PRECISION COMPARISON routine at 0A0CH.
NOTE: The routine at 0A0CH algebraically compares the single precision value in BC/DE to the single precision value REG 1.
The results are stored in A as follows:- A=00H if REG 1 = BCDE
- A=01H if REG 1>BCDE; and
- A=FFH if REG 1<BCDE.
112D-112FJump back to 111BH if the the POSITIVE flag is set (meaning the single precision value in REG 1 is greater than 1×10^16).
1130-1131LD D,06HNow we know that the SINGLE precision value in REG 1 is less than 1×10^16. Load register D with the maximum length of a single precision value (which is 6).
1135-1137GOSUB to 1201H to adjust the current value of REG 1 so that the single precision value is 99,999 < X < 999,999. On the return from that GOSUB, A will equal the number of times the value was scaled up or down as a + or -.
1138POP HLGet the origin of the ASCII buffer from the stack and put it in register pair HL.
1139POP BCGet 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-113CJUMP forward to 1157H if the value in REG 1 had to be scaled up (multiplied by 10) to get it in range.
113DPUSH BCSave the value in register pair BC (B was the number of #‘s before and C is the number of #‘s after) to the stack.
113ELD E,ALoad register E with the number of times the current value in REG 1 was divided.
113FLD A,BLoad register A with the number of digits before the decimal point requested.
1140SUB A,DSubtract the maximum length for the current number type in register D (which is 6) from the number of digits requested in register A.
1141SUB A,ESubtract the number of times the current value in REG 1 was divided in register E from the adjusted value in register A.
1142-1144If the POSITIVE flag is set, gosub to 1269H to put leading zeros into the input buffer if necessary.
1148-114AGOSUB to 12A4H to convert the integer portion of the current value in REG 1 to an ASCII string.
114BOR ECheck to see if there are any trailing zeros needed by testing the number of times the value was scaled.
114FOR ECheck to see if commas or the decimal point is needed.
1153POP DEGet the edit counts value from the stack and put it in register pair DE.
1157 – LEVEL II BASIC MATH ROUTINE – “FFXXVS”
This routine will print a SINGLE PRECISION or DOUBLE PREVISION number that has fractional digits
1157LD E,ALoad register E with the number of times the current value in REG 1 was scaled (multiplied by 10).
1158LD A,CLoad register A with the number of digits requested to the right of the decimal point.
1159OR ACheck to see if any digits to the right of the decimal point was requested.
115A-115CGo decrement the number of digits requested to the right of the decimal point if necessary.
115DADD A,EAdd 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.
1161XOR AZero register A and indicate that there is on scaling down needed.
1162PUSH BCSave the value in register pair BC (B was the number of #‘s before and C is the number of #‘s after) to the stack.
1163PUSH AFSave the value in register pair AF (the scale count) to the stack.
1167-1169Loop until the value in REG 1 is properly adjusted. When this is done, A will hold the number of times it was divided by 10.
116APOP BCGet the original scale count from the stack and put it in register pair BC.
116BLD A,ELoad register A with the number of times the value in REG 1 was multiplied in register E.
116CSUB A,BSubtract the value in register B from the value in register A.
116DPOP BCGet the before/after value from the stack and put it in register pair BC.
116ELD E,ALoad register E with the adjusted scale factor value in register A.
116FADD A,DAdd 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.
1170LD A,BLoad register A with the number of #‘s before (stored in B).
1174SUB A,DWe 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.
1175SUB A,EThen, subtract the adjusted scale value in register E from the adjusted value in register A.
1176-1178If that subtraction leads to a positive number, go put leading zeros into the input buffer.
1179PUSH BCSave the value in register pair BC (B was the number of #‘s before and C is the number of #‘s after) to the stack.
117F – LEVEL II BASIC MATH ROUTINE – “FFXXV3”
This routine will print a number without integer digits.
1182LD A,CLoad 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.
1186LD C,AReload register C with the number of digits requested to the right of the decimal point in register A.
1187XOR AZero Register A.
1188SUB A,DSubtract the maximum length for the current value in register D from the value in register A.
1189SUB A,ESubtract the value in register E from the adjusted value in register A.
118DPUSH BCSave the value in register pair BC (B was the number of #‘s before and C is the number of #‘s after) to the stack.
118ELD B,ALoad register B with the value in register A (which is 0).
118FLD C,ALoad register C with the value in register A (which is 0).
119A – LEVEL II BASIC MATH ROUTINE – “FFXXV7”
This routine will print trailing zeroes.
1190-1192GOSUB to 12A4H to convert the integer portion of the SINGLE precision value in REG 1 to an ASCII string.
1193POP BCGet the number of #‘s before and number of #‘s after and put it back in register pair BC.
1194OR CCheck to see if there are any digits to the right of the decimal point requested and set the status accordingly.
1197-1199LD HL,(40F3H)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 holds the temporary storage location.
119AADD A,EAdd the value in register E to the value in register A to get the number of digits before the decimal point.
119BDEC ADecrement the adjusted value in register A.
119C-119EIf dropping A by 1 still results in a positive number, GOSUB 1269H to put that number of zeros into the input buffer.
119FLD D,BLoad register D with the number of digits to the left of the decimal point requested (from Register B).
11A3 – LEVEL II BASIC MATH ROUTINE – “FFXIFL”
This routine will print an integer in fixed format/floating point notation.
11A3PUSH HLSave the current position of the input buffer (in register pair HL) to the stack.
11A4PUSH DESave the edit flags (in register pair BC) to the stack.
11A8POP DEGet the edit flags from the stack and put it in register pair DE.
11A9XOR AZero register A, clear the status flags.
11AA – LEVEL II BASIC MATH ROUTINE – “FFXFLV”
This routine will print a SINGLE or DOUBLE PRECISION number in fixed format/floating point notation.
11AA-11ACSlip the next 2 instructions to 11B0H (using a Z-80 trick) to skip the next instruction if the current value in REG 1 is SINGLE precision.
11AD-11AELD E,10HLoad register E with the maximum length of a double precision value (which is 16).
11AFH01 + LD E,06H
or
LD BC, 1E06HZ-80 Trick! By putting a 01 here, the opcode becomes a 3 byte opcode, turning 01 1E 06 into LD BC, 1E06H. This would corrupt BC, but otherwise would then make the next instruction 11B2H, skipping the next instruction of LD E,06H because, well, it doesn’t exist!
11B0H – Continuation Routine (From 11AAH) if the current value in REG 1 is SINGLE precision.
11B0-11B1LD E,06HLoad register E with the maximum length of a single precision value (which is 6).
11B5SCFSet the CARRY FLAG (to force a jump at 11F3 on the first pass).
11B9POP HLGet the input buffer position from the stack and put it in register pair HL.
11BAPOP BCGet the number of #‘s before and the number of #‘s after from the stack and put it in register pair BC.
11BBPUSH AFSave the decimal point and the flag for test at 11F3H in register pair AF to the stack.
11BCLD A,CLoad register A with the number of digits to the right of the decimal point requested (stored in register C).
11BDOR ASet the status so we can see if there are any digits to the right of the decimal point requested through a zero register.
11BEPUSH AFSave the original trailing digit count (in register pair AF) to the stack.
11BF-11C1If 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.
11C2ADD A,BAdd 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.
11C3LD C,ALoad register C with the total digit count (held in register A).
11C4LD A,DLoad register A with the value of the edit flag in register D.
11C5-11C6AND 04HCheck to see if the sign follows the ASCII string.
11C7-11C8CP 01HSet the CARRY FLAG according to the sign following the ASCII string test (it will be No Carry if a sign follows).
11C9SBC A,AAdjust register A so that it will reflect the sign following the ASCII string test (A will be 0 if there is no sign, and FEH otherwise).
11CALD D,ALoad register D with the edit flag (from register A).
11CBADD A,CAdd the value in register C to the value in register A so as to adjust the count of the digits to print if a sign follows.
11CCLD C,ALoad register C with the adjusted value in register A.
11CDSUB A,ESubtract 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.
11CEPUSH AFSave the divisor count (from register pair AF) to the stack.
11CFPUSH BCSave the character count (from register pair BC) to the stack.
11D0-11D2GOSUB to 0F18H to divide the current value in REG 1 by ten, Register A number of times.
11D6POP BCGet the counter of the #‘s from the stack and put it in register pair BC.
11D7POP AFGet the division count from the stack and put it in register pair AF.
11D8PUSH BCSave the value in Register Pair BC to the STACK.
11D9PUSH AFSave the value in register pair AF to the stack.
11DA-11DCSkip the next instruction (i.e., jump to 11DEH) if there are any trailing zeroes.
11DDXOR AZero register A and all status flags.
11DFINC ABump the value in register A so that it will be positive.
11E0ADD A,BAdd the number of digits requested to the left of the decimal point in register B to the adjusted value in register A.
11E1INC ABump the adjusted value in register A.
11E2ADD A,DAdd 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.
11E3LD B,ACopy Register A into Register B so that B holds the number of digits before the decimal point.
11E4-11E5LD C,00HLoad register C with zero (so that there are no commas).
11E9POP AFGet the number of #’s before from the stack and put it in register pair AF.
11EDPOP BCGet the number of #’s before and the number of #‘s after from the stack and put it in register pair BC.
11EEPOP AFGet the count of numbers before the decimal point from the stack and put it in register pair AF.
11EF-11F1GOSUB to 092FH to decrement the input buffer pointer in register pair HL if there are none.
11F2POP AFGet the first time flag from the stack and put it in register pair AF.
11F3-11F4Jump to 11F8H (to add the exponent) if the CARRY FLAG was set during the first pass.
11F5ADD A,EAdd the value in register E to the value in register A.
11F6SUB A,BSubtract the number of digits to the left of the decimal point requested in register B from the adjusted value in register A.
11F7SUB A,DSubtract the value in register D from the value in register A to get the size of the exponent.
11F9-11FBGOSUB to 1074H to figure the value of the exponent for the current value in REG 1
11FCEX DE,HLLoad register pair HL with the value of the input buffer pointer in register pair DE.
11FDPOP DEGet the value from the stack and put it in register pair DE. Clear the stack.
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.
1201PUSH DESave the value in register pair DE to the stack.
1202XOR AZero register A and all the flags.
1203PUSH AFSave the value in register pair AF to the stack.
1204RST 20HWe 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 REG 1 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
- Double Precision is NZ/NC/P/E and A is 5.
1205-1207If that test shows we have a SINGLE PRECISION number (through getting a Parity-Odd flag), jump to 1222H.
1208-120ALD A,(4124H)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 REG 1.
120B-120CCP 91HCheck to see if the double precision value in REG 1 uses more than 16 bits of precision for the integer portion of the double precision value.
NOTE: Results from a CP:- Z: A and * are the same
- NZ: A and * are NOT the same
- C: A < *
- NC: A => *
120D-120FJump to 1222H if the double precision value in REG 1 uses more than 16 bits of precision for its integer portion.
1210-1212LD DE,1364HLoad register pair DE with the starting address for the double precision constant equal to 5.5x10e2.
1213-1215LD HL,4127HLoad register pair HL with the starting address for REG2.
NOTE: 4127H-412EH holds REG 2.
1219-121BGOSUB to 0DA1H to call the DOUBLE PRECISION MULTIPLY routine at 0DA1H (which multiplies the double precision value in REG 1 by the value in REG 2. The product is left in REG 1).
121CPOP AFGet the number of times the DOUBLE precision value was multiplied to scale it up from the stack and put it in register pair AF.
121D-121ESUB A,0AHSubtract ten from the value in register A.
121FPUSH AFSave the value in register pair AF to the stack.
1225RST 20HWe 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 REG 1 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
- Double Precision is NZ/NC/P/E and A is 5.
1226-1228In ROM 1.2 this is a big bug fix. Now if the shows we do NOT have a STRING, jump to 1233H
1229-122BLD BC,9143HLoad register pair BC with the exponent and the MSB of a single precision constant.
122C-122ELD DE,4FF9HLoad 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-1231GOSUB to 0A0CH to call the SINGLE PRECISION COMPARISON routine at 0A0CH.
NOTE: The routine at 0A0CH algebraically compares the single precision value in BC/DE to the single precision value REG 1.
The results are stored in A as follows:- A=00H if REG 1 = BCDE
- A=01H if REG 1>BCDE; and
- A=FFH if REG 1<BCDE.
1233-1235LD DE,136CHLoad register pair DE with the starting address of a double precision constant equal to 9.9921El4.
1236-1238Go compare the double precision constant pointed to by register pair DE to the double precision value in REG 1.
1239-123BJump to 124CH if the current value in REG 1 is greater than the constant compared to it (more than 5 digits in integer or less than 17 digits in DOUBLE precision).
123CPOP AFGet the value of the scaled counter from the stack and put it in register pair AF.
1240PUSH AFSave the value in register pair AF to the stack. A is the negative of the number of times the value was multiplied.
1243POP AFGet the scaled count from the stack and put it in Register A.
1247PUSH AFSave the value in register pair AF to the stack. A is the count of the number of times it was divided.
124BPOP AFGet the value from the stack and put it in register pair AF. A = + times divided or – times multiplied.
Difference between M1 and M3 ROMs: This change first appeared in the “new” ROMs for the Model I. The order of two instructions (OR A and POP DE) have been reversed for no apparent reason.
124CPOP DEGet the value from the stack and put it in register pair DE.
124DOR AIn ROM v1.2 sets the status flags. This also realigns the memory addresses from changes to v1.2 ROM.
124ERETReturn.
124FRST 20HWe 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 REG 1 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
- Double Precision is NZ/NC/P/E and A is 5.
1253-1255LD BC,9474HNow 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-1258LD DE,23F8HLoad 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-125BCall the SINGLE PRECISION COMPARISON routine at 0A0CH.
NOTE: The routine at 0A0CH algebraically compares the single precision value in BC/DE to the single precision value REG 1.
The results are stored in A as follows:- A=00H if REG 1 = BCDE
- A=01H if REG 1>BCDE; and
- A=FFH if REG 1<BCDE.
125E-1260LD DE,1374HLoad register pair DE with the starting address of a double precision constant equal to 1El6H.
1261-1263GOSUB to 0A49H to compare the double precision constant pointed to by register pair DE to the double precision value in REG 1.
1264Get the return address from the stack and put it in register pair HL so we can go to 1244H.
1268JP (HL)Jump to the caller (which was POPed from the stack).
This routine puts leading zeroes into the input buffer
1269OR ACheck to see if the value in register A is equal to zero.
126ARET ZReturn if the value in register A is equal to zero.
126BDEC ADecrement the value in register A to show that an ASCII zero was moved to the print buffer.
126C-126DLD (HL),”0″Save a 0 at the location of the input buffer pointer in register pair HL.
126EINC HLBump the input buffer pointer in register pair HL.
1277-1278LD (HL),”0″Save a zero character at the location of the input buffer pointer in register pair HL.
1279INC HLBump the input buffer pointer in register pair HL.
127ADEC ADecrement the counter of trailing zeroes to add in register A.
127DH – Subroutine to set up BC for decimal point and comma counters. On entry: Register D holds the number of digits to print, Register E holds the count of the times the value was scaled up or down.
127DLD A,ELoad register A with the value in register E so that A holds the count of the times the value was scaled up or down.
127EADD A,DAdd the number of digits to print (from Register D) to the value in register A.
127FINC ABump the adjusted value in register A so now A holds the number of digits before the decimal point.
1280LD B,ALoad register B with the leading digit count (from register A).
1281INC ABump the value in register A so not A holds the leading digits + 2.
1282-1283SUB A,03HSubtract three from the adjusted value in register A which, when combined with the next instruction as a loop, divides modulo 3.
1286-1287ADD A,05HAdd 5 to A to get a positive remainder. This will give 4, 3, or 2 as the comma count.
1288LD C,ALoad register C with the comma count in register A.
LD A,(40D8H)Load register A with the value of the edit flag (stored at 40D8H).
NOTE: 40D8H-40D9H holds the temporary storage location.
128C-128DAND 40HMask the EDIT FLAG against 40H (Binary: 0100 0000) to isolate bit 6 (the comma bit) in the edit flag word to see if commas are requested.
128ERET NZReturn with Register C = Comma count if commas are requested.
1291H – Subroutine to count the leading digits before the decimal point.
1291DEC BDecrement the decimal point counter in register B to see if the zero flag sets or not.
1294-1295LD (HL),”.”Save a . at the location of the input buffer pointer in register pair HL.
1296-1298LD (40F3H),HLSave the address of the decimal point position (which is held in 40F3H) in register pair HL.
NOTE: 40F3H-40F4H holds the temporary storage location.
1299INC HLBump the input buffer pointer in register pair H to the first character of the fractional part of a numberL.
129ALD C,BZero the comma/decimal counter in register C (because B is zero since the above jump didn’t fire) to stop any more decimal points and commas.
129BRETReturn.
129CH – Continuation Routine (from 1292H) if the decimal point position hasn’t been reached.
129CDEC CDecrement the decimal/comma counter in register C.
129DRET NZReturn if this location is not the end of a 3 character group (and so it doesn’t need a comma).
129E-129FLD (HL),”,”If didn’t jump out, then we need a comma here so put a comma at the location of the input buffer pointer in register pair HL.
12A0INC HLBump the input buffer pointer (to account for the new comma) in register pair HL.
12A1-12A2LD C,03HReset the comma counter by setting it to 3.
12A3RETReturn.
12A4 – Routine to Convert the INTEGER porton of a DOUBLE precision value to its ASCII equivalent.
12A4PUSH DESave the edit flags (stored in register pair DE) to the stack.
12A5RST 20HWe 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 REG 1 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
- Double Precision is NZ/NC/P/E and A is 5.
12A6-12A8If we have a single precision number (PO Flag Set), JUMP to 12EAH to convert a SINGLE precision number into its INTEGER equivalent.
12A9PUSH BCNow that we know we have a DOUBLE PRECISION number, save leading digit count/comma count (in register pair BC) to the stack.
12AAPUSH HLSave the input buffer address (in register pair HL) to the stack.
12AE-12B0LD HL,137CHLoad register pair HL with the starting address of a double precision constant equal to 0.5.
12B1-12B3GOSUB to 09F7H to move the double precision value pointed to by register pair HL to REG 1.
12B4-12B6GOSUB to 0C77H – DOUBLE PRECISION ADD function (which adds the double precision value in REG 2 to the value in REG 1 (which is the constant 0.5). Result is left in REG 1).
12B7XOR AZero register A and clear the status flags.
12BBPOP HLGet the input buffer address from the stack and put it in register pair HL.
12BCPOP BCGet the counters from the stack and put it in register pair BC.
12BD-12BFLD DE,138CHLoad 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-12C1LD A,0AHLoad register A with the number of times to divide the double precision value in REG 1 by a power of 10.
12C2-12C4GOSUB to 1291H to add a decimal point or comma (as applicable) into the input buffer if necessary.
12C5PUSH BCSave 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.
12C6PUSH AFSave the division count (stored in register pair AF) to the stack.
12C7PUSH HLSave the current input buffer address (stored in register pair HL) to the stack.
12C8PUSH DESave the address of the power table (stored in register pair DE) to the stack.
12C9-12CALD B,2FHLoad register B (which will be the quotient in ASCII for each division) with the ASCII value for a zero character minus one.
12CCPOP HLGet the address of the power table (i.e., the divisor) from the stack and put it in register pair HL and …
12CDPUSH HL… put it right back into the stack so that it can be restored during the loop.
12CE-12D0GOSUB 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-12D2Jump 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).
12D3POP HLGet the address of the power table from the stack and put it in register pair HL.
12D4-12D6GOSUB 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 REG 1 to make it a positive value. Return with the correct remainder in REG 1.
12D7EX DE,HLLoad register pair DE with the starting address for the current power of 10 (stored in register pair HL).
12D8POP HLGet the current input buffer address from the stack and put it in register pair HL.
12D9LD (HL),BSave the ASCII value for the digit in register B at the location of the input buffer pointer (stored in register pair HL).
12DAINC HLBump the input buffer pointer in register pair HL since we have just put a digit there.
12DBPOP AFGet the status flags from the stack and put it in register pair AF so that we can test for 10 times.
12DCPOP BCGet the counts of digits before/after the decimal point value from the stack and put it in register pair BC.
12DDDEC ADecrement the counter value in register A (we are going to loop 10 times).
12E0PUSH BCSave the the counts of digits before/after the decimal point value (stored in register pair BC) to the stack.
12E1PUSH HLSave the current input buffer pointer (stored in register pair HL) to the stack.
12E2-12E4LD HL,411DHLoad register pair HL with the starting address for REG 1 (which holds the last half of the DOUBLE prevision value)
Note: 411DH-4124H holds REG l.
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.
12EAPUSH BCSave the leading digit count/comma count (in register pair BC) to the stack.
12EBPUSH HLSave the current input buffer pointer (stored in register pair HL) to the stack.
12EC-12EEGOSUB to 0708H to add a single precision value of 0.5 to the single precision value in REG 1. The result is stored in BC/DE.
12EFINC ABump the MSB.
12F0-12F2GOSUB to 0AFBH to convert the positive single precision value in REG 1 to an integer. The result is stored in BC/DE.
12F3-12F5GOSUB to 09B4H (which moves the SINGLE PRECISION value in DC/DE [which is the integer portion of the original single precision value] into REG 1).
12F6POP HLGet the current input buffer pointer value from the stack and put it in register pair HL.
12F7POP BCGet the leading digit count/comma count value from the stack and put it in register pair BC.
12F8XOR AZero register A.
12F9-12FBLD DE,13D2HLoad register pair DE with the starting address for a series of integer values (in this case, 100,000).
CCFComplement the CARRY FLAG. This is the first time switch for the division loop of 12FC-1327H.
12FD-12FFGOSUB to 1291H to put a decimal point or a comma into the input buffer if necessary .
1300PUSH BCSave the counts of digits before/after the decimal point value (stored in register pair BC) to the stack.
1301PUSH AFSave the CARRY FLAG for the count of the number of times through this loop (stored in register pair AF) to the stack.
1302PUSH HLSave the current input buffer pointer value (stored in register pair HL) to the stack.
1303PUSH DESave the division table address (stored in register pair DE) to the stack.
1304-1306GOSUB to 09BFH (which loads the SINGLE PRECISION value in REG 1 into register pair BC/DE).
1307POP HLGet the division table address (the integer value for 100,000) from the stack and put it in register pair HL.
1308-1309LD B,2FHLoad register B with the ASCII value for a zero character minus one.
130AH – 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.
130AINC BBump the ASCII value from the digit in register B to increase the ASCII value from 0 and upward.
130BLD A,ELoad register A with the LSB of the single precision value in register E.
130CSUB (HL)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.
130DLD E,ALoad register E with the adjusted LSB of the single precision value in register A.
130EINC HLBump the value of the memory pointer in register pair HL to the next digit of 100,000.
130FLD A,DLoad register A with the NMSB of the single precision value in register D.
1310SBC A,(HL)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.
1311LD D,ALoad register D with the adjusted NMSB of the single precision value in register A.
1312INC HLBump the value of the memory pointer in register pair HL to the MSB of 100,000.
1313LD A,CLoad register A with the MSB of the single precision value in register C.
1314SBC A,(HL)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).
1315LD C,ALoad register C with the adjusted MSB of the single precision value in register A.
1316DEC HLDecrement the value of the memory pointer in register pair HL to the NMSB of 100,000.
1317DEC HLDecrement the value of the memory pointer in register pair HL again, now to the LSB of 100,000.
131A-131CWe need to add 100,000 to C/DE 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.
131DINC HLBump the value of the memory pointer in register pair HL to now point to the 10,000 constant.
131E-1320Save the remainder as a current value by GOSUB to 09B4H (which moves the SINGLE PRECISION value in DC/DE into REG 1).
1321EX DE,HLLoad register pair DE with the address of the next value to divide the current value in REG 1 by (which is the constant of 10,000).
1322POP HLGet the value of the memory pointer from the stack and put it in register pair HL.
1323LD (HL),BSave the ASCII value for the digit in register B at the location of the input buffer pointer in register pair HL.
1324INC HLBump the value of the input buffer pointer in register pair HL.
1325POP AFGet the CARRY FLAG from the stack and put it in register pair AF.
1326POP BCGet the value from the stack and put it in register pair BC so it can be saved later.
1327-1328If the CARRY FLAG is set, then reset it and loop the dividing by 10,000 until the integer portion is found.
1329INC DEIf 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.
132AINC DEand again bump the value of the memory pointer in register pair DE, so now DE points to the constant 1,000.
132B-132CLD A,04HLoad register A with the number of digits for the ASCII string to be figured.
132FH – This routine will convert an INTEGER to ASCII.
132FPUSH DESave the edit flags (stored in register pair DE) to the stack.
1330-1332LD DE,13D8HLoad register pair DE with the starting address of the descending powers of 10 starting at 10,000.
1333-1334LD A,05HLoad register A with the number of digits for the ASCII string to be built (i.e., 5).
1335H – This routine will convert the last x (based on A) digits of an INTEGER to ASCII.
1338PUSH BCSave the counts of digits before/after the decimal point value (stored in register pair BC) to the stack.
1339PUSH AFSave the number of digits counter (stored in register A) to the stack.
133APUSH HLSave the address of the power table (stored in register pair HL) to the stack.
133BEX DE,HLLoad register pair HL with the starting address of the descending powers of 10 starting at 10,000 (stored in register pair DE).
133CLD C,(HL)Load register C with the LSB for the power of 10 stored in register pair HL.
133DINC HLBump the value of the memory pointer in register pair HL to be the MDB of the power of 10.
133ELD B,(HL)Load register B with the MSB for the integer value at the location of the memory pointer in register pair HL.
133FPUSH BCSave the integer value of the power of 10 in register pair BC to the stack.
1340INC HLBump the value of the memory pointer in register pair HL to the next value in the power of 10 table.
1341EX (SP),HLExchange the memory pointer of the next power of 10 (stored in register pair HL) with the value in the stack, and vice versa.
1342EX DE,HLLoad register pair DE with the current value from the stack (stored in register pair HL).
1343-1345LD HL,(4121H)Load register pair HL with the integer value in REG 1.
1346-1347LD B,2FHSince 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.
1348 – 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).
1348INC BBump the ASCII value for the digit in register B (so it starts at 0 and moves up each loop).
1349LD A,LLoad register A with the LSB of the integer value in register L.
134ASUB ESubtract 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.
134BLD L,ALoad register L with the adjusted value of the LSB of the integer value in register A.
134CLD A,HLoad register A with the value of the MSB of the integer value in register H.
134DSBC A,DSubtract the MSB of the integer value in register D from the value of the MSB of the integer value in register A.
134ELD H,ALoad register H with the adjusted value of the MSB of the integer value in register A.
134F-1350Loop back to 1348H until the CARRY FLAG is triggered because the quotient (stored in HL) is less than the current power of 10.
1351ADD HL,DEAdd the remainder (stored as an integer in register pair DE) to the quotient (stored in register pair HL as an integer).
1352-1354LD (4121H),HLSave the integer remainder (stored in register pair HL) in REG 1.
1355POP DEGet the address of the next power of 10 from the stack and put it in register pair DE.
1356POP HLGet the memory pointer for the output buffer from the stack and put it in register pair HL.
1357LD (HL),BSave 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).
1358INC HLBump the value of the input buffer pointer in register pair HL since we just filled that spot with an ASCII value.
1359POP AFGet the number of digits to convert from the stack and put it in A.
135APOP BCGet the counts of digits before/after the decimal point value from the stack and put it into register pair BC.
135BDEC ADecrement the value of the counter in register A (which is a countdown from 5).
135C-135DIf 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-1360So 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.
1361LD (HL),ASave 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.
1362POP DEGet the value from the stack (which was whatever value was in DE when this routine started) and put it in register pair DE.
1363RETReturn.
1364-136B – DOUBLE PRECISION CONSTANT STORAGE LOCATION
1364-136BH00 00 00 00 F9 02 15 A2A double precision constant equal to 1E10 (or 10 x 10E9)is stored here.
136C-1373 – DOUBLE PRECISION CONSTANT STORAGE LOCATION
136C-1373HFD FF 9F 31 A9 5F 63 B2A double precision constant equal to 9.9921E14 (or 1 x 10e15) is stored here.
1374-137B – DOUBLE PRECISION CONSTANT STORAGE LOCATION
1374-137BHFE FF 03 BF C9 1B 0E B6A double precision constant equal to 1×10^16 is stored here.
137C-1383 – DOUBLE PRECISION CONSTANT STORAGE LOCATION
137C-1383H00 00 00 00 00 00 00 80A double precision constant equal to 0.5 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
1384-138BH00 00 04 BF C9 1B 0E B6A double precision constant equal to 1×10^16 is stored here.
138A-138DH0E B5 00 80BYTE SAVING NOTE: A double precision constant equal to .502778.
138C-13D1 – DOUBLE PRECISION INTEGER CONSTANT STORAGE LOCATION
138C-1392H00 80 C6 A5 7E 8D 031 x 10e15.
1393-1399H00 40 7A 10 F3 5A 001 x 10e14.
139A-13A0H00 A0 72 4E 18 09 001 x 10e13.
13A1-13A7H00 10 A5 D5 E8 00 001 x 10e12.
13A1-13A7H00 10 A5 D5 E8 00 001 x 10e12.
13A8-13AEH00 E8 76 48 17 00 001 x 10e11 (which is 100,000,000,000).
13AF-13B5H00 E4 0B 54 02 00 001 x 10e10 (which is 10,000,000,000).
13B6-13BCH00 CA 9A 3B 00 00 001 x 10e09 (which is 1,000,000,000).
13BD-13C3H00 E1 F4 05 00 00 001 x 10e08 (which is 100,000,000).
13C4-13CAH80 96 98 00 00 00 001 x 10e07 (which is 10,000,000).
13CB-13D1H40 42 0F 00 00 00 001 x 10e06 (which is 1,000,000).
13D2H-13D9H – SINGLE PRECISION INTEGER CONSTANT STORAGE LOCATION
13D2-13D4HA0 86 011 x 10e04 (which is 100,000).
13D5-13D7H10 27 001 x 10e03 (which is 10,000).
13D8-13D9HE8 031 x 10e02 (which is 1,000).
13DA-13DBHE8 031 x 10e01 (which is 100).
13DEH101 x 10e00 (which is 10).
13E1-13E6 – LEVEL II BASIC MATH ROUTINE
13E1NOPDo nothing.
LD HL,0982HLoad register pair HL with 0982H.
NOTE: 0982H is the address of the routine for conversion of floating point numbers from negative to positive.
13E5EX (SP),HLExchange the value of that routines jump address to the stack with the value of the return address in register pair HL.
13E6JP (HL)Jump to the address in register pair HL, which is basically a return to caller.
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-13F1GOSUB 09A4 which moves the SINGLE PRECISION value in REG 1 to the stack (stored in LSB/MSB/Exponent order).
13EA-13ECLD HL,1380HLoad register pair HL with the starting address of a single precision constant equal to 0.5 (which will be the exponent).
13F0-13F1Jump 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-13F4Make 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 REG 1 from integer or double precision into single precision).
13F5POP BCGet the MSB of the single precision value from the stack and put it in register pair BC.
13F6POP DEGet the NMSB and the LSB of the single precision value from the stack and put it in register pair DE.
NOTE: To use a ROM call to raise a single precision number (the base) to a single precision power (the exponent), store the base (single precision) in registers BCDE, and store the exponent (also single precision) in 4121H-4124H and then CALL 13F7H. The result (in single precision format) is in 4121H-4124H and in approximately 50 milliseconds.
13F7-13F9GOSUB 0955H to check the sign for the single precision value in REG 1 (the exponent).
13FALD A,BLoad register A with the MSB of the number to be raised (stored as a single precision value in register B).
13FB-13FCJump to the EXP(n) routine at 1439H if the exponent (the single precision value in REG 1) is equal to zero.
13FD-13FFSkip the next 2 opcodes (which check to see if zero is involved) if the exponent (the single precision value in REG 1) is positive.
1400OR ACheck to see if the value to be raised (i.e., the single precision value in register pairs BC and DE) is equal to zero.
1401-1403Display a ?/0 ERROR message if the single precision value in REG 1 is negative and the single precision value in register pairs BC and DE is equal to zero.
/0 ERROR entry point.
1404OR AANOTHER 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-1407Jump to 0779H if the value to be raised (i.e., the single precision value in register pairs BC and DE) is equal to zero.
1408PUSH DEAt 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.
1409PUSH BCSave the exponent and the MSB of the single precision value in register pair BC to the stack.
140ALD A,CLoad register A with the value of the MSB of the single precision value to be raised (which is stored in register C).
140B-140COR 7FHTest the sign of the based by turning on bits 0-6 of the MSB of the single precision value (0111 1111) in register A.
140D-140FLoad the exponent (the power) into BC/DE by GOSUB to 09BF which loads the SINGLE PRECISION value in REG 1 (the exponent) into register pair BC/DE.
1410-1412Jump down to 1421H if the base (the single precision value to the stack) is positive.
1413PUSH DESave the NMSB and the LSB of the exponent (the single precision value in register pair DE) to the stack.
1414PUSH BCSave the exponent and the LSB of the single precision value in register pair BC to the stack.
1415-1417GOSUB to 0B40H to figure the integer portion of the exponent (i.e., the single precision value in REG 1) into A with the truncated floating point portion into REG 1.
1418POP BCRestore the exponent and the MSB of the single precision value from the stack and put it in register pair BC.
1419POP DERestore the NMSB and the LSB of the single precision value from the stack and put it in register pair DE.
141APUSH AFSave the integer portion of the exponent (i.e., the value in register pair AF) to the stack.
141B-141DCompare the original exponent to the truncated one by GOSUB to 0A0CH.
NOTE: The routine at 0A0CH algebraically compares the single precision value in BC/DE to the single precision value REG 1.
The results are stored in A as follows:- A=00H if REG 1 = BCDE
- A=01H if REG 1>BCDE; and
- A=FFH if REG 1<BCDE.
141EPOP HLGet the exponent as an integer from the stack and put it in register H.
141FLD A,HLoad register A with the exponent as an integer (as stored in register H).
1420RRAIf the exponent (as an integer) is odd, set the CARRY FLAG.
1422-1424LD (4123H),HLSave the value of the original exponent and the MSB of the single precision value (stored in register pair HL) in REG 1.
1425POP HLGet the rest of the exponent from the stack and put it in register pair HL.
1426-1428LD (4121H),HLSave 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 REG 1.
1429-142BIf the CARRY FLAG is set (i.e. the exponent is odd and the base is negative) GOSUB to 13E2H.
142C-142EIf the exponent is an integer and the base is negative, GOSUB to 0983H to invert the value of the exponent.
142FPUSH DESave the NMSB and the LSB of the exponent (i.e., the single precision value in register pair DE) to the stack.
1430PUSH BCSave the MSB of the exponent (i.e., the single precision value in register pair BC) to the stack.
1431-1433CALL the LOG(N) routine at 0809H (which computes the natural log (base E) of the single precision value in REG 1. The result is returned as a single precision value in REG 1. Can give an ILLEGAL FUNCTION CALL erro if a negative base is raised to a power with a fraction).
1434POP BCGet the exponent and the MSB of the single precision value from the stack and put it in register pair BC.
1435POP DEGet the NMSB and the LSB of the single precision from the stack and put it in register pair DE.
1436-1438We 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 REG 1 by the value in (BC/DE). The product is left in REG 1.
1439 – EXP routine. Single-precision only. (REG 1 = EXP(REG1)).
A call to 1439H raises E (natural base) to the value in REG 1 which must be a single precision value. The result will be returned in REG 1 as a single precision number.
NOTE: To use a ROM call to find EXP(X), where X is a single precision variable, store the value of X in 4121H-4124H and then CALL 1439H. The result (in single precision format) is in 4121H-4124Hin approximately 28 milliseconds. NOTE: A fatal error occurs if the result is as large as 2 to the power of 127.
1439-143BH
“EXP”Call 09A4 to move the SINGLE PRECISION value in REG 1 (the exponent) to the stack (stored in LSB/MSB/Exponent order).
143C-143ELD BC,8138HLoad register pair BC with the exponent and MSB of a single precision constant.
143F-1441LD DE,AA3BHLoad 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-1444We 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 REG 1 by the value in (BC/DE). The product is left in REG 1.
1445-1447LD A,(4124H)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 REG 1.
1448-1449CP 88HCheck to see if the integer portion of the single precision value in REG 1 uses more than 7 bits of precision by comparing it against a mask of 1000 1000.
144A-144CJump to 0931H if the single precision value in REG 1 uses more than 7 bits of precision for its integer portion.
144D-144FSo now that we know the integer portion is less than 8 bits, we need to get the integer and put it into Register A by GOSUB to 0B40H to get the integer portion of the value in REG 1 and return with it in register A.
1450-1451ADD A,80HAdjust the value in register A by masking it against 80H (Binary: 1000 0000).
1452-1453ADD A,02HAdjust the value in register A by adding 2 more (Binary: 1000 0010).
1454-1456If (exponent * 2 ln 2) is => 126 (meaning when 2 was added it it, it overflowed with a 128), jump to 0931H.
1457PUSH AFSave the integer value (+82H) (as stored in register pair AF) to the stack.
1458-145ALD HL,07F8HLoad register pair HL with a single precision constant equal to 1.0 (as found at 1458H).
145B-145DGo add the single precision constant 1.0 (as pointed to by register pair HL) to the current value in REG 1 which is EXP * 2 ln 2.
145E-1460Need to multiply that by ln 2, so GOSUB to 0841H to multiply (1 + [EXP * 2 ln 2]) (as stored in REG 1) by 0.693147.
1461POP AFGet the integerized value of EXP * 2 ln 2 (as stored in the stack) and put it in register pair AF.
1462POP BCGet 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 …
1463POP DEand then get the NMSB and the LSB of the single precision value from the stack and put it in register pair DE.
1464PUSH AFSave the integerized EXP * 2 ln 2 (stored in register pair AF) to the stack.
1465-1467Now 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 REG 1. The difference is left in REG 1).
1468-146ATo force that difference to be a positive number we GOSUB to 0982H which makes the current single precision value in REG 1 positive.
146B-146DLD HL,1479HLoad register pair HL with the starting address for a series of 8 coefficients.
1471-1473LD DE,0000HWe need to load the integerized equivalent of EXP * 2 lnt 2 into BC/DE so first we load register pair DE with zero …
1474POP BC… and then get the value from the stack and put it in register pair BC.
1475LD C,DLoad register C with zero (since Register D was filled with a zero in 1471H).
1476-1478We 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 REG 1 by the value in (BC/DE). The product is left in REG 1.
1479-1499 – SINGLE PRECISION CONSTANT STORAGE LOCATION
This represents 1/6, -1/5, 1/4, -1/3, 1/2, -1, and 1
1479H09The number of single precision constants (9) which follow are stored here.
147A-147DH40 2E 94 74A single precision constant equal to -0.00014171607 (-1.413165 * 10e-4) is stored here.
147E-1481H70 4F 2E 77A single precision constant equal to 0.00132988204 (1.32988 * 10e-3, roughly -1/6) is stored here.
1482-1485H6E 02 88 7AA single precision constant equal to -0.00830136052 (-8.30136 * 10e-3, roughly -1/5) is stored here.
1486-1489HE7 A0 2A 7CA single precision constant equal to 0.04165735095 (roughly 1/4) is stored here.
148A-148DH50 AA AA 7EA single precision constant equal to -0.16666531543 (roughly -1/3) is stored here.
148E-1491HFF FF 7F 7FA single precision constant equal to 0.49999996981 (roughly 1/2) is stored here.
1492-1495H00 00 80 81A single precision constant equal to -1.0 is stored here.
1496-1499H00 00 00 81A single precision constant equal to 1.0 is stored here.
149A-14C8 – LEVEL II BASIC MATH ROUTINE
This is a general purpose summation routine which computes the series SUM ((((x^2 * c0+c1)x^2 +c2)x^2 + … cN)x 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.
149A-149CGOSUB to 09A4 to which move the SINGLE PRECISION value in REG 1 to the stack (stored in LSB/MSB/Exponent order).
149D-149FLD DE,0C32HLoad register pair DE with the return address of 0C32H.
NOTE: 0C32H pops BC and DE and then JUMPs to JP 0847H.
14A0PUSH DESave DE to the STACK.
14A1PUSH HLSave the memory pointer of list containing the number of terms followed by the coefficients (as stored in register pair HL) to the stack.
14A2-14A4GOSUB to 09BFH which loads the SINGLE PRECISION value in REG 1 into register pair BC/DE.
14A5-14A7Since REG 1 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 REG 1 by the value in (BC/DE). The product is left in REG 1).
14A8POP HLRestore the address of the coefficient from the stack and put it in register pair HL.
14A9-14ABWe 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 REG 1 to the stack (stored in LSB/MSB/Exponent order).
14ACLD A,(HL)Load register A with the number of values to be figured at the location of the memory pointer in register pair HL.
14ADINC HLBump the value of the memory pointer in register pair HL so that it points to the next coefficient.
14AE-14B0Now load the coefficient (stored in HL) and move it to REG 1 by GOSUB to 09B1H (which moves a SINGLE PRECISION number pointed to by HL to REG 1).
14B1H06 F1Z-80 Trick! See the general explanation at 10F8H.
14B3-14B4POP BC
POP DEGet the value of x from the stack and put it in register pair BC/DE.
14B5DEC ACount 1 of the terms as computed by decrementing the counter in register A.
14B6RET ZIf that decrement results in a zero (meaning the series of computations has been completed) return out of the subroutine.
14B7-14B8PUSH DE
PUSH BCSave the NMSB and the LSB of x from DE to the stack and save the MSB of x from BC to the stack.
14B9PUSH AFSave counter of remaining terms to compute (stored in register A) to the stack.
14BAPUSH HLSave the value of the memory pointer to the next coefficient (stored in register pair HL) to the stack.
14BB-14BDCompute C(I)*x by GOSUB to 0847H which is the SINGLE PRECISION MULTIPLY routine (which multiplies the current value in REG 1 by the value in (BC/DE). The product is left in REG 1.
14BEPOP HLRestore the coefficient table address (from the stack) to register pair HL.
14BF-14C1Get 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).
14C2PUSH HLSave the next coefficient (stored in register pair HL) to the stack.
14C3-14C5Compute 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 REG 1. The sum is left in REG 1).
14C6POP HLRestore the coefficient table address (from the stack) to register pair HL.
14C9-1540 – LEVEL II BASIC RND(n). Generates a single-precisions random number between 0 and 1, or 1 and n depending on the parameter passed in REG 1, The random value is returned in REG 1 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.
NOTE: To run a RND(J) function via a ROM call just The RND(J) function (with J a nonzero integer) load the value of J into the HL register pair. Then CALL 14CCH and then CALL 0A7FH. The result (in integer format) is in 4121H-4122H and in HL in approximately 5.7 milliseconds. The input variable J must have a value between 1 and 32767, inclusive, or an FC error will occur.
14C9-14CBH
“RNDM”Call the CONVERT TO INTEGER routine at 0A7FH (where the contents of REG 1 are converted from single or double precision to integer and deposited into HL).
14CCLD A,HLoad register A with the value of the MSB for the integer value in register H.
14CDOR ACheck to see if the integer value in register pair HL is negative.
14CE-14D0Display a ?FC ERROR message if the integer value in register pair HL is negative.
14D1OR LTo test for HL=0, the opcode pair of LD A,H / OR L is a simplest way. Only if both H and L are zero, will A be zero.
14D2-14D4If 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)) if the integer value in register pair HL is equal to zero (meaning the call was for RND(0)).
14D5PUSH HLSince it wasn’t zero, we need to save the n of RND(n) (as stored in register pair HL) to the stack.
14D6-14D8GOSUB to 14F0H (which generates RND(0)) and return with the single precision result in REG 1.
14D9-14DBLoad the random number into BC/DE by a GOSUB to 09BFH which loads the SINGLE PRECISION value in REG 1 into register pair BC/DE.
14DCEX DE,HLLoad register pair HL with the NMSB and the LSB of the single precision value in register pair DE.
14DDEX (SP),HLExchange the integer value to the stack with NMSB and the LSB of the single precision value in register pair HL. At this point, the random number is in the stack and the n (of RND(n)) is stored in register pair HL.
14DEPUSH BCSave the RND(0) value to the stack.
14DF-14E1Convert 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 REG 1.
14E2-14E3POP BC
POP DERestore the RND(0) value from the stack and put it into register pair BC/DE.
14E4-14E6Multiply the RND(0) value (currently in BC/DE) by the n of RND(n) (currently in REG 1) by GOSUB to 0847H which is the SINGLE PRECISION MULTIPLY routine (which multiplies the current value in REG 1 by the value in (BC/DE). The product is left in REG 1.
14E7-14E9LD HL,07F8HLoad register pair HL with the starting address of a single precision constant equal to 1.0.
14EA-14ECIncrease 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 REG 1 (which is the random number). Return with the single precision result in REG 1
14ED-14EFWith the random number now in REG 1, jump to 0B40H (which will convert it to an integer and RETurn to the subroutine caller).
14F0H – This routine calculates RND(0).
NOTE: To run a RND(0) function via a ROM call just CALL 14F0H. No input variable is necessary. The result (in single precision format) is in 4121H-4124H in approximately 2.4 milliseconds.
14F0-14F2LD HL,4090HLoad register pair HL with the starting address for a table used for figuring random numbers.
NOTE: 4090H holds the random number seed 2
14F3PUSH HLSave the starting address for a table used for figuring random numbers (stored in HL) to the stack.
14F4-14F6LD DE,0000HLoad register pair DE with zero (which will be the NMLSB and LSB of the starting value).
14F7LD C,ELoad register C with zero (C will be the MSB of the starting value).
14F8-14F9LD H,03HLoad register H with the counter value for the loop (which will be 3).
EX DE,HLExchange the counters in register pair HL with the NMSB and the LSB of the random number in register pair DE.
14FDADD HL,HLMultiply the NMSB and the LSB of the random number in register pair HL by two.
14FEEX DE,HLExchange the NMSB and the LSB of the random number in register pair HL with the counters in register pair DE.
14FFLD A,CLoad register A with the MSB of the random number in register C.
1500RLAMultiply the MSB of the random number in register A by two.
1501LD C,ALoad register C with the adjusted MSB of the random number in register A.
1502EX (SP),HLExchange the counter values in register pair HL with the value of the memory pointer to the stack.
1503LD A,(HL)Load register A with the table value (held at the location of the memory pointer in register pair HL).
1504RLCAMultiply the value in register A by two.
1505LD (HL),ASave the doubled value (stored in register A) at the location of the memory pointer in register pair HL.
1506EX (SP),HLExchange the memory pointer in register pair HL with the counter values to the stack.
150APUSH HLIf we are here, the table value overflowed so we need to save the counter values in register pair HL to the stack.
150B-150DLD HL,(40AAH)Load register pair HL with the NMSB and the LSB of the random number seed.
NOTE: 40AAH-40ADH holds the random number seed.
150EADD HL,DEAdd 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.
150FEX DE,HLLoad register pair DE with the adjusted NMSB and LSB of the random number in register pair HL.
1510-1512LD A,(40ACH)Load register A with the MSB of the random number seed.
1513ADC A,CAdd the MSB of the random number in register C to the MSB of the random number seed in register A.
1514LD C,ALoad register C with the adjusted MSB of the random number in register A.
1515POP HLGet the counter values from the stack and put it in register pair HL.
1516DEC LDecrement the loop counter in register L.
151AEX (SP),HLExchange the counter values in register pair HL with the memory pointer of the table value to the stack.
151BINC HLBump to the next table value.
151CEX (SP),HLExchange the value of the table value in register pair HL with the counter value to the stack.
151DDEC HDecrement the counter value of the outer loop (in register H).
1521POP HLClear the flag table address from the stack. The fact that it is going into HL is not important.
1522-1524LD HL,B065HLoad register pair HL with the value to reseed the random number seed.
1525ADD HL,DEAdd the seed (from register pair HL) to the NMSB and the LSB of the random number in register pair DE.
1526-1528LD (40AAH),HLSave 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.
152C-152DLD A,05HLoad register A with a 5.
152EADC A,CAdd 5 (the value held in A) and the MSB of the random number in register C.
152F-1531LD (40ACH),ASave the adjusted value in register A as the MSB of the random number seed.
1532EX DE,HLSwap DE and HL so as to move the NMSB and LSB to DE so that we will have a BC/DE pair for the random number.
1533-1534LD B,80HLoad register B with a value for the sign flag and the exponent (Binary: 1000 0000).
1535-1537LD HL,4125HLoad register pair HL with the address for the sign value storage location.
NOTE: 4125H-4126H is used by floating point routines.
1538LD (HL),BSave the sign result (1000 0000) in register B at the location of the memory pointer in register pair HL.
1539DEC HLDecrement to exponent (held in register pair HL).
153ALD (HL),BSet the exponent to (1000 0000) so that the value will be < 1.
153BLD C,ALoad register C with the value of the MSB for the single precision random number in register A.
153C-153DLD B,00HZero the value of the exponent in register B.
153E-1540Jump 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
COS routine. Single-precision only.(REG 1 = COS(REG 1)).
A call to 1541H computes the cosine for an angle given in radians. The angle must be a floating point value in REG 1; the cosine will be returned in REG 1 as a floating point value.
NOTE: To use a ROM call to find COS(X), where X is a single precision variable (in radians), store the value of X in 4121H-4124H and then CALL 1541H. The result (in single precision format) is in 4121H-4124Hin approximately 25 milliseconds.
1541-1543H
“COSN”LD HL,158BHLoad register pair HL with the starting address of a single precision constant equal to 1.57079637029 (which is pi / 2).
1544-1546GOSUB to 070BH to add 1.57079637029 (stored in HL) to the single precision value in REG 1 and then pass through to the SIN() routine which is next.
1547-158A – LEVEL II BASIC SIN
SIN(n) routine. Single-precision only.(REG 1 = SIN(REG 1)).
A call to 1549H returns the sine as a single precision value in REG 1. The sine must be given in radians in REG 1.
The actual calculation routine is:
Assume X <= 360 degrees.
Recompute x as x=x/360 so that x=< 1.
If x <= 90 degrees go to step 7.
If x <= 180 degrees then x=0.5-x and then go to step 7.
If x <= 270 degrees then x=0.5-x.
Recompute x as x=x-1.0.
Compute SIN using the power series.
NOTE: To use a ROM call to find SIN(X), where X is a single precision variable, store the value of X in 4121H-4124H and then CALL 1547H. The result (in single precision format) is in 4121H-4124Hin approximately 25 milliseconds. NOTE: The argument (X) must be in radians.
1547-1549H
“SINE”Call 09A4 which moves the SINGLE PRECISION value in REG 1 (the x in a SIN(x) call) to the stack (stored in LSB/MSB/Exponent order).
154A-154CLD BC,8349HLoad register pair BC with the exponent and the MSB of a single precision constant.
154D-154FLD DE,0FDBHLoad 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-1552Move 2 x pi value (held in DC/BE) into REG 1 by GOSUB to 09B4H (which moves the SINGLE PRECISION value in DC/DE into REG 1).
1553-1554POP BC
POP DEPut the x from a SIN(x) call into BC/DE.
1555-1557To divide the x from a SIN(x) call (held in BC/DE) by pi*2 (held in REG 1) we must GOSUB 80A2H to divide the single precision value in register pairs BC and DE by the single precision value in REG 1. Return with the single precision result in REG 1.
1558-155AMove that value (x / 2*pi) from REG 1 to the stack by GOSUB to 09A4H which moves the SINGLE PRECISION value in REG 1 to the stack (stored in LSB/MSB/Exponent order).
155B-155DGo figure the integer portion for the single precision value in REG 1 by calling 0B40H. We need to do this so we can isolate the remainder.
155EH,155FPOP BC
POP DEPut the quotient and remainder of x/2*pi into BC/DE.
1560-1562To 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 REG 1 (the integer part of the result). The difference is left in REG 1).
1563-1565LD HL,158FHLoad register pair HL with the starting address of a single precision constant equal to 0.25.
1566-1568Next in calculating a SIN we would need to subtract .25 (held in HL) from the fractional part (held in REG 1) so as to see if it is <= to 90 degrees. To do this we GOSUB 0710H to subtract the single precision value in REG 1 from the single precision constant pointed to by register pair HL. Return with the result in REG 1.
1569-156BGo check the sign of the result of that (.25 – fractional part) subtraction which is held in REG 1.
156CSCFSet the CARRY FLAG.
156D-156FJump to 1577H if the single precision value in REG 1 is positive (meaning it is < than 90 degrees).
1570-1572If we are here, it is => 90 degrees, so we need to add .5 to the single precision value in REG 1. Return with the result in REG 1
1573-1575Go check the sign for the single precision value in REG 1 which basically checks to see if it is > 0.75 (meaning < 270 degrees).
1576OR ATest the value of the sign test in register A.
1577PUSH AFSave the sign indicator (+ or -1) in register pair AF to the stack.
157B-157DLD HL,158FHLoad register pair HL with the starting address of a single precision constant equal to 0.25.
157E-1580Add .25 (stored in HL) to the current value in REG 1 by GOSUB to 070BH (result is saved in REG 1).
1581POP AFGet the sign reversal flag from the stack and put it in register pair AF.
1582-1584Set 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-1587LD HL,1593HLoad register pair HL with 1593H (which is the starting address for a series of single precision values for a set of computations).
158BH-15A7H – SINGLE PRECISION CONSTANT STORAGE LOCATION
158B-158EHDB 0F 49 81A single precision constant equal to 1.57079637029 is stored here.
05HThe number of single precision constants (05) which follows is stored here. These are the coefficients used in the power series to compute SIN(x).
1598-159BH64H 26H 99H 87HA single precision constant equal to -76.5749816893 is stored here.
159C-159FH58H 34H 23H 87HA single precision constant equal to 81.6022338865 is stored here.
15A0-15A3HE0H 6DH A5H 86HA single precision constant equal to -41.3416748045 is stored here.
15A4-15A7HDAH 0FH 49H 83HA single precision constant equal to 6.28318500497 is stored here.
15A8-15BC – LEVEL II BASIC TAN ROUTINE – “TAN”
TAN(n)
Single-precision only.(REG 1 = TAN(REG 1)).
A call to 15A8H computes the tangent of an angle in radians. The angle must be specified as a single precision value in REG 1. The tangent will be left in REG 1.
Uses the fact that TAN(x) = SIN(x) / COS(x)
NOTE: To use a ROM call to find TAN(X), where X is a single precision variable (in radians), store the value of X in 4121H-4124H and then CALL 15A8H. The result (in single precision format) is in 4121H-4124Hin approximately 54 milliseconds. NOTE: A fatal error occurs if the result is as large as 2 to the power of 127, which will be the case if the value of X is sufficiently close to any odd multiple of pi/2 radians.
15A8-15AACall 09A4 which moves the SINGLE PRECISION value in REG 1 to the stack (stored in LSB/MSB/Exponent order).
15AB-15ADCall the SIN(n) routine at 1547H (which returns the sine as a single precision value in REG 1. The sine must be given in radians in REG 1.
15AEH,15AFPOP BC
POP HLGet the original exponent and value from the stack and put it in register pair BC/HL.
15B0-15B2Call 09A4 which moves the SIN(x) single precision value (stored in REG) 1 to the stack (stored in LSB/MSB/Exponent order).
15B3EX DE,HLLoad register pair DE with the NMSB and the LSB of the single precision value in register pair HL.
15B7-15B9Call 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 REG 1 as a floating point value.
15BD-15E2 – LEVEL II BASIC ATN ROUTINE – “ATAN”
ATN(n) routine.
Single-precision only.(REG 1 = ATN(REG 1)).
A call to 15BD returns the angle in radians, for the floating point tangent value in REG 1. The angle will be left as a single precision value in REG 1.
The method of computation used in this routine is:
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.
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.
Evaluate the series: (((x^2*c0+c1) x^2+c2) … c8)x
If the flag from step 1 is not set, then invert the sign of the series result.
If the original value is < 1 then return to the caller. Otherwise, compute pi/2-value from step 4 and then return.
NOTE: To use a ROM call to find ATN(X), where X is a single precision variable, store the value of X in 4121H-4124H and then CALL 15BDH. The result (in single precision format, in radians) is in 4121H-4124Hin approximately 27 milliseconds.
15C0-15C2If the single precision value in REG 1 is negative then GOSUB to 13E2H to return address of 0982H to the stack pointer.
15C6-15C8LD A,(4124H)Load register A with the exponent of the tangent (which is a single precision value in REG 1).
15C9-15CACP 81HCheck to see if the the exponent of the tangent (which is a single precision value in REG 1) is less than one by comparing it against 81H (Binary: 1000 0001). Results:- If A=”1″ it sets the ZERO FLAG.
- If A<“1” then the CARRY FLAG will be set
- If A>=”1″ then the NO CARRY FLAG will be set.
15CD-15CFLD BC,8100HLoad register pair BC with an exponent and a MSB for a single precision value. This also sets C to 00H.
15D0LD D,CZero the NMSB of the single precision value in register D.
15D1LD E,CZero the LSB of the single precision value in register E.
15D2-15D4GOSUB 082AH to get the reciprocal of the tangent. This routine divides the single precision value in REG 1 into the single precision constant in register pairs BC and DE.
15D5-15D7LD HL,0710HLoad register pair HL with a return address of 0710H (which is the subtract routine to be called once the series is calculated).
15D8PUSH HLSave the value of the return address in register pair HL to the stack.
LD HL,15E3HLoad register pair HL with the starting address for a series of single precision numbers for a set of computations.
15DF-15E1LD HL,158BHLoad register pair HL with the starting address of a single precision constant equal to 1.57079637029 (which is pi/2).
15E2RETReturn. 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
15E3H09HThe number of single precision constants (9) which follows is stored here
15E4-15E7H4A D7 3B 78A single precision constant equal to 0.00286622549 is stored here.
15E8-15EBH02 6E 84 7BA single precision constant equal to -0.01616573699 is stored here.
15EC-15EFHFE C1 2F 7CA single precision constant equal to 0.04290961441 is stored here.
15F0-15F3H74 31 9A 3DA single precision constant equal to 0.07528963666 is stored here.
15F4-15F7H84 3D 5A 7DA single precision constant equal to 0.10656264407 is stored here.
15F8-15FBHC8 7F 91 7EA single precision constant equal to -0.14208900905 is stored here.
15FC-15FFHE4 BB 4C 7EA single precision constant equal to 0.19993549561 is stored here.
1600-1603H6C AA AA 7FA single precision constant equal to -0.33333146561 is stored here.
1604-1607H00 00 00 01A 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.
Word
Token
Address
Word
Token
Address
ABS D9 0977 | AND D2 25FD
ASC F6 2A0F | ATN E4 15BD
AUTO B7 2008 | CDBL F1 0ADB
CHR$( F7 2A1F | CINT EF 0A7F
CLEAR B8 1E7A | CLOAD B9 2C1F
CLOSE A6 4185 | CLS 84 01C9
CMD 85 4173 | CONT B3 1DE4
COS El 1541 | CSAVE BA 2BF5
CSNG F0 0ABl | CVD E8 415E
CVI E6 4152 | CVS E7 4158
DATA 88 1F05 | DEF DD 415B
DEFDBL 9B 1E09 | DEFINT 99 1E03
DEFSNG 9A 1E06 | DEFSTR 98 1E00
DELETE B6 2BC6 | DIM 8A 2608
EDIT 9D 2E60 | ELSE 95 1F07
END 80 1DAE | EOF E9 4161
ERL C2 24DD | ERR C3 24CF
ERROR 9E 1FF4 | EXP E0 1439
FIELD A3 417C | FIX F2 0B26
FN BE 4155 | FOR 81 1CA1
FRE DA 27D4 | GET A4 4174
GOSUB 91 1EB1 | GOTO 5D 1EC2
IF 8F 2039 | INKEY$ C9 019D
INP DB 2AEF | INPUT 89 219A
INSTR C5 419D | INT D8 0B37
KILL AA 4191 | LEFT$ F8 2A61
LEN F3 2A03 | LET 8C 1F21
LINE 9C 41A3 | LIST B4 2B2E
LLIST B5 2B29 | LOAD A7 4188
LOC EA 4164 | LOF EB 4167
LOG DF 0809 | LPRINT AF 2067
LSET AB 4197 | MEM C8 27C9
MERGE A8 418B | MID$ FA 2A9A
MKD$ EE 4170 | NAME A9 418E
NEW BB 1B49H | NEXT 87 22B6
NOT CB 25C4 | ON A1 1FC6
OPEN A2 4179 | OR D3 25F7
OUT AO 2AFB | PEEK E5 2CAA
POINT C6 0132 | POKE B1 2CB1
POS DC 27F5 | PRINT B2 206F
PUT A5 4182 | RANDOM 86 01D3
READ 8B 21EF | REM 93 1F07
RESET 82 0138 | RESTORE 90 1D91
RESUME 9F 1FAFH | RETURN 92 1EDEH
RIGHT$ F9 2A91 | RND DE 14C9
RSET AC 419A | RUN 8E 1EA3
SAVE AD 41A0 | SET 83 0135
SGN D7 098A | SIN E2 1547
SQR CD 13E7 | STEP cc 2B01
STOP 94 1DA9 | STR$ F4 2836
STRING$ C4 2A2F | SYSTEM AE 02B2
TAB( BC 2137 | TAN E3 15A8
THEN CA | TIME$ C7 4176
TO BD | TROFF 97 1DF8
TRON 96 1DF8 | USING BF 2CBD
USR C1 27FE | VAL FF 2AC5
VARPTR C0 24EB | + CD 249F
– CE 2532 | * CF
/ D0 | ? D1
> D4 | = D5
< D6 | & 26
‘ FB 3A93
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.
18F7SUB 00HSubtract the LSB
18F9LD L,ARestore the value to L
18FALD A,HGet the middle byte
18FBSBC A,00HSubtract the middle byte
18FDLD H,AMove the difference to H
18FELD A,BGet the MSB
18FFSBC A,00HSubtract the MSB
1901LD B,AMove it back to A
1902LD A,00HClear A
1904RETRETurn.
1905-191C – STORAGE LOCATION FOR VALUES PLACED IN RAM UPON INITIALIZATION.
This code is moved to 408E during non-disk initial setup.
1918HXDifference between M1 and M3 ROMs: 1917H – 1918H contains 434CH in the Model I, 444CH in the Model III. This value is loaded to 40A0H (the start of string space pointer) during power-up.
191CHXDifference between M1 and M3 ROMs: 191BH – 191CH contains 42E9H in the Model I, 43E9H in the Model III. This value is loaded to 40A4H (the start of BASIC program pointer) during power-up.
191DH-1935H – MESSAGE STORAGE LOCATION
1936-1954 – SCAN STACK ROUTINE
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.
1936-1938LD HL,0004HLoad register pair HL with 4 so that we can backspace.
1939ADD HL,SPAdd 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.
193ALD A,(HL)Load register A with the value held at the current stack point MINUS 4.
193BINC HLBump 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-193DCP 81HCheck to see if the value in register A (which is the current stack pointer – 4) is a FOR token.
193ERET NZReturn if the value in register A isn’t a FOR token. This returns with A being non-zero because there was no FOR push.
193FLD C,(HL)Load register C with the LSB of the FOR‘s variable address.
1940INC HLBump the value of the memory pointer in register pair HL so as to backspace the current stack pointer by yet another byte.
1941LD B,(HL)Load register B with the MSB of the FOR‘s variable address.
1942INC HLBump the value of the memory pointer in register pair HL so now HL will be the address of the FOR variable on the stack.
1943PUSH HLSave the value in register pair HL (which is the address of the FOR variable) to the stack.
1944LD L,CLoad register L with the LSB of the FOR variable’s address in register C.
1945LD H,BLoad register H with the MSB of the FOR variable’s address in register B.
1946LD A,DLoad register A with the MSB of the variable address in register D. This sets up fto test the user specified variable address.
1947OR ECheck to see if the variable address in register pair DE is equal to zero.
1948EX DE,HLExchange 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.
1949-194ASkip the next 2 opcodes if the variable address in register pair DE was equal to zero.
194BEX DE,HLExchange 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.
194CRST 18HThis 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:- HL<DE: CARRY SET
- HL>DE: NO CARRY
- HL><DE: NZ
- HL=DE: Z
LD BC,000EHLoad register pair BC with the value to backspace to next FOR token (which is 10).
1950POP HLGet the memory pointer from the stack of the sign of the increment flag and put it in register pair HL.
1951RET ZReturn if the FOR block matched the NEXT index block.
1952ADD HL,BCIf it didn’t match, execute that 10 byte stepback in BC for the next possible FOR push.
1955-1962 – DATA MOVEMENT ROUTINE
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.
1958PUSH BCSave the end address of the list to move (stored in BC) to the stack.
1959EX (SP),HLSave the end address of the list to move (stored in the stack now) to register pair HL.
195APOP BCGet the end address of the move from the stack and put it in register pair BC.
195BRST 18HNow we need to check 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:- HL<DE: CARRY SET
- HL>DE: NO CARRY
- HL><DE: NZ
- HL=DE: Z
195CLD A,(HL)Get a byte from the source list and put it in register A.
195DLD (BC),ASave the byte into wherever BC is pointing.
RET ZReturn 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).
195FDEC BCDecrement the source address (in register pair BC).
1960DEC HLDecrement the destination address (in register pair HL).
1963-197D – MEMORY CHECK ROUTINE – Computes the amount of space between HL and the end of memory at FFC6H.
1963PUSH HLSave the value in register pair HL to the stack.
1964-1966LD HL,(40FDH)Load register pair HL with the starting address of free memory (which is stored at 40FDH).
NOTE: 40FDH-40FEH holds the pointer to the starting address of free memory.
1967-1968LD B,00HLoad register B with zero.
1969ADD HL,BCAdd 2 times the number of bytes required to start of free area (held in register pair BC) to the value in register pair HL.
196AADD HL,BCAdd 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-196C3EH E5HZ-80 Trick! See the general explanation at 10F8H.
196D-196ELD A,C6HLoad register A with C6H (which is the the LSB of FFC6H; the top of memory).
196FSUB LSubtract the LSB of the value of the new memory pointer in register L from the value in register A.
1970LD L,ALoad register L with the adjusted value in register A (i.e., the free memory pointer resulting from subtracting the new starting address).
1971-1972LD A,FFHLoad register A with the MSB of the top of memory.
1973SBC A,HSubtract the MSB of the new memory pointer in register H from the value in register A. If the free space list exceeds FFC6 then the CARRY FLAG gets set, meaning memory overflowed.
1976LD H,ANext 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.
1977ADD HL,SPAdd the value of the stack pointer to the adjusted value in register pair HL.
1978POP HLGet the value from the stack and put it in register pair HL.
1979RET CIf the CARRY FLAG is set, then we have no overflow – so we better RETURN because the next step is an OM error processor.
197A-197B – OM ERROR entry point.
197A-197BLD E,0CHLoad register E with the ?OM ERROR.
197E-1AF7 – LEVEL II BASIC COMMAND MODE
197E-1980LD HL,(40A2H)Load register pair HL with the value of the current BASIC line number.
NOTE: 40A2H-40A3H holds the current BASIC line number.
1981LD A,HLoad register A with the MSB of the current BASIC line number in register H.
1982AND LCombine the LSB of the current BASIC line number in register L with the MSB of the current line number in register A.
1983INC ABump 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-1985Jump to 198EH if Level II BASIC is still in the command mode (rather than being in execution mode).
1986-1988LD A,(40F2H)Load register A with contents of 40F2H.
NOTE: 40F2H holds the error flag.
1989OR ACheck to see if the error flag is set.
198A-198BLD E,22HLoad register E with a ?NR ERROR code.
198E-1990Otherwise, jump to 1DC1H (the READY routine) because there was an error in the input phase.
1991-1993LD HL,(40DAH)Load register pair HL with the DATA line number (which is stored at 16602).
NOTE: 40DAH-40DBH holds DATA line number.
1994-1996LD (40A2H),HLSave the DATA line number in register pair HL.
NOTE: 40A2H-40A3H holds the current BASIC line number.
1997-1998LD E,02HLoad register E with a ?SN ERROR code.
SN ERROR entry point.
199C-199ELD BC,001EHLoad register BC with a ?NF ERROR code.
?NF ERROR entry point.
199F-19A1LD BC,241EHLoad register BC with a ?RW ERROR code.
?RW ERROR entry point.
LD HL,(40A2H)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-19A7LD (40EAH),HLSave the value of the current BASIC line number with the error in register pair HL.
NOTE: 40EAH-40EBH holds the line number with error.
19A8-19AALD (40ECH),HLSave the value of the current BASIC line number with the error in register pair HL.
NOTE: 40ECH-40EDH holds EDIT line number.
LD BC,19B4HLoad register pair BC with the return address of 19B4H which is the continuation address after a reinitialization.
LD HL,(40E8H)Load register pair HL with the value of the stack pointer (which is stored at 40E8H).
NOTE: 40E8H-40E9H holds Stack pointer pointer.
19B5LD A,ELoad register A with the value of the error code in register E.
19B6LD C,ELoad register C with the value of the error code in register E.
19B7-19B9LD (409AH),ASave the value of the error code (from in register A) into 409AH.
NOTE: 409AH holds the RESUME flag.
19BA-19BCLD HL,(40E6H)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-19BFLD (40EEH),HLSave the value of the current BASIC program pointer (which is stored in 40EEH) in register pair HL.
NOTE: 40EEH-40EFH is used by RESUME.
19C0EX DE,HLLoad register pair DE with the value of the current BASIC program pointer in register pair HL.
19C1-19C3LD HL,(40EAH)Load register pair HL with the value of the last number line executed (which is stored in 16618).
NOTE: 40EAH-40EBH holds the line number with error.
19C4-19C5LD A,H
AND LThe easiest way to test a 2 Byte Register is to AND the MSB and LSB together, as the only way to get 1111 would be if both the LSB and MSB were 1111. Here, HL las the last line number executed.
19C6INC ABump the value of the combined current BASIC line number. This will test to against FFFFH which would mean we are still in the input phase.
19C7-19C8Jump to 19D0H if Level II BASIC is in the command mode (meaning the line number was FFFFH, which then flipped to zero on the prior INC command).
19C9-19CBLD (40F5H),HLSave the value of the current BASIC line number in register pair HL to (40F5H).
NOTE: 40F5H-40F6H holds the last line number executed.
19CCEX DE,HLLoad register pair HL with the value of the current BASIC program pointer in register pair DE.
19CD-19CFLD (40F7H),HLSave the value of the current BASIC program pointer (which is stored in 16631) in register pair HL.
NOTE: 40F7H-40F8H holds the last byte executed.
19D0-19D2LD HL,(40F0H)Load register pair HL with memory contents held at (40F0H).
NOTE: 40F0H-40F1H holds the ON ERROR adress.
19D3LD A,HLoad register A with the MSB of the ON ERROR address in register H.
19D4OR LCombine the LSB of the ON ERROR address in register L with the MSB of the ON ERROR address in register A.
19D5EX DE,HLLoad register pair DE with the ON ERROR address in register pair HL.
19D6-19D8LD HL,40F2HLoad register pair HL with the address of the error flag (which is 40F2H).
NOTE: 40F2H holds the error flag.
19DBAND (HL)Combine the value of the error flag at the location of the memory pointer in register pair HL with the combined value of the ON ERROR address in register A.
19DC-19DDJump to 19E3H (to error out) if register A is non zero (meaning that there was no ON ERROR address).
19DEDEC (HL)Decrement the value of the error flag at the location of the memory pointer in register pair HL so that RESUME will work.
19DFEX DE,HLLoad register pair HL with the ON ERROR address in register pair DE.
19E3XOR AZero register A.
19E4LD (HL),AClear 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..
19E5LD E,CLoad register E with the value of the error code in register C.
19E6-19E8We need to position the video to the next line, so go display a carriage return on the video display if necessary.
19E9-19EBLD HL,18C9HLoad register pair HL with the starting address for the table of error messages.
19EC-19EECALL 41A6HGo to the DOS link at 41A6H (whcih would load and execute BASIC error messages as supplied by DOS).
NOTE: 41A6H-41E4H holds DOS links.
In NEWDOS 2.1, this would be a call to load a DISK BASIC error, with Register E holding the error number.
19EFLD D,ASince we are non-DOS, we continue by loading register D with zero.
19F0-19F1LD A,3FHLoad register A with a “?” (which is ASCII code 3FH).
19F5ADD HL,DEAdd the value of the error code in register pair DE to the starting address of the table of error messages in register pair HL.
19F6LD A,(HL)Load register A with the first character of the error message at the location of the table pointer in register pair HL.
19F7-19F9GOSUB to 032AH to display the first character of the error message in register A.
19FARST 10HError 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.
NOTE:- The RST 10H routine loads the next character from the string pointed to by the HL register into the A-register and clears the CARRY FLAG if it is alphabetic, or sets it if is alphanumeric.
- Blanks and control codes 09H and 0BH 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.
19FB-19FDGOSUB to 032AH to display the second character of the error message in register A.
19FE-1A00LD HL,191DHLoad register pair HL with 191DH which is the starting address of the READY message.
1A01PUSH HLSave the starting address of the READY message (held in HL) to the stack.
1A02-1A04LD HL,(40EAH)Load register pair HL with the value of the current BASIC line number (i.e., the statement causing the error).
NOTE: 40EAH-40EBH holds the line number with error.
1A05EX (SP),HLExchange 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-1A08We need to display the Level II BASIC ERROR message so we call the WRITE MESSAGE routine at 28A7H.
NOTE:
- The routine at 28A7 displays the message pointed to by HL on current system output device (usually video).
- The string to be displayed must be terminated by a byte of machine zeros or a carriage return code 0D.
- If terminated with a carriage return, control is returned to the caller after taking the DOS exit at 41D0H (JP 5B99H).
1A09POP HLGet the value of the BASIC line number with the error from the stack and put it in register pair HL.
1A0A-1A0CLD DE,FFFEHLoad register pair DE with FFFEH.
This basically reserves the line number 65534 as a trigger for the next few steps.
1A0DRST 18HNow 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:- HL<DE: CARRY SET
- HL>DE: NO CARRY
- HL><DE: NZ
- HL=DE: Z
1A0E-1A10Jump to 0674H if we are in the initialization routine because the error line number was FFFEH.
1A11LD A,HWe need to see if were in command mode, which is signalled by CURRENT LINE NUMBER of 0. The first step is to load register A with the MSB of the current BASIC line number in register H.
1A12AND LCombine the LSB of the current BASIC line number in register L with the MSB of the current BASIC line number in register A.
1A13INC ABump 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-1A16GOSUB to 0FA7H to display the current BASIC line number in register pair HL if Level II BASIC isn’t in the command mode.
1A17H3E C1Z-80 Trick! See the general explanation at 10F8H.
1A19 – “$READY” – Jump to Model II BASIC “READY”
To exit from a machine-language program into BASIC’s immediate mode, jump (not call) to $READY.
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-1A1ECALL 41ACHGo call the DOS link at 41ACH.
In NEWDOS 2.1, this is the start of BASIC just before BASIC shows the READY prompt.
1A25-1A27LD HL,1929HLoad register pair HL with the starting address of the Level II BASIC READY message.
1A28-1A2AWe need to display the Level II BASIC READY message, so we call the WRITE MESSAGE routine at 28A7H.
NOTE:
- The routine at 28A7 displays the message pointed to by HL on current system output device (usually video).
- The string to be displayed must be terminated by a byte of machine zeros or a carriage return code 0D.
- If terminated with a carriage return, control is returned to the caller after taking the DOS exit at 41D0H (JP 5B99H).
1A2B-1A2DLD A,(409AH)Load register A with the value of the current error code.
NOTE: 409AH holds the RESUME flag.
1A2E-1A2FSUB 02HCheck 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..
1A33 – Many routines jump here as the start of the Level II BASIC interpreter.
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-1A35LD HL,FFFFHLoad register pair HL with the command mode line number of FFFFH.
NOTE: FFFFH is the command mode line number.
1A36-1A38LD (40A2H),HLSave the line number in register pair HL as the current BASIC line number.
NOTE: 40A2H-40A3H holds the current BASIC line number.
1A39-1A3BLD A,(40E1H)Load register A with the value of the AUTO flag. It will be zero if not in AUTO, and anything else if in AUTO.
1A3COR ACheck to see if in the AUTO mode.
1A3F-1A41LD HL,(40E2H)We are in AUTO mode so load register pair HL with the current AUTO line number.
NOTE: 40E2H-40E3H holds Current BASIC line number.
1A42PUSH HLSave the current AUTO line number (stored in register pair HL) to the stack.
1A43-1A45GOSUB 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 and display it at the current cursor position on the video screen) to display the AUTO line number.
1A46POP DEGet the current AUTO line number from the stack and put it in register pair DE.
1A47PUSH DESave the current AUTO line number in register pair DE to the stack.
1A48-1A4ACall 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-1A4CLD A,”*”Load register A with a * (which will be code for a matching line number).
1A4D-1A4EIf 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-1A50LD A,20HIf 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.
Go display the character in register A on the video display (which will be a “*” if a matching line number was found).
1A57POP DEGet the current line number from the stack and put it in register pair DE.
1A5AXOR AThe BREAK key was pressed so we need to zero register A to clear the AUTO increment flag.
1A5B-1A5DLD (40E1H),ASave the value in register A as the current AUTO flag (to turn off AUTO).
NOTE: 40E1H will hold 0 if no AUTO and non-zero if AUTO.
If we are here, then the BREAK key was not pressed.
1A60-1A62LD HL,(40E4H)Load register pair HL with the value of the AUTO increment.
NOTE: 40E4H-40E5H holds the AUTO increment number.
1A63ADD HL,DESince 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-1A65If 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.
1A66PUSH DESave the current AUTO line number in register pair DE to the stack.
1A67-1A69LD DE,FFF9HLoad 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).
1A6ARST 18HNow 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:- HL<DE: CARRY SET
- HL>DE: NO CARRY
- HL><DE: NZ
- HL=DE: Z
1A6BPOP DEGet the current AUTO line number from the stack and put it in register pair DE.
1A6C-1A6DIf 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-1A70LD (40E2H),HLSave the adjusted AUTO line number in register pair HL as the current AUTO line number.
NOTE: 40E2H-40E3H holds Current BASIC line number.
1A71-1A72OR FFHLoad register A with the AUTO flag value.
1A76-1A77LD A,3EHLoad register A with a > (the prompt that follows READY)
1A81RST 10HSince 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.
NOTE:- The RST 10H routine loads the next character from the string pointed to by the HL register into the A-register and clears the CARRY FLAG if it is alphabetic, or sets it if is alphanumeric.
- Blanks and control codes 09H and 0BH 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.
1A82INC ABump the value of the character in register A. This sets the status flags but saves the CARRY FLAG.
1A83DEC ADecrement the value of the character in register A so we can test for an end of statement.
1A87PUSH AFSave the value in register pair AF to the stack (including the CARRY FLAG).
1A88-1A8ACall the ASCII TO INTEGER routine at 1E5AH.
NOTE:- The routine at 1E5A converts the ASCII string pointed to by HL to an integer deposited into DE. If the routine finds a non-numerica character, the conversion is stopped
1A8BH – This little looping routine is to clear any trailing blanks between the line number and the statement.
1A8BDEC HLDecrement the value of the input buffer pointer in register pair HL.
1A8CLD A,(HL)Load register A with the value of the character at the location of the input buffer pointer in register pair HL.
1A8D-1A8ECP 20HCheck to see if the character at the location of the input buffer pointer in register A is a space.
1A8F-1A90Loop back to 1A8BH if the character at the location of the input buffer pointer in register A is a space.
1A91INC HLBump the value of the input buffer pointer in register pair HL so that it points to the first character following a line number.
1A92LD A,(HL)Load register A with that character.
1A93-1A94CP 20HCheck to see if the character at the location of the input buffer pointer in register A is a space.
1A95-1A97If 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.
1A98PUSH DESave 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-1A9BTokenize the input via a GOSUB to 1BC0H. BC will equal the length of the encoded statement when its done.
1A9CPOP DEGet the value of the BASIC line number (which is an integer) from the stack.
1A9DPOP AFGet the CARRY FLAG (from the 1A81H character fetch) and put it in register pair AF.
1A9E-1AA0LD (40E6H),HLSave the input buffer pointer in register pair HL.
NOTE: 40E6H-40E7H holds the temporary storage location.
1AA1-1AA3CALL 41B2HGo call the DOS line at 4182H.
In NEWDOS 2.1, this is the input scanner after tokenizing the current statement.
1AA4-1AA6Jump to 1D5AH if there wasn’t a line number with the input (meaning it was a direct statement or a system command).
1AA7PUSH DESave the BASIC line number (as an integer stored in register pair DE) to the stack.
1AA8PUSH BCSave the length of the tokenized input (stored in register pair BC) to the stack.
1AA9XOR AZero register A.
1AAA-1AACLD (40DDH),ASave the value in register A (which is a 00H) as the input flag.
NOTE: 40DDH holds INPUT flag.
1AADRST 10HSince 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.
NOTE:- The RST 10H routine loads the next character from the string pointed to by the HL register into the A-register and clears the CARRY FLAG if it is alphabetic, or sets it if is alphanumeric.
- Blanks and control codes 09H and 0BH 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.
1AAEOR ASet the flags.
1AAFPUSH AFSave the status flag to the stack.
1AB0EX DE,HLLoad register pair HL with the integer value of the BASIC line number (held in register pair DE).
1AB1-1AB3LD (40ECH),HLSave the integer value of the line number (held in register pair HL) to 40ECH.
NOTE: 40ECH-40EDH holds EDIT line number.
1AB4EX DE,HLExchange 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-1AB7Call 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.
1AB8PUSH BCSave the address of the line number in the BASIC program (if it exists) in register pair BC to the stack.
1AB9-1ABBIf there wasn’t a matching line number in the BASIC program, GOSUB to 2BE4H to move the closest line number up in memory to make room for another line.
1ABCPOP DEGet the integer address of the BASIC line number from the stack and put it in register pair DE.
1ABDPOP AFRestore the status from the 1AADH token scan into register pair AF.
1ABEPUSH DESave the integer address of the BASIC line number to the stack.
1ABF-1AC0Jump 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.
1AC1POP DEGet the address of the BASIC line number from the stack and put it in register pair DE.
1AC2-1AC4LD HL,(40F9H)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.
1AC5EX (SP),HLExchange the length of the tokenized input to the stack with the end of the BASIC program pointer in register pair HL.
1AC6POP BCGet the end of the BASIC program pointer from the stack and put it in register pair BC.
1AC7ADD HL,BCAdd 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.
1AC8PUSH HLSave the adjusted end of the BASIC program pointer in register pair HL to the stack.
1AC9-1ACBGo check to see if there is enough room in memory for the new BASIC line by GOSUB to 1955H.
1ACCPOP HLGet the new end of the BASIC program pointer from the stack and put it in register pair HL.
1ACD-1ACFLD (40F9H),HLSave 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.
1AD0EX DE,HLLoad register pair HL with the address of the BASIC line.
1AD1LD (HL),HSave the MSB of the address of the BASIC line in register H.
1AD2POP DEGet the value of the BASIC line number from the stack and put it in register pair DE.
1AD3PUSH HLSave the value of the memory pointer in register pair HL to the stack.
1AD4INC HLBump the value of the memory pointer in register pair HL (which bumps it to the LSB of the line number entry).
1AD5INC HLBump the value of the memory pointer in register pair HL (which bumps it to the MSB of the line number entry).
1AD6LD (HL),ESave the LSB of the BASIC line number in register E at the location of the memory pointer in register pair HL.
1AD7INC HLBump the value of the memory pointer in register pair HL.
1AD8LD (HL),DSave 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.
1AD9INC HLBump the value of the BASIC line number in register pair HL.
1ADAEX DE,HLLoad register pair DE with first data byte address following the line number (held in register pair HL).
1ADB-1ADDLD HL,(40A7H)Load register pair HL with the value of the tokenized input pointer
Note: 40A7H-40A8H holds Input Buffer pointer.
1ADEEX DE,HLExchange the value of the memory pointer in register pair DE with the value of the tokenized input pointer in register pair HL.
1ADFDEC DEDecrement the value of the tokenized input buffer pointer in register pair DE.
1AE0DEC DEDecrement the value of the tokenized input buffer pointer in register pair DE.
1AE1LD A,(DE)Load register A with the value at the location of the tokenized input buffer pointer in register pair DE.
1AE2LD (HL),ASave the value in register A at the location of the memory pointer in register pair HL.
1AE3INC HLBump the store address (held in register pair HL).
1AE4INC DEBump the fetch address (held in register pair DE).
1AE5OR ACheck to see if the character in register A is an end of the line character.
1AE8POP DEGet the address of the line in the program table from the stack and put it in register pair DE.
1AEC-1AEECALL 41B5HGo call the DOS link at 41B5H.
In NEWDOS 2.1, this is the input scanner after updating the PST (Program Statement Table).
1AF2-1AF4CALL 41B8HGo call the DOS link at 41B8H.
In NEWDOS 2.1, this is the input scanner after reinitializing BASIC
1AF8-1B0F – LINE POINTERS ROUTINE
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.
1AF8LD HL,(40A4H)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).
1AFBEX DE,HLMove the PST address to DE.
1AFCLD H,DLoad register H with the MSB of the memory pointer in register D.
1AFDLD L,ELoad register L with the LSB of the memory pointer in register E.
1AFELD A,(HL)Load register A with the value at the location of the memory pointer in register pair HL.
1AFFINC HLBump the value of the memory pointer in register pair HL.
1B00OR (HL)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.
1B01RET ZReturn if done.
INC HLSince 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.
1B03INC HLBump the value of the memory pointer in register pair HL.
1B04INC HLBump the value of the memory pointer in register pair HL.
1B05XOR AZero register A and clear the flags.
1B06CP (HL)Check to see if the character at the location of the memory pointer in register HL is an end of the BASIC line character.
1B07INC HLBump the value of the memory pointer in register pair HL.
1B0AEX DE,HLExchange 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.
1B0BLD (HL),ESave the LSB of the next BASIC line’s starting address in register E at the location of the memory pointer in register pair HL.
1B0CINC HLBump the value of the memory pointer in register pair HL.
1B0DLD (HL),DSave the MSB of the next BASIC line’s starting address in register D at the location of the memory pointer in register pair HL.
1B10-1B48 – EVALUATE LINE NUMBERS
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.
1B10-1B12LD DE,0000HLoad register pair DE (which will be the line counter) with zero.
1B13PUSH DESave the value in register pair DE to the stack.
1B16POP DEGet the value from the stack and put it in register pair DE (which will be the line number).
1B17-1B19Go 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.
1B1APUSH DESave the first line number’s value (stored in register pair DE) to the stack.
1B1B-1B1CJump if there isn’t a second line number to be evaluated given (i.e, LIST 3000-).
1B1D-1B1ERST 08H
CEHIf 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 the Aregister 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).
1B22-1B24Go 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-1B27Go 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.
1B28EX DE,HLLoad 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.
1B29POP DEGet the value of the first line number from the stack and put it in register pair DE.
1B2AEX (SP),HLExchange the return address to the stack with the value of the second line number in register pair HL.
1B2BPUSH HLSave the value of the return address in register pair HL to the stack so we can properly exit later.
1B2C – 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.
1B2CLD HL,(40A4H)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).
1B2FLD B,HLoad register B with the value of the MSB of the memory pointer in register H.
1B30LD C,LLoad register C with the LSB of the memory pointer in register L. Now BC will hold the address of the current line in the PST.
1B31LD A,(HL)Load register A with the LSB of the address of the next line (held in register pair HL).
1B32INC HLBump the value of the memory pointer in register pair HL to the MSB of the address of the next line.
1B33OR (HL)Combine the value at the location of the memory pointer in register pair HL with the value in register A and set the status flags.
1B34DEC HLRestore HL to the start of the current line.
1B35RET ZReturn if this is the end of PST (=the end of the BASIC program).
1B36INC HLIt’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.
1B37INC HLBump the value of the memory pointer in register pair HL.
1B38LD A,(HL)Load register A with the LSB of the current BASIC line number at the location of the memory pointer in register pair HL.
1B39INC HLBump the value of the memory pointer in register pair HL to point to the MSB of the current BASIC line number.
1B3ALD H,(HL)Load register H with the MSB of the current BASIC line number at the location of the memory pointer in register pair HL.
1B3BLD L,ALoad register L with the LSB of the current BASIC line number in register A.
1B3CRST 18HNow 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:- HL<DE: CARRY SET
- HL>DE: NO CARRY
- HL><DE: NZ
- HL=DE: Z
1B3DLD H,BLoad register H with the MSB of the memory pointer in register B.
1B3ELD L,CLoad register L with the LSB of the memory pointer in register C.
1B3FLD A,(HL)Load register A with the value at the location of the memory pointer in register pair HL.
1B40INC HLBump the value of the memory pointer in register pair HL.
1B41LD H,(HL)Load register H with the MSB of the next BASIC line pointer at the location of the memory pointer in register pair HL.
1B42LD L,ALoad register L with the LSB of the next BASIC line pointer in register A to form the address of the next line in HL.
1B43CCFComplement 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.
1B44RET ZReturn 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.
If we are here, then we have no match.
1B45CCFComplement (reverse) the CARRY FLAG.
1B46RET NCIf 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.
1B49-1B5C – LEVEL II BASIC NEW ROUTINE
1B49RET NZGo to the Level II BASIC error routine and display a ?SN ERROR message if there is any input following the NEW token.
1B4A-1B4CCall the CLEAR SCREEN routine at 01C9 (which cleans the screen, changes to 64 characters, and homes the screen).
LD HL,(40A4H)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).
1B50GOSUB to the TROFF routine at 1DF8H (which just loads A with a zero for TROFF, and puts that 0 into 411BH).
1B53LD (40E1H),AReset 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.
1B56LD (HL),AWe 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.
1B57INC HL… bump the value of the memory pointer in register pair HL …
1B58LD (HL),A… and save a zero at the location of the memory pointer in register pair HL.
1B59INC HLBump the value of the memory pointer in register pair HL.
1B5ALD (40F9H),HLSave 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
Differences between M1 and M3 ROMs: The locations 1B5DH – 1B5FH are part of the RUN, NEW, EDIT, etc. commands; in the Model I these three bytes contain a LD HL,(40A4H) instruction (resets HL to point to the start of the BASIC program). In the Model III, this has been replaced by a CALL 046BH instruction, which unprotects the video display in addition to resetting HL to the start of the BASIC program.
- 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
The ability to RUN a BASIC program from an assembly language program is valuable for linking the two programs.
1B60DEC HLDecrement the value in register pair HL to backspace.
LD (40DFH),HLSave the adjusted value in register pair HL into 40DFH.
NOTE: 40DFH-40E0H is used by DOS.
1B64-1B65LD B,1AHLoad register B with the number of variable names to be initialized (which is 26).
1B66-1B68LD HL,4101HLoad register pair HL with the starting address of the variable declaration table (which is 4101H).
NOTE: 4101H-411AH holds Variable Declaration Table.
1B69-1B6ALD (HL),04HSet the variable at the location of the memory pointer in register pair HL to a single precision variable.
1B6BINC HLBump the value of the memory pointer in register pair HL to the next variable.
1B6EXOR AZero register A.
1B6F-1B71LD (40F2H),ASave 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 the error flag.
1B72LD L,AZero register L.
1B73LD H,AZero register H.
1B74-1B76LD (40F0H),HLSave a zero (held in register pair HL) as the current ON ERROR address.
NOTE: 40F0H-40F1H is used by ON ERROR.
1B77-1B79LD (40F7H),HLSave a zero (held in register pair HL) as the current BREAK, STOP, or END address.
NOTE: 40F7H-40F8H holds the last byte executed.
1B7A-1B7CLD HL,(40B1H)Load register pair HL with the top of the memory pointer held in 40B1H.
NOTE: 40B1H-40B2H holds MEMORY SIZE? pointer.
1B7D-1B7FLD (40D6H),HLSave the top of memory pointer (held in register pair HL) as the next available address in the string space pointer.
NOTE: 40D6H-40D7H holds Next available location in string space pointer.
1B83-1B85LD HL,(40F9H)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-1B88LD (40FBH),HLSave the value in register pair HL as the new simple variables pointer.
- Note: 40FBH-40FCH holds the starting address of the BASIC array variable storage area.
1B89-1B8BLD (40FDH),HLSave the value in register pair HL as the new array variables pointer.
NOTE: 40FDH-40FEH holds the pointer to the starting address of free memory.
1B8C-1B8ECALL 41BBHGo call the DOS line at 41BBH.
In NEWDOS 2.1 this initializes BASIC for a new routine.1B8FH – Inside the RUN routine – Initialize the Level II BASIC variables and pointers
1B8FPOP BCGet the return address from the stack because we are about to change the stack pointer.
1B90-1B92LD HL,(40A0H)Load register pair HL with the start of string space pointer.
- Note: 40A0H-40A1H holds the start of string space pointer.
1B93DEC HLDecrement the value of the memory pointer in register pair HL.
1B94DEC HLDecrement the value of the memory pointer in register pair HL (so now HL has the sart of the string space pointer – 2).
1B95-1B97LD (40E8H),HLSave the string space pointer – 2 (in register pair HL) as the stack pointer
Note: 40E8H-40E9H holds Stack pointer pointer.
1B98INC HLBump the value of the memory pointer in register pair HL.
1B99INC HLBump the value of the memory pointer in register pair HL so it is back to being the start of the string space pointer.
1B9ALD SP,HLLoad the stack pointer with the start of the string space pointer (held in register pair HL).
1B9B-1B9DLD HL,40B5HLoad register pair HL with the start of the string work area (which is 40B5H).
NOTE: 40B5H-40D2H holds Temporary string work area.
1B9E-1BA0LD (40B3H),HLSave the value in register pair HL as the next available location in the string work area pointer.
NOTE: 40B3H-40B4H holds Next available location in the temporary string work area pointer.
1BA7XOR AZero register A.
1BA8LD H,AZero register H.
1BA9LD L,AZero register L.
1BAA-1BACLD (40DCH),AClear the FOR statement flag.
NOTE: 40DCH holds FOR flag.
1BADPUSH HLSave the value in register pair HL (which is RUN) to the stack.
1BAEPUSH BCSave the value in register pair BC (which is the address to continue executing code) to the stack.
1BAF-1BB1LD HL,(40DFH)Load register pair HL with the current value of the BASIC program pointer.
NOTE: 40DFH-40E0H holds Used by DOS.
1BB2RETReturn.
1BB3-1BBF – KEYBOARD INPUT ROUTINE
This is the last of the general purpose input routines. This routine functions identically to the 361H routine with the exception that it prints a “?” on the screen (like INPUT does with BASIC) before allowing input from the keyboard.
To use a ROM call to display “?” on the video screen at the current cursor position (Non-DOS Systems Only), and then to input a string of up to 240 characters, execute CALL 1BB3H. The input string will be in consecutive memory locations starting at the address contained in 40A7H-40A8H, with a zero byte at the end. The HL register pair will contain an address one less than the starting address of the stored input.
1BB3-1BB4H
“INPUT”LD A,3FHLoad register A with a ?.
1BB8-1BB9LD A,20HLoad register A with a space.
1BC0-1C8F – TOKENIZE INPUT ROUTINE
1BC0XOR AZero register A.
1BC1-1BC3LD (40B0H),ASave the value in register A as the current value of the tokenization flag.
NOTE: 40B0H holds the temporary storage location.
1BC1-1BC3LD (409FH),ASave the value in register A into the DATA FLAG held in 409FH.
NOTE: Bit 0 HIGH means inside a quote. Bit 1 HIGH means inside a DATA. Bit 2 HIGH means inside a REM.
NOTE: In the original Model III ROM, this byte was placed into 40B0H which was just a temporary storage location.
1BC4LD C,AZero register C.
1BC5EX DE,HLLoad register pair DE with the address of the first character after the line number (as stored in register pair HL).
1BC6-1BC8LD HL,(40A7H)Load register pair HL with the starting address of the input buffer.
NOTE: 40A7H-40A8H holds Input Buffer pointer.
1BC9DEC HLWe need to backspace twice so … decrement the value of the input buffer pointer in register pair HL.
1BCADEC HL… and again decrement the value of the input buffer pointer in register pair HL.
1BCBEX DE,HLExchange the string address – 2 from HL into DE, and the current input string address from DE into HL.
1BCCLD A,(HL)Load register A with the character at the current input string address (in register pair HL).
1BCD-1BCECP 20HCheck to see if the character in register A is a space.
1BD2LD B,ALoad register B with the value of the character in register A.
1BD3-1BD4CP 22HCheck to see if the character in register A is a “.
1BD5-1BD7Jump to 1C77H if the character in register A is a “. 1C77H will move the entire field between the quotes into the a code string.
1BD8OR ACheck to see if the character in register A is an end of the input character and set the status flags.
1BDC-1BDELD A,(40B0H)Load register A with the value of the tokenization flag for DATA.
NOTE: 40B0H holds the temporary storage location.
1BDC-1BDELD A,(409FH)Load register A with the value of the DATA FLAG.
NOTE: Bit 0 HIGH means inside a quote. Bit 1 HIGH means inside a DATA. Bit 2 HIGH means inside a REM.
NOTE: In the original Model III ROM, this byte was read from 40B0H which was just a temporary storage location.
1BDFOR ACheck to see if a DATA statement is being processed.
1BE0LD A,(HL)Load register A with the value of the next character.
1BE4-1BE5CP 3FHCheck to see if the character in register A is a ? (meaning a PRINT statement).
1BE6-1BE7LD A,B2HLoad register A with a PRINT token of B2H.
1BE8-1BEAJump to 1C5BH if the character at the location of the input buffer pointer in register pair HL is a ?. This will replace the ? with PRINT.
1BEBLD A,(HL)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-1BEDCP 30HCheck to see if the character in register A is less than a zero character (alpha numeric).
NOTE: Results from a CP:- Z: A and * are the same
- NZ: A and * are NOT the same
- C: A < *
- NC: A => *
1BEE-1BEFJump to 1BF5H if the character in register A is less than a zero character, meaning it is not a digit or letter.
1BF0-1BF1CP 3CHCheck to see if the character in register A is less than < character (which is a test to see if it is 0-9, :, ;, <, constant or special character.
NOTE: Results from a CP:- Z: A and * are the same
- NZ: A and * are NOT the same
- C: A < *
- NC: A => *
1BF2-1BF4Jump to 1C5BH if the character in register A is 0-9, :, ;, <, constant or special character.
1BF5PUSH DESave the value of the input buffer pointer in register pair DE to the stack.
1BF6-1BF8LD DE,164FHLoad register pair DE with the starting address of the reserved words list.
1BF9PUSH BCSave the value in Register Pair BC to the STACK.
1BFA-1BFCLD BC,1C3DHLoad register pair BC with the return address after matching the reserved word list.
1BFDPUSH BCSave the return address in register pair BC to the stack .
1BFE-1BFFLD B,7FHLoad register B with the initial reserved words counter.
1C00LD A,(HL)Load register A with the character at the location of the input buffer pointer in register pair HL.
1C01-1C02CP 61HCheck to see if the character in register A is lower�case.
NOTE: Results from a CP:- Z: A and * are the same
- NZ: A and * are NOT the same
- C: A < *
- NC: A => *
1C05-1C06CP 7BHCheck to see if the character in register A is lower�case.
1C07-1C08Jump down 2 instructions to 1C0CH if the character in register A isn’t lowercase.
1C09-1C0AAND 5FHMake the lowercase character in register A upper�case.
1C0BLD (HL),ASave the adjusted character in register A at the location of the input buffer pointer in register pair HL.
1C0CLD C,(HL)Load register C with the character at the location of the input buffer pointer in register pair HL.
1C0DEX DE,HLExchange the input buffer pointer in register pair HL with the reserved words list pointer in register pair DE.
1C0EINC HLBump the value of the reserved words list pointer to the next reserved word and put that in register pair HL.
1C0FOR (HL)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-1C12Jump to 1C0EH if the character at the location of the reserved words list pointer in register pair HL doesn’t have bit 7 set.
1C13INC BBump the value of the reserved words counter in register B.
1C14LD A,(HL)Load register A with the character at the location of the reserved words list pointer in register pair HL.
1C15-1C16AND 7FHReset bit 7 (the sign bit) of the character in register A.
1C17RET ZReturn if this is the end of the reserved words list.
1C18CP CCheck 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.
1C1BEX DE,HLExchange the value of the reserved words list pointer in register pair HL with the value of the input buffer pointer in register pair DE.
1C1CPUSH HLSave the starting address of the current symbol (stored register pair HL) to the stack.
1C1DINC DEBump the value of the reserved words list pointer in register pair DE.
1C1ELD A,(DE)Load register A with the character at the location of the reserved words list pointer in register pair DE.
1C1FOR ACheck to see if bit 7 of the character in register A is set.
1C20-1C22Jump to 1C39H if we have the control element (i.e., bit 7 of the character in register A is set).
1C23LD C,ALoad register C with the character in register A.
1C24LD A,BLoad register A with the value of the reserved words counter in register B.
1C25-1C26CP 8DHCheck to see if the current reserved word being checked is GOTO.
1C29RST 10HSince 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.
NOTE:- The RST 10H routine loads the next character from the string pointed to by the HL register into the A-register and clears the CARRY FLAG if it is alphabetic, or sets it if is alphanumeric.
- Blanks and control codes 09H and 0BH 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.
1C2ADEC HLDecrement the value of the input buffer pointer in register pair HL.
1C2BINC HLBump the value of the input buffer pointer in register pair HL to point to the next character.
1C2CLD A,(HL)Load register A with the next element from the string input (i.e., the character at the location of the input buffer pointer in register pair HL).
1C2D-1C2ECP 61HCheck to see if the character in register A is lower-case. Results:- If A=61H it sets the ZERO FLAG
- If A<61H then the CARRY FLAG will be set
- if A>=61H then the NO CARRY FLAG will be set.
If A is a not lower case then C will be set.
1C31-1C32AND 5FHMask A against 5FH (Binary: 0101 1111) to turn off bits 5 and 7 (which locks A to be between 00H and 7FH).
1C33CP CCheck to see if the character in register A (the input element) matches the character in register C (the syntax element).
1C34-1C35Jump back to 1C1DH if the character in the input matches the reserved words character.
1C36POP HLIf we didn’t just jump away, we need to restart the scan from the last point in the syntax list (which is stored in the stack) and put it into HL.
1C39LD C,BLoad register C with the value of the reserved words counter in register B.
1C3AGet the value from the stack and put it in register pair AF (which is just disposing of the HL push from 1C1CH).
1C3BEX DE,HLExchange the current string with the syntax tree address for the string.
1C3CRETReturn.
1C3DEX DE,HLExchange the reserved words list pointer in register pair HL with the input buffer pointer in register pair DE.
1C3ELD A,CLoad register A with the value of the reserved words counter in register C.
1C3FPOP BCGet the value from the stack and put it in register pair BC (basically to clear the return address from the stack).
1C40POP DEGet the input buffer pointer -2 from the stack and put it in register pair DE.
1C41EX DE,HLExchange the input buffer pointer in register pair HL with the input buffer pointer in register pair DE. HL will be the buffer origin – 2 and DE will be the current string address.
1C42-1C43CP 95HCheck to see if the token in register A is an ELSE token.
1C44-1C45LD (HL),3AHSave a colon at the location of the input buffer pointer -2 in register pair HL.
1C48INC CBump the value of the counter in register C (which is tracking the token buffer).
1C49INC HLBump the value of the input buffer pointer in register pair HL (which is the token buffer).
1C4A-1C4BCP 0FBHCheck to see if the token in register A is a REM token.
1C4E-1C4FLD (HL),3AHSave a “:” at the memory location of the input buffer pointer in register pair HL.
1C50INC HLBump the value of the input buffer pointer in register pair HL (because we just inserted a :).
1C51-1C52LD B,93HLoad register B with a REM token.
1C53LD (HL),BSave the REM token in register B at the memory location of the input buffer pointer in register pair HL.
1C54INC HLBump the value of the input buffer pointer in register pair HL (because we just inserted a REM token).
1C55EX DE,HLExchange the value of the input buffer pointer in register pair HL with the value of the input buffer pointer in register pair DE.
1C56INC CBump the value of the counter in register C.
1C57INC CBump the value of the counter in register C.
1C5AEX DE,HLExchange the value of the input buffer pointer in register pair HL with the value of the input buffer pointer in register pair DE.
1C5CLD (DE),ASave the value of the token in register A at the location of the input buffer pointer in register pair DE.
1C5DINC DEBump the value of the input buffer pointer in register pair DE.
1C5EINC CBump the value of the counter in register C (which is the index/counter for the next syntax element).
1C5F-1C60SUB 3AHCheck to see if the character in register A is a : to flag a multi-statement line.
1C61-1C62Jump to 1C67H if the character in register A is a colon and we have a multi-statement line.
1C63-1C64CP 4EHCheck to see if the token in register A is a DATA token.
LD (40B0H),ASave the value in register A as the tokenization flag for DATA.
NOTE: 40B0H holds the temporary storage location.
LD (409FH),ASave the value in register A into the DATA FLAG held in 409FH.
NOTE: Bit 0 HIGH means inside a quote. Bit 1 HIGH means inside a DATA. Bit 2 HIGH means inside a REM.
NOTE: In the original Model III ROM, this byte was placed into 40B0H which was just a temporary storage location.
1C6FLD B,ALoad register B with a zero.
1C70LD A,(HL)Load register A with the character at the location of the input buffer pointer in register pair HL.
1C71OR ACheck to see if the character in register A is an end of the input character.
1C72-1C73Jump out of this loop to 1C7DH if the character in register A is an end of the input character.
1C74CP BCheck to see if the character in register B matches the character in register A.
1C75-1C76Jump to 1C5BH if the character in register B matches the character in register A.
1C77INC HLBump the value of the input buffer pointer in register pair HL.
1C78LD (DE),ASave the character in register A at the location of the input buffer pointer in register pair DE.
1C79INC CBump the value of the counter in register C.
1C7AINC DEBump the value of the input buffer pointer in register pair DE.
Still Inside the TOKENIZE INPUT ROUTINE – This routine is called if the character in register A is an end of the input character.
1C7D-1C7FLD HL,0005HLoad register pair HL with a five.
1C80LD B,HLoad register B with zero.
1C81ADD HL,BCAdd 5 to the length of the token buffer so far.
1C82LD B,HLoad register B with the MSB of the value in register H.
1C83LD C,LLoad register C with the LSB of the value in register L.
1C84-1C86LD HL,(40A7H)Load register pair HL with the start address of the input buffer.
NOTE: 40A7H-40A8H holds the pointer to the start of the Input Buffer.
1C87DEC HLDecrement the value of the input buffer pointer in register pair HL.
1C88DEC HLDecrement the value of the input buffer pointer in register pair HL.
1C89DEC HLDecrement the value of the input buffer pointer in register pair HL.
1C8ALD (DE),AZero the location of the input buffer pointer in register pair DE.
1C8BINC DEBump the value of the input buffer pointer in register pair DE.
1C8CLD (DE),AZero the location of the input buffer pointer in register pair DE.
1C8DINC DEBump the value of the input buffer pointer in register pair DE.
1C8ELD (DE),AZero the location of the input buffer pointer in register pair DE.
1C8FRETReturn.
1C90-1C95 – RST 0018H CODE
The RST 18H code is located here. (Unsigned compare (HL-DE)).
This is 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:
- HL<DE: CARRY SET
- HL>DE: NO CARRY
- HL><DE: NZ
- HL=DE: Z
1C90H
“CHLDE”LD A,HLoad register A with the MSB of the value in register H.
1C91SUB DSubtract the value of the MSB of the value in register D from the MSB of the value in register A.
1C92RET NZReturn if the MSB of the value in register D doesn’t equal the MSB of the value in register H.
1C93LD A,LLoad register A with the LSB of the value in register L.
1C94SUB ESubtract the LSB of the value in register E from the LSB of the value in register A.
1C95RETReturn.
1C96-1CA0 – RST 0008H CODE
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 the Aregister 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).
1C96LD A,(HL)Load register A with the character at the location of the current BASIC program pointer in register pair HL.
1C97EX (SP),HLSave 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.
1C98CP (HL)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.
1C99INC HLBump the value of the return address in register pair HL.
1C9AEX (SP),HLRestore the return address (meaning the RST 08H plus 1 byte plus 1 byte) to the stack pointer.
1CA1-1D1D – Level II BASIC FOR ROUTINE
1CA1-1CA2LD A,64HLoad register A with the value for the FOR flag.
1CA3-1CA5LD (40DCH),ASave the value in register A as the current value of the FOR flag.
NOTE: 40DCH holds FOR flag.
1CA9EX (SP),HLExchange the value of the current BASIC program pointer in register pair HL with the value to the stack.
1CAA-1CACGOSUB to 1936H to check to see if there is a FOR statement to the stack already using the same variable name (called the index).
1CADPOP DEGet the current BASIC program pointer from the stack (which should be the TO token and put it in register pair DE.
1CAE-1CAFIf there isn’t a matching FOR statement to the stack, skip the next 4 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.
1CB0ADD HL,BCAdd the value in register pair BC (which is the offset to the end of the stack frame) to the value in register pair HL. After this addition, we should be pointing to the end of the first FOR frame push.
1CB1LD SP,HLReset 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-1CB4LD (40E8H),HLSave the value in register pair HL as the stack pointer, get ready for a NF error.
NOTE: 40E8H-40E9H holds Stack pointer pointer.
1CB5EX DE,HLExchange the value of the current BASIC program pointer in register pair DE with the value of the stack pointer address in register pair HL.
1CB6-1CB7LD C,08HLoad register C with the 1/2 the amount of space needed.
1CB8-1CBAGo check to see if there is enough memory (i.e., 16 bytes) left by calling 1963H (which is the MEMORY CHECK ROUTINE).
1CBBPUSH HLSave 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-1CBEKeep scanning the current BASIC program (pointer is in register pair HL) until it points to the end of the BASIC statement.
1CBFEX (SP),HLExchange 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.
1CC0PUSH HLSave the value of the current BASIC program pointer in register pair HL to the stack. This should be pointing to the TO token.
1CC1-1CC3LD HL,(40A2H)Load register pair HL with the value (in binary) of the current BASIC line number.
NOTE: 40A2H-40A3H holds the current BASIC line number.
1CC4EX (SP),HLExchange the value of the current BASIC line number in register pair HL with the value of the current BASIC program pointer to the stack.
1CC5-1CC6RST 08H
BDHSince 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 the Aregister 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).
1CC7RST 20HWe 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 REG 1 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
- Double Precision is NZ/NC/P/E and A is 5.
1CC8-1CCAIf that test shows we have a STRING, go to the Level II BASIC error routine and display a TM ERROR message.
1CCB-1CCDIf that test shows we have a DOUBLE PRECISION number, go display a ?TM ERROR message.
1CCEPUSH AFWe have an integer, so let’s keep going and save the value in register pair AF (the type flags) to the stack.
lCCFH-lCDlGo 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 REG 1.
1CD2POP AFRestore the index type flags from the from the stack and put it in register pair AF.
1CD3PUSH HLSave the value of the current BASIC program pointer (which is the code string after the TO pointer) in register pair HL to the stack.
1CD7-1CD9Call the CONVERT TO INTEGER routine at 0A7FH (where the contents of REG 1 are converted from single or double precision to integer and deposited into HL).
1CDAEX (SP),HLExchange the integer value in register pair HL (the current TO value) with the value of the current BASIC program pointer to the stack.
1CDB-1CCDLD DE,0001HLoad register pair DE with a default STEP value of 1.
1CDELD A,(HL)Load register A with the character at the location of the current BASIC program pointer in register pair HL.
1CDF-1CE0CP CCHCheck to see if the character in register A is CCH which is the STEP token.
1CE1-1CE3So 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.
1CE4PUSH DESave the STEP index value (in register pair DE) to the stack.
1CE5PUSH HLSave the current BASIC program pointer (in register pair HL) to the stack.
1CE6EX DE,HLExchange 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-1CE9GOSUB to 099EH to get the sign of the STEP value into A. It will be A=+1 if positive and A=-1 if negative.
Need the TO value to be integer so GOSUB to the CONVERT TO SINGLE PRECISION routine at 0AB1H (which converts the contents of REG 1 from integer or double precision into single precision).
1CEF-1CF1Call 09BF which loads the SINGLE PRECISION value in REG 1 (the TO value in integer) into register pair BC/DE.
1CF2POP HLGet 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.
1CF3H,1CF4PUSH BC
PUSH DESave all 4 bytes of the TO value to the stack.
1CF5-1CF7LD BC,8100HLoad register pair BC with the exponent and the MSB for a single precision constant.
1CF8LD D,CZero the NMSB for the single precision constant in register D.
1CF9LD E,DZero the LSB for the single precision constant in register E. Register pairs BC and DE now hold a single precision constant equal to one.
1CFALD A,(HL)Load register A with the character at the location of the current BASIC program pointer in register pair HL.
1CFB-1CFCCP CCHCheck to see if the character in register A is a STEP token.
1CFD-1CFELD A,01HLoad register A with the default STEP value (in this case, 1).
1CFF-1D00Skip 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-1D03Go evaluate the expression at the location of the current BASIC program pointer (which is the STEP instruction and return with the result in REG 1
1D04PUSH HLSave the value of the current BASIC program pointer in register pair HL to the stack.
1D05-1D07Convert the STEP value to single precision by calling the CONVERT TO SINGLE PRECISION routine at 0AB1H (which converts the contents of REG 1 from integer or double precision into single precision).
1D08-1D0ALoad the STEP value into BC/DE by calling 09BF which loads the SINGLE PRECISION value in REG 1 into register pair BC/DE.
1D0B-1D0DGo get the sign for the STEP value (held in REG 1) into register A. A will be +1 if positive, and -1 if negative.
1D0EPOP HLGet the value of the current BASIC program pointer from the stack and put it in register pair HL.
1D0FPUSH BCSave the exponent and the NMSB for the single precision value in register pair BC to the stack.
1D10PUSH DESave the NMSB and the LSB for the single precision value in register pair DE to the stack.
1D11LD C,ALoad register C with the sign value for the STEP value in register A.
1D12RST 20HWe 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 REG 1 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
- Double Precision is NZ/NC/P/E and A is 5.
1D13LD B,ALoad register B with type-adjusted and sign value of the number type flag test in register A.
1D14PUSH BCSave the type-adjusted and sign value in register pair BC to the stack.
1D15PUSH HLSave the value of the current BASIC program pointer in register pair HL to the stack.
1D16-1D18LD HL,(40DFH)Load register B with a FOR x=y token.
NOTE: 40DFH-40E0H holds Used by DOS.
1D19EX (SP),HLPut the code address string into HL and put the address of the x variable into the stack.
1D1A-1D1BLD B,81HLoad register B with the FOR token.
1D1CPUSH BCSave the FOR and token and the sign of the STEP increment BC to the stack.
1D1DINC SPBump 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
1D21OR ASet the flags to test for what key was pressed.
1D22-1D24GOSUB to 1DA0H if the key pressed was a SHIFT-@. This will save the address of the last byte executed in the current line.
1D25-1D27LD (40E6H),HLSave the value of the current BASIC program pointer.
NOTE: 40E6H-40E7H holds the temporary storage location.
1D28-1D2BLD (40E8H),SPSave the value of the stack pointer.
NOTE: 40E8H-40E9H holds Stack pointer pointer.
1D2CLD A,(HL)Load register A with the value at the location of the current BASIC program pointer in register pair HL.
1D2D-1D2ECP 3AHCheck to see if the character in register A is a :.
1D2F-1D30If the character is a :, jump to 1D5AH since that means this is a brand new statement on this line.
1D31OR AThere wasn’t a colon, so the only valid thing we can find now is an END OF LINE character. This will check to see if the character in register A is an end of the BASIC line character.
1D32-1D34Go 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.
1D35INC HLSo 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.
1D36LD A,(HL)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.
1D37INC HLBump the value of the current BASIC program pointer in register pair HL.
1D38OR (HL)Check to see if the next BASIC line pointer is equal to zero.
1D3CINC HLIf 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.
1D3DLD E,(HL)Load register E with the LSB of the BASIC line number at the location of the current BASIC program pointer in register pair HL.
1D3EINC HLBump the value of the current BASIC program pointer in register pair HL.
1D3FLD D,(HL)Load register D with the MSB of the BASIC line number at the location of the current BASIC program pointer in register pair HL.
1D40EX DE,HLExchange the value of the BASIC line number in register pair DE with the value of the current BASIC program pointer in register pair HL.
1D41-1D43LD (40A2H),HLSave the value of the BASIC line number in register pair HL.
NOTE: 40A2H-40A3H holds the current BASIC line number.1D44 – Honor a TRON by showing the line number if it is in effect.
1D44-1D46LD A,(411BH)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 the TRON/TROFF flag.
1D47OR ACheck for TRON.
1D4APUSH DEIf 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-1D4CLD A,3CHLoad register A with a <.
1D50-1D52Call 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-1D54LD A,3EHLoad register A with a >
1D58POP DEGet the value of the current BASIC program pointer from the stack and put it in register pair DE.1D59 – Done with the TRON, so let us continue.
1D59EX DE,HLLoad register pair HL with the value of the current BASIC program pointer in register pair DE.
RST 10HWe 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.
NOTE:- The RST 10H routine loads the next character from the string pointed to by the HL register into the A-register and clears the CARRY FLAG if it is alphabetic, or sets it if is alphanumeric.
- Blanks and control codes 09H and 0BH 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.
1D5B-1D5DLD DE,1D1EHLoad register pair DE with the return address to go to after executing one verb.
1D5EPUSH DESave that return address in register pair DE to the stack.
1D5FReturn (back to 1D1EH) if the character at the location of the current BASIC program pointer (in register pair HL) is an end of the BASIC line character.
1D60-1D61SUB 80HCheck 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.
1D65-1D66CP 3CHCheck to see if the token in register A is below the TAB( token.
1D67-1D69Jump out of here to 2AE7H if the token in register A is greater than or equal to a TAB( token, meaning TAB( to MID$(.
1D6ARLCAMultiply the token value in register A by two. This doubles the remainder of the routine address offset.
1D6BLD C,ALoad the adjusted token value in register C from register A.
1D6C-1D6DLD B,00HLoad register B with zero so that BC now holds “00” and (2 x the token).
1D6EEX DE,HLLoad register pair DE with the value of the current BASIC program pointer in register pair HL.
1D6F-1D71LD HL,1822HLoad register pair HL with the list of BASIC execution addresses.
1D72ADD HL,BCAdd 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.
1D73LD C,(HL)Load register C with the LSB of the execution address at the location of the memory pointer in register pair HL.
1D74INC HLBump the value of the memory pointer in register pair HL.
1D75LD B,(HL)Load register B with the MSB of the execution address at the location of the memory pointer in register pair HL.
1D76PUSH BCSave the value of the execution address in register pair BC to the stack.
1D77EX DE,HLLoad 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
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).
1D78H
“FETCH”INC HLBump the value of the current BASIC program pointer in register pair HL to the next character.
1D79LD A,(HL)Load register A with the value of the character at the location of the current BASIC program pointer in register pair HL.
1D7A-1D7BCP 3AHCheck to see if the character at the location of the current BASIC program pointer in register A is greater than or equal to a :. Results:- If A=: it sets the ZERO FLAG
- If A<: then the CARRY FLAG will be set
- if A>=: then the NO CARRY FLAG will be set.
1D7CRET NCReturn 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-1D7ECP 20HCheck to see if the character at the location of the current BASIC program pointer in register A is a space.
1D7F-1D81Loop if the character at the location of the current BASIC program pointer in register A is a space.
1D82-1D83CP 0BHCheck 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). Results:- If A=0BH it sets the ZERO FLAG
- If A<0BH then the CARRY FLAG will be set
- if A>=0BH then the NO CARRY FLAG will be set.
1D84-1D85Jump if the character at the location of the current BASIC program pointer in register A if greater than or equal to 0BH.
1D86-1D87CP 09HCheck 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 horizontal tab). Results:- If A=09H it sets the ZERO FLAG
- If A<09H then the CARRY FLAG will be set
- if A>=09H then the NO CARRY FLAG will be set.
1D88-1D8ALoop 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-1D8CCP 30HCheck to see if the character at the location of the current BASIC program pointer in register A is greater than or equal to a 0. Results:- If A=0 it sets the ZERO FLAG
- If A<0 then the CARRY FLAG will be set
- if A>=0 then the NO CARRY FLAG will be set.
1D8DCCFComplement (invert) the CARRY FLAG so that it will set the CARRY FLAG if that ascii character is numeric (i..e, greater than or equal to 30H).
1D8EINC AClear the CARRY FLAG if it is not numeric (i.e., it is less than 30).
1D8FDEC ASet the status flags (except for the CARRY FLAG) according to the character at hand.
1D90RETReturn.
1D91-1D9A – LEVEL II BASIC RESTORE ROUTINE
1D91EX DE,HLSave the contents of HL by loading its contents into DE.
1D92-1D94LD HL,(40A4H)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).
1D95DEC HLBackspace from the start of the BASIC program pointer.
1D96-1D98LD (40FFH),HLSave the start of the program pointer -1 into 40FFH.
NOTE: 40FFH-4100H holds READ pointer.
1D99EX DE,HLRestore the HL from being held in DE.
1D9ARETReturn.
1D9B-1DAD – SCAN KEYBOARD ROUTINE
1D9EOR ASet the flags (to see if a key was pressed).
1D9FRET ZReturn if a key wasn’t pressed.1DA0H – Inside the SCAN KEYBOARD ROUTINE – This will process a SHIFT + @ (Pause) Keypress
1DA0-1DA1CP 60HCheck to see if the key pressed in register A is a SHIFT + @.
1DA2-1DA4If you got a SHIFT + @ we now need to honor that by waiting for yet another key to be pressed.
1DA5-1DA7LD (4099H),ASave the key pressed in register A as the value of the last key pressed.
NOTE: 4099H holds the Last key pressed.
1DA8DEC ACheck to see if the BREAK key was pressed.1DA9H-1DADH – Inside the SCAN KEYBOARD ROUTINE – This will process a STOP.
1DA9RET NZReturn if the BREAK key wasn’t pressed.
This is the STOP entry point.
1DAAINC AReadjust the value of the key pressed in register A.
1DAE-1DE3 – LEVEL II BASIC END ROUTINE
1DAERET NZReturn and display a ?SN ERROR message if there is anything following the END token.
1DAFPUSH AFSave the value in register pair AF to the stack.
1DB0-1DB2CALL Z,41BBHIf this is a DOS system, then call the DOS link at 41BBH instead of continuing here.
1DB3POP AFRestore the END status to the A register.
LD (40E6H),HLSave the value of the current BASIC program pointer in register pair HL.
NOTE: 40E6H-40E7H holds the temporary storage location.
1DB7-1DB9LD HL,40B5HLoad register pair HL with the starting address of the temporary string work area.
NOTE: 40B5H-40D2H holds Temporary string work area.
1DBA-1DBCLD (40B3H),HLSave the value in register pair HL as the new temporary string work area pointer.
NOTE: 40B3H-40B4H holds Next available location in the temporary string work area pointer.
1DBD-1DBFH21 F6 FFZ-80 space saving trick
1DBE-1DBFOR FFHSet the flags.
1DC0POP BCGet the value from the stack and put it in register pair BC. This clears out the stack.
LD HL,(40A2H)Load register pair HL with the value of the current BASIC line number in binary.
NOTE: 40A2H-40A3H holds the current BASIC line number.
1DC4PUSH HLSave the value of the current BASIC line number (in binary) in register pair HL to the stack.
1DC5PUSH AFSave 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.
1DC6LD A,LThese 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.
1DC7AND HCombine the MSB of the current BASIC line number in register H with the LSB of the current BASIC line number in register A.
1DC8INC ABump the combined value of the current BASIC line number in register A.
1DC9-1DCAIncreasing FFFF by 1 would flip the Z flag on, meaning there was no line number. If there was no line number, skip the nex 3 instructions and go to 1D44H.
1DCB-1DCDLD (40F5H),HLIf we are here, we have a line number so save the line number we ended on in register pair HL.
NOTE: 40F5H-40F6H holds the last line number executed.
1DCE-1DD0LD HL,(40E6H)Load register pair HL with the value of the current BASIC program pointer .
NOTE: 40E6H-40E7H holds the temporary storage location.
1DD1-1DD3LD (40F7H),HLSave the value of the current BASIC program pointer in register pair HL.
NOTE: 40F7H-40F8H holds the last byte executed.
1DDAPOP AFRestore A so we can see if this is an END (where A=0) or a STOP (where A=1).
1DDB-1DDDLD HL,1930HLoad register pair HL with the starting address of the BREAK message.
1DE1-1DE3At 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.
1DE4-1DE6LD HL,(40F7H)Load register pair HL with the value of the continuation address.
NOTE: 40F7H-40F8H holds the last byte executed.
1DE7-1DE8LD A,H
OR LTest HL for 0. The easiest way to test a 2 byte register for zero is to load the MSB into A and then OR it with the LSB. if the MSB was 0 and the LSB was 0, then A will be 0.
1DE9-1DEALD E,20HLoad register E with a ?CN ERROR code.
1DEB-1DEDIf HL was zero, then a CONT isn’t possible, so JUMP to 19A2H to display a ?CN ERROR.
1DEEEX DE,HLIf 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-1DF1LD HL,(40F5H)Load HL with the value of the last BASIC line number executed.
NOTE: 40F5H-40F6H holds the last line number executed.
1DF2-1DF4LD (40A2H),HLSave 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.
1DF5EX DE,HLSwap so that HL will be the address of the continuation line.
1DF6RETReturn (continue running but from the CONT line number).
1DF7H-1DFCH – TRON and TROFF Routine
1DF7H – TRON Entry Point (Set A with AFH)
1DF7-1DF8LD A,AFHLoad register A with AFH (Decimal: 175), which is the value for TRON when placed into 411BH.
1DF8H – TROFF Entry Point (Set A with 00H)
1DF8XOR AZ-80 trick. This command is only visible if jumped to. This zeros register A.
1DF9-1DFC – COMMON CODE SHARED BY TRON AND TROFF – Put A into (411BH)
1DF9-1DFBLD (411BH),ASave the value in register A as the current value of the TRON/TROFF flag.
NOTE: 411BH holds the TRON/TROFF flag. 0=off (TROFF), 175=on (TRON)
1DFCRETRETURN.
1DFD-1DFF – DISK ROUTINE NOT USED BY LEVEL II BASIC.
1DFDPOP AF
1DFEPOP HL
1DFFRET
1E00H-1E3CH – DEFxxx Routine
1E00-1E02 – INSIDE THE DEFxxx ROUTINE – DEFSTR Entry Point
1E00-1E01LD E,03HLoad register E with the DEFSTR string number type flag (03H).
1E02H32 1B 41Z-80 Trick! See the general explanation at 10F8H.
1E03H-1E05H – INSIDE THE DEFxxx ROUTINE – DEFINT Entry Point
1E03-1E04LD E,02HLoad register E with the DEFINT integer number type flag (02H).
1E05H011 1E 04Z-80 Trick! See the general explanation at 10F8H.
1E06H-1E08H – INSIDE THE DEFxxx ROUTINE – DEFSNG Entry Point
1E06-1E07LD E,04HLoad register E with the DEFSNG single precision number type flag (04H).
1E08H011 E0 08Z-80 Trick! See the general explanation at 10F8H.
1E09-1E0AH – INSIDE THE DEFxxx ROUTINE – DEFDBL Entry Point
1E09-1E0ALD E,08HLoad register E with the DEFDBL double precision number type flag (08H).
1E0BH-1E3CH – INSIDE THE DEFxxx ROUTINE – Common code shared by all the above – 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-1E0DGOSUB to 1E3DH to check 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-1E10LD BC,1997HLoad register pair BC with a return address which will return to the ?SN ERROR routine.
1E11PUSH BCSave the ?SN ERROR address (in register pair BC) to the stack.
1E12RET CReturn 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-1E14SUB 41HSubtract 41H from the letter’s value in register A so that it will be in the range of 0-25.
1E15LD C,ALoad register C with the adjusted value in register A.
1E16LD B,ALoad register B with the adjusted value in register A.
1E17RST 10HSince 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.
NOTE:- The RST 10H routine loads the next character from the string pointed to by the HL register into the A-register and clears the CARRY FLAG if it is alphabetic, or sets it if is alphanumeric.
- Blanks and control codes 09H and 0BH 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.
1E18-1E19CP CEHCheck to see if the character at the location of the current BASIC program pointer in register A is a –.
1E1A-1E1BIf 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.
1E1CRST 10HIf 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.
NOTE:- The RST 10H routine loads the next character from the string pointed to by the HL register into the A-register and clears the CARRY FLAG if it is alphabetic, or sets it if is alphanumeric.
- Blanks and control codes 09H and 0BH 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.
1E1D-1E1FGOSUB to 1E3DH to check 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.
1E20RET CReturn if the character at the location of the current BASIC program pointer in register A isn’t alphabetic.
1E21-1E22SUB 41HSubtract 41H from the letter’s value in register A so that it will be in the range of 0-25.
1E23LD B,ALoad register B with the adjusted value in register A.
1E24RST 10HSince 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.
NOTE:- The RST 10H routine loads the next character from the string pointed to by the HL register into the A-register and clears the CARRY FLAG if it is alphabetic, or sets it if is alphanumeric.
- Blanks and control codes 09H and 0BH 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.
1E25LD A,BLoad register A with the value of the second letter in register B.
1E26SUB CSubtract the value of the first letter in register C from the value of the second letter in Register A.
1E27RET CIf the CARRY FLAG is set (meaning that varible names are not in ascending order … the one in Register C is earlier than the one in Register A), return (to a syntax error).
1E28INC ABump the value in register A so that it holds the number of variable names to be changed.
1E29EX (SP),HLClear the error address and save the current code string address.
1E2A-1E2CLD HL,4101HLoad register pair HL with 4101H which is the starting address of the variable declaration table.
NOTE: 4101H-411AH holds Variable Declaration Table.
1E2D-1E2ELD B,00HLoad register B with zero.
1E2FADD HL,BCFind the next entry in the type table 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.
1E30LD (HL),EE 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.
1E31INC HLBump the value of the memory pointer in register pair HL.
1E32DEC ADecrement the count of the number of variables to be changed in register A.
1E35POP HLRestore the code string pointer into register pair HL.
1E36LD A,(HL)Load A with the character at the location of the current BASIC program pointer in register pair HL.
1E37-1E38CP 2CHCheck to see if the character at the location of the current BASIC program pointer in register A is a ,.
1E39RET NZReturn if the character at the location of the current BASIC program pointer in register A isn’t a ,.
1E3ARST 10HSince 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.
NOTE:- The RST 10H routine loads the next character from the string pointed to by the HL register into the A-register and clears the CARRY FLAG if it is alphabetic, or sets it if is alphanumeric.
- Blanks and control codes 09H and 0BH 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.
1E3D-1E44 – EXAMINE VARIABLE – See if the value pointed to at the memory location (HL) is an ASCII letter. C Flag is set for yes, NC Flag for no.
1E3DLD A,(HL)Load register A with the character at the location of the current BASIC program pointer in register pair HL.
1E3E-1E3FCP 41HCheck to see if the character at the location of the current BASIC program pointer in register A is less than an A. Results:- If A=A it sets the ZERO FLAG
- If A<A then the CARRY FLAG will be set
- If A>=A then the NO CARRY FLAG will be set
1E40RET CReturn if the character at the location of the current BASIC program pointer in register A is less than an A.
1E41-1E42CP 5BHCheck to see if the character at the location of the current BASIC program pointer in register A is greater than a Z. Results:- If A=Z it sets the ZERO FLAG
- If A<Z then the CARRY FLAG will be set
- If A>=Z then the NO CARRY FLAG will be set
1E43CCFComplement 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.
1E44RETReturn.
1E45-1E4E – EXAMINE VARIABLE
This is called when evaluating a subscript for a variable reference. It will evaluate if the value is positive or negative.
1E45RST 10HGet 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.
NOTE:- The RST 10H routine loads the next character from the string pointed to by the HL register into the A-register and clears the CARRY FLAG if it is alphabetic, or sets it if is alphanumeric.
- Blanks and control codes 09H and 0BH 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.
1E46-1E48GOSUB to 2B02H to 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.
1E49RET PReturn 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.
1E4A-1E4BLD E,08HLoad register E with an ?FC ERROR code.
1E4C-1E4EDisplay 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 – ASCII TO BINARY
1E4FLD A,(HL)Load register A with the character at the location of the current BASIC program (which is pointed to by register pair HL).
1E50-1E51CP 2EHCheck to see if the character at the location of the current BASIC program pointer in register A is a .. Results:- If A=. it sets the ZERO FLAG
- If A<. then the CARRY FLAG will be set
- If A>=. then the NO CARRY FLAG will be set
1E52EX DE,HLLoad register pair DE with the value of the current BASIC program pointer in register pair HL.
1E53-1E55LD HL,(40ECH)Load register pair HL with the current BASIC line number.
NOTE: 40ECH-40EDH holds EDIT line number.
1E56EX DE,HLExchange the value of the current BASIC program pointer in register pair DE with the current BASIC line number in register pair HL.
1E57-1E59Jump 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 – “DECBIN” – 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.
1E5AHDEC HLBackspace HL (the current BASIC program pointer) to the current character.
1E5B-1E5DLD DE,0000HLoad register pair DE with zero.
1E5ERST 10HRe-process that previous character through a RST 10H call.
NOTE:- The RST 10H routine loads the next character from the string pointed to by the HL register into the A-register and clears the CARRY FLAG if it is alphabetic, or sets it if is alphanumeric.
- Blanks and control codes 09H and 0BH 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.
1E5FRET NCReturn if the character at the location of the current BASIC program pointer in register A isn’t numeric.
1E60PUSH HLSave the value of the current BASIC program pointer in register pair HL to the stack.
1E61PUSH AFSave the value in register pair AF (which is the digit plus flags resulting from the RST 10H call) to the stack.
1E62-1E64LD HL,1998HLoad 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.
1E65RST 18HNow 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:- HL<DE: CARRY SET
- HL>DE: NO CARRY
- HL><DE: NZ
- HL=DE: Z
1E66-1E68Go to the Level II BASIC error routine and display a SN ERROR message if the value in register pair DE is greater than 6552.
1E69LD H,DLoad 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.
1E6ALD L,ELoad 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.
1E6BADD HL,DEMultiply the integer value in register pair HL by two.
1E6CADD HL,HLAdd 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.
1E6DADD HL,DEAdd 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.
1E6EADD HL,HLAdd 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.
1E6FPOP AFPut the last ASCII digit (from the stack) into AF.
1E70-1E71SUB 30HConvert the ASCII digit in register A to binary.
1E72LD E,ALoad register E with the binary value of the character in register A.
1E73-1E74LD D,00HLoad register D with zero so that DE will be 0000 through 0009 (the binary equivalent of the digit).
1E75ADD HL,DEAdd 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.
1E76EX DE,HLSwap DE and HL. This will have the effect of setting DE to be 10(base 10) * DE + A.
1E77POP HLRestore the pointer to the next digit (from the stack) into HL.
1E7A-1EA0 – LEVEL II BASIC CLEAR ROUTINE. If Z FLAG is set, no number of bytes was provided (i.e., CLEAR instead of CLEAR 20).
1E7A-1E7CJump 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-1D7FGOSUB to 1E46H to evaluate the number of bytes to be reserved for string space and return with the integer result in register pair DE.
1E80DEC HLDecrement the current BASIC program pointer in register pair HL.
1E81RST 10HEvaluate 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.
NOTE:- The RST 10H routine loads the next character from the string pointed to by the HL register into the A-register and clears the CARRY FLAG if it is alphabetic, or sets it if is alphanumeric.
- Blanks and control codes 09H and 0BH 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.
1E82RET NZReturn 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.
1E83PUSH HLSave the value of the current BASIC program pointer in register pair HL to the stack.
1E84-1E86LD HL,(40B1H)Load the top of memory pointer into register pair HL.
NOTE: 40B1H-40B2H holds MEMORY SIZE? pointer.
1E87LD A,LLoad register A with the LSB of the top of memory pointer in register L.
1E88SUB ESubtract 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.
1E89LD E,ALoad register E with the LSB of the start of string space in register A.
1E8ALD A,HLoad register A with the MSB of the top of memory pointer in register H.
1E8BSBC A,DSubtract 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.
1E8CLD D,ALoad register D with the MSB of the start of string space pointer in register A.
1E8D-1E8FIf 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-1E92LD HL,(40F9H)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-1E95LD BC,0028HLoad register pair BC with the least amount of space needed for BASIC program variables.
1E96ADD HL,BCAdd the value in register pair BC to the end of BASIC program pointer in register pair HL.
1E97RST 18HNow 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:- HL<DE: CARRY SET
- HL>DE: NO CARRY
- HL><DE: NZ
- HL=DE: Z
1E98-1E9ADisplay 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.
1E9BEX DE,HLPut the new start of the string area address into HL.
1E9C-1E9ELD (40A0H),HLLoad the start of string space pointer with HL.
- Note: 40A0H-40A1H holds the start of string space pointer.
1E9FPOP HLRestore the code string pointer back into HL.
1EA3-1EB0 – LEVEL II BASIC RUN ROUTINE. If Z FLAG is set, no line number was provided (i.e., RUN instead of RUN nnnn).
1EA6-1EA8CALL 41C7HGOSUB to 41C7H which is where the RUN nnnn code would be under DOS.
If we are here, then the command was RUN nnnn and we are in Cassette BASIC.
1EAC-1EAELD BC,1D1EHLoad register pair BC with the continuation addres in the execution driver.
1EB1-1EC1 – LEVEL II BASIC GOSUB ROUTINE
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-1EB2LD C,03HLoad register B with the number of bytes needed for the GOSUB push.
1EB6POP BCGet the return address from the stack and put it in register pair BC.
1EB7PUSH HLSave the value of the current BASIC program pointer in register pair HL to the stack.
1EB8PUSH HLCreate a hole to be filled in later by once again saving the value of the current BASIC program pointer to the stack.
1EB9-1EBBLD HL,(40A2H)Load register pair HL with the value of the current BASIC line number in binary.
NOTE: 40A2H-40A3H holds the current BASIC line number.
1EBCEX (SP),HLPut the binary value for the current line number into the hole in the stack AND restore the code string pointer.
1EBD-1EBELD A,91HLoad register A with a GOSUB token.
1EBFPUSH AFSave the GOSUB marker (in register pair AF) to the stack.
1EC0INC SPBump the value of the stack pointer.
1EC1PUSH BCSave the return address in register pair BC (which is to the GOTO code) to the stack.
1EC2-1EDD – LEVEL II BASIC GOTO ROUTINE. Register pair DE should hold the nnnn for the GOTO nnnn command.
1EC2-1EC4We need to put the line number to branch to into DE so we GOSUB to the ASCII TO INTEGER routine at 1E5A.
NOTE:- The routine at 1E5A converts the ASCII string pointed to by HL to an integer deposited into DE. If the routine finds a non-numerica character, the conversion is stopped
1EC5-1EC7GOSUB to 1F07H to bump the current BASIC program pointer in register pair HL until it points to the end of the current BASIC line.
1EC8PUSH HLSave the value of the current BASIC program pointer in register pair HL to the stack.
1EC9-1ECBLD HL,(40A2H)Load register pair HL with the binary equivalent of the last line number.
NOTE: 40A2H-40A3H holds the current BASIC line number.
1ECCRST 18HNow 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:- HL<DE: CARRY SET
- HL>DE: NO CARRY
- HL><DE: NZ
- HL=DE: Z
1ECDPOP HLGet the value of the current BASIC program pointer from the stack and put it in register pair HL.
1ECEINC HLBump 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-1ED1If the line number to branch to (in register pair DE) is greater than the current BASIC line number then GOSUB to 1B2FH to find where the line number is located at a LATER location.
1ED2-1ED4If 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.
1ED5LD H,BLoad register H with the MSB of the new BASIC program pointer in register B. BC is still holding the address of the requested line number.
1ED6LD L,CLoad register L with the LSB of the new BASIC program pointer in register C.
1ED7DEC HLDecrement the value of the current BASIC program pointer in register pair HL to get to the start of the line.
1ED8RET CIf a line number was found, RETURN from this routine to the execution driver (to start execution at the new line number).
Inside the GOTO ROUTINE – If we are here, the line number nnnn was not found, so error out.
1ED9-1EDALD E,0EHLoad register E with an ?UL ERROR code.
1EDE-1E04 – LEVEL II BASIC RETURN ROUTINE
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.
1EDERET NZDisplay a ?SN ERROR message if there is anything following the RETURN token.
1EDF-1EE0LD D,FFHLoad register D with FFH (a dummy address for the search routine).
1EE1-1EE3GOSUB to 1936H to backspace the stack pointer by four and return with the value at the location of the stack pointer in register A.
1EE4LD SP,HLLoad the stack pointer with the new value in register pair HL.
1EE5-1EE7HSLD (40E8H),HLSave the stack pointer position in register pair HL.
NOTE: 40E8H-40E9H holds Stack pointer pointer.
1EE8-1EE9CP 91HCheck to see if the value in register A is a GOSUB token.
1EEA-1EEBLD E,04HLoad register E with a ?RG ERROR code.
1EEC – ?RG ERROR entry point.
1EEFPOP HLGet the binary value of the GOSUB line number from the stack and put it in register pair HL.
1EF0-1EF2LD (40A2H),HLSave the GOSUB line number in register pair HL as the current BASIC line number.
NOTE: 40A2H-40A3H holds the current BASIC line number.
1EF3INC HLBump the value of the current BASIC line number in register pair HL.
1EF4LD A,H
OR LThe way to test HL for 0 is to LOAD A,H and OR L, so A will be 0 only if BOTH H and L were 0. If HL=0 then HL was FFFFH and we have an overflow or a command mode.
1EF8H-lEFALD A,(40DDH)If we are here, we may have a one liner! Load register A with the command mode flag.
NOTE: 40DDH holds INPUT flag.
lEFBOR ACheck for the command mode.
1EFF-1F01LD HL,1D1EHLoad register pair HL with the return address.
1F02EX (SP),HLExchange the value of the current BASIC program pointer to the stack with the return address in register pair HL.
1F03H3E E1Z-80 Trick! See the general explanation at 10F8H.
1F05-1F20 – SCAN ROUTINE
This is also the DATA entry point.
1F05H01Z-80 Trick! See the general explanation at 10F8H.
1F06H3AZ-80 Trick! See the general explanation at 10F8H.
1F07-1F08LD C,00HLoad register C with zero.
1F09-1F0ALD B,00HLoad register B with zero.
1F0CLD C,BLoad register C with the stop scan character in register B.
1F0DLD B,ALoad register B with the stop scan character in register A.
LD A,(HL)Load register A with the character at the location of the current BASIC program pointer in register pair HL.
1F0FOR ACheck to see if the character at the location of the current BASIC program pointer in register A is an end of the BASIC line character.
1F10RET ZReturn if the character at the location of the current BASIC program pointer in register A is an end of the BASIC line character.
1F11CP BCheck 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.
1F12RET ZReturn 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.
1F13INC HLBump the value of the current BASIC program pointer in register pair HL.
1F14-1F15CP 22HCheck to see if the character at the location of the current BASIC program pointer in register A is a “.
1F16-1F17Loop if the character at the location of the current BASIC program pointer in register A is a quote.
1F18-1F19SUB 8FHCheck to see if the character at the location of the current BASIC program pointer in register A is a IF token.
1F1A-1F1BLoop back to 1F0EH if the character at the location of the current BASIC program pointer in register A isn’t an IF token.
1F1CCP BCheck 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.
1F1DADC A,DAdd the value in register D to the value in register A.
1F1ELD D,ALoad register D with the value in register A.
1F21-1F6B – LEVEL II BASIC LET ROUTINE
1F21-1F23Call 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-1F25RST 08H
D5HTest 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 the Aregister 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).
1F26EX DE,HLExchange the address of the variable in register pair DE with the value of the current BASIC program pointer in register pair HL.
1F27-1F29LD (40DFH),HLSave the addres of the variable in register pair HL.
NOTE: 40DFH-40E0H holds Used by DOS.
1F2AEX DE,HLExchange the value of the current BASIC program pointer in register pair DE with the address of the variable in register pair HL.
1F2BPUSH DESave the address of the variable in register pair DE to the stack.
1F2CRST 20HWe 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 REG 1 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
- Double Precision is NZ/NC/P/E and A is 5.
1F2DPUSH AFSave 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-1F30Go evaluate the expression at the location of the current BASIC program pointer in register pair HL and return with the result in REG 1.
1F31POP AFGet the value from the stack and put it in register pair AF.
1F32EX (SP),HLExchange the address of the variable to the stack with the value of the current BASIC program pointer in register pair HL.
1F33-1F34ADD A,03HAdjust 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-1F37Go to 2819H to convert the result in REG 1 to the same number type for the variable .
1F3BPUSH HLSave the address of the variable in register pair DE to the stack.
1F3E-1F40LD HL,(4121H)Load register pair HL with the starting address of the string’s VARPTR in REG 1.
1F41PUSH HLSave the VARPTR for the string result in register pair HL to the stack.
1F42INC HLBump the value of the VARPTR for the string result in register pair HL.
1F43LD E,(HL)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.
1F44INC HLBump the value of the VARPTR for the string result in register pair HL.
1F45LD D,(HL)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-1F48LD HL,(40A4H)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).
1F49RST 18HNow 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:- HL<DE: CARRY SET
- HL>DE: NO CARRY
- HL><DE: NZ
- HL=DE: Z
1F4A-1F4BJump 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.
1F4C-1F4ELD HL,(40A0H)Load register pair HL with the start of the string space pointer.
- Note: 40A0H-40A1H holds the start of string space pointer.
1F4FRST 18HNow 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:- HL<DE: CARRY SET
- HL>DE: NO CARRY
- HL><DE: NZ
- HL=DE: Z
1F50POP DEGet the VARPTR for the string result from the stack and put it in register pair DE.
1F51-1F52Jump 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.
1F53-1F55LD HL,(40F9H)Load register pair HL with the simple variables pointer.
- Note: 40F9H-40FAH holds the starting address of the simple variable storage area.
1F56RST 18HNow 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:- HL<DE: CARRY SET
- HL>DE: NO CARRY
- HL><DE: NZ
- HL=DE: Z
1F57-1F58Jump 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-1F5AH3E D1
LD A,D1HZ-80 Trick
1F5APOP DEGet the VARPTR for the string result from the stack and put it in register pair DE.
1F5EEX DE,HLExchange the VARPTR for the string in register pair DE with the string’s address in register pair HL.
1F65EX (SP),HLExchange the address of the variable in register pair BL with the address of the variable to the stack.
1F69POP DEGet the address of the variable from the stack and put it in register pair DE.
1F6APOP HLGet the value of the current BASIC program pointer from the stack and put it in register pair HL.
1F6BRETReturn.
1F6C-1FAE – LEVEL II BASIC ERROR ON ROUTINE
1F6C-1F6DCP 9EHCheck 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-1F6FJump down to 1F95H if the character at the location of the current BASIC program pointer in register A isn’t an ERROR token.
1F70RST 10HIf 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.
NOTE:- The RST 10H routine loads the next character from the string pointed to by the HL register into the A-register and clears the CARRY FLAG if it is alphabetic, or sets it if is alphanumeric.
- Blanks and control codes 09H and 0BH 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.
1F71-1F72RST 08H
8DHThe 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 the Aregister 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-1F75Convert the next constant into binary (with the result in DE). To do this, call the ASCII TO INTEGER routine at 1E5A.
NOTE:- The routine at 1E5A converts the ASCII string pointed to by HL to an integer deposited into DE. If the routine finds a non-numerica character, the conversion is stopped
1F76LD A,D
OR ETo test DE for zero, LOAD A,D and then OR E. A will be 0 only if BOTH D and E were 0
1F7A-1F7CGo find the location of the line number in register pair DE and return with the location of the line number in register pair BC.
1F7DH,1F7ELD D,B
LD E,CPut the line number from BC into DE
1F7FPOP HLGet the value of the current BASIC program pointer from the stack and put it in register pair HL.
1F83EX DE,HLExchange the location of the BASIC line in register pair DE with the value of the current BASIC pro gram pointer in register pair HL.
1F84-1F86LD (40F0H),HLSave the location of the BASIC line in register pair HL.
NOTE: 40F0H-40F1H is used by ON ERROR.
1F87EX DE,HLExchange the value of the current BASIC program pointer in register pair DE with the location of the BASIC line in register pair HL.
1F88RET CRETURN out of this routine to the execution driver if it was not ON ERROR GOTO 0000.
1F89-1F8BLD A,(40F2H)Load register A with the value of the error flag.
NOTE: 40F2H holds the error flag.
1F8COR ACheck to see if the error flag is set.
1F8DRET ZRETURN out of this routine to the execution driver if the override flag is not set.
1F8E-1F90LD A,(409AH)Load register A with the error code.
NOTE: 409AH holds the RESUME flag.
1F91LD E,ALoad register E with the value of the error code in register A.
1F92-1F94Go to the Level II error routine and display the error message for the error code in register E.
1F95 – Still in the ON routine, but 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-1F97First 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.
1F98LD A,(HL)Load register A with the next character (which should be a token) at the location of the current BASIC program pointer in register pair HL.
1F99LD B,ASave that token into register B.
1F9A-1F9BCP 91HCheck to see if the character at the location of the current BASIC program pointer in register A is a GOSUB token.
1F9C-1F9DSkip the next 2 opcodes if the character at the location of current BASIC program pointer in register A is a GOSUB token .
1F9E-1F9FRST 08H
8DHNow 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 the Aregister 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).
1FA0DEC HLDecrement the value of the current BASIC program pointer in register pair HL to point to the GOTO token.
1FA1LD C,ELoad register C with the LSB of the expression after the ON token in register E (i.e., the “n” from ON n GOTO).
1FA2DEC CDecrement the line number counter in register C.
1FA3LD A,BLoad register A with the token in register B (which is either a GOSUB or GOTO token).
1FA7-1FA9Evaluate the line number at the location of the current BASIC program pointer and return with the result in register pair DE.
1FAA-1FABCP 2CHCheck 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.
1FACRET NZReturn if the character at the location of the current BASIC program pointer in register A isn’t a ,.
1FAF-1FF3 – LEVEL II BASIC RESUME ROUTINE
1FAF-1FB1LD DE,40F2HLoad register pair DE with the address of the Level II BASIC error flag.
NOTE: 40F2H holds the error flag.
1FB2LD A,(DE)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.
1FB3OR ACheck for an error.
1FB7INC AClear the error flag in register A.
1FB8-1FBALD (409AH),ASave the new error flag in register A.
NOTE: 409AH holds the RESUME flag.
1FBBLD (DE),ASave the new error flag in register A at the location of the memory pointer in register pair DE.
1FBCLD A,(HL)Load register A with the character at the location of the current BASIC program pointer in register pair HL.
1FBD-1FBECP 87HCheck to see if the character at the location of the current BASIC program pointer in register A is a NEXT token.
1FBF-1FC0Jump 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-1FC3Get the binary equivalent of the line number into DE by calling the ASCII TO INTEGER routine at 1E5A.
NOTE:- The routine at 1E5A converts the ASCII string pointed to by HL to an integer deposited into DE. If the routine finds a non-numerica character, the conversion is stopped
1FC4RET NZReturn to the execution driver if there wasn’t a line number at the location of the current BASIC program pointer.
1FC5LD A,D
OR ETo test DE against zero, LOAD A, D and OR E, so A will be 0 only if BOTH D and E are zero
1FC7-1FC9Jump to the GOTO code at 1EC5H if the line number in register pair DE isn’t equal to zero (i.e., it was RESUME nnnn).
1FCAINC ABump the value in register A so that it will indicate RESUME 0.
1FCDRST 10HSince 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.
NOTE:- The RST 10H routine loads the next character from the string pointed to by the HL register into the A-register and clears the CARRY FLAG if it is alphabetic, or sets it if is alphanumeric.
- Blanks and control codes 09H and 0BH 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.
1FCERET NZReturn if this is the end of the BASIC statement.
1FCF – This is the RESUME 0 routine
1FCF-1FD1LD HL,(40EEH)Get the value of the current BASIC program pointer and put it in register pair HL.
NOTE: 40EEH-40EFH is used by RESUME.
1FD2EX DE,HLLoad register pair DE with the value of the current BASIC program pointer in register pair HL.
1FD3-1FD5LD HL,(40EAH)Load register pair HL with the current BASIC line number.
NOTE: 40EAH-40EBH holds the line number with error.
1FD6-1FD8LD (40A2H),HLSave 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.
1FD9EX DE,HLLoad register pair HL with the value of the current BASIC program pointer in register pair DE.
1FDARET NZReturn to the execution driver if this is RESUME 0.
1FDBLD A,(HL)Get the character at the location of the current BASIC program pointer in register pair HL and put it in register A.
1FDCOR ACheck 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-1FDEJump 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.
1FDFINC HLBump the value of the current BASIC program pointer in register pair HL to skip over the zero byte terminator.
1FE0INC HLBump the value of the current BASIC program pointer in register pair HL to skip over the LSB of the pointer to the next statement.
1FE1INC HLBump the value of the current BASIC program pointer in register pair HL to skip over the MSB of the pointer to the next statement.
1FE2INC HLBump 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.
1FE3INC HLBump 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.
1FE4LD A,DLoad register A with the MSB of the line number with the error in register D.
1FE5AND ECombine 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.
1FE6INC ABump the combined value of the line number with the error in register A. This will finish the test of DE by turning the FFFFH into 0000H.
1FEA-1FECLD A,(40DDH)Load register A with the command mode flag.
NOTE: 40DDH holds INPUT flag.
1FEDDEC ACheck to see if the command mode flag in register A is set.
1FF4H-2007 – LEVEL II BASIC ERROR ROUTINE – Evaluates n for ERROR n
1FF4-1FF6Go evaluate the expression at the location of the current BASIC program pointer in register pair HL and return with the result in A.
1FF7RET NZReturn if this isn’t the end of the BASIC statement.
1FF8OR ASet up to check to see if the error number in register A is equal to zero.
1FFCDEC ASubtract one from the error code in register A.
1FFDADD A,AMultiply the error code in register A by two (so now A = 2(A-1)).
1FFELD E,ALoad register E with 2(A-1).
1FFF-2000CP 2DHCheck to see if the error code in register A is less than 2DH. Results:- If A=2DH it sets the ZERO FLAG
- If A<2DH then the CARRY FLAG will be set
- if A>=2DH then the NO CARRY FLAG will be set.
2001-2002Jump 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).
NOTE:
- The RST 10H routine loads the next character from the string pointed to by the HL register into the A-register and clears the CARRY FLAG if it is alphabetic, or sets it if is alphanumeric.
- Blanks and control codes 09H and 0BH 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.
1034 – LEVEL II BASIC MATH ROUTINE – “FOUINI”
This routine initializes the input buffer for an ASCII conversion. It is called by the FLOATING to ASCII Conversion Routine (at 0FBEH) and by the BINARY to ASCII Conversion Routine (at 0FAFH).
NOTE: 40D8H-40D9H holds the temporary storage location.
NOTE: 4130H-4149H holds Internal print buffer.
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
NOTE: Results from a CP:
- Z: A and * are the same
- NZ: A and * are NOT the same
- C: A < *
- NC: A => *
NOTE: Results from a CP:
- Z: A and * are the same
- NZ: A and * are NOT the same
- C: A < *
- NC: A => *
NOTE: The RST 20H routine determines the type of the current value in REG 1 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
- Double Precision is NZ/NC/P/E and A is 5.
NOTE: 4130H-4149H holds Internal print buffer.
- If A=04H it sets the ZERO FLAG
- If A<04H then the CARRY FLAG will be set
- If A>=04H then the NO CARRY FLAG will be set
Alternative interpretation is Jump to 11A3H if the variable is a string; which will leave us now with only an integer value.
10A6 – This is where the PRINT USING routine will edit for INTEGER values.
NOTE: 40F3H-40F4H holds the temporary storage location.
NOTE:
- The RST 10H routine loads the next character from the string pointed to by the HL register into the A-register and clears the CARRY FLAG if it is alphabetic, or sets it if is alphanumeric.
- Blanks and control codes 09H and 0BH 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.
NOTE:
- The RST 10H routine loads the next character from the string pointed to by the HL register into the A-register and clears the CARRY FLAG if it is alphabetic, or sets it if is alphanumeric.
- Blanks and control codes 09H and 0BH 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.
1109 – This is where the PRINT USING routine will edit for FLOATING POINT values.
1124H – Continuation point if the current value in REG 1 is single precision.
NOTE: The routine at 0A0CH algebraically compares the single precision value in BC/DE to the single precision value REG 1.
The results are stored in A as follows:
- A=00H if REG 1 = BCDE
- A=01H if REG 1>BCDE; and
- A=FFH if REG 1<BCDE.
1157 – LEVEL II BASIC MATH ROUTINE – “FFXXVS”
This routine will print a SINGLE PRECISION or DOUBLE PREVISION number that has fractional digits
117F – LEVEL II BASIC MATH ROUTINE – “FFXXV3”
This routine will print a number without integer digits.
119A – LEVEL II BASIC MATH ROUTINE – “FFXXV7”
This routine will print trailing zeroes.
NOTE: 40F3H-40F4H holds the temporary storage location.
11A3 – LEVEL II BASIC MATH ROUTINE – “FFXIFL”
This routine will print an integer in fixed format/floating point notation.
11AA – LEVEL II BASIC MATH ROUTINE – “FFXFLV”
This routine will print a SINGLE or DOUBLE PRECISION number in fixed format/floating point notation.
or
LD BC, 1E06H
11B0H – Continuation Routine (From 11AAH) if the current value in REG 1 is SINGLE precision.
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.
NOTE: The RST 20H routine determines the type of the current value in REG 1 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
- Double Precision is NZ/NC/P/E and A is 5.
NOTE: Results from a CP:
- Z: A and * are the same
- NZ: A and * are NOT the same
- C: A < *
- NC: A => *
NOTE: 4127H-412EH holds REG 2.
NOTE: The RST 20H routine determines the type of the current value in REG 1 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
- Double Precision is NZ/NC/P/E and A is 5.
NOTE: The routine at 0A0CH algebraically compares the single precision value in BC/DE to the single precision value REG 1.
The results are stored in A as follows:
- A=00H if REG 1 = BCDE
- A=01H if REG 1>BCDE; and
- A=FFH if REG 1<BCDE.
Difference between M1 and M3 ROMs: This change first appeared in the “new” ROMs for the Model I. The order of two instructions (OR A and POP DE) have been reversed for no apparent reason.
NOTE: The RST 20H routine determines the type of the current value in REG 1 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
- Double Precision is NZ/NC/P/E and A is 5.
NOTE: The routine at 0A0CH algebraically compares the single precision value in BC/DE to the single precision value REG 1.
The results are stored in A as follows:
- A=00H if REG 1 = BCDE
- A=01H if REG 1>BCDE; and
- A=FFH if REG 1<BCDE.
This routine puts leading zeroes into the input buffer
127DH – Subroutine to set up BC for decimal point and comma counters. On entry: Register D holds the number of digits to print, Register E holds the count of the times the value was scaled up or down.
NOTE: 40D8H-40D9H holds the temporary storage location.
1291H – Subroutine to count the leading digits before the decimal point.
NOTE: 40F3H-40F4H holds the temporary storage location.
129CH – Continuation Routine (from 1292H) if the decimal point position hasn’t been reached.
12A4 – Routine to Convert the INTEGER porton of a DOUBLE precision value to its ASCII equivalent.
NOTE: The RST 20H routine determines the type of the current value in REG 1 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
- Double Precision is NZ/NC/P/E and A is 5.
Note: 411DH-4124H holds REG l.
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.
130AH – 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.
132FH – This routine will convert an INTEGER to ASCII.
1335H – This routine will convert the last x (based on A) digits of an INTEGER to ASCII.
1348 – 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).
1364-136B – DOUBLE PRECISION CONSTANT STORAGE LOCATION
136C-1373 – DOUBLE PRECISION CONSTANT STORAGE LOCATION
1374-137B – DOUBLE PRECISION CONSTANT STORAGE LOCATION
137C-1383 – DOUBLE PRECISION CONSTANT STORAGE LOCATION
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
138C-13D1 – DOUBLE PRECISION INTEGER CONSTANT STORAGE LOCATION
13D2H-13D9H – SINGLE PRECISION INTEGER CONSTANT STORAGE LOCATION
13E1-13E6 – LEVEL II BASIC MATH ROUTINE
NOTE: 0982H is the address of the routine for conversion of floating point numbers from negative to positive.
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
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).
NOTE: To use a ROM call to raise a single precision number (the base) to a single precision power (the exponent), store the base (single precision) in registers BCDE, and store the exponent (also single precision) in 4121H-4124H and then CALL 13F7H. The result (in single precision format) is in 4121H-4124H and in approximately 50 milliseconds.
/0 ERROR entry point.
NOTE: The routine at 0A0CH algebraically compares the single precision value in BC/DE to the single precision value REG 1.
The results are stored in A as follows:
- A=00H if REG 1 = BCDE
- A=01H if REG 1>BCDE; and
- A=FFH if REG 1<BCDE.
1439 – EXP routine. Single-precision only. (REG 1 = EXP(REG1)).
A call to 1439H raises E (natural base) to the value in REG 1 which must be a single precision value. The result will be returned in REG 1 as a single precision number.
NOTE: To use a ROM call to find EXP(X), where X is a single precision variable, store the value of X in 4121H-4124H and then CALL 1439H. The result (in single precision format) is in 4121H-4124Hin approximately 28 milliseconds. NOTE: A fatal error occurs if the result is as large as 2 to the power of 127.
“EXP”
1479-1499 – SINGLE PRECISION CONSTANT STORAGE LOCATION
This represents 1/6, -1/5, 1/4, -1/3, 1/2, -1, and 1
149A-14C8 – LEVEL II BASIC MATH ROUTINE
This is a general purpose summation routine which computes the series SUM ((((x^2 * c0+c1)x^2 +c2)x^2 + … cN)x 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.
NOTE: 0C32H pops BC and DE and then JUMPs to JP 0847H.
POP DE
PUSH BC
14C9-1540 – LEVEL II BASIC RND(n). Generates a single-precisions random number between 0 and 1, or 1 and n depending on the parameter passed in REG 1, The random value is returned in REG 1 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.
NOTE: To run a RND(J) function via a ROM call just The RND(J) function (with J a nonzero integer) load the value of J into the HL register pair. Then CALL 14CCH and then CALL 0A7FH. The result (in integer format) is in 4121H-4122H and in HL in approximately 5.7 milliseconds. The input variable J must have a value between 1 and 32767, inclusive, or an FC error will occur.
“RNDM”
POP DE
14F0H – This routine calculates RND(0).
NOTE: To run a RND(0) function via a ROM call just CALL 14F0H. No input variable is necessary. The result (in single precision format) is in 4121H-4124H in approximately 2.4 milliseconds.
NOTE: 4090H holds the random number seed 2
NOTE: 40AAH-40ADH holds the random number seed.
NOTE: 40AAH-40ADH holds the random number seed.
NOTE: 4125H-4126H is used by floating point routines.
1541-1546 – LEVEL II BASIC COS
COS routine. Single-precision only.(REG 1 = COS(REG 1)).
A call to 1541H computes the cosine for an angle given in radians. The angle must be a floating point value in REG 1; the cosine will be returned in REG 1 as a floating point value.
NOTE: To use a ROM call to find COS(X), where X is a single precision variable (in radians), store the value of X in 4121H-4124H and then CALL 1541H. The result (in single precision format) is in 4121H-4124Hin approximately 25 milliseconds.
“COSN”
1547-158A – LEVEL II BASIC SIN
SIN(n) routine. Single-precision only.(REG 1 = SIN(REG 1)).
A call to 1549H returns the sine as a single precision value in REG 1. The sine must be given in radians in REG 1.
The actual calculation routine is:
Assume X <= 360 degrees.
Recompute x as x=x/360 so that x=< 1.
If x <= 90 degrees go to step 7.
If x <= 180 degrees then x=0.5-x and then go to step 7.
If x <= 270 degrees then x=0.5-x.
Recompute x as x=x-1.0.
Compute SIN using the power series.
NOTE: To use a ROM call to find SIN(X), where X is a single precision variable, store the value of X in 4121H-4124H and then CALL 1547H. The result (in single precision format) is in 4121H-4124Hin approximately 25 milliseconds. NOTE: The argument (X) must be in radians.
“SINE”
POP DE
POP DE
158BH-15A7H – SINGLE PRECISION CONSTANT STORAGE LOCATION
15A8-15BC – LEVEL II BASIC TAN ROUTINE – “TAN”
TAN(n)
Single-precision only.(REG 1 = TAN(REG 1)).
A call to 15A8H computes the tangent of an angle in radians. The angle must be specified as a single precision value in REG 1. The tangent will be left in REG 1.
Uses the fact that TAN(x) = SIN(x) / COS(x)
NOTE: To use a ROM call to find TAN(X), where X is a single precision variable (in radians), store the value of X in 4121H-4124H and then CALL 15A8H. The result (in single precision format) is in 4121H-4124Hin approximately 54 milliseconds. NOTE: A fatal error occurs if the result is as large as 2 to the power of 127, which will be the case if the value of X is sufficiently close to any odd multiple of pi/2 radians.
POP HL
15BD-15E2 – LEVEL II BASIC ATN ROUTINE – “ATAN”
ATN(n) routine.
Single-precision only.(REG 1 = ATN(REG 1)).
A call to 15BD returns the angle in radians, for the floating point tangent value in REG 1. The angle will be left as a single precision value in REG 1.
The method of computation used in this routine is:
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.
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.
Evaluate the series: (((x^2*c0+c1) x^2+c2) … c8)x
If the flag from step 1 is not set, then invert the sign of the series result.
If the original value is < 1 then return to the caller. Otherwise, compute pi/2-value from step 4 and then return.
NOTE: To use a ROM call to find ATN(X), where X is a single precision variable, store the value of X in 4121H-4124H and then CALL 15BDH. The result (in single precision format, in radians) is in 4121H-4124Hin approximately 27 milliseconds.
- If A=”1″ it sets the ZERO FLAG.
- If A<“1” then the CARRY FLAG will be set
- If A>=”1″ then the NO CARRY FLAG will be set.
15E3-1607 – SINGLE PRECISION CONSTANTS STORAGE LOCATION
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
Word | Token | Address | Word | Token | Address | |
ABS | D9 | 0977 | | | AND | D2 | 25FD |
ASC | F6 | 2A0F | | | ATN | E4 | 15BD |
AUTO | B7 | 2008 | | | CDBL | F1 | 0ADB |
CHR$( | F7 | 2A1F | | | CINT | EF | 0A7F |
CLEAR | B8 | 1E7A | | | CLOAD | B9 | 2C1F |
CLOSE | A6 | 4185 | | | CLS | 84 | 01C9 |
CMD | 85 | 4173 | | | CONT | B3 | 1DE4 |
COS | El | 1541 | | | CSAVE | BA | 2BF5 |
CSNG | F0 | 0ABl | | | CVD | E8 | 415E |
CVI | E6 | 4152 | | | CVS | E7 | 4158 |
DATA | 88 | 1F05 | | | DEF | DD | 415B |
DEFDBL | 9B | 1E09 | | | DEFINT | 99 | 1E03 |
DEFSNG | 9A | 1E06 | | | DEFSTR | 98 | 1E00 |
DELETE | B6 | 2BC6 | | | DIM | 8A | 2608 |
EDIT | 9D | 2E60 | | | ELSE | 95 | 1F07 |
END | 80 | 1DAE | | | EOF | E9 | 4161 |
ERL | C2 | 24DD | | | ERR | C3 | 24CF |
ERROR | 9E | 1FF4 | | | EXP | E0 | 1439 |
FIELD | A3 | 417C | | | FIX | F2 | 0B26 |
FN | BE | 4155 | | | FOR | 81 | 1CA1 |
FRE | DA | 27D4 | | | GET | A4 | 4174 |
GOSUB | 91 | 1EB1 | | | GOTO | 5D | 1EC2 |
IF | 8F | 2039 | | | INKEY$ | C9 | 019D |
INP | DB | 2AEF | | | INPUT | 89 | 219A |
INSTR | C5 | 419D | | | INT | D8 | 0B37 |
KILL | AA | 4191 | | | LEFT$ | F8 | 2A61 |
LEN | F3 | 2A03 | | | LET | 8C | 1F21 |
LINE | 9C | 41A3 | | | LIST | B4 | 2B2E |
LLIST | B5 | 2B29 | | | LOAD | A7 | 4188 |
LOC | EA | 4164 | | | LOF | EB | 4167 |
LOG | DF | 0809 | | | LPRINT | AF | 2067 |
LSET | AB | 4197 | | | MEM | C8 | 27C9 |
MERGE | A8 | 418B | | | MID$ | FA | 2A9A |
MKD$ | EE | 4170 | | | NAME | A9 | 418E |
NEW | BB | 1B49H | | | NEXT | 87 | 22B6 |
NOT | CB | 25C4 | | | ON | A1 | 1FC6 |
OPEN | A2 | 4179 | | | OR | D3 | 25F7 |
OUT | AO | 2AFB | | | PEEK | E5 | 2CAA |
POINT | C6 | 0132 | | | POKE | B1 | 2CB1 |
POS | DC | 27F5 | | | B2 | 206F | |
PUT | A5 | 4182 | | | RANDOM | 86 | 01D3 |
READ | 8B | 21EF | | | REM | 93 | 1F07 |
RESET | 82 | 0138 | | | RESTORE | 90 | 1D91 |
RESUME | 9F | 1FAFH | | | RETURN | 92 | 1EDEH |
RIGHT$ | F9 | 2A91 | | | RND | DE | 14C9 |
RSET | AC | 419A | | | RUN | 8E | 1EA3 |
SAVE | AD | 41A0 | | | SET | 83 | 0135 |
SGN | D7 | 098A | | | SIN | E2 | 1547 |
SQR | CD | 13E7 | | | STEP | cc | 2B01 |
STOP | 94 | 1DA9 | | | STR$ | F4 | 2836 |
STRING$ | C4 | 2A2F | | | SYSTEM | AE | 02B2 |
TAB( | BC | 2137 | | | TAN | E3 | 15A8 |
THEN | CA | | | TIME$ | C7 | 4176 | |
TO | BD | | | TROFF | 97 | 1DF8 | |
TRON | 96 | 1DF8 | | | USING | BF | 2CBD |
USR | C1 | 27FE | | | VAL | FF | 2AC5 |
VARPTR | C0 | 24EB | | | + | CD | 249F |
– | CE | 2532 | | | * | CF | |
/ | D0 | | | ? | D1 | ||
> | D4 | | | = | D5 | ||
< | D6 | | | & | 26 | ||
‘ | FB | 3A93 |
18C9-18F6 – STORAGE LOCATION FOR LEVEL II BASIC ERROR MESSAGES – “ERRTAB”
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.
1905-191C – STORAGE LOCATION FOR VALUES PLACED IN RAM UPON INITIALIZATION.
This code is moved to 408E during non-disk initial setup.
191DH-1935H – MESSAGE STORAGE LOCATION
1936-1954 – SCAN STACK ROUTINE
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.
- HL<DE: CARRY SET
- HL>DE: NO CARRY
- HL><DE: NZ
- HL=DE: Z
1955-1962 – DATA MOVEMENT ROUTINE
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.
- HL<DE: CARRY SET
- HL>DE: NO CARRY
- HL><DE: NZ
- HL=DE: Z
1963-197D – MEMORY CHECK ROUTINE – Computes the amount of space between HL and the end of memory at FFC6H.
NOTE: 40FDH-40FEH holds the pointer to the starting address of free memory.
197A-197B – OM ERROR entry point.
197E-1AF7 – LEVEL II BASIC COMMAND MODE
NOTE: 40A2H-40A3H holds the current BASIC line number.
NOTE: 40F2H holds the error flag.
NOTE: 40DAH-40DBH holds DATA line number.
NOTE: 40A2H-40A3H holds the current BASIC line number.
SN ERROR entry point.
?NF ERROR entry point.
?RW ERROR entry point.
NOTE: 40A2H-40A3H holds the current BASIC line number.
NOTE: 40EAH-40EBH holds the line number with error.
NOTE: 40ECH-40EDH holds EDIT line number.
NOTE: 40E8H-40E9H holds Stack pointer pointer.
NOTE: 409AH holds the RESUME flag.
NOTE: 40E6H-40E7H holds the temporary storage location.
NOTE: 40EEH-40EFH is used by RESUME.
NOTE: 40EAH-40EBH holds the line number with error.
AND L
NOTE: 40F5H-40F6H holds the last line number executed.
NOTE: 40F7H-40F8H holds the last byte executed.
NOTE: 40F0H-40F1H holds the ON ERROR adress.
NOTE: 40F2H holds the error flag.
NOTE: 41A6H-41E4H holds DOS links.
In NEWDOS 2.1, this would be a call to load a DISK BASIC error, with Register E holding the error number.
NOTE:
- The RST 10H routine loads the next character from the string pointed to by the HL register into the A-register and clears the CARRY FLAG if it is alphabetic, or sets it if is alphanumeric.
- Blanks and control codes 09H and 0BH 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.
NOTE: 40EAH-40EBH holds the line number with error.
NOTE:
- The routine at 28A7 displays the message pointed to by HL on current system output device (usually video).
- The string to be displayed must be terminated by a byte of machine zeros or a carriage return code 0D.
- If terminated with a carriage return, control is returned to the caller after taking the DOS exit at 41D0H (JP 5B99H).
This basically reserves the line number 65534 as a trigger for the next few steps.
- HL<DE: CARRY SET
- HL>DE: NO CARRY
- HL><DE: NZ
- HL=DE: Z
1A19 – “$READY” – Jump to Model II BASIC “READY”
To exit from a machine-language program into BASIC’s immediate mode, jump (not call) to $READY.
“READY”
Re-entry into BASIC command mode entry point. (see 6CCH also).
In NEWDOS 2.1, this is the start of BASIC just before BASIC shows the READY prompt.
NOTE:
- The routine at 28A7 displays the message pointed to by HL on current system output device (usually video).
- The string to be displayed must be terminated by a byte of machine zeros or a carriage return code 0D.
- If terminated with a carriage return, control is returned to the caller after taking the DOS exit at 41D0H (JP 5B99H).
NOTE: 409AH holds the RESUME flag.
1A33 – Many routines jump here as the start of the Level II BASIC interpreter.
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.
NOTE: FFFFH is the command mode line number.
NOTE: 40A2H-40A3H holds the current BASIC line number.
NOTE: 40E2H-40E3H holds Current BASIC line number.
NOTE: 40E1H will hold 0 if no AUTO and non-zero if AUTO.
If we are here, then the BREAK key was not pressed.
NOTE: 40E4H-40E5H holds the AUTO increment number.
There is an explanation at 1E5AH as to why 65529 is the highest possible line number (vs 65535 which would make more sense).
- HL<DE: CARRY SET
- HL>DE: NO CARRY
- HL><DE: NZ
- HL=DE: Z
NOTE: 40E2H-40E3H holds Current BASIC line number.
NOTE:
- The RST 10H routine loads the next character from the string pointed to by the HL register into the A-register and clears the CARRY FLAG if it is alphabetic, or sets it if is alphanumeric.
- Blanks and control codes 09H and 0BH 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.
NOTE:
- The routine at 1E5A converts the ASCII string pointed to by HL to an integer deposited into DE. If the routine finds a non-numerica character, the conversion is stopped
1A8BH – This little looping routine is to clear any trailing blanks between the line number and the statement.
NOTE: 40E6H-40E7H holds the temporary storage location.
In NEWDOS 2.1, this is the input scanner after tokenizing the current statement.
NOTE: 40DDH holds INPUT flag.
NOTE:
- The RST 10H routine loads the next character from the string pointed to by the HL register into the A-register and clears the CARRY FLAG if it is alphabetic, or sets it if is alphanumeric.
- Blanks and control codes 09H and 0BH 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.
NOTE: 40ECH-40EDH holds EDIT line number.
- Note: 40F9H-40FAH holds the starting address of the simple variable storage area.
- Note: 40F9H-40FAH holds the starting address of the simple variable storage area.
Note: 40A7H-40A8H holds Input Buffer pointer.
In NEWDOS 2.1, this is the input scanner after updating the PST (Program Statement Table).
In NEWDOS 2.1, this is the input scanner after reinitializing BASIC
1AF8-1B0F – LINE POINTERS ROUTINE
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.
- Note: 40A4H-40A5H holds the starting address of BASIC program text also known as the PROGRAM STATEMENT TABLE (PST).
1B10-1B48 – EVALUATE LINE NUMBERS
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.
CEH
1B2C – 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.
- Note: 40A4H-40A5H holds the starting address of BASIC program text also known as the PROGRAM STATEMENT TABLE (PST).
- HL<DE: CARRY SET
- HL>DE: NO CARRY
- HL><DE: NZ
- HL=DE: Z
If we are here, then we have no match.
1B49-1B5C – LEVEL II BASIC NEW ROUTINE
- Note: 40A4H-40A5H holds the starting address of BASIC program text also known as the PROGRAM STATEMENT TABLE (PST).
- Note: 40F9H-40FAH holds the starting address of the simple variable storage area.
1B5D-1BB2 – LEVEL II BASIC RUN ROUTINE
Differences between M1 and M3 ROMs: The locations 1B5DH – 1B5FH are part of the RUN, NEW, EDIT, etc. commands; in the Model I these three bytes contain a LD HL,(40A4H) instruction (resets HL to point to the start of the BASIC program). In the Model III, this has been replaced by a CALL 046BH instruction, which unprotects the video display in addition to resetting HL to the start of the BASIC program.
- 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
The ability to RUN a BASIC program from an assembly language program is valuable for linking the two programs.
NOTE: 40DFH-40E0H is used by DOS.
NOTE: 4101H-411AH holds Variable Declaration Table.
NOTE: 40F2H holds the error flag.
NOTE: 40F0H-40F1H is used by ON ERROR.
NOTE: 40F7H-40F8H holds the last byte executed.
NOTE: 40B1H-40B2H holds MEMORY SIZE? pointer.
NOTE: 40D6H-40D7H holds Next available location in string space pointer.
- Note: 40F9H-40FAH holds the starting address of the simple variable storage area.
- Note: 40FBH-40FCH holds the starting address of the BASIC array variable storage area.
NOTE: 40FDH-40FEH holds the pointer to the starting address of free memory.
1B8C-1B8ECALL 41BBHGo call the DOS line at 41BBH.
In NEWDOS 2.1 this initializes BASIC for a new routine.1B8FH – Inside the RUN routine – Initialize the Level II BASIC variables and pointers
In NEWDOS 2.1 this initializes BASIC for a new routine.
- Note: 40A0H-40A1H holds the start of string space pointer.
Note: 40E8H-40E9H holds Stack pointer pointer.
NOTE: 40B5H-40D2H holds Temporary string work area.
NOTE: 40B3H-40B4H holds Next available location in the temporary string work area pointer.
NOTE: 40DCH holds FOR flag.
NOTE: 40DFH-40E0H holds Used by DOS.
1BB3-1BBF – KEYBOARD INPUT ROUTINE
This is the last of the general purpose input routines. This routine functions identically to the 361H routine with the exception that it prints a “?” on the screen (like INPUT does with BASIC) before allowing input from the keyboard.
To use a ROM call to display “?” on the video screen at the current cursor position (Non-DOS Systems Only), and then to input a string of up to 240 characters, execute CALL 1BB3H. The input string will be in consecutive memory locations starting at the address contained in 40A7H-40A8H, with a zero byte at the end. The HL register pair will contain an address one less than the starting address of the stored input.
“INPUT”
1BC0-1C8F – TOKENIZE INPUT ROUTINE
NOTE: 40B0H holds the temporary storage location.
NOTE: Bit 0 HIGH means inside a quote. Bit 1 HIGH means inside a DATA. Bit 2 HIGH means inside a REM.
NOTE: In the original Model III ROM, this byte was placed into 40B0H which was just a temporary storage location.
NOTE: 40A7H-40A8H holds Input Buffer pointer.
NOTE: 40B0H holds the temporary storage location.
NOTE: Bit 0 HIGH means inside a quote. Bit 1 HIGH means inside a DATA. Bit 2 HIGH means inside a REM.
NOTE: In the original Model III ROM, this byte was read from 40B0H which was just a temporary storage location.
NOTE: Results from a CP:
- Z: A and * are the same
- NZ: A and * are NOT the same
- C: A < *
- NC: A => *
NOTE: Results from a CP:
- Z: A and * are the same
- NZ: A and * are NOT the same
- C: A < *
- NC: A => *
NOTE: Results from a CP:
- Z: A and * are the same
- NZ: A and * are NOT the same
- C: A < *
- NC: A => *
NOTE:
- The RST 10H routine loads the next character from the string pointed to by the HL register into the A-register and clears the CARRY FLAG if it is alphabetic, or sets it if is alphanumeric.
- Blanks and control codes 09H and 0BH 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.
- If A=61H it sets the ZERO FLAG
- If A<61H then the CARRY FLAG will be set
- if A>=61H then the NO CARRY FLAG will be set.
NOTE: 40B0H holds the temporary storage location.
NOTE: Bit 0 HIGH means inside a quote. Bit 1 HIGH means inside a DATA. Bit 2 HIGH means inside a REM.
NOTE: In the original Model III ROM, this byte was placed into 40B0H which was just a temporary storage location.
Still Inside the TOKENIZE INPUT ROUTINE – This routine is called if the character in register A is an end of the input character.
NOTE: 40A7H-40A8H holds the pointer to the start of the Input Buffer.
1C90-1C95 – RST 0018H CODE
The RST 18H code is located here. (Unsigned compare (HL-DE)).
This is 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:
- HL<DE: CARRY SET
- HL>DE: NO CARRY
- HL><DE: NZ
- HL=DE: Z
“CHLDE”
1C96-1CA0 – RST 0008H CODE
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 the Aregister 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).
1CA1-1D1D – Level II BASIC FOR ROUTINE
NOTE: 40DCH holds FOR flag.
NOTE: 40E8H-40E9H holds Stack pointer pointer.
NOTE: 40A2H-40A3H holds the current BASIC line number.
BDH
NOTE: The RST 20H routine determines the type of the current value in REG 1 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
- Double Precision is NZ/NC/P/E and A is 5.
PUSH DE
NOTE: The RST 20H routine determines the type of the current value in REG 1 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
- Double Precision is NZ/NC/P/E and A is 5.
NOTE: 40DFH-40E0H holds Used by DOS.
1D1E-1D77 – LEVEL II BASIC INTERPRETER
NOTE: 40E6H-40E7H holds the temporary storage location.
NOTE: 40E8H-40E9H holds Stack pointer pointer.
1D41-1D43LD (40A2H),HLSave the value of the BASIC line number in register pair HL.
NOTE: 40A2H-40A3H holds the current BASIC line number.1D44 – Honor a TRON by showing the line number if it is in effect.
NOTE: 40A2H-40A3H holds the current BASIC line number.
NOTE: 411BH holds the TRON/TROFF flag.
1D58POP DEGet the value of the current BASIC program pointer from the stack and put it in register pair DE.1D59 – Done with the TRON, so let us continue.
NOTE:
- The RST 10H routine loads the next character from the string pointed to by the HL register into the A-register and clears the CARRY FLAG if it is alphabetic, or sets it if is alphanumeric.
- Blanks and control codes 09H and 0BH 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-1D90 – RST 0010H CODE
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).
“FETCH”
- If A=: it sets the ZERO FLAG
- If A<: then the CARRY FLAG will be set
- if A>=: then the NO CARRY FLAG will be set.
- If A=0BH it sets the ZERO FLAG
- If A<0BH then the CARRY FLAG will be set
- if A>=0BH then the NO CARRY FLAG will be set.
- If A=09H it sets the ZERO FLAG
- If A<09H then the CARRY FLAG will be set
- if A>=09H then the NO CARRY FLAG will be set.
- If A=0 it sets the ZERO FLAG
- If A<0 then the CARRY FLAG will be set
- if A>=0 then the NO CARRY FLAG will be set.
1D91-1D9A – LEVEL II BASIC RESTORE ROUTINE
- Note: 40A4H-40A5H holds the starting address of BASIC program text also known as the PROGRAM STATEMENT TABLE (PST).
NOTE: 40FFH-4100H holds READ pointer.
1D9B-1DAD – SCAN KEYBOARD ROUTINE
1D9FRET ZReturn if a key wasn’t pressed.1DA0H – Inside the SCAN KEYBOARD ROUTINE – This will process a SHIFT + @ (Pause) Keypress
NOTE: 4099H holds the Last key pressed.
1DA8DEC ACheck to see if the BREAK key was pressed.1DA9H-1DADH – Inside the SCAN KEYBOARD ROUTINE – This will process a STOP.
This is the STOP entry point.
1DAE-1DE3 – LEVEL II BASIC END ROUTINE
NOTE: 40E6H-40E7H holds the temporary storage location.
NOTE: 40B5H-40D2H holds Temporary string work area.
NOTE: 40B3H-40B4H holds Next available location in the temporary string work area pointer.
NOTE: 40A2H-40A3H holds the current BASIC line number.
NOTE: 40F5H-40F6H holds the last line number executed.
NOTE: 40E6H-40E7H holds the temporary storage location.
NOTE: 40F7H-40F8H holds the last byte executed.
1DE4-1DF6 – LEVEL II BASIC CONT ROUTINE.
NOTE: 40F7H-40F8H holds the last byte executed.
OR L
NOTE: 40F5H-40F6H holds the last line number executed.
NOTE: 40A2H-40A3H holds the current BASIC line number.
1DF7H-1DFCH – TRON and TROFF Routine
1DF7H – TRON Entry Point (Set A with AFH)
1DF8H – TROFF Entry Point (Set A with 00H)
1DF9-1DFC – COMMON CODE SHARED BY TRON AND TROFF – Put A into (411BH)
NOTE: 411BH holds the TRON/TROFF flag. 0=off (TROFF), 175=on (TRON)
1DFD-1DFF – DISK ROUTINE NOT USED BY LEVEL II BASIC.
1E00H-1E3CH – DEFxxx Routine
1E00-1E02 – INSIDE THE DEFxxx ROUTINE – DEFSTR Entry Point
1E03H-1E05H – INSIDE THE DEFxxx ROUTINE – DEFINT Entry Point
1E06H-1E08H – INSIDE THE DEFxxx ROUTINE – DEFSNG Entry Point
1E09-1E0AH – INSIDE THE DEFxxx ROUTINE – DEFDBL Entry Point
1E0BH-1E3CH – INSIDE THE DEFxxx ROUTINE – Common code shared by all the above – 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.
NOTE:
- The RST 10H routine loads the next character from the string pointed to by the HL register into the A-register and clears the CARRY FLAG if it is alphabetic, or sets it if is alphanumeric.
- Blanks and control codes 09H and 0BH 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.
NOTE:
- The RST 10H routine loads the next character from the string pointed to by the HL register into the A-register and clears the CARRY FLAG if it is alphabetic, or sets it if is alphanumeric.
- Blanks and control codes 09H and 0BH 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.
NOTE:
- The RST 10H routine loads the next character from the string pointed to by the HL register into the A-register and clears the CARRY FLAG if it is alphabetic, or sets it if is alphanumeric.
- Blanks and control codes 09H and 0BH 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.
NOTE: 4101H-411AH holds Variable Declaration Table.
NOTE:
- The RST 10H routine loads the next character from the string pointed to by the HL register into the A-register and clears the CARRY FLAG if it is alphabetic, or sets it if is alphanumeric.
- Blanks and control codes 09H and 0BH 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.
1E3D-1E44 – EXAMINE VARIABLE – See if the value pointed to at the memory location (HL) is an ASCII letter. C Flag is set for yes, NC Flag for no.
- If A=A it sets the ZERO FLAG
- If A<A then the CARRY FLAG will be set
- If A>=A then the NO CARRY FLAG will be set
- If A=Z it sets the ZERO FLAG
- If A<Z then the CARRY FLAG will be set
- If A>=Z then the NO CARRY FLAG will be set
1E45-1E4E – EXAMINE VARIABLE
This is called when evaluating a subscript for a variable reference. It will evaluate if the value is positive or negative.
NOTE:
- The RST 10H routine loads the next character from the string pointed to by the HL register into the A-register and clears the CARRY FLAG if it is alphabetic, or sets it if is alphanumeric.
- Blanks and control codes 09H and 0BH 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.
1E4A – FC ERROR entry point.
1E4F-1E79 – ASCII TO BINARY
- If A=. it sets the ZERO FLAG
- If A<. then the CARRY FLAG will be set
- If A>=. then the NO CARRY FLAG will be set
NOTE: 40ECH-40EDH holds EDIT line number.
1E5A – “DECBIN” – 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.
NOTE:
- The RST 10H routine loads the next character from the string pointed to by the HL register into the A-register and clears the CARRY FLAG if it is alphabetic, or sets it if is alphanumeric.
- Blanks and control codes 09H and 0BH 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.
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.
- HL<DE: CARRY SET
- HL>DE: NO CARRY
- HL><DE: NZ
- HL=DE: Z
This is so we can multiply HL (which should hold the number 6552) by 10.
This is so we can multiply HL (which should hold the number 6552) by 10.
As noted above, adding in any digit can only result in HL going to 65529.
1E7A-1EA0 – LEVEL II BASIC CLEAR ROUTINE. If Z FLAG is set, no number of bytes was provided (i.e., CLEAR instead of CLEAR 20).
NOTE:
- The RST 10H routine loads the next character from the string pointed to by the HL register into the A-register and clears the CARRY FLAG if it is alphabetic, or sets it if is alphanumeric.
- Blanks and control codes 09H and 0BH 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.
NOTE: 40B1H-40B2H holds MEMORY SIZE? pointer.
- Note: 40F9H-40FAH holds the starting address of the simple variable storage area.
- HL<DE: CARRY SET
- HL>DE: NO CARRY
- HL><DE: NZ
- HL=DE: Z
- Note: 40A0H-40A1H holds the start of string space pointer.
1EA3-1EB0 – LEVEL II BASIC RUN ROUTINE. If Z FLAG is set, no line number was provided (i.e., RUN instead of RUN nnnn).
If we are here, then the command was RUN nnnn and we are in Cassette BASIC.
1EB1-1EC1 – LEVEL II BASIC GOSUB ROUTINE
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.
NOTE: 40A2H-40A3H holds the current BASIC line number.
1EC2-1EDD – LEVEL II BASIC GOTO ROUTINE. Register pair DE should hold the nnnn for the GOTO nnnn command.
NOTE:
- The routine at 1E5A converts the ASCII string pointed to by HL to an integer deposited into DE. If the routine finds a non-numerica character, the conversion is stopped
NOTE: 40A2H-40A3H holds the current BASIC line number.
- HL<DE: CARRY SET
- HL>DE: NO CARRY
- HL><DE: NZ
- HL=DE: Z
Inside the GOTO ROUTINE – If we are here, the line number nnnn was not found, so error out.
1EDE-1E04 – LEVEL II BASIC RETURN ROUTINE
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.
NOTE: 40E8H-40E9H holds Stack pointer pointer.
1EEC – ?RG ERROR entry point.
NOTE: 40A2H-40A3H holds the current BASIC line number.
OR L
NOTE: 40DDH holds INPUT flag.
1F05-1F20 – SCAN ROUTINE
This is also the DATA entry point.
1F21-1F6B – LEVEL II BASIC LET ROUTINE
D5H
NOTE: 40DFH-40E0H holds Used by DOS.
NOTE: The RST 20H routine determines the type of the current value in REG 1 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
- Double Precision is NZ/NC/P/E and A is 5.
- Note: 40A4H-40A5H holds the starting address of BASIC program text also known as the PROGRAM STATEMENT TABLE (PST).
- HL<DE: CARRY SET
- HL>DE: NO CARRY
- HL><DE: NZ
- HL=DE: Z
- Note: 40A0H-40A1H holds the start of string space pointer.
- HL<DE: CARRY SET
- HL>DE: NO CARRY
- HL><DE: NZ
- HL=DE: Z
- Note: 40F9H-40FAH holds the starting address of the simple variable storage area.
- HL<DE: CARRY SET
- HL>DE: NO CARRY
- HL><DE: NZ
- HL=DE: Z
LD A,D1H
1F6C-1FAE – LEVEL II BASIC ERROR ON ROUTINE
NOTE:
- The RST 10H routine loads the next character from the string pointed to by the HL register into the A-register and clears the CARRY FLAG if it is alphabetic, or sets it if is alphanumeric.
- Blanks and control codes 09H and 0BH 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.
8DH
NOTE:
- The routine at 1E5A converts the ASCII string pointed to by HL to an integer deposited into DE. If the routine finds a non-numerica character, the conversion is stopped
OR E
LD E,C
NOTE: 40F0H-40F1H is used by ON ERROR.
NOTE: 40F2H holds the error flag.
NOTE: 409AH holds the RESUME flag.
1F95 – Still in the ON routine, but 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.
8DH
1FAF-1FF3 – LEVEL II BASIC RESUME ROUTINE
NOTE: 40F2H holds the error flag.
NOTE: 409AH holds the RESUME flag.
NOTE:
- The routine at 1E5A converts the ASCII string pointed to by HL to an integer deposited into DE. If the routine finds a non-numerica character, the conversion is stopped
OR E
NOTE:
- The RST 10H routine loads the next character from the string pointed to by the HL register into the A-register and clears the CARRY FLAG if it is alphabetic, or sets it if is alphanumeric.
- Blanks and control codes 09H and 0BH 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.
1FCF – This is the RESUME 0 routine
NOTE: 40EEH-40EFH is used by RESUME.
NOTE: 40EAH-40EBH holds the line number with error.
NOTE: 40A2H-40A3H holds the current BASIC line number.
NOTE: 40DDH holds INPUT flag.
1FF4H-2007 – LEVEL II BASIC ERROR ROUTINE – Evaluates n for ERROR n
- If A=2DH it sets the ZERO FLAG
- If A<2DH then the CARRY FLAG will be set
- if A>=2DH then the NO CARRY FLAG will be set.