Prev: 12303 Up: Map Next: 12457
12308: THE 'ADDITION' OPERATION (offset 15)
The address of this routine is found in the table of addresses. It is called via the calculator literal 15 by the routines at BEEP, NEXT, CIRCLE, DRAW, CD_PRMS1, S_RND, DEC_TO_FP, INT_TO_FP, FP_TO_BC, series, exp, ln, get_argt, sin, atn and asn. It is also called indirectly via fp_calc_2, and the routine at subtract continues here.
The first of three major arithmetical subroutines, this subroutine carries out the floating-point addition of two numbers, each with a 4-byte mantissa and a 1-byte exponent. In these three subroutines, the two numbers at the top of the calculator stack are added/multiplied/divided to give one number at the top of the calculator stack, a 'last value'.
HL points to the second number from the top, the augend/multiplier/dividend. DE points to the number at the top of the calculator stack, the addend/multiplicand/divisor. Afterwards HL points to the resultant 'last value' whose address can also be considered to be STKEND-5.
But the addition subroutine first tests whether the 2 numbers to be added are 'small integers'. If they are, it adds them quite simply in HL and BC, and puts the result directly on the stack. No two's complementing is needed before or after the addition, since such numbers are held on the stack in two's complement form, ready for addition.
Input
DE Address of the first byte of the addend/multiplicand/divisor
HL Address of the first byte of the augend/multiplier/dividend
addition 12308 LD A,(DE) Test whether the first bytes of both numbers are zero.
12309 OR (HL)
12310 JR NZ,FULL_ADDN If not, jump for full addition.
12312 PUSH DE Save the pointer to the second number.
12313 INC HL Point to the second byte of the first number and save that pointer too.
12314 PUSH HL
12315 INC HL Point to the less significant byte.
12316 LD E,(HL) Fetch it in E.
12317 INC HL Point to the more significant byte.
12318 LD D,(HL) Fetch it in D.
12319 INC HL Move on to the second byte of the second number.
12320 INC HL
12321 INC HL
12322 LD A,(HL) Fetch it in A (this is the sign byte).
12323 INC HL Point to the less significant byte.
12324 LD C,(HL) Fetch it in C.
12325 INC HL Point to the more significant byte.
12326 LD B,(HL) Fetch it in B.
12327 POP HL Fetch the pointer to the sign byte of the first number; put it in DE, and the number in HL.
12328 EX DE,HL
12329 ADD HL,BC Perform the addition: result in HL.
12330 EX DE,HL Result to DE, sign byte to HL.
12331 ADC A,(HL) Add the sign bytes and the carry into A; this will detect any overflow.
12332 RRCA
12333 ADC A,0 A non-zero A now indicates overflow.
12335 JR NZ,ADDN_OFLW Jump to reset the pointers and to do full addition.
12337 SBC A,A Define the correct sign byte for the result.
12338 LD (HL),A Store it on the stack.
12339 INC HL Point to the next location.
12340 LD (HL),E Store the low byte of the result.
12341 INC HL Point to the next location.
12342 LD (HL),D Store the high byte of the result.
12343 DEC HL Move the pointer back to address the first byte of the result.
12344 DEC HL
12345 DEC HL
12346 POP DE Restore STKEND to DE.
12347 RET Finished.
Note that the number -65536 can arise here in the form 00 FF 00 00 00 as the result of the addition of two smaller negative integers, e.g. -65000 and -536. It is simply stacked in this form. This is a mistake. The Spectrum system cannot handle this number.
Most functions treat it as zero, and it is printed as -1E-38, obtained by treating is as 'minus zero' in an illegitimate format.
One possible remedy would be to test for this number at about byte 12338 and, if it is present, to make the second byte 128 and the first byte 145, so producing the full five-byte floating-point form of the number, i.e. 91 80 00 00 00, which causes no problems. See also the remarks in 'truncate'.
ADDN_OFLW 12348 DEC HL Restore the pointer to the first number.
12349 POP DE Restore the pointer to the second number.
FULL_ADDN 12350 CALL RE_ST_TWO Re-stack both numbers in full five-byte floating-point form.
The full addition subroutine first calls PREP_ADD for each number, then gets the two numbers from the calculator stack and puts the one with the smaller exponent into the addend position. It then calls SHIFT_FP to shift the addend up to 32 decimal places right to line it up for addition. The actual addition is done in a few bytes, a single shift is made for carry (overflow to the left) if needed, the result is two's complemented if negative, and any arithmetic overflow is reported; otherwise the subroutine jumps to TEST_NORM to normalise the result and return it to the stack with the correct sign bit inserted into the second byte.
12353 EXX Exchange the registers.
12354 PUSH HL Save the next literal address.
12355 EXX Exchange the registers.
12356 PUSH DE Save pointer to the addend.
12357 PUSH HL Save pointer to the augend.
12358 CALL PREP_ADD Prepare the augend.
12361 LD B,A Save its exponent in B.
12362 EX DE,HL Exchange the pointers.
12363 CALL PREP_ADD Prepare the addend.
12366 LD C,A Save its exponent in C.
12367 CP B If the first exponent is smaller, keep the first number in the addend position; otherwise change the exponents and the pointers back again.
12368 JR NC,SHIFT_LEN
12370 LD A,B
12371 LD B,C
12372 EX DE,HL
SHIFT_LEN 12373 PUSH AF Save the larger exponent in A.
12374 SUB B The difference between the exponents is the length of the shift right.
12375 CALL FETCH_TWO Get the two numbers from the stack.
12378 CALL SHIFT_FP Shift the addend right.
12381 POP AF Restore the larger exponent.
12382 POP HL HL is to point to the result.
12383 LD (HL),A Store the exponent of the result.
12384 PUSH HL Save the pointer again.
12385 LD L,B M4 to H and M5 to L (see FETCH_TWO).
12386 LD H,C
12387 ADD HL,DE Add the two right bytes.
12388 EXX N2 to H' and N3 to L' (see FETCH_TWO).
12389 EX DE,HL
12390 ADC HL,BC Add left bytes with carry.
12392 EX DE,HL Result back in D'E'.
12393 LD A,H Add H', L' and the carry; the resulting mechanisms will ensure that a single shift right is called if the sum of 2 positive numbers has overflowed left, or the sum of 2 negative numbers has not overflowed left.
12394 ADC A,L
12395 LD L,A
12396 RRA
12397 XOR L
12398 EXX
12399 EX DE,HL The result is now in DED'E'.
12400 POP HL Get the pointer to the exponent.
12401 RRA The test for shift (H', L' were 0 for positive numbers and 255 for negative numbers).
12402 JR NC,TEST_NEG
12404 LD A,1 A counts a single shift right.
12406 CALL SHIFT_FP The shift is called.
12409 INC (HL) Add 1 to the exponent; this may lead to arithmetic overflow.
12410 JR Z,ADD_REP_6
TEST_NEG 12412 EXX Test for negative result: get sign bit of L' into A (this now correctly indicates the sign of the result).
12413 LD A,L
12414 AND 128
12416 EXX
12417 INC HL Store it in the second byte position of the result on the calculator stack.
12418 LD (HL),A
12419 DEC HL
12420 JR Z,GO_NC_MLT If it is zero, then do not two's complement the result.
12422 LD A,E Get the first byte.
12423 NEG Negate it.
12425 CCF Complement the carry for continued negation, and store byte.
12426 LD E,A
12427 LD A,D Get the next byte.
12428 CPL One's complement it.
12429 ADC A,0 Add in the carry for negation.
12431 LD D,A Store the byte.
12432 EXX Proceed to get next byte into the A register.
12433 LD A,E
12434 CPL One's complement it.
12435 ADC A,0 Add in the carry for negation.
12437 LD E,A Store the byte.
12438 LD A,D Get the last byte.
12439 CPL One's complement it.
12440 ADC A,0 Add in the carry for negation.
12442 JR NC,END_COMPL Done if no carry.
12444 RRA Else, get .5 into mantissa and add 1 to the exponent; this will be needed when two negative numbers add to give an exact power of 2, and it may lead to arithmetic overflow.
12445 EXX
12446 INC (HL)
ADD_REP_6 12447 JP Z,REPORT_6 Give the error if required.
12450 EXX
END_COMPL 12451 LD D,A Store the last byte.
12452 EXX
GO_NC_MLT 12453 XOR A Clear A and the carry flag.
12454 JP TEST_NORM Exit via TEST_NORM.
Prev: 12303 Up: Map Next: 12457