~ubuntu-branches/ubuntu/breezy/avr-libc/breezy

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
/*  -*- Mode: Asm -*-  */
/*
    addsf3x.S is part of     FPlib V 0.3.0       ported to avr-as
    for copyright and details see readme.fplib

 *----------------------------------------------------------------------------------------
 *
 *--- addition kernel : used by other high level functions
 * add two extended numbers RX = AX + BX
 * AX  rA3 : rA2:rA1:rA0:rAE sign stored in rT1c.7, rAE cleared by fp_split1
 * BX  rB3 : rB2:rB1:rB0:rBE sign(A) ^ sign(B) stored in T
 * RX  rA3 : rA2:rA1:rA0:rAE resulting sign stored in rT1c.7 (rT1c.7 complemented, if B > A)
 */

#include "gasava.inc"
#include "fplib.inc"

          TEXT_SEG(fplib, __addsf3x)
          FUNCTION(__addsf3x)

GLOBAL(__addsf3x)
    CP      rAE,rBE         ; some high level functions use ___addsf3x
    CPC     rA0,rB0         ; directely with preset rAE,rBE
    CPC     rA1,rB1         ;
    CPC     rA2,rB2         ;
    CPC     rA3,rB3         ; A - B
    BREQ    ___addsf3x_300
    BRCC    ___addsf3x_100  ; A >= B

    BRTC    ___addsf3x_01   ; if T clear the A & B of same sign
    COM     rT1c            ; else complement sign
 ___addsf3x_01:
    MOV     rT0,rAE
    MOV     rAE,rBE
    MOV     rBE,rT0
    MOV     rT0,rA0
    MOV     rA0,rB0
    MOV     rB0,rT0
    MOV     rT0,rA1
    MOV     rA1,rB1
    MOV     rB1,rT0
    MOV     rT0,rA2
    MOV     rA2,rB2
    MOV     rB2,rT0
    MOV     rT0,rA3
    MOV     rA3,rB3
    MOV     rB3,rT0

 ; now A > B
 ___addsf3x_100:               ; denormalize lower mantissa until exponents are the same
    CLR     rTI0               ; holds mantissa extension beyond rBE
    TST     rB3                ;
    BREQ    ___addsf3x_130     ; A + 0

    SUB     rB3,rA3            ; get difference, rB3 negative
    BREQ    ___addsf3x_120     ; same : no shift
    CPI     rB3,LOW(-25)       ; no significant digits left after shift
    BRCS    ___addsf3x_130     ;
 ___addsf3x_110:                                                     ;
    LSR     rB2                                                      ;
    ROR     rB1                                                      ;
    ROR     rB0                                                      ;
    ROR     rBE                ; fraction >> 1                       ;
    SBCI    rTI0,0             ; mark if any overflow beyond rBE     ;
    INC     rB3                ; exponent ++
    BRNE    ___addsf3x_110     ;

 ___addsf3x_120:
    BRTS    ___addsf3x_200     ; branch if different sign
    ADD     rAE,rBE            ; maybe rAE and rBE are preset
    adc     rA0,rB0            ;
    adc     rA1,rB1            ;
    adc     rA2,rB2            ; add both mantissae
    BRCC    ___addsf3x_130     ; no fraction overflow if C = 0
    ROR     rA2                ; correct overflow
    ROR     rA1
    ROR     rA0
    ROR     rAE               ; fraction >> 1
    SBCI    rTI0,0            ; mark if any overflow beyond rBE
    INC     rA3               ; exponent++
 ___addsf3x_130:
    BST     rT1c,7
    MOV     rT0,rTI0
    RET

 ___addsf3x_200:
    SUB     rAE,rTI0          ; extended mantissa : 0 - lost bits
    CLR     rAE
    SBC     rAE,rBE           ; subtract the lower from the larger
    SBC     rA0,rB0           ; extended mantissa : if rBE == 0x80 -> rAE = 0x80
    SBC     rA1,rB1           ;
    SBC     rA2,rB2           ;
    RJMP    ___addsf3x_130    ;

 ; A == B
 ___addsf3x_300:
    BRTC    ___addsf3x_100    ; same sign, test for zero & add
    RJMP    _U(__fp_zerox)     ; different signs

          ENDFUNC