Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | .file "reg_u_sub.S" |
2 | /*---------------------------------------------------------------------------+ | |
3 | | reg_u_sub.S | | |
4 | | | | |
5 | | Core floating point subtraction routine. | | |
6 | | | | |
7 | | Copyright (C) 1992,1993,1995,1997 | | |
8 | | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia | | |
9 | | E-mail billm@suburbia.net | | |
10 | | | | |
11 | | Call from C as: | | |
12 | | int FPU_u_sub(FPU_REG *arg1, FPU_REG *arg2, FPU_REG *answ, | | |
13 | | int control_w) | | |
14 | | Return value is the tag of the answer, or-ed with FPU_Exception if | | |
15 | | one was raised, or -1 on internal error. | | |
16 | | | | |
17 | +---------------------------------------------------------------------------*/ | |
18 | ||
19 | /* | |
20 | | Kernel subtraction routine FPU_u_sub(reg *arg1, reg *arg2, reg *answ). | |
21 | | Takes two valid reg f.p. numbers (TAG_Valid), which are | |
22 | | treated as unsigned numbers, | |
23 | | and returns their difference as a TAG_Valid or TAG_Zero f.p. | |
24 | | number. | |
25 | | The first number (arg1) must be the larger. | |
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 | ENTRY(FPU_u_sub) | |
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 | subl PARAM7,%ecx /* exp1 - exp2 */ | |
47 | ||
48 | #ifdef PARANOID | |
49 | /* source 2 is always smaller than source 1 */ | |
50 | js L_bugged_1 | |
51 | ||
52 | testl $0x80000000,SIGH(%edi) /* The args are assumed to be be normalized */ | |
53 | je L_bugged_2 | |
54 | ||
55 | testl $0x80000000,SIGH(%esi) | |
56 | je L_bugged_2 | |
57 | #endif /* PARANOID */ | |
58 | ||
59 | /*--------------------------------------+ | |
60 | | Form a register holding the | | |
61 | | smaller number | | |
62 | +--------------------------------------*/ | |
63 | movl SIGH(%edi),%eax /* register ms word */ | |
64 | movl SIGL(%edi),%ebx /* register ls word */ | |
65 | ||
66 | movl PARAM3,%edi /* destination */ | |
67 | movl PARAM6,%edx | |
68 | movw %dx,EXP(%edi) /* Copy exponent to destination */ | |
69 | ||
70 | xorl %edx,%edx /* register extension */ | |
71 | ||
72 | /*--------------------------------------+ | |
73 | | Shift the temporary register | | |
74 | | right the required number of | | |
75 | | places. | | |
76 | +--------------------------------------*/ | |
77 | ||
78 | cmpw $32,%cx /* shrd only works for 0..31 bits */ | |
79 | jnc L_more_than_31 | |
80 | ||
81 | /* less than 32 bits */ | |
82 | shrd %cl,%ebx,%edx | |
83 | shrd %cl,%eax,%ebx | |
84 | shr %cl,%eax | |
85 | jmp L_shift_done | |
86 | ||
87 | L_more_than_31: | |
88 | cmpw $64,%cx | |
89 | jnc L_more_than_63 | |
90 | ||
91 | subb $32,%cl | |
92 | jz L_exactly_32 | |
93 | ||
94 | shrd %cl,%eax,%edx | |
95 | shr %cl,%eax | |
96 | orl %ebx,%ebx | |
97 | jz L_more_31_no_low /* none of the lowest bits is set */ | |
98 | ||
99 | orl $1,%edx /* record the fact in the extension */ | |
100 | ||
101 | L_more_31_no_low: | |
102 | movl %eax,%ebx | |
103 | xorl %eax,%eax | |
104 | jmp L_shift_done | |
105 | ||
106 | L_exactly_32: | |
107 | movl %ebx,%edx | |
108 | movl %eax,%ebx | |
109 | xorl %eax,%eax | |
110 | jmp L_shift_done | |
111 | ||
112 | L_more_than_63: | |
113 | cmpw $65,%cx | |
114 | jnc L_more_than_64 | |
115 | ||
116 | /* Shift right by 64 bits */ | |
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 | jne L_more_than_65 | |
126 | ||
127 | /* Shift right by 65 bits */ | |
128 | /* Carry is clear if we get here */ | |
129 | movl %eax,%edx | |
130 | rcrl %edx | |
131 | jnc L_shift_65_nc | |
132 | ||
133 | orl $1,%edx | |
134 | jmp L_more_63_no_low | |
135 | ||
136 | L_shift_65_nc: | |
137 | orl %ebx,%ebx | |
138 | jz L_more_63_no_low | |
139 | ||
140 | orl $1,%edx | |
141 | jmp L_more_63_no_low | |
142 | ||
143 | L_more_than_65: | |
144 | movl $1,%edx /* The shifted nr always at least one '1' */ | |
145 | ||
146 | L_more_63_no_low: | |
147 | xorl %ebx,%ebx | |
148 | xorl %eax,%eax | |
149 | ||
150 | L_shift_done: | |
151 | L_subtr: | |
152 | /*------------------------------+ | |
153 | | Do the subtraction | | |
154 | +------------------------------*/ | |
155 | xorl %ecx,%ecx | |
156 | subl %edx,%ecx | |
157 | movl %ecx,%edx | |
158 | movl SIGL(%esi),%ecx | |
159 | sbbl %ebx,%ecx | |
160 | movl %ecx,%ebx | |
161 | movl SIGH(%esi),%ecx | |
162 | sbbl %eax,%ecx | |
163 | movl %ecx,%eax | |
164 | ||
165 | #ifdef PARANOID | |
166 | /* We can never get a borrow */ | |
167 | jc L_bugged | |
168 | #endif /* PARANOID */ | |
169 | ||
170 | /*--------------------------------------+ | |
171 | | Normalize the result | | |
172 | +--------------------------------------*/ | |
173 | testl $0x80000000,%eax | |
174 | jnz L_round /* no shifting needed */ | |
175 | ||
176 | orl %eax,%eax | |
177 | jnz L_shift_1 /* shift left 1 - 31 bits */ | |
178 | ||
179 | orl %ebx,%ebx | |
180 | jnz L_shift_32 /* shift left 32 - 63 bits */ | |
181 | ||
182 | /* | |
183 | * A rare case, the only one which is non-zero if we got here | |
184 | * is: 1000000 .... 0000 | |
185 | * -0111111 .... 1111 1 | |
186 | * -------------------- | |
187 | * 0000000 .... 0000 1 | |
188 | */ | |
189 | ||
190 | cmpl $0x80000000,%edx | |
191 | jnz L_must_be_zero | |
192 | ||
193 | /* Shift left 64 bits */ | |
194 | subw $64,EXP(%edi) | |
195 | xchg %edx,%eax | |
196 | jmp fpu_reg_round | |
197 | ||
198 | L_must_be_zero: | |
199 | #ifdef PARANOID | |
200 | orl %edx,%edx | |
201 | jnz L_bugged_3 | |
202 | #endif /* PARANOID */ | |
203 | ||
204 | /* The result is zero */ | |
205 | movw $0,EXP(%edi) /* exponent */ | |
206 | movl $0,SIGL(%edi) | |
207 | movl $0,SIGH(%edi) | |
208 | movl TAG_Zero,%eax | |
209 | jmp L_exit | |
210 | ||
211 | L_shift_32: | |
212 | movl %ebx,%eax | |
213 | movl %edx,%ebx | |
214 | movl $0,%edx | |
215 | subw $32,EXP(%edi) /* Can get underflow here */ | |
216 | ||
217 | /* We need to shift left by 1 - 31 bits */ | |
218 | L_shift_1: | |
219 | bsrl %eax,%ecx /* get the required shift in %ecx */ | |
220 | subl $31,%ecx | |
221 | negl %ecx | |
222 | shld %cl,%ebx,%eax | |
223 | shld %cl,%edx,%ebx | |
224 | shl %cl,%edx | |
225 | subw %cx,EXP(%edi) /* Can get underflow here */ | |
226 | ||
227 | L_round: | |
228 | jmp fpu_reg_round /* Round the result */ | |
229 | ||
230 | ||
231 | #ifdef PARANOID | |
232 | L_bugged_1: | |
233 | pushl EX_INTERNAL|0x206 | |
234 | call EXCEPTION | |
235 | pop %ebx | |
236 | jmp L_error_exit | |
237 | ||
238 | L_bugged_2: | |
239 | pushl EX_INTERNAL|0x209 | |
240 | call EXCEPTION | |
241 | pop %ebx | |
242 | jmp L_error_exit | |
243 | ||
244 | L_bugged_3: | |
245 | pushl EX_INTERNAL|0x210 | |
246 | call EXCEPTION | |
247 | pop %ebx | |
248 | jmp L_error_exit | |
249 | ||
250 | L_bugged_4: | |
251 | pushl EX_INTERNAL|0x211 | |
252 | call EXCEPTION | |
253 | pop %ebx | |
254 | jmp L_error_exit | |
255 | ||
256 | L_bugged: | |
257 | pushl EX_INTERNAL|0x212 | |
258 | call EXCEPTION | |
259 | pop %ebx | |
260 | jmp L_error_exit | |
261 | ||
262 | L_error_exit: | |
263 | movl $-1,%eax | |
264 | ||
265 | #endif /* PARANOID */ | |
266 | ||
267 | L_exit: | |
268 | popl %ebx | |
269 | popl %edi | |
270 | popl %esi | |
271 | leave | |
272 | ret |