-
Notifications
You must be signed in to change notification settings - Fork 157
/
fldm386.asm
320 lines (298 loc) · 13.6 KB
/
fldm386.asm
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
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
;*****************************************************************************
;*
;* Open Watcom Project
;*
;* Portions Copyright (c) 1983-2002 Sybase, Inc. All Rights Reserved.
;*
;* ========================================================================
;*
;* This file contains Original Code and/or Modifications of Original
;* Code as defined in and that are subject to the Sybase Open Watcom
;* Public License version 1.0 (the 'License'). You may not use this file
;* except in compliance with the License. BY USING THIS FILE YOU AGREE TO
;* ALL TERMS AND CONDITIONS OF THE LICENSE. A copy of the License is
;* provided with the Original Code and Modifications, and is also
;* available at www.sybase.com/developer/opensource.
;*
;* The Original Code and all software distributed under the License are
;* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
;* EXPRESS OR IMPLIED, AND SYBASE AND ALL CONTRIBUTORS HEREBY DISCLAIM
;* ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF
;* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR
;* NON-INFRINGEMENT. Please see the License for the specific language
;* governing rights and limitations under the License.
;*
;* ========================================================================
;*
;* Description: long double math library - multiply __FLDM, ___LDM
;*
;*****************************************************************************
ifdef _BUILDING_MATHLIB
include mdef.inc
include struct.inc
modstart fldm386, dword
endif
;<><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><>
;<>
;<> long double math library
;<>
;<> inputs: EAX - pointer to long double (op1)
;<> EDX - pointer to long double (op2)
;<> EBX - pointer to long double (result)
;<>
;<><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><>
xdefp __FLDM ; 10-byte real multiply
xdefp ___LDM ; 10-byte real multiply
;=====================================================================
defp __FLDM
push ESI ; save ESI
push ECX ; save ECX
push EBX ; save EBX
mov SI,8[EDX] ; load op2
mov ECX,4[EDX] ; ...
mov EBX,[EDX] ; ...
shl ESI,16 ; shift to the top
mov SI,8[EAX] ; load op1
mov EDX,4[EAX] ; ...
mov EAX,[EAX] ; ...
call ___LDM ; do the multiply
pop EBX ; restore pointer to result
mov [EBX],EAX ; store result
mov 4[EBX],EDX ; ...
mov 8[EBX],SI ; ...
pop ECX ; restore ECX
pop ESI ; restore ESI
ret ; return
;
; op1 is a NaN or infinity
;
mulnan1:_guess ; guess: op1 is +/- inf and op2 is 0
or EAX,EAX ; - quit if op1 is NaN
_quif ne ; - ...
cmp EDX,80000000h ; - ...
_quif ne ; - ...
or EBX,EBX ; - quit if op2 not 0
_quif ne ; - ...
or ECX,ECX ; - ...
_quif ne ; - ...
mov ESI,0FFFFFFFFh ; - answer is -NaN
sar EDX,1 ; - ...
ret ; - return
_endguess ; endguess
_guess ; guess:
dec SI ; - adjust low exponent
add ESI,10000h ; - increment high exponent
_quif c ; - quit if op2 is NaN
_quif o ; - ...
; op2 is not a NaN or infinity
; if op1 is +/- infinity, then flip its sign if op2 is negative
or EAX,EAX ; - check low word
_if e ; - if 0
cmp EDX,80000000h ; - - check high word
_endif ; - endif
_if e ; - if op1 is +/- infinity
or ESI,ESI ; - - if op2 is negative
_if s ; - - then
xor SI,8000h ; - - - flip sign
_endif ; - - endif
_endif ; - endif
ret ; - return op1
_endguess ; endguess
sub ESI,10000h ; readjust high exponent
;
; both operands are NaNs and/or infinity
;
_guess ; guess: fabs(op1) < fabs(op2)
cmp EDX,ECX ; - compare high words
_if e ; - if high words equal
cmp EAX,EBX ; - - compare low words
_endif ; - endif
_quif a ; - quit if op1 > op2
_if e ; - if op1 == op2
; if op1 is +/- infinity, then flip its sign if op2 is negative
or EAX,EAX ; - - check low word
_if e ; - - if 0
cmp EDX,80000000h; - - - check high word
_endif ; - - endif
_if ne ; - - if op1 is not +/- infinity
ret ; - - - return op1
_endif ; - - endif
or SI,SI ; - - if op1 is negative
_if s ; - - then
xor ESI,EDX ; - - - flip sign
_endif ; - - endif
_endif ; - endif
mov EDX,ECX ; - load op2
mov EAX,EBX ; - ...
shr ESI,16 ; - ...
_endguess ; endguess
ret ; return
;
; op1 is not a NaN or infinity, but op2 is
;
mulnan2:sub ESI,10000h ; readjust high exponent
_guess ; guess: op2 is infinity
or EBX,EBX ; - quit if op2 not infinity
_quif ne ; - ...
cmp ECX,80000000h ; - ...
_quif ne ; - ...
or EAX,EAX ; - if op1 is 0
_if e ; - ...
or EDX,EDX ; - - check high word
_endif ; - endif
_if e ; - if op1 is 0
sar ECX,1 ; - - return -NaN
mov ESI,0FFFFFFFFh; - - ...
_else ; - else
or SI,SI ; - - if op1 is negative
_if s ; - - then
xor ESI,ECX ; - - - flip sign bit
_endif ; - - endif
_endif ; - endif
_endguess ; endguess
mov EDX,ECX ; return op2
mov EAX,EBX ; ...
shr ESI,16 ; shift exponent to bottom
ret ; return
endproc __FLDM
defp ___LDM
add SI,1 ; add 1 to exponent
jc mulnan1 ; quit if NaN
jo mulnan1 ; ...
add ESI,0FFFFh ; readjust low exponent and inc high word
jc short mulnan2 ; quit if NaN
jo short mulnan2 ; ...
sub ESI,10000h ; readjust high exponent
_guess ; guess: op1 is 0
or EAX,EAX ; - quit if op1 is not 0
_quif ne ; - ...
or EDX,EDX ; - quit if op1 is not 0
_quif ne ; - ...
_shl SI,1 ; - place sign in carry
_if e ; - if operand one is 0
ret ; - - return 0
_endif ; - endif
rcr SI,1 ; - restore sign of op1
_endguess ; endguess
_guess ; guess: op2 is 0
or ECX,ECX ; - quit if op2 is not 0
_quif ne ; - ...
or EBX,EBX ; - quit if op2 is not 0
_quif ne ; - ...
test ESI,7FFF0000h ; - quit if op2's exponent is not 0
_quif ne ; - ...
sub EAX,EAX ; - ...
sub EDX,EDX ; - ...
sub ESI,ESI ; - ...
ret ; - return 0
_endguess ; endguess
push EBP ; save EBP
push EDI ; save EDI
xchg ECX,ESI ; get exponents and signs into ECX
mov EDI,ECX ; get exponent and sign of op1 into EDI
rol EDI,16 ; shift to top
sar EDI,16 ; duplicate sign
sar ECX,16 ; ...
and EDI,080007FFFh ; isolate signs and exponent
and ECX,080007FFFh ; ...
_guess ; guess: overflow
add ECX,EDI ; - determine exponent of result and sign
sub CX,3FFEh ; - remove extra bias
_quif c ; - quit if exponent is negative
cmp CX,7FFFh ; - quit if not overflow
_quif b ; - . . .
jmp mul_oflow ; - handle overflow
_endguess ; endguess
cmp CX,-64 ; if exponent is too small
_if l ; then underflow
sub EAX,EAX ; - set result to 0
sub EDX,EDX ; - ...
sub ECX,ECX ; - ...
jmp _mulret ; - return (underflow)
_endif ; endif
push ECX ; save sign and exponent
sub EBP,EBP ; zero EBP
push ESI ; save high part of op2
push EDX ; save high part of op1
push EAX ; save low part of op1
mul EBX ; low part of op1 * low part of op2
xchg EAX,ESI ; ESI becomes start of the sticky bits
mov ECX,EDX ; save high part of result
pop EDX ; restore low part of op1
mul EDX ; low part of op1 * high part of op2
mov EDI,EDX ; save high part of product
add ECX,EAX ; add partial product
adc EDI,EBP ; ...
adc EBP,EBP ; ...
pop EAX ; restore high part of op1
xchg EAX,EBX ; flip with low part of op2
mul EBX ; high part of op1 * low part of op2
add ECX,EAX ; add partial product
adc EDI,EDX ; ...
adc EBP,0 ; ...
mov EAX,EBX ; get high part of op1
pop EDX ; restore high part of op2
mul EDX ; high part of op1 * high part of op2
add EAX,EDI ; add partial product
adc EDX,EBP ; ...
mov EBX,ECX ; get guard bits
pop ECX ; restore sign and exponent
_if ns ; if not normalized
_shl EBX,1 ; - shift left 1
_rcl EAX,1 ; - ...
_rcl EDX,1 ; - ...
dec CX ; - decrement exponent
_endif ; endif
_shl EBX,1 ; get guard bit
_if c ; if set
_if e ; - if rest of sticky bits are 0
or ESI,ESI ; - - check the bottom sticky bits
setne BL ; - - ...
shr EBX,1 ; - - if all sticky bits are zero
_if nc ; - - then
mov ESI,EAX ; - - - get bottom bit of result
shr ESI,1 ; - - - as rounding bit
_endif ; - - endif
_endif ; - endif
adc EAX,0 ; - round up
adc EDX,0 ; - ...
_if c ; - if fraction overflowed
rcr EDX,1 ; - - shift right
rcr EAX,1 ; - - ...
inc CX ; - - increment exponent
cmp CX,7FFFh ; - - quit if overflow
je mul_oflow ; - - . . .
_endif ; - endif
_endif ; endif
or CX,CX ; if exponent <= 0
_if le ; then (denormal result)
_if e ; - if exponent = 0
mov CL,1 ; - - set shift count to 1
_else ; - else
neg CX ; - - negate to get shift count
_endif ; - endif
sub EBX,EBX ; - for zero fill
shrd EAX,EDX,CL ; - align the fraction
shrd EDX,EBX,CL ; - ...
sub CX,CX ; - set exponent to 0
_endif ; endif
_mulret:
_shl ECX,1 ; get sign
rcr CX,1 ; shift into exponent
mov ESI,ECX ; get exponent and sign of result into SI
pop EDI ; restore EDI
pop EBP ; restore EBP
ret ; return
mul_oflow: ; overflow
mov CX,7FFFh ; set exponent for infinity
mov EDX,80000000h ; set fraction
sub EAX,EAX ; ...
jmp short _mulret ; return
endproc ___LDM
ifdef _BUILDING_MATHLIB
endmod
endf equ end
else
endf equ <>
endif
endf