| Routines

3014: THE 'ADDITION' OPERATION (offset +0F)

The address of this routine is found in the table of addresses. It is called via the calculator literal +0F 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 | 3014 | LD A,(DE) | Test whether the first bytes of both numbers are zero.
| 3015 | OR (HL)
| 3016 | JR NZ,FULL_ADDN | If not, jump for full addition.
| 3018 | PUSH DE | Save the pointer to the second number.
| 3019 | INC HL | Point to the second byte of the first number and save that pointer too.
| 301A | PUSH HL
| 301B | INC HL | Point to the less significant byte.
| 301C | LD E,(HL) | Fetch it in E.
| 301D | INC HL | Point to the more significant byte.
| 301E | LD D,(HL) | Fetch it in D.
| 301F | INC HL | Move on to the second byte of the second number.
| 3020 | INC HL
| 3021 | INC HL
| 3022 | LD A,(HL) | Fetch it in A (this is the sign byte).
| 3023 | INC HL | Point to the less significant byte.
| 3024 | LD C,(HL) | Fetch it in C.
| 3025 | INC HL | Point to the more significant byte.
| 3026 | LD B,(HL) | Fetch it in B.
| 3027 | POP HL | Fetch the pointer to the sign byte of the first number; put it in DE, and the number in HL.
| 3028 | EX DE,HL
| 3029 | ADD HL,BC | Perform the addition: result in HL.
| 302A | EX DE,HL | Result to DE, sign byte to HL.
| 302B | ADC A,(HL) | Add the sign bytes and the carry into A; this will detect any overflow.
| 302C | RRCA
| 302D | ADC A,$00 | A non-zero A now indicates overflow.
| 302F | JR NZ,ADDN_OFLW | Jump to reset the pointers and to do full addition.
| 3031 | SBC A,A | Define the correct sign byte for the result.
| 3032 | LD (HL),A | Store it on the stack.
| 3033 | INC HL | Point to the next location.
| 3034 | LD (HL),E | Store the low byte of the result.
| 3035 | INC HL | Point to the next location.
| 3036 | LD (HL),D | Store the high byte of the result.
| 3037 | DEC HL | Move the pointer back to address the first byte of the result.
| 3038 | DEC HL
| 3039 | DEC HL
| 303A | POP DE | Restore STKEND to DE.
| 303B | 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 3032 and, if it is present, to make the second byte +80 and the first byte +91, 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 | 303C | DEC HL | Restore the pointer to the first number.
| 303D | POP DE | Restore the pointer to the second number.
FULL_ADDN | 303E | 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.
| 3041 | EXX | Exchange the registers.
| 3042 | PUSH HL | Save the next literal address.
| 3043 | EXX | Exchange the registers.
| 3044 | PUSH DE | Save pointer to the addend.
| 3045 | PUSH HL | Save pointer to the augend.
| 3046 | CALL PREP_ADD | Prepare the augend.
| 3049 | LD B,A | Save its exponent in B.
| 304A | EX DE,HL | Exchange the pointers.
| 304B | CALL PREP_ADD | Prepare the addend.
| 304E | LD C,A | Save its exponent in C.
| 304F | 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.
| 3050 | JR NC,SHIFT_LEN
| 3052 | LD A,B
| 3053 | LD B,C
| 3054 | EX DE,HL
SHIFT_LEN | 3055 | PUSH AF | Save the larger exponent in A.
| 3056 | SUB B | The difference between the exponents is the length of the shift right.
| 3057 | CALL FETCH_TWO | Get the two numbers from the stack.
| 305A | CALL SHIFT_FP | Shift the addend right.
| 305D | POP AF | Restore the larger exponent.
| 305E | POP HL | HL is to point to the result.
| 305F | LD (HL),A | Store the exponent of the result.
| 3060 | PUSH HL | Save the pointer again.
| 3061 | LD L,B | M4 to H and M5 to L (see FETCH_TWO).
| 3062 | LD H,C
| 3063 | ADD HL,DE | Add the two right bytes.
| 3064 | EXX | N2 to H' and N3 to L' (see FETCH_TWO).
| 3065 | EX DE,HL
| 3066 | ADC HL,BC | Add left bytes with carry.
| 3068 | EX DE,HL | Result back in D'E'.
| 3069 | 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.
| 306A | ADC A,L
| 306B | LD L,A
| 306C | RRA
| 306D | XOR L
| 306E | EXX
| 306F | EX DE,HL | The result is now in DED'E'.
| 3070 | POP HL | Get the pointer to the exponent.
| 3071 | RRA | The test for shift (H', L' were +00 for positive numbers and +FF for negative numbers).
| 3072 | JR NC,TEST_NEG
| 3074 | LD A,$01 | A counts a single shift right.
| 3076 | CALL SHIFT_FP | The shift is called.
| 3079 | INC (HL) | Add 1 to the exponent; this may lead to arithmetic overflow.
| 307A | JR Z,ADD_REP_6
TEST_NEG | 307C | EXX | Test for negative result: get sign bit of L' into A (this now correctly indicates the sign of the result).
| 307D | LD A,L
| 307E | AND $80
| 3080 | EXX
| 3081 | INC HL | Store it in the second byte position of the result on the calculator stack.
| 3082 | LD (HL),A
| 3083 | DEC HL
| 3084 | JR Z,GO_NC_MLT | If it is zero, then do not two's complement the result.
| 3086 | LD A,E | Get the first byte.
| 3087 | NEG | Negate it.
| 3089 | CCF | Complement the carry for continued negation, and store byte.
| 308A | LD E,A
| 308B | LD A,D | Get the next byte.
| 308C | CPL | One's complement it.
| 308D | ADC A,$00 | Add in the carry for negation.
| 308F | LD D,A | Store the byte.
| 3090 | EXX | Proceed to get next byte into the A register.
| 3091 | LD A,E
| 3092 | CPL | One's complement it.
| 3093 | ADC A,$00 | Add in the carry for negation.
| 3095 | LD E,A | Store the byte.
| 3096 | LD A,D | Get the last byte.
| 3097 | CPL | One's complement it.
| 3098 | ADC A,$00 | Add in the carry for negation.
| 309A | JR NC,END_COMPL | Done if no carry.
| 309C | 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.
| 309D | EXX
| 309E | INC (HL)
ADD_REP_6 | 309F | JP Z,REPORT_6 | Give the error if required.
| 30A2 | EXX
END_COMPL | 30A3 | LD D,A | Store the last byte.
| 30A4 | EXX
GO_NC_MLT | 30A5 | XOR A | Clear A and the carry flag.
| 30A6 | JP TEST_NORM | Exit via TEST_NORM.