Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/arch/x86/math-emu/reg_u_sub.S
10817 views
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 [email protected] |
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
273
274