10FA KEY CONTR not handled by 1894 OUT LINE4 error marker is "?" with FLASH 18C1 OUT FLASH sets ATTR T direct for error marker 1909 OUT C 2 prints flashing CEGKL cursor 2211 CO TEMP 5 sorted out from other control characters 2273 CO TEMP C mask prepared for ATTR T 2287 CO TEMP E bit 7/6 of mask set buffer see printer buffer, 2DE3 PRINT FP BYTE COMP 3564 (353B no-l-eql) Jumps from: 3575 SEC PLUS "Bytes: " message 09EC see cassette messages BYTE ZERO 327E (3214 truncate) Jumps from: auto ----- CALCULATE subroutine 335B see also 0028 FP CALC For the way the subroutine operates, see 0028 FP CALC; here I shall confine myself to describing how the calculator is used. This is explained in "ROM Disassembled", at 335B CALCULATE, but the explanation a) assumes that you remember how floating-point numbers are formatted in the Spectrum, and b) makes some vital omissions. 1. FP numbers always consist of five bytes. 1.1 Full form. The algorithm is as follows: Divide any number by two repeatedly till the result is less than one but more than or equal to a half. The result m is the_true_mantissa; the number of divisions is e, the_true _exponent. If the number is less than a half to start with, multiply instead of dividing, and count e as negative. m can have a maximum of 8 hex digits. Now the five bytes of the FP number in the Spectrum system are: Byte 1: the true exponent + 80h; the_exponent_byte Byte 2: the first byte of the true mantissa; as it standsfor negative numbers, less 80h for positive numbers; the_sign _byte Bytes 3-5: the remaining bytes of the mantissa. Positive powers of 2 (including 1 = 2**0) have zero in the mantissa bytes: 2**X = 2**(X + 1) * 0.8h = FP 8(X+1) 00 00 00 00 See the Appendix to this index for BASIC programs to calculate FP number forms. The FP number may be doubled or halved simply by incrementing or decrementing the exponent byte; this trick is used several times in the ROM. Reference is occasionally made in the notes to the _true_exponent and_true_mantissa: the true exponent means the exponent without the deduction of 80h, and the true mantissa themantissa without the zeroing of the sign bit for positive numbers. These forms are never stored, only created for use in particular calculations. Forms are similarly sometimes prepared in which the mantissa isn't within the range half -> one; shifting the mantissa bits to the right and incrementing the exponent, or to the left and decrementing the exponent, providing there are leading zeroes, doesn't change the number. See the examples below; 73d = 2**8 times 0.49h or 2**7 times 0.92h. The binary expression of these two mantissas is 49h = 01001001b 92h = 10010010b Correction of such shifted forms, ie shifting them back so that the mantissa comes within the normal range, is referred to as_normalization: this term usually includes the addition of 80h to the true exponent and marking the hi bit of the mantissa as a sign bit. Apart from their use in the calculator, remember that every number in a BASIC program is followed by 0E and then the five-byte FP form of the number in the representation of the line in the program area; see under number marker. 1.2 Small integer FP format. There is an alternative form for whole numbers less than 10000h/65536d: byte 1: 00 byte 2: 00 for positive, FFh for negative byte 3: low byte byte 4: high byte byte 5: immaterial, usually zero Negative numbers must be subtracted from 10000h before bytes 3 and 4 are calculated in this format. NB 1.2.1. If the first byte is zero, the number must be in small integer format - in_full_FP_format this would be a number less than 2 to the power -80h/128d, which isn't allowed. NB 1.2.2. The second byte is the_sign_byte - its bit 7, the_sign_bit, is 1 for negative numbers, 0 for positive, in either format. NB 1.2.3. Some 5-byte numbers aren't in FP format - the _string_parameters of a variable or print string - although theyare handled in many similar ways. They too may have 00 in the first byte. See under strings for a further discussion of these. NB 1.2.4. There is a third format, a_compressed form, whichis used in the stk-data and stk-zero routines, and is usually called the_stk-data_form in this index; it is derived from the expanded format, but takes up less room in the ROM, from 2 to maximum 5 bytes. See under stk-data. _Examples: 73d = 49h = 2**8 * 0.49h = 2**7 * 0.92h full FP format: 87 12 00 00 00 small integer format: 00 00 49 00 00 500d = 1F4h = 2**8 * 1.F4 = 2**9 * 0.FA full FP format: 89 7A 00 00 00 small integer format: 00 00 F4 01 00 pi = 3.1415927d = 2**2 * 0.C90FDAA2h full FP format: 82 49 0F DA A2 e**pi = 23.140693d = 2**5 * 0.B92023A8h full FP format: 85 39 20 23 A8 -41764d = -A324h = 10000h - 5CDCh = -2**10h * 0.A324h full FP format: 90 A3 24 00 00 small integer format: 00 FF DC 5C 00 2. The calculator is used by calling restart 0028 FP CALC, following the RST 28h command with at least one_literal, single bytes from the list at 32D7 which signal the calculations to be performed. The last literal must be 38h end-calc. The literals are sometimes called_calculator_offsets in the notes. Subroutines which can be called by literals following FPCALC are shown in this index with their names in lower case. Most of them can also be called direct from m/c, and some are socalled by the ROM. Any operands for the calculations must first be placed on the_calculator_stack, see below, and the result of the calculator operations is left as the_last_value on the stack. There is also a special_memory for the calculator, see below. The calculator stack and memory are in general undisturbed by the other operations of the ROM, and RST 28h can be used repeatedly, perhaps with manipulations of the stack or memory values by other m/c routines, without breaks in the continuity of the calculation. There are literals for unconditional and conditional jumps over the literal string, and a looping literal 35 dec-jr- nz which works much like DJNZ, using the system variable 5C67 BREG as DJNZ uses the B register. An alternative way of using the calculator is by literal3B fp-calc-2; see the index entry for it, and 274C S STK LIST under 24FB SCANNING for the only ROM example. This performs the calculation signalled by whatever literal it finds in the B register on entry to the restart 28h. The advantage is that a sequence of calculations can be built up by the m/c program itself on the machine stack, rather than being preset by the programmer. NB 2.1. Division by zero will produce an error report. Division by zero can be avoided by use of literal 30_not: for examples, see 238D DR 3 PRMS under 2382 DRAW and 384A sqr. NB 2.2. One of the fanciest examples of calculation in the ROM is the sequence from 2382 DRAW to 2477 LINE DRAW. If you canfigure this out you will have mastered the FP calculator! The use of the series generator to calculate Chebyshev polynomials is perhaps even fancier, see the index entry, but isn't likely to be imitated by most m/c programmers. 3. The calculator stack. All the calculations of the FP calculator operate on the top one or two numbers on the calculator stack, which extends upwards from the address in 5C63STKBOT to the address in 5C65 STKEND. Unlike the machine stack, the calculator stack is "the right way up": the number on the top of the stack is actually higher in memory than the number below it. Each number takes up 5 bytes, and the size of the stack is limited by the overall memory; if a calculation loop leaves numbers on the stack, it should be cleared either by the literal02 delete, or by calling 16C5 SET STK, to avoid piling up the stack, which can lead to memory overflow. Otherwise the stack isgenerally undisturbed, and you can make repeated use of RST 28h in the confidence that the numbers you need will still be on thestack. Reference is often made in the notes to the_last_value on the calculator stack, ie the last value to be placed there; it is the first to come off. It is also sometimes called the_topor_topmost_number, or the_first_number. As a rule, calculator operations involving two operands operate_with the last value_on the second last; thus in subtraction X - Y or division X/Y, Y is the last value. The notes often introduce hideous confusion by calling Y in such operations the_second_operand, so that the second operand is thelast value and the first operand is the second value on the stack. In the case of addition and multiplication X and Y are interchangeable, but even here, inexcusably, the notes persist in using these baffling expressions. The last value is a 5-byte number, usually in full FP format; on exit from the calculator routines its first byte address is held in HL, and the address following its fifth byte in DE. It may represent the parameters of a string; if so, bit 6of FLAGS is set. If this flag is zero, the last value is read asrepresenting a number. Numbers can be put on the stack in FP form by: 3.1. calling 2D28 STACK A, which puts the byte in A on the topof the stack as a positive integer; 3.2. calling 2D2B STACK BC, which puts the two-byte positive integer in BC on top of the stack; 3.3. calling 33B4 STACK NUM, which copies a FP number constructed elsewhere in RAM to the last value position on the stack; 3.4. calling 2AB6 STK STORE, which puts on the stack a number whose bytes are held byte 1 in A byte 2 in E byte 3 in D byte 4 in C byte 5 in B If byte 1 is to be zero, you can call 2AB1 STK ST 0 instead. 3.5. using literal 34 stk-data; it requires reformatting of the FP number; see 33C6 stk-data 3.6. using literals A0 to A4, stk-zero, stk-one, stk- half, stk-pi/2, stk-ten, which each put one of the five standard constants on the stack; you can also make your own list of standard constants and use the ROM routines to index into your list and put any of them on the stack, see 341B stk-zero. Numbers may be got from the stack after the CALCULATE routine has terminated by: 3.7. reading the 5 bytes of the FP number from the stack: after literal 38h end, the HL register holds the address of the first byte of the last value 3.8. calling 2DD5 FP TO A or 2DA2 FP TO BC: the integer value of the last FP number on the stack will be returned in the A register, for single-byte integers, or BC register respectively.These routines don't produce error reports, so they won't crash your system, but both return with C if the number is too big andwith NZ if it is negative, so you can trap errors for yourself 3.8.1 calling 1E94 FIND INT1 and 1E99 FIND INT2 instead; but if the value isn't a positive number within the capacity of the register, these subroutines will crash your system and print"Integer out of range" 3.9. calling 2307 STK TO BC, which puts the top_two values on the stack in the BC register, top number to B. They must be positive integers less than 256d. This is useful for drawing on the screen; eg it can be followed directly by 22DC PLOT, which plots a point at y=B, x=C 3.10. calling 2BF1 STK FETCH, which takes the last value from the stack and puts it in the AEDCB registers, cf 3.4 above 3.11. calling 2DE3 PRINT FP, which prints the top number of thestack on the screen; you can print any integer by PUSH BC/CALL STK BC/CALL PRINT FP, or the result of using CALCULATE by CALL PRINT FP immediately. 3.12. You can also print an integer directly from BC by calling 1A1B OUT NUM 1; or an integer at the address held in HL_in_reversed_form by calling 1A28 OUT NUM 2. OUT NUM 1 prints the number without leading spaces, OUT NUM 2 with them - ie the integer always fills four spaces. These routines are designed tobe used for line numbers, and don't work if the integer is bigger than 270Fh/9999d, but it isn't too hard to write your own"Chinese copy" of them with an extra couple of lines in 1A30 OUTNUM 3 to take care of one more digit. Other routines are used by the ROM, but these are the most useful for machine code programming. Most of the calculations delete the numbers that they use, or replace them with others; you can save the number at thetop of the stack by duplicating it with literal 31 duplicate, orby putting it in the calculator memory. For a simple example of the use of the stack, see 34AC peek. 4. The calculator memory consists of thirty bytes starting at the address in 5C68 MEM; this is usually 5C92 MEMBOT, though occasionally it is relocated to an ad hoc position to avoid disturbing the MEMBOT values. The thirty bytes can hold six FP numbers in locations referred to as_mem-0,_mem-_1,_..._mem-5; the literals C0 to C5 st-mem-0/5 copy a number from the top of the stack to the corresponding memory location, without deleting it from the stack, literals E0 to E5 get-mem-0/5 copy a number from the memory location to the top of the stack, without deleting it from the memory, or deleting the number which was on top before,and which goes to second place. If the memory is relocated, morethan six numbers can be held, see under 342D st-mem. The location of any number in the memory can be found bya call to 3406 LOC MEM. "ROM Disassembled" fails to warn you that several of thecalculation routines use the memory, and therefore will corrupt anything you have put in the locations used: - all memory locations are corrupted by the BASIC CIRCLE and DRAW routines, and all except mem-0 by 2DE3 PRINT FP; but otherwise mem-4 and mem-5 are safe - mem-0 to 3 are all corrupted by 06 to-power, 26 exp, 28sqr - mem-0 to 2 are all corrupted by 1F sin, 20 cos, 21 tan,22 asn, 23 acs, 24 atn, 25 ln, 86/88/8C series-06/08/0C - mem-0 and mem-1 are both corrupted by 3C e-to-fp - mem-0 alone is corrupted by 27 int or 39 get-argt, and also by syntax checking of numbers in BASIC - mem-0, mem-1 and mem-2 literals are also used by FOR...NEXT loops. In this case mem-0 is corrupted, but the othertwo are used only after the memory has been relocated, so the normal locations are undisturbed. Introduction routines for all functions 0028 FP CALC entry to calculator 0053 ERROR 2 clears calculator stack 03F8 BEEP converts duration/pitch to timer/cycles 0427 BE OCTAVE converts last value to frequency 06C3 SA CODE zero start placed on stack 06F0 SA CODE 2 zero length placed on stack 0723 SA LINE 1 line number passed to stack 11A7 REMOVE FP removes FP numbers from BASIC line 1313 MAIN G calculator stack cleared 169E RESERVE makes room below calculator stack 16BF SET WORK work space and calculator stack cleared 16C5 SET STK only stack cleared, MEM set to MEMBOT