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