Routines 
Prev: 30C0  Up: Map 
The address of this routine is found in the table of addresses. It is called via the calculator literal +04 by the routines at BEEP, CIRCLE, DRAW, CD_PRMS1, S_RND, DEC_TO_FP, INT_TO_FP, e_to_fp, LOG_2_A, series, n_mod_m, exp, ln, get_argt, sin, atn, asn and to_power. It is also called indirectly via fp_calc_2.
This subroutine first tests whether the two numbers to be multiplied are 'small integers'. If they are, it uses INT_FETCH to get them from the stack, HL_HLxDE to multiply them and INT_STORE to return the result to the stack. Any overflow of this 'short multiplication' (i.e. if the result is not itself a 'small integer') causes a jump to multiplication in full five byte floatingpoint form (see below).


multiply  30CA  LD A,(DE)  Test whether the first bytes of both numbers are zero.  
30CB  OR (HL)  
30CC  JR NZ,MULT_LONG  If not, jump for 'long' multiplication.  
30CE  PUSH DE  Save the pointers to the second number.  
30CF  PUSH HL  And to the first number.  
30D0  PUSH DE  And to the second number yet again.  
30D1  CALL INT_FETCH  Fetch sign in C, number in DE.  
30D4  EX DE,HL  Number to HL now.  
30D5  EX (SP),HL  Number to stack, second pointer to HL.  
30D6  LD B,C  Save first sign in B.  
30D7  CALL INT_FETCH  Fetch second sign in C, number in DE.  
30DA  LD A,B  Form sign of result in A: like signs give plus (+00), unlike give minus (+FF).  
30DB  XOR C  
30DC  LD C,A  Store sign of result in C.  
30DD  POP HL  Restore the first number to HL.  
30DE  CALL HL_HLxDE  Perform the actual multiplication.  
30E1  EX DE,HL  Store the result in DE.  
30E2  POP HL  Restore the pointer to the first number.  
30E3  JR C,MULT_OFLW  Jump on overflow to 'full' multiplication.  
30E5  LD A,D  These 5 bytes ensure that 00 FF 00 00 00 is replaced by zero; that they should not be needed if this number were excluded from the system is noted at ADDN_OFLW.  
30E6  OR E  
30E7  JR NZ,MULT_RSLT  
30E9  LD C,A  
MULT_RSLT  30EA  CALL INT_STORE  Now store the result on the stack.  
30ED  POP DE  Restore STKEND to DE.  
30EE  RET  Finished.  
MULT_OFLW  30EF  POP DE  Restore the pointer to the second number.  
MULT_LONG  30F0  CALL RE_ST_TWO  Restack both numbers in full five byte floatingpoint form.  
The full multiplication subroutine prepares the first number for multiplication by calling PREP_M_D, returning if it is zero; otherwise the second number is prepared by again calling PREP_M_D, and if it is zero the subroutine goes to set the result to zero. Next it fetches the two numbers from the calculator stack and multiplies their mantissas in the usual way, rotating the first number (treated as the multiplier) right and adding in the second number (the multiplicand) to the result whenever the multiplier bit is set. The exponents are then added together and checks are made for overflow and for underflow (giving the result zero). Finally, the result is normalised and returned to the calculator stack with the correct sign bit in the second byte.


30F3  XOR A  A is set to zero so that the sign of the first number will go into A.  
30F4  CALL PREP_M_D  Prepare the first number, and return if zero. (Result already zero.)  
30F7  RET C  
30F8  EXX  Exchange the registers.  
30F9  PUSH HL  Save the next literal address.  
30FA  EXX  Exchange the registers.  
30FB  PUSH DE  Save the pointer to the multiplicand.  
30FC  EX DE,HL  Exchange the pointers.  
30FD  CALL PREP_M_D  Prepare the 2nd number.  
3100  EX DE,HL  Exchange the pointers again.  
3101  JR C,ZERO_RSLT  Jump forward if 2nd number is zero.  
3103  PUSH HL  Save the pointer to the result.  
3104  CALL FETCH_TWO  Get the two numbers from the stack.  
3107  LD A,B  M5 to A (see FETCH_TWO).  
3108  AND A  Prepare for a subtraction.  
3109  SBC HL,HL  Initialise HL to zero for the result.  
310B  EXX  Exchange the registers.  
310C  PUSH HL  Save M1 and N1 (see FETCH_TWO).  
310D  SBC HL,HL  Also initialise HL' for the result.  
310F  EXX  Exchange the registers.  
3110  LD B,$21  B counts thirty three shifts.  
3112  JR STRT_MLT  Jump forward into the loop.  
Now enter the multiplier loop.


MLT_LOOP  3114  JR NC,NO_ADD  Jump forward to NO_ADD if no carry, i.e. the multiplier bit was reset.  
3116  ADD HL,DE  Else, add the multiplicand in D'E'DE (see FETCH_TWO) into the result being built up in H'L'HL.  
3117  EXX  
3118  ADC HL,DE  
311A  EXX  
NO_ADD  311B  EXX  Whether multiplicand was added or not, shift result right in H'L'HL; the shift is done by rotating each byte with carry, so that any bit that drops into the carry is picked up by the next byte, and the shift continued into B'C'CA.  
311C  RR H  
311E  RR L  
3120  EXX  
3121  RR H  
3123  RR L  
STRT_MLT  3125  EXX  Shift right the multiplier in B'C'CA (see FETCH_TWO and above). A final bit dropping into the carry will trigger another add of the multiplicand to the result.  
3126  RR B  
3128  RR C  
312A  EXX  
312B  RR C  
312D  RRA  
312E  DJNZ MLT_LOOP  Loop 33 times to get all the bits.  
3130  EX DE,HL  Move the result from H'L'HL to D'E'DE.  
3131  EXX  
3132  EX DE,HL  
3133  EXX  
Now add the exponents together.


3134  POP BC  Restore the exponents  M1 and N1.  
3135  POP HL  Restore the pointer to the exponent byte.  
3136  LD A,B  Get the sum of the two exponent bytes in A, and the correct carry.  
3137  ADD A,C  
3138  JR NZ,MAKE_EXPT  If the sum equals zero then clear the carry; else leave it unchanged.  
313A  AND A  
MAKE_EXPT  313B  DEC A  Prepare to increase the exponent by +80.  
313C  CCF  
This entry point is used by the routine at division.


DIVN_EXPT  313D  RLA  These few bytes very cleverly make the correct exponent byte. Rotating left then right gets the exponent byte (true exponent plus +80) into A.  
313E  CCF  
313F  RRA  
3140  JP P,OFLW1_CLR  If the sign flag is reset, no report of arithmetic overflow needed.  
3143  JR NC,REPORT_6  Report the overflow if carry reset.  
3145  AND A  Clear the carry now.  
OFLW1_CLR  3146  INC A  The exponent byte is now complete; but if A is zero a further check for overflow is needed.  
3147  JR NZ,OFLW2_CLR  
3149  JR C,OFLW2_CLR  
314B  EXX  If there is no carry set and the result is already in normal form (bit 7 of D' set) then there is overflow to report; but if bit 7 of D' is reset, the result in just in range, i.e. just under 2**127.  
314C  BIT 7,D  
314E  EXX  
314F  JR NZ,REPORT_6  
OFLW2_CLR  3151  LD (HL),A  Store the exponent byte, at last.  
3152  EXX  Pass the fifth result byte to A for the normalisation sequence, i.e. the overflow from L into B'.  
3153  LD A,B  
3154  EXX  
This entry point is used by the routine at addition.
The remainder of the subroutine deals with normalisation and is common to all the arithmetic routines.


TEST_NORM  3155  JR NC,NORMALISE  If no carry then normalise now.  
3157  LD A,(HL)  Else, deal with underflow (zero result) or near underflow (result 2**128): return exponent to A, test if A is zero (case 2**128) and if so produce 2**128 if number is normal; otherwise produce zero. The exponent must then be set to zero (for zero) or 1 (for 2**128).  
3158  AND A  
NEAR_ZERO  3159  LD A,$80  
315B  JR Z,SKIP_ZERO  
ZERO_RSLT  315D  XOR A  
SKIP_ZERO  315E  EXX  
315F  AND D  
3160  CALL ZEROS_4_5  
3163  RLCA  
3164  LD (HL),A  Restore the exponent byte.  
3165  JR C,OFLOW_CLR  Jump if case 2**128.  
3167  INC HL  Otherwise, put zero into second byte of result on the calculator stack.  
3168  LD (HL),A  
3169  DEC HL  
316A  JR OFLOW_CLR  Jump forward to transfer the result.  
The actual normalisation operation.


NORMALISE  316C  LD B,$20  Normalise the result by up to 32 shifts left of D'E'DE (with A adjoined) until bit 7 of D' is set. A holds zero after addition so no precision is gained or lost; A holds the fifth byte from B' after multiplication or division; but as only about 32 bits can be correct, no precision is lost. Note that A is rotated circularly, with branch at carry...eventually a random process.  
SHIFT_ONE  316E  EXX  
316F  BIT 7,D  
3171  EXX  
3172  JR NZ,NORML_NOW  
3174  RLCA  
3175  RL E  
3177  RL D  
3179  EXX  
317A  RL E  
317C  RL D  
317E  EXX  
317F  DEC (HL)  The exponent is decremented on each shift.  
3180  JR Z,NEAR_ZERO  If the exponent becomes zero, then numbers from 2**129 are rounded up to 2**128.  
3182  DJNZ SHIFT_ONE  Loop back, up to 32 times.  
3184  JR ZERO_RSLT  If bit 7 never became 1 then the whole result is to be zero.  
Finish the normalisation by considering the 'carry'.


NORML_NOW  3186  RLA  After normalisation add back any final carry that went into A. Jump forward if the carry does not ripple right back.  
3187  JR NC,OFLOW_CLR  
3189  CALL ADD_BACK  
318C  JR NZ,OFLOW_CLR  
318E  EXX  If it should ripple right back then set mantissa to 0.5 and increment the exponent. This action may lead to arithmetic overflow (final case).  
318F  LD D,$80  
3191  EXX  
3192  INC (HL)  
3193  JR Z,REPORT_6  
The final part of the subroutine involves passing the result to the bytes reserved for it on the calculator stack and resetting the pointers.


OFLOW_CLR  3195  PUSH HL  Save the result pointer.  
3196  INC HL  Point to the sign byte in the result.  
3197  EXX  The result is moved from D'E'DE to BCDE, and then to ACDE.  
3198  PUSH DE  
3199  EXX  
319A  POP BC  
319B  LD A,B  
319C  RLA  The sign bit is retrieved from its temporary store and transferred to its correct position of bit 7 of the first byte of the mantissa.  
319D  RL (HL)  
319F  RRA  
31A0  LD (HL),A  The first byte is stored.  
31A1  INC HL  Next.  
31A2  LD (HL),C  The second byte is stored.  
31A3  INC HL  Next.  
31A4  LD (HL),D  The third byte is stored.  
31A5  INC HL  Next.  
31A6  LD (HL),E  The fourth byte is stored.  
31A7  POP HL  Restore the pointer to the result.  
31A8  POP DE  Restore the pointer to second number.  
31A9  EXX  Exchange the register.  
31AA  POP HL  Restore the next literal address.  
31AB  EXX  Exchange the registers.  
31AC  RET  Finished.  
REPORT_6  31AD  RST $08  Call the error handling routine.  
31AE  DEFB $05 
Prev: 30C0  Up: Map 