Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | Download | RSS feed

  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
  454.