Subversion Repositories Kolibri OS

Rev

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