1 | /* SPDX-License-Identifier: GPL-2.0 */ |
2 | .file "reg_u_add.S" |
3 | /*---------------------------------------------------------------------------+ |
4 | | reg_u_add.S | |
5 | | | |
6 | | Add two valid (TAG_Valid) FPU_REG numbers, of the same sign, and put the | |
7 | | result in a destination FPU_REG. | |
8 | | | |
9 | | Copyright (C) 1992,1993,1995,1997 | |
10 | | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia | |
11 | | E-mail billm@suburbia.net | |
12 | | | |
13 | | Call from C as: | |
14 | | int FPU_u_add(FPU_REG *arg1, FPU_REG *arg2, FPU_REG *answ, | |
15 | | int control_w) | |
16 | | Return value is the tag of the answer, or-ed with FPU_Exception if | |
17 | | one was raised, or -1 on internal error. | |
18 | | | |
19 | +---------------------------------------------------------------------------*/ |
20 | |
21 | /* |
22 | | Kernel addition routine FPU_u_add(reg *arg1, reg *arg2, reg *answ). |
23 | | Takes two valid reg f.p. numbers (TAG_Valid), which are |
24 | | treated as unsigned numbers, |
25 | | and returns their sum as a TAG_Valid or TAG_Special f.p. number. |
26 | | The returned number is normalized. |
27 | | Basic checks are performed if PARANOID is defined. |
28 | */ |
29 | |
30 | #include "exception.h" |
31 | #include "fpu_emu.h" |
32 | #include "control_w.h" |
33 | |
34 | .text |
35 | SYM_FUNC_START(FPU_u_add) |
36 | pushl %ebp |
37 | movl %esp,%ebp |
38 | pushl %esi |
39 | pushl %edi |
40 | pushl %ebx |
41 | |
42 | movl PARAM1,%esi /* source 1 */ |
43 | movl PARAM2,%edi /* source 2 */ |
44 | |
45 | movl PARAM6,%ecx |
46 | movl %ecx,%edx |
47 | subl PARAM7,%ecx /* exp1 - exp2 */ |
48 | jge L_arg1_larger |
49 | |
50 | /* num1 is smaller */ |
51 | movl SIGL(%esi),%ebx |
52 | movl SIGH(%esi),%eax |
53 | |
54 | movl %edi,%esi |
55 | movl PARAM7,%edx |
56 | negw %cx |
57 | jmp L_accum_loaded |
58 | |
59 | L_arg1_larger: |
60 | /* num1 has larger or equal exponent */ |
61 | movl SIGL(%edi),%ebx |
62 | movl SIGH(%edi),%eax |
63 | |
64 | L_accum_loaded: |
65 | movl PARAM3,%edi /* destination */ |
66 | movw %dx,EXP(%edi) /* Copy exponent to destination */ |
67 | |
68 | xorl %edx,%edx /* clear the extension */ |
69 | |
70 | #ifdef PARANOID |
71 | testl $0x80000000,%eax |
72 | je L_bugged |
73 | |
74 | testl $0x80000000,SIGH(%esi) |
75 | je L_bugged |
76 | #endif /* PARANOID */ |
77 | |
78 | /* The number to be shifted is in %eax:%ebx:%edx */ |
79 | cmpw $32,%cx /* shrd only works for 0..31 bits */ |
80 | jnc L_more_than_31 |
81 | |
82 | /* less than 32 bits */ |
83 | shrd %cl,%ebx,%edx |
84 | shrd %cl,%eax,%ebx |
85 | shr %cl,%eax |
86 | jmp L_shift_done |
87 | |
88 | L_more_than_31: |
89 | cmpw $64,%cx |
90 | jnc L_more_than_63 |
91 | |
92 | subb $32,%cl |
93 | jz L_exactly_32 |
94 | |
95 | shrd %cl,%eax,%edx |
96 | shr %cl,%eax |
97 | orl %ebx,%ebx |
98 | jz L_more_31_no_low /* none of the lowest bits is set */ |
99 | |
100 | orl $1,%edx /* record the fact in the extension */ |
101 | |
102 | L_more_31_no_low: |
103 | movl %eax,%ebx |
104 | xorl %eax,%eax |
105 | jmp L_shift_done |
106 | |
107 | L_exactly_32: |
108 | movl %ebx,%edx |
109 | movl %eax,%ebx |
110 | xorl %eax,%eax |
111 | jmp L_shift_done |
112 | |
113 | L_more_than_63: |
114 | cmpw $65,%cx |
115 | jnc L_more_than_64 |
116 | |
117 | movl %eax,%edx |
118 | orl %ebx,%ebx |
119 | jz L_more_63_no_low |
120 | |
121 | orl $1,%edx |
122 | jmp L_more_63_no_low |
123 | |
124 | L_more_than_64: |
125 | movl $1,%edx /* The shifted nr always at least one '1' */ |
126 | |
127 | L_more_63_no_low: |
128 | xorl %ebx,%ebx |
129 | xorl %eax,%eax |
130 | |
131 | L_shift_done: |
132 | /* Now do the addition */ |
133 | addl SIGL(%esi),%ebx |
134 | adcl SIGH(%esi),%eax |
135 | jnc L_round_the_result |
136 | |
137 | /* Overflow, adjust the result */ |
138 | rcrl $1,%eax |
139 | rcrl $1,%ebx |
140 | rcrl $1,%edx |
141 | jnc L_no_bit_lost |
142 | |
143 | orl $1,%edx |
144 | |
145 | L_no_bit_lost: |
146 | incw EXP(%edi) |
147 | |
148 | L_round_the_result: |
149 | jmp fpu_reg_round /* Round the result */ |
150 | |
151 | |
152 | |
153 | #ifdef PARANOID |
154 | /* If we ever get here then we have problems! */ |
155 | L_bugged: |
156 | pushl EX_INTERNAL|0x201 |
157 | call EXCEPTION |
158 | pop %ebx |
159 | movl $-1,%eax |
160 | jmp L_exit |
161 | |
162 | L_exit: |
163 | popl %ebx |
164 | popl %edi |
165 | popl %esi |
166 | leave |
167 | RET |
168 | #endif /* PARANOID */ |
169 | SYM_FUNC_END(FPU_u_add) |
170 | |