Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
553 | serge | 1 | ;***************************************************************************** |
2 | ;* |
||
3 | ;* Open Watcom Project |
||
4 | ;* |
||
5 | ;* Portions Copyright (c) 1983-2002 Sybase, Inc. All Rights Reserved. |
||
6 | ;* |
||
7 | ;* ======================================================================== |
||
8 | ;* |
||
9 | ;* This file contains Original Code and/or Modifications of Original |
||
10 | ;* Code as defined in and that are subject to the Sybase Open Watcom |
||
11 | ;* Public License version 1.0 (the 'License'). You may not use this file |
||
12 | ;* except in compliance with the License. BY USING THIS FILE YOU AGREE TO |
||
13 | ;* ALL TERMS AND CONDITIONS OF THE LICENSE. A copy of the License is |
||
14 | ;* provided with the Original Code and Modifications, and is also |
||
15 | ;* available at www.sybase.com/developer/opensource. |
||
16 | ;* |
||
17 | ;* The Original Code and all software distributed under the License are |
||
18 | ;* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER |
||
19 | ;* EXPRESS OR IMPLIED, AND SYBASE AND ALL CONTRIBUTORS HEREBY DISCLAIM |
||
20 | ;* ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF |
||
21 | ;* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR |
||
22 | ;* NON-INFRINGEMENT. Please see the License for the specific language |
||
23 | ;* governing rights and limitations under the License. |
||
24 | ;* |
||
25 | ;* ======================================================================== |
||
26 | ;* |
||
27 | ;* Description: REAL*4 math library. |
||
28 | ;* |
||
29 | ;***************************************************************************** |
||
30 | |||
31 | |||
32 | ; |
||
33 | ; inputs: EAX - operand 1 (high word, low word resp. ) (op1) |
||
34 | ; EDX - operand 2 (op2) |
||
35 | ; |
||
36 | ; operations are performed as op1 (*) op2 where (*) is the selected |
||
37 | ; operation |
||
38 | ; |
||
39 | ; output: EAX - result |
||
40 | ; |
||
41 | ; F4Add, F4Sub - written 28-apr-84 |
||
42 | ; - modified by A.Kasapi 15-may-84 |
||
43 | ; - to: Calculate sign of result |
||
44 | ; - Guard bit in addition for extra accuracy |
||
45 | ; Add documentation |
||
46 | ; F4Mul - written 16-may-84 |
||
47 | ; - by Athos Kasapi |
||
48 | ; F4DIV - written may-84 by " |
||
49 | ; |
||
50 | include mdef.inc |
||
51 | include struct.inc |
||
52 | |||
53 | .287 |
||
54 | modstart fsmth386 |
||
55 | |||
56 | xref __8087 ; indicate that NDP instructions are present |
||
57 | |||
58 | xref __fdiv_m32 |
||
59 | |||
60 | datasegment |
||
61 | extrn __real87 : byte ; cstart |
||
62 | extrn __chipbug : byte |
||
63 | fsadd dd _chkadd |
||
64 | fsmul dd _chkmul |
||
65 | fsdiv dd _chkdiv |
||
66 | enddata |
||
67 | |||
68 | |||
69 | xref F4DivZero ; Fstatus |
||
70 | xref F4OverFlow ; Fstatus |
||
71 | xref F4UnderFlow ; Fstatus |
||
72 | |||
73 | xdefp __FSA ; add real*4 to real*4 |
||
74 | xdefp __FSS ; subtract real*4 from real*4 |
||
75 | xdefp __FSM ; 4-byte real multiply |
||
76 | xdefp __FSD ; 4-byte real divide |
||
77 | |||
78 | |||
79 | defpe __FSS |
||
80 | or EDX,EDX ; if op2 is 0 |
||
81 | je short ret_op1 ; then return operand 1 |
||
82 | xor EDX,80000000h ; flip the sign of op2 and add |
||
83 | |||
84 | defpe __FSA |
||
85 | or EDX,EDX ; if op2 is 0 |
||
86 | je short ret_op1 ; then return operand 1 |
||
87 | or EAX,EAX ; if op1 is 0 |
||
88 | _if e ; then |
||
89 | mov EAX,EDX ; - return operand 2 |
||
90 | ret_op1: ret ; - return |
||
91 | _endif ; endif |
||
92 | jmp fsadd |
||
93 | |||
94 | __FSA87: |
||
95 | push EBP ; save EBP |
||
96 | mov EBP,ESP ; get access to stack |
||
97 | push EAX ; push operand 1 |
||
98 | fld dword ptr -4[EBP]; load operand 1 |
||
99 | push EDX ; push operand 2 |
||
100 | fadd dword ptr -8[EBP]; add operand 2 to operand 1 |
||
101 | _ret87: |
||
102 | fstp dword ptr -4[EBP]; store result |
||
103 | add ESP,4 ; clean up stack |
||
104 | fwait ; wait |
||
105 | pop EAX ; load result into EAX |
||
106 | cmp EAX,80000000H ; is result -0.0 |
||
107 | _if e ; if it is then |
||
108 | xor EAX,EAX ; - make it positive |
||
109 | _endif ; endif |
||
110 | pop EBP ; restore EBP |
||
111 | ret ; return |
||
112 | |||
113 | __FSAemu: |
||
114 | push ECX ; save ECX |
||
115 | push EBX ; save EBX |
||
116 | ;<> Scheme for calculating sign of result: |
||
117 | ;<> The sign word is built and kept in CL |
||
118 | ;<> Bits 0 and 1 hold the sum of the sign bits |
||
119 | ;<> shifted out of op_1 and op_2 |
||
120 | ;<> Bit 2 holds the sign of the larger operand. It is assumed to be |
||
121 | ;<> op_1 until op_2 is found larger |
||
122 | |||
123 | sub ECX,ECX ; clear ECX |
||
124 | _shl EAX,1 ; get sign of op1 |
||
125 | _rcl CL,1 ; |
||
126 | mov CH,CL ; |
||
127 | _shl CL,1 ; |
||
128 | _shl CL,1 ; |
||
129 | add CL,CH ; |
||
130 | rol EAX,8 ; get exponent of op1 into AL |
||
131 | _shl EDX,1 ; get sign of op2 |
||
132 | adc CL,0 ; place in CL |
||
133 | rol EDX,8 ; get exponent of op2 in DL |
||
134 | mov BL,AL ; get exponent of op1 |
||
135 | mov BH,DL ; get exponent of op2 |
||
136 | |||
137 | mov AL,0 ; zero rest of fraction |
||
138 | stc ; put implied 1 bit into top bit of |
||
139 | rcr EAX,1 ; ... fraction |
||
140 | mov DL,0 ; zero rest of fraction |
||
141 | stc ; put implied 1 bit into top bit |
||
142 | rcr EDX,1 ; ... of fraction |
||
143 | |||
144 | mov CH,BL ; assume op1 > op2 |
||
145 | sub BL,BH ; calculate difference in exponents |
||
146 | _if ne ; if different |
||
147 | _if b ; - if op1 < op2 |
||
148 | mov CH,BH ; - - get larger exponent for result |
||
149 | neg BL ; - - negate the shift count |
||
150 | xchg EAX,EDX ; - - flip operands |
||
151 | xor CL,4 |
||
152 | |||
153 | ;<> op_2 is larger, so its sign now occupies bit 2 of sign word. This |
||
154 | ;<> information is only correct if the signs of op-1 and op-2 are different. |
||
155 | ;<> Since we look past bit 1 for sign only if the signs are different, bit2 |
||
156 | ;<> will supply the correct information when it is needed. We get the sign of |
||
157 | ;<> op_2 by flipping the sign of op_1, already in bit 2 |
||
158 | |||
159 | _endif ; - endif |
||
160 | xchg CL,BL ; - get shift count |
||
161 | cmp CL,32 ; - if count >= 32 |
||
162 | _if ge ; - then |
||
163 | sub EDX,EDX ; - - answer is 0 |
||
164 | _else ; - else |
||
165 | shr EDX,CL ; - - align fraction |
||
166 | _endif ; - endif |
||
167 | xchg CL,BL ; - put back |
||
168 | _endif ; endif |
||
169 | shr CL,1 ; get bit 0 of sign word - value is 0 if |
||
170 | ; both operands have same sign, 1 if not |
||
171 | _if nc ; if signs are the same |
||
172 | add EAX,EDX ; - add the fractions |
||
173 | _if c ; - if carry |
||
174 | rcr EAX,1 ; - - shift fraction right 1 bit |
||
175 | inc CH ; - - increment exponent |
||
176 | _if z ; - - if we overflowed |
||
177 | ror CL,1 ; - - - set sign of infinity |
||
178 | rcr EAX,1 ; - - - . . . |
||
179 | jmp short add_oflow;- - - handle overflow |
||
180 | _endif ; - - endif |
||
181 | _endif ; - endif |
||
182 | _else ; else (signs are different) |
||
183 | shr CL,1 ; - skip junk bit |
||
184 | sub EAX,EDX ; - subtract the fractions |
||
185 | _guess ; - guess |
||
186 | _quif nc ; - - quit if no borrow |
||
187 | inc CL ; - - sign := sign of op_2 |
||
188 | neg EAX ; - - negate the fraction |
||
189 | _admit ; - admit |
||
190 | or EAX,EAX ; - - quit if answer is not 0 |
||
191 | _quif ne ; - - . . . |
||
192 | pop EBX ; - - restore EBX |
||
193 | pop ECX ; - - restore ECX |
||
194 | ret ; - - return (answer is 0) |
||
195 | _endguess ; - endguess |
||
196 | _endif ; endif |
||
197 | |||
198 | ; normalize the fraction |
||
199 | add EAX,00000080h ; round up fraction if required |
||
200 | mov AL,0 ; zero bottom 8 bits 10-jul-89 |
||
201 | _guess underflow ; guess |
||
202 | _quif nc ; - quit if round up didn't overflow frac |
||
203 | inc CH ; - adjust exponent |
||
204 | _admit ; admit |
||
205 | _loop ; - loop (shift until high bit appears) |
||
206 | _shl EAX,1 ; - - shift fraction left |
||
207 | _quif c,underflow ; - - quit if carry has appeared |
||
208 | dec CH ; - - decrement exponent |
||
209 | _until e ; - until underflow |
||
210 | jmp short add_uflow ; - handle underflow |
||
211 | _endguess ; endguess |
||
212 | mov AL,CH ; get exponent |
||
213 | ror EAX,8 ; rotate into position |
||
214 | ror CL,1 ; get sign bit |
||
215 | rcr EAX,1 ; shift it into result |
||
216 | pop EBX ; restore EBX |
||
217 | pop ECX ; restore ECX |
||
218 | ret ; return |
||
219 | |||
220 | add_uflow: ; handle underflow |
||
221 | pop EBX ; restore EBX |
||
222 | pop ECX ; restore ECX |
||
223 | jmp F4UnderFlow ; goto underflow routine |
||
224 | |||
225 | add_oflow: ; handle overflow |
||
226 | pop EBX ; restore EBX |
||
227 | pop ECX ; restore ECX |
||
228 | jmp F4OverFlow ; handle overflow |
||
229 | endproc __FSA |
||
230 | endproc __FSS |
||
231 | |||
232 | ;===================================================================== |
||
233 | |||
234 | defpe __FSM |
||
235 | |||
236 | ;<> multiplies X by Y and places result in C. |
||
237 | ;<> X2 and X1 represent the high and low words of X. Similarly for Y and C |
||
238 | ;<> Special care is taken to use only six registers, so the code is a bit |
||
239 | ;<> obscure |
||
240 | |||
241 | _guess ; guess: answer not 0 |
||
242 | or EAX,EAX ; - see if first arg is zero |
||
243 | _quif e ; - quit if op1 is 0 |
||
244 | or EDX,EDX ; - quit if op2 is 0 |
||
245 | _quif e ; - . . . |
||
246 | jmp fsmul ; - perform multiplication |
||
247 | _endguess ; endguess |
||
248 | sub EAX,EAX ; set answer to 0 |
||
249 | ret ; return |
||
250 | |||
251 | __FSM87: |
||
252 | push EBP ; save EBP |
||
253 | mov EBP,ESP ; get access to stack |
||
254 | push EAX ; push operand 1 |
||
255 | fld dword ptr -4[EBP]; load operand 1 |
||
256 | push EDX ; push operand 2 |
||
257 | fmul dword ptr -8[EBP]; mulitply operand 1 by operand 2 |
||
258 | jmp _ret87 ; goto common epilogue |
||
259 | |||
260 | __FSMemu: |
||
261 | push ECX ; save ECX |
||
262 | _shl EAX,1 ; get sign of op1 |
||
263 | _rcl ECX,1 ; save it |
||
264 | _shl EDX,1 ; get sign of op2 |
||
265 | adc ECX,0 ; calc sign of result |
||
266 | ror ECX,1 ; move to the top |
||
267 | rol EAX,8 ; move exponent of op1 into AL |
||
268 | rol EDX,8 ; move exponent of op2 into DL |
||
269 | sub AL,7Fh ; remove bias from exponents |
||
270 | sub DL,7Fh ; . . . |
||
271 | add DL,AL ; add exponents |
||
272 | _if o ; if over or underflow |
||
273 | js short mul_oflow ; - report overflow if signed |
||
274 | jmp short mul_uflow ; - handle underflow |
||
275 | _endif ; endif |
||
276 | cmp DL,81h ; check for underflow |
||
277 | jle short mul_uflow ; quit if underflow |
||
278 | add DL,7fh+1 ; bias exponent |
||
279 | mov CL,DL ; save exponent |
||
280 | mov AL,0 ; zero rest of fraction |
||
281 | mov DL,0 ; ... |
||
282 | stc ; turn on implied 1 bit in fraction |
||
283 | rcr EAX,1 ; ... |
||
284 | stc ; turn on implied 1 bit in fraction |
||
285 | rcr EDX,1 ; ... |
||
286 | mul EDX ; calc fraction |
||
287 | or EDX,EDX ; check top bit |
||
288 | _if ns ; if not set |
||
289 | _shl EDX,1 ; - move left 1 |
||
290 | dec CL ; - decrement exponent |
||
291 | _endif ; endif |
||
292 | sar EDX,8 ; place fraction in correct location |
||
293 | adc EDX,0 ; round up |
||
294 | adc CL,0 ; increment exponent if necessary |
||
295 | jz short mul_oflow ; report overflow if required |
||
296 | shl EDX,9 ; get rid of implied 1 bit |
||
297 | mov DL,CL ; get exponent |
||
298 | ror EDX,8 ; rotate into position except for sign |
||
299 | _shl ECX,1 ; get sign |
||
300 | rcr EDX,1 ; place sign in result |
||
301 | mov EAX,EDX ; place in correct register |
||
302 | pop ECX ; restore ECX |
||
303 | ret ; return |
||
304 | |||
305 | mul_uflow: ; underflow |
||
306 | pop ECX ; restore ECX |
||
307 | jmp F4UnderFlow ; . . . |
||
308 | |||
309 | mul_oflow: ; overflow |
||
310 | mov EAX,ECX ; get sign |
||
311 | pop ECX ; restore ECX |
||
312 | jmp F4OverFlow ; report overflow |
||
313 | endproc __FSM |
||
314 | |||
315 | ;==================================================================== |
||
316 | |||
317 | defpe __FSD |
||
318 | jmp fsdiv |
||
319 | |||
320 | __FSDbad_div: |
||
321 | push EBP ; save EBP |
||
322 | mov EBP,ESP ; get access to stack |
||
323 | push EAX ; push operand 1 |
||
324 | fld dword ptr -4[EBP]; load operand 1 |
||
325 | push EDX ; push operand 2 |
||
326 | call __fdiv_m32 ; divide operand 1 by operand 2 |
||
327 | push EDX ; __fdiv_m32 popped operand 2, _ret87 wants it |
||
328 | jmp _ret87 ; goto common epilogue |
||
329 | |||
330 | __FSD87: |
||
331 | push EBP ; save EBP |
||
332 | mov EBP,ESP ; get access to stack |
||
333 | push EAX ; push operand 1 |
||
334 | fld dword ptr -4[EBP]; load operand 1 |
||
335 | push EDX ; push operand 2 |
||
336 | fdiv dword ptr -8[EBP]; divide operand 1 by operand 2 |
||
337 | jmp _ret87 ; goto common epilogue |
||
338 | |||
339 | |||
340 | __FSDemu: |
||
341 | _shl EDX,1 ; shift sign of divisor into carry |
||
342 | _if e ; if divisor is zero |
||
343 | jmp F4DivZero ; - handle divide by zero |
||
344 | _endif ; endif |
||
345 | push ECX ; save ECX |
||
346 | _rcl ECX,1 ; save sign in ECX |
||
347 | _shl EAX,1 ; shift sign of dividend into carry |
||
348 | _if e ; if dividend is 0, then |
||
349 | pop ECX ; - restore ECX |
||
350 | ret ; - return |
||
351 | _endif ; endif |
||
352 | adc ECX,0 ; now calculate save sign of result in ECX |
||
353 | ror ECX,1 ; rotate sign to top |
||
354 | rol EAX,8 ; get exponent into AL |
||
355 | rol EDX,8 ; get exponent into DL |
||
356 | sub AL,7Fh ; calculate exponent of result |
||
357 | sub DL,7Fh ; . . . |
||
358 | sub AL,DL ; . . . |
||
359 | _if o ; if over or underflow |
||
360 | jns short div_uflow ; - handle underflow |
||
361 | _shl ECX,1 ; - get sign of infinity |
||
362 | rcr EAX,1 ; - . . . |
||
363 | jmp short div_oflow ; - handle overflow |
||
364 | _endif ; endif |
||
365 | cmp AL,81h ; check for underflow |
||
366 | jle short div_uflow ; . . . |
||
367 | add AL,7Fh ; restore bias to exponent |
||
368 | mov CH,AL ; save calculated exponent |
||
369 | mov AL,0 ; zero bottom of fraction |
||
370 | mov DL,0 ; ... |
||
371 | stc ; rotate implied '1'bit back into divisor |
||
372 | rcr EDX,1 ; . . . |
||
373 | stc ; rotate implied '1' bit into dividend |
||
374 | rcr EAX,1 ; . . . |
||
375 | push ECX ; save sign and exponent |
||
376 | mov ECX,EDX ; save divisor |
||
377 | mov EDX,EAX ; place dividend into EDX |
||
378 | sub EAX,EAX ; set rest to 0 |
||
379 | shr EDX,1 ; so we don't get a divide overflow trap |
||
380 | div ECX ; do the divide |
||
381 | pop ECX ; restore sign and exponent |
||
382 | or EAX,EAX ; check top bit |
||
383 | _if ns ; if not set |
||
384 | _shl EAX,1 ; - move left 1 |
||
385 | dec CH ; - decrement exponent |
||
386 | _endif ; endif |
||
387 | sar EAX,8 ; place fraction in correct location |
||
388 | adc EAX,0 ; round up |
||
389 | _guess ; guess have to inc exponent |
||
390 | _quif nc ; - quit if no carry |
||
391 | inc CH ; - increment exponent |
||
392 | _quif nz ; - quit if no overflow |
||
393 | mov EAX,ECX ; - get sign of infinity |
||
394 | jmp short div_oflow ; - handle overflow |
||
395 | _endguess ; endguess |
||
396 | shl EAX,9 ; get rid of implied 1 bit |
||
397 | mov AL,CH ; get exponent |
||
398 | ror EAX,8 ; rotate into position except for sign |
||
399 | _shl ECX,1 ; get sign |
||
400 | rcr EAX,1 ; place sign in result |
||
401 | pop ECX ; restore ECX |
||
402 | ret ; return to caller |
||
403 | |||
404 | div_uflow: ; handle underflow |
||
405 | pop ECX ; restore ECX |
||
406 | jmp F4UnderFlow ; handle underflow |
||
407 | |||
408 | |||
409 | div_oflow: ; handle overflow |
||
410 | pop ECX ; restore ECX |
||
411 | jmp F4OverFlow ; handle overflow |
||
412 | endproc __FSD |
||
413 | |||
414 | |||
415 | _chkadd: call _chk8087 |
||
416 | jmp fsadd |
||
417 | |||
418 | _chkmul: call _chk8087 |
||
419 | jmp fsmul |
||
420 | |||
421 | _chkdiv: call _chk8087 |
||
422 | jmp fsdiv |
||
423 | |||
424 | |||
425 | _chk8087 proc near |
||
426 | push eax ; save AX |
||
427 | cmp byte ptr __real87,0 ; if real 80x87 NDP present |
||
428 | _if ne ; then |
||
429 | mov eax,offset __FSA87 ; - get addr of add rtn |
||
430 | mov fsadd,eax ; - ... |
||
431 | mov eax,offset __FSM87 ; - get addr of mul rtn |
||
432 | mov fsmul,eax ; - ... |
||
433 | test byte ptr __chipbug, 1 ; - if we've got a bad divider |
||
434 | _if ne ; - then |
||
435 | mov eax,offset __FSDbad_div ; - - get addr of div rtn |
||
436 | _else ; - else |
||
437 | mov eax,offset __FSD87 ; - - get addr of div rtn |
||
438 | _endif ; - endif |
||
439 | mov fsdiv,eax ; - ... |
||
440 | _else ; else |
||
441 | mov eax,offset __FSAemu ; - get addr of add rtn |
||
442 | mov fsadd,eax ; - ... |
||
443 | mov eax,offset __FSMemu ; - get addr of mul rtn |
||
444 | mov fsmul,eax ; - ... |
||
445 | mov eax,offset __FSDemu ; - get addr of div rtn |
||
446 | mov fsdiv,eax ; - ... |
||
447 | _endif ; endif |
||
448 | pop eax ; restore AX |
||
449 | ret ; return |
||
450 | endproc _chk8087 |
||
451 | |||
452 | endmod |
||
453 | end>>>>>>>>>>>>>>>> |