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*8 math library.
  28. ;*
  29. ;*****************************************************************************
  30.  
  31.  
  32. ;
  33. ;     inputs: EDX,EAX - operand 1 (high word, low word resp. ) (op1)
  34. ;             ECX,EBX - operand 2                              (op2)
  35. ;
  36. ;     operations are performed as op1 (*) op2 where (*) is the selected
  37. ;     operation
  38. ;
  39. ;     output: EDX,EAX - result    (high word, low word resp. )
  40. ;
  41. ;
  42. include mdef.inc
  43. include struct.inc
  44.  
  45. .8087
  46.         modstart        fdmth386
  47.  
  48.         xref            __8087  ; indicate that NDP instructions are present
  49.  
  50.         datasegment
  51.         extrn   __real87 : byte         ; 8087.asm
  52.         enddata
  53.  
  54.         xref    F8DivZero       ; Fstatus
  55.         xref    F8OverFlow      ; Fstatus
  56.         xref    F8UnderFlow     ; Fstatus
  57.  
  58.         xdefp   __FDA           ; add real*8 to real*8
  59.         xdefp   __FDS           ; subtract real*8 from real*8
  60.         xdefp   __FDM           ; 8-byte real multiply
  61.  
  62.  
  63.         defpe   __FDS
  64.         xor     ECX,80000000h   ; flip the sign of op2 and add
  65.  
  66.         defpe   __FDA
  67.         or      EBX,EBX         ; if low word of op2 is 0
  68.         _if     e               ; then
  69.           _shl  ECX,1           ; - place sign in carry
  70.           je    ret_op1         ; - if op2 is 0 then return operand 1
  71.           rcr   ECX,1           ; - put sign back
  72.         _endif                  ; endif
  73.         or      EAX,EAX         ; if op1 is 0
  74.         _if     e               ; then
  75.           _shl  EDX,1           ; - place sign in carry
  76.           _if   e               ; - if op1 really is 0
  77.             mov   EDX,ECX       ; - - return operand 2
  78.             mov   EAX,EBX       ; - - . . .
  79. ret_op1:    ret                 ; - - return
  80.           _endif                ; - endif
  81.           rcr   EDX,1           ; - put sign back
  82.         _endif                  ; endif
  83.  
  84.         cmp     byte ptr __real87,0; if 8087 not to be used
  85.         je      short __FDAemu  ; then emulate
  86.  
  87. __FDA87:
  88.         push    EDX             ; push operand 1
  89.         push    EAX             ; . . .
  90.         fld     qword ptr [ESP] ; load operand 1
  91.         push    ECX             ; push operand 2
  92.         push    EBX             ; . . .
  93.         fadd    qword ptr [ESP] ; add operand 2 to operand 1
  94. _ret87:
  95.         fstp    qword ptr 8[ESP]; store result
  96.         add     ESP,8           ; clean up stack
  97.         fwait                   ; wait
  98.         pop     EAX             ; load result into EDX:EAX
  99.         pop     EDX             ; . . .
  100.         cmp     EDX,80000000H   ; is it a negative zero?
  101.         _if     e               ; if it is then
  102.           sub   EDX,EDX         ; - make it positive 0.0
  103.           mov   EAX,EDX         ; - ...
  104.         _endif                  ; endif
  105.         ret                     ; return
  106.  
  107. __FDAemu:
  108.         push    EBP             ; save EBP
  109.         push    EDI             ; save EDI
  110.         push    ESI             ; save EDI
  111.         mov     EDI,EDX         ; get high part of op1
  112.         mov     ESI,ECX         ; get high part of op2
  113.         sar     EDI,20          ; shift exponent to bottom, duplicating sign
  114.         sar     ECX,20          ; shift exponent to bottom, duplicating sign
  115.         and     EDI,0800007FFh  ; isolate signs and exponent
  116.         and     ECX,0800007FFh  ; ...
  117.         mov     EBP,ECX         ; assume op1 < op2
  118.         rol     EDI,16          ; rotate signs to bottom
  119.         rol     ECX,16          ; ...
  120.         add     CX,DI           ; calc sign of result
  121.         rol     EDI,16          ; rotate signs to top
  122.         rol     ECX,16          ; ...
  123.         and     EDX,000FFFFFh   ; isolate fraction
  124.         and     ESI,000FFFFFh   ; isolate fraction
  125.         or      DI,DI           ; if op1 is not a denormal
  126.         _if     ne              ; then
  127.           or    EDX,00100000h   ; - turn on implied 1 bit
  128.         _endif                  ; endif
  129.         or      CX,CX           ; if op2 is not a denormal
  130.         _if     ne              ; then
  131.           or    ESI,00100000h   ; - turn on implied 1 bit
  132.         _endif                  ; endif
  133.         _shl    EAX,1           ; shift left 1 to make room for guard bit
  134.         _rcl    EDX,1           ; ...
  135.         _shl    EBX,1           ; ...
  136.         _rcl    ESI,1           ; ...
  137.         sub     CX,DI           ; calculate difference in exponents
  138.         _if     ne              ; if different
  139.           _if   b               ; - if op1 < op2
  140.             mov   EBP,EDI       ; - - get larger exponent for result
  141.             neg   CX            ; - - negate the shift count
  142.             xchg  EAX,EBX       ; - - flip operands
  143.             xchg  EDX,ESI       ; - - . . .
  144.           _endif                ; - endif
  145.           cmp     CX,53+1       ; - if shift count too big
  146.           _if     a             ; - then, return operand 1
  147.             mov   EDX,ESI       ; - - get value in correct registers
  148.             mov   EAX,EBX       ; - - . . .
  149.             _shl  EBP,1         ; - - get sign
  150.             rcr   EDX,1         ; - - rebuild operand 1
  151.             rcr   EAX,1         ; - - ...
  152.             and   EDX,800FFFFFh ; - - ...
  153.             ror   EBP,13        ; - - rotate exponent into position
  154.             and   EBP,7FF00000h ; - - ...
  155.             or    EDX,EBP       ; - - put in exponent
  156.             pop   ESI           ; - - restore ESI
  157.             pop   EDI           ; - - restore EDI
  158.             pop   EBP           ; - - restore EBP
  159.             ret                 ; - - return
  160.           _endif                ; - endif
  161.         _endif                  ; endif
  162.         or      ECX,ECX         ; get bit 0 of sign word - value is 0 if
  163.                                 ; both operands have same sign, 1 if not
  164.         _if     s               ; if signs are different
  165.           neg   ESI             ; - negate the fraction of op2
  166.           neg   EBX             ; - . . .
  167.           sbb   ESI,0           ; - . . .
  168.           xor   EBP,80000000h   ; - flip sign
  169.         _endif                  ; endif
  170.         sub     EDI,EDI         ; get a zero for sticky bits
  171.         cmp     CL,0            ; if shifting required
  172.         _if     ne              ; then
  173.           push    EBX           ; - save EBX
  174.           sub     EBX,EBX       ; - for zero fill
  175.           cmp     CL,32         ; - if shift count >= 32
  176.           _if     ae            ; - then
  177.             or    EAX,EAX       ; - - check low order word for 1 bits
  178.             setne BL            ; - - BL=1 if EAX non zero
  179.             mov   EDI,EBX       ; - - save sticky bits
  180.             sub   EBX,EBX       ; - - for zero fill
  181.             mov   EAX,EDX       ; - - shift right 32
  182.             sub   EDX,EDX       ; - - zero high word
  183. ;;;         sub   CL,32         ; - - adjust shift count
  184.           _endif                ; - endif
  185.           shrd    EBX,EAX,CL    ; - get the extra sticky bits
  186.           or      EDI,EBX       ; - save them
  187.           sub     EBX,EBX       ; - for zero fill
  188.           shrd    EAX,EDX,CL    ; - align the fractions
  189.           shrd    EDX,EBX,CL    ; - ...
  190.           pop     EBX           ; - restore EBX
  191.         _endif                  ; endif
  192.  
  193.         add     EAX,EBX         ; add the fractions
  194.         adc     EDX,ESI         ; . . .
  195.         _if     s               ; if answer is negative
  196.           cmp   CL,53           ; - if shift count >= 53
  197.           _if   ae              ; - then
  198.             test  EDI,7FFFFFFFh ; - - check the sticky bits
  199.             setne BL            ; - - make single sticky bit
  200.             shr   EBX,1         ; - - carry set if sticky=1
  201.             adc   EAX,0         ; - - round up fraction if required
  202.             adc   EDX,0         ; - - . . .
  203.           _endif                ; - endif
  204.           neg   EDX             ; - negate the fraction
  205.           neg   EAX             ; - . . .
  206.           sbb   EDX,0           ; - . . .
  207.           xor   EBP,80000000h   ; - flip the sign
  208.         _endif                  ; endif
  209.         mov     EBX,EAX         ; get result
  210.         or      EBX,EDX         ; if not zero
  211.         _if     ne              ; then
  212.           or    BP,BP           ; - if exponent is 0
  213.           je    short denormal  ; - denormal when exponent hits 0
  214.           _loop                 ; - loop (normalize)
  215.             test  EDX,7FE00000h ; - - stop when bit slides into exponent field
  216.             _quif ne            ; - - ...
  217.             dec   BP            ; - - decrement exponent
  218.             je    short denormal; - - denormal when exponent hits 0
  219.             _shl  EAX,1         ; - - shift fraction left one bit
  220.             _rcl  EDX,1         ; - - ...
  221.           _endloop              ; - endloop
  222.           test  EDX,00400000h   ; - if we got a carry
  223.           _if   ne              ; - then
  224.             shr   EDX,1         ; - - shift fraction right 1
  225.             rcr   EAX,1         ; - - ...
  226.             adc   EDI,0         ; - - keep sticky bit
  227.             inc   BP            ; - - increment exponent
  228.             cmp   BP,07FFh      ; - - quit if overflow
  229.             je    add_oflow     ; - - . . .
  230.           _endif                ; - endif
  231.           ; normalize the fraction
  232.           shr   EDX,1           ; - get guard bit
  233.           rcr   EAX,1           ; - ...
  234.           _if     c             ; - if guard bit is on
  235.             or    EDI,EDI       ; - - check the sticky bits
  236.             setne BL            ; - - make single sticky bit
  237.             or    EBX,EAX       ; - - or sticky bit with bottom bit
  238.             shr   EBX,1         ; - - carry set if sticky=1 or bottom=1
  239.             adc   EAX,0         ; - - round up fraction if required
  240.             adc   EDX,0         ; - - . . .
  241.             test  EDX,00200000h ; - - if we got a carry (02-nov-90)
  242.             _if   ne            ; - - then
  243.               shr   EDX,1       ; - - - shift fraction right 1
  244.               rcr   EAX,1       ; - - - ...
  245.               inc   BP          ; - - - increment exponent
  246.               cmp   BP,07FFh    ; - - - quit if overflow
  247.               je    add_oflow   ; - - - . . .
  248.             _endif              ; - - endif
  249.           _endif                ; - endif
  250.           and   EDX,000FFFFFh   ; - get rid of implied 1 bit
  251.           mov   ECX,EBP         ; - get sign
  252.           shl   EBP,21          ; - shift exponent to top
  253.           _shl  ECX,1           ; - get sign
  254.           rcr   EBP,1           ; - put it in
  255.           or    EDX,EBP         ; - put exponent and sign into result
  256.         _endif                  ; endif
  257.         pop     ESI             ; restore ESI
  258.         pop     EDI             ; restore EDI
  259.         pop     EBP             ; restore EBP
  260.         ret                     ; return
  261.  
  262. denormal:                       ; handle denormal
  263.         _shl    EBP,1           ; get sign
  264.         rcr     EDX,1           ; put it in result
  265.         rcr     EAX,1           ; ...
  266.         pop     ESI             ; restore ESI
  267.         pop     EDI             ; restore EDI
  268.         pop     EBP             ; restore EBP
  269.         ret                     ; return
  270.  
  271. add_oflow:                      ; handle overflow
  272.         mov     EAX,EBP         ; get proper sign for infinity
  273.         pop     ESI             ; restore ESI
  274.         pop     EDI             ; restore EDI
  275.         pop     EBP             ; restore EBP
  276.         jmp     F8OverFlow      ; handle overflow
  277.         endproc __FDA
  278.         endproc __FDS
  279. ;=====================================================================
  280. ;<> multiplies X by Y and places result in C.
  281. ;<> X2 and X1 represent the high and low words of X. Similarly for Y and C
  282. ;<> Special care is taken to use only six registers, so the code is a bit
  283. ;<> obscure
  284.  
  285.         defpe   __FDM
  286.         _guess                  ; guess: one of the operands is 0
  287.           or    EAX,EAX         ; - see if first arg is zero
  288.           _quif ne              ; - quit if op1 is not 0
  289.           _shl  EDX,1           ; - place sign in carry
  290.           _if   e               ; - if operand one is 0
  291.             ret                 ; - - return
  292.           _endif                ; - endif
  293.           rcr   EDX,1           ; - restore sign
  294.         _endguess               ; endguess
  295.         _guess                  ; guess: op2 is 0
  296.           or    EBX,EBX         ; - quit if op2 is not 0
  297.           _quif ne              ; - . . .
  298.           _shl  ECX,1           ; - place sign in carry
  299.           _if   e               ; - if operand 2 is 0
  300.             sub   EAX,EAX       ; - - set result to 0
  301.             sub   EDX,EDX       ; - - . . .
  302.             ret                 ; - - return
  303.           _endif                ; - endif
  304.           rcr   ECX,1           ; - restore sign of op2
  305.         _endguess               ; endguess
  306.  
  307.         cmp     byte ptr __real87,0; if 8087 not to be used
  308.         je      short __FDMemu  ; then emulate
  309.  
  310. __FDM87:
  311.         push    EDX             ; push operand 1
  312.         push    EAX             ; . . .
  313.         fld     qword ptr [ESP] ; load operand 1
  314.         push    ECX             ; push operand 2
  315.         push    EBX             ; . . .
  316.         fmul    qword ptr [ESP] ; multiply operand 1 by operand 2
  317.         jmp     _ret87          ; goto common epilogue
  318.  
  319. __FDMemu:
  320.         push    EBP             ; save EBP
  321.         push    EDI             ; save EDI
  322.         push    ESI             ; save EDI
  323.         mov     EDI,EDX         ; get high part of op1
  324.         mov     ESI,ECX         ; get high part of op2
  325.         sar     EDI,20          ; shift exponent to bottom, duplicating sign
  326.         sar     ECX,20          ; shift exponent to bottom, duplicating sign
  327.         and     EDI,0800007FFh  ; isolate signs and exponent
  328.         and     ECX,0800007FFh  ; ...
  329.         rol     EDI,16          ; rotate signs to bottom
  330.         rol     ECX,16          ; ...
  331.         add     CX,DI           ; calc sign of result
  332.         rol     EDI,16          ; rotate signs to top
  333.         rol     ECX,16          ; ...
  334.         and     EDX,000FFFFFh   ; isolate fraction
  335.         and     ESI,000FFFFFh   ; isolate fraction
  336.         or      DI,DI           ; if op1 is a denormal
  337.         _if     e               ; then
  338.           inc   DI              ; - adjust exponent by 1
  339.           _loop                 ; - loop (normalize it)         27-jul-90
  340.             dec   DI            ; - - decrement exponent
  341.             _shl  EAX,1         ; - - shift left 1
  342.             _rcl  EDX,1         ; - - ...
  343.             test  EDX,00100000h ; - - check for implied 1 bit
  344.           _until  ne            ; - until normalized
  345.         _endif                  ; endif
  346.         or      EDX,00100000h   ; turn on implied 1 bit
  347.         or      CX,CX           ; if op2 is a denormal
  348.         _if     e               ; then
  349.           inc   CX              ; - adjust exponent by 1
  350.           _loop                 ; - loop (normalize it)         27-jul-90
  351.             dec   CX            ; - - decrement exponent
  352.             _shl  EBX,1         ; - - shift left 1
  353.             _rcl  ESI,1         ; - - ...
  354.             test  ESI,00100000h ; - - check for implied 1 bit
  355.           _until  ne            ; - until normalized
  356.         _endif                  ; endif
  357.         or      ESI,00100000h   ; turn on implied 1 bit
  358.  
  359.         _guess                  ; guess: overflow
  360.           add   CX,DI           ; - determine exponent of result
  361.           sub   CX,03ffh        ; - remove extra bias
  362.           _quif s               ; - quit if exponent is negative
  363.           cmp   CX,07FFh        ; - quit if not overflow
  364.           _quif b               ; - . . .
  365.           mov   EAX,ECX         ; - put sign into EAX
  366.           pop   ESI             ; - restore ESI
  367.           pop   EDI             ; - restore EDI
  368.           pop   EBP             ; - restore EBP
  369.           jmp   F8OverFlow      ; - handle overflow
  370.         _endguess               ; endguess
  371.         cmp     CX,-53          ; if exponent is too small
  372.         _if     l               ; then underflow
  373.           pop   ESI             ; - restore ESI
  374.           pop   EDI             ; - restore EDI
  375.           pop   EBP             ; - restore EBP
  376.           jmp   F8UnderFlow     ; - handle underflow
  377.         _endif                  ; endif
  378.         push    ECX             ; save sign and exponent
  379.         mov     CL,11           ; shift fractions to top of registers
  380.         shld    EDX,EAX,CL      ; ...
  381.         shld    EAX,EBP,CL      ; ...
  382.         and     EAX,0FFFFF800h  ; ...
  383.         shld    ESI,EBX,CL      ; ...
  384.         shld    EBX,EBP,CL      ; ...
  385.         and     EBX,0FFFFF800h  ; ...
  386.  
  387.         sub     EBP,EBP         ; zero EBP
  388.         push    ESI             ; save high part of op2
  389.         push    EDX             ; save high part of op1
  390.         push    EAX             ; save low part of op1
  391.         mul     EBX             ; low part of op1 * low part of op2
  392.         xchg    EAX,ESI         ; ESI becomes start of the sticky bits
  393.         mov     ECX,EDX         ; save high part of result
  394.         pop     EDX             ; restore low part of op1
  395.         mul     EDX             ; low part of op1 * high part of op2
  396.         mov     EDI,EDX         ; save high part of product
  397.         add     ECX,EAX         ; add partial product
  398.         adc     EDI,EBP         ; ...
  399.         adc     EBP,EBP         ; ...
  400.         pop     EAX             ; restore high part of op1
  401.         xchg    EAX,EBX         ; flip with low part of op2
  402.         mul     EBX             ; high part of op1 * low part of op2
  403.         add     ECX,EAX         ; add partial product
  404.         adc     EDI,EDX         ; ...
  405.         adc     EBP,0           ; ...
  406.         mov     EAX,EBX         ; get high part of op1
  407.         pop     EDX             ; restore high part of op2
  408.         mul     EDX             ; high part of op1 * high part of op2
  409.         add     EAX,EDI         ; add partial product
  410.         adc     EDX,EBP         ; ...
  411.         sub     EBX,EBX         ; get zero for zero fill
  412.         mov     CL,10           ; shift result over
  413.         shrd    EBX,EAX,CL      ; ... get sticky bits 18-feb-91
  414.         shrd    EAX,EDX,CL      ; ...
  415.         shrd    EDX,EBX,CL      ; ...
  416.         pop     ECX             ; restore sign and exponent
  417.  
  418.         _loop                   ; loop
  419.           test  EDX,00200000h   ; - test to see if bit in exponent field
  420.           _quif e               ; - quit if not
  421.           shr   EDX,1           ; - shift result right
  422.           rcr   EAX,1           ; - . . .
  423.           rcr   EBX,1           ; - save carry
  424.           inc   CX              ; - inc exponent for every shift
  425.           cmp   CX,07FFh        ; - quit if overflow
  426.           je    mul_oflow       ; - . . .
  427.         _endloop                ; endloop
  428.         _shl    EBX,1           ; get guard bit
  429.         _if     c               ; if set
  430.           _if   e               ; - if rest of sticky bits are 0
  431.             or    ESI,ESI       ; - - check the bottom sticky bits
  432.             setne BL            ; - - ...
  433.             shr   EBX,1         ; - - if all sticky bits are zero
  434.             _if   nc            ; - - then
  435.               mov   ESI,EAX     ; - - - get bottom bit of result
  436.               shr   ESI,1       ; - - - as rounding bit
  437.             _endif              ; - - endif
  438.           _endif                ; - endif
  439.           adc   EAX,0           ; - round up
  440.           adc   EDX,0           ; - ...
  441.           test  EDX,00200000h   ; - test to see if bit in exponent field
  442.           _if   ne              ; - if fraction overflowed
  443.             shr   EDX,1         ; - - shift right
  444.             rcr   EAX,1         ; - - ...
  445.             inc   CX            ; - - increment exponent
  446.             cmp   CX,07FFh      ; - - quit if overflow
  447.             je    mul_oflow     ; - - . . .
  448.           _endif                ; - endif
  449.         _endif                  ; endif
  450.         or      CX,CX           ; if exponent <= 0
  451.         _if     le              ; then (denormal result)
  452.           _if   e               ; - if exponent = 0
  453.             mov   CL,1          ; - - set shift count to 1
  454.           _else                 ; - else
  455.             neg   CX            ; - - negate to get shift count
  456.             dec   CX            ; - - adjust
  457.           _endif                ; - endif
  458.           sub   EBX,EBX         ; - for zero fill
  459.           shrd  EAX,EDX,CL      ; - align the fraction
  460.           shrd  EDX,EBX,CL      ; - ...
  461.           sub   CX,CX           ; - set exponent to 0
  462.         _endif                  ; endif
  463.         and     EDX,000FFFFFh   ; isolate fraction
  464.         mov     ESI,ECX         ; get copy of sign
  465.         ror     ECX,11          ; get exponent
  466.         _shl    ESI,1           ; get sign
  467.         rcr     ECX,1           ; put it in
  468.         and     ECX,0FFF00000h  ; isolate sign and exponent
  469.         or      EDX,ECX         ; place it in result
  470.         pop     ESI             ; restore ESI
  471.         pop     EDI             ; restore EDI
  472.         pop     EBP             ; restore EBP
  473.         ret                     ; return
  474.  
  475. mul_oflow:                      ; overflow
  476.         mov     EAX,ECX         ; get sign of infinity
  477.         pop     ESI             ; restore ESI
  478.         pop     EDI             ; restore EDI
  479.         pop     EBP             ; restore EBP
  480.         jmp     F8OverFlow      ; handle overflow
  481.         endproc __FDM
  482.  
  483.         endmod
  484.         end
  485.