Prev: 12480 Up: Map Next: 12719
12490: THE 'MULTIPLICATION' OPERATION (offset 4)
The address of this routine is found in the table of addresses. It is called via the calculator literal 4 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 floating-point form (see below).
Input
DE Address of the first byte of the second number
HL Address of the first byte of the first number
multiply 12490 LD A,(DE) Test whether the first bytes of both numbers are zero.
12491 OR (HL)
12492 JR NZ,MULT_LONG If not, jump for 'long' multiplication.
12494 PUSH DE Save the pointers to the second number.
12495 PUSH HL And to the first number.
12496 PUSH DE And to the second number yet again.
12497 CALL INT_FETCH Fetch sign in C, number in DE.
12500 EX DE,HL Number to HL now.
12501 EX (SP),HL Number to stack, second pointer to HL.
12502 LD B,C Save first sign in B.
12503 CALL INT_FETCH Fetch second sign in C, number in DE.
12506 LD A,B Form sign of result in A: like signs give plus (0), unlike give minus (255).
12507 XOR C
12508 LD C,A Store sign of result in C.
12509 POP HL Restore the first number to HL.
12510 CALL HL_HLxDE Perform the actual multiplication.
12513 EX DE,HL Store the result in DE.
12514 POP HL Restore the pointer to the first number.
12515 JR C,MULT_OFLW Jump on overflow to 'full' multiplication.
12517 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.
12518 OR E
12519 JR NZ,MULT_RSLT
12521 LD C,A
MULT_RSLT 12522 CALL INT_STORE Now store the result on the stack.
12525 POP DE Restore STKEND to DE.
12526 RET Finished.
MULT_OFLW 12527 POP DE Restore the pointer to the second number.
MULT_LONG 12528 CALL RE_ST_TWO Re-stack both numbers in full five byte floating-point 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.
12531 XOR A A is set to zero so that the sign of the first number will go into A.
12532 CALL PREP_M_D Prepare the first number, and return if zero. (Result already zero.)
12535 RET C
12536 EXX Exchange the registers.
12537 PUSH HL Save the next literal address.
12538 EXX Exchange the registers.
12539 PUSH DE Save the pointer to the multiplicand.
12540 EX DE,HL Exchange the pointers.
12541 CALL PREP_M_D Prepare the 2nd number.
12544 EX DE,HL Exchange the pointers again.
12545 JR C,ZERO_RSLT Jump forward if 2nd number is zero.
12547 PUSH HL Save the pointer to the result.
12548 CALL FETCH_TWO Get the two numbers from the stack.
12551 LD A,B M5 to A (see FETCH_TWO).
12552 AND A Prepare for a subtraction.
12553 SBC HL,HL Initialise HL to zero for the result.
12555 EXX Exchange the registers.
12556 PUSH HL Save M1 and N1 (see FETCH_TWO).
12557 SBC HL,HL Also initialise HL' for the result.
12559 EXX Exchange the registers.
12560 LD B,33 B counts thirty three shifts.
12562 JR STRT_MLT Jump forward into the loop.
Now enter the multiplier loop.
MLT_LOOP 12564 JR NC,NO_ADD Jump forward to NO_ADD if no carry, i.e. the multiplier bit was reset.
12566 ADD HL,DE Else, add the multiplicand in D'E'DE (see FETCH_TWO) into the result being built up in H'L'HL.
12567 EXX
12568 ADC HL,DE
12570 EXX
NO_ADD 12571 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.
12572 RR H
12574 RR L
12576 EXX
12577 RR H
12579 RR L
STRT_MLT 12581 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.
12582 RR B
12584 RR C
12586 EXX
12587 RR C
12589 RRA
12590 DJNZ MLT_LOOP Loop 33 times to get all the bits.
12592 EX DE,HL Move the result from H'L'HL to D'E'DE.
12593 EXX
12594 EX DE,HL
12595 EXX
Now add the exponents together.
12596 POP BC Restore the exponents - M1 and N1.
12597 POP HL Restore the pointer to the exponent byte.
12598 LD A,B Get the sum of the two exponent bytes in A, and the correct carry.
12599 ADD A,C
12600 JR NZ,MAKE_EXPT If the sum equals zero then clear the carry; else leave it unchanged.
12602 AND A
MAKE_EXPT 12603 DEC A Prepare to increase the exponent by 128.
12604 CCF
This entry point is used by the routine at division.
DIVN_EXPT 12605 RLA These few bytes very cleverly make the correct exponent byte. Rotating left then right gets the exponent byte (true exponent plus 128) into A.
12606 CCF
12607 RRA
12608 JP P,OFLW1_CLR If the sign flag is reset, no report of arithmetic overflow needed.
12611 JR NC,REPORT_6 Report the overflow if carry reset.
12613 AND A Clear the carry now.
OFLW1_CLR 12614 INC A The exponent byte is now complete; but if A is zero a further check for overflow is needed.
12615 JR NZ,OFLW2_CLR
12617 JR C,OFLW2_CLR
12619 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.
12620 BIT 7,D
12622 EXX
12623 JR NZ,REPORT_6
OFLW2_CLR 12625 LD (HL),A Store the exponent byte, at last.
12626 EXX Pass the fifth result byte to A for the normalisation sequence, i.e. the overflow from L into B'.
12627 LD A,B
12628 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 12629 JR NC,NORMALISE If no carry then normalise now.
12631 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).
12632 AND A
NEAR_ZERO 12633 LD A,128
12635 JR Z,SKIP_ZERO
ZERO_RSLT 12637 XOR A
SKIP_ZERO 12638 EXX
12639 AND D
12640 CALL ZEROS_4_5
12643 RLCA
12644 LD (HL),A Restore the exponent byte.
12645 JR C,OFLOW_CLR Jump if case 2**-128.
12647 INC HL Otherwise, put zero into second byte of result on the calculator stack.
12648 LD (HL),A
12649 DEC HL
12650 JR OFLOW_CLR Jump forward to transfer the result.
The actual normalisation operation.
NORMALISE 12652 LD B,32 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 12654 EXX
12655 BIT 7,D
12657 EXX
12658 JR NZ,NORML_NOW
12660 RLCA
12661 RL E
12663 RL D
12665 EXX
12666 RL E
12668 RL D
12670 EXX
12671 DEC (HL) The exponent is decremented on each shift.
12672 JR Z,NEAR_ZERO If the exponent becomes zero, then numbers from 2**-129 are rounded up to 2**-128.
12674 DJNZ SHIFT_ONE Loop back, up to 32 times.
12676 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 12678 RLA After normalisation add back any final carry that went into A. Jump forward if the carry does not ripple right back.
12679 JR NC,OFLOW_CLR
12681 CALL ADD_BACK
12684 JR NZ,OFLOW_CLR
12686 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).
12687 LD D,128
12689 EXX
12690 INC (HL)
12691 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 12693 PUSH HL Save the result pointer.
12694 INC HL Point to the sign byte in the result.
12695 EXX The result is moved from D'E'DE to BCDE, and then to ACDE.
12696 PUSH DE
12697 EXX
12698 POP BC
12699 LD A,B
12700 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.
12701 RL (HL)
12703 RRA
12704 LD (HL),A The first byte is stored.
12705 INC HL Next.
12706 LD (HL),C The second byte is stored.
12707 INC HL Next.
12708 LD (HL),D The third byte is stored.
12709 INC HL Next.
12710 LD (HL),E The fourth byte is stored.
12711 POP HL Restore the pointer to the result.
12712 POP DE Restore the pointer to second number.
12713 EXX Exchange the register.
12714 POP HL Restore the next literal address.
12715 EXX Exchange the registers.
12716 RET Finished.
This entry point is used by the routines at DEC_TO_FP, addition and division.
Report 6 - Arithmetic overflow.
REPORT_6 12717 RST 8 Call the error handling routine.
12718 DEFB 5
Prev: 12480 Up: Map Next: 12719