home *** CD-ROM | disk | FTP | other *** search
/ PC Extra Super CD 1998 January / PCPLUS131.iso / DJGPP / V2MISC / WMEMU2S.ZIP / LINUX / DRIVERS / FPU-EMU / REG_DIV.S < prev    next >
Encoding:
Text File  |  1994-02-03  |  5.3 KB  |  252 lines

  1.     .file    "reg_div.S"
  2. /*---------------------------------------------------------------------------+
  3.  |  reg_div.S                                                                |
  4.  |                                                                           |
  5.  | Divide one FPU_REG by another and put the result in a destination FPU_REG.|
  6.  |                                                                           |
  7.  | Copyright (C) 1992,1993,1994                                              |
  8.  |                       W. Metzenthen, 22 Parker St, Ormond, Vic 3163,      |
  9.  |                       Australia.  E-mail   billm@vaxc.cc.monash.edu.au    |
  10.  |                                                                           |
  11.  | Call from C as:                                                           |
  12.  |   void reg_div(FPU_REG *a, FPU_REG *b, FPU_REG *dest,                     |
  13.  |                                    unsigned int control_word)             |
  14.  |                                                                           |
  15.  +---------------------------------------------------------------------------*/
  16.  
  17. #include "exception.h"
  18. #include "fpu_asm.h"
  19.  
  20.  
  21. .text
  22.     .align 2
  23.  
  24. .globl    _reg_div
  25. _reg_div:
  26.     pushl    %ebp
  27.     movl    %esp,%ebp
  28. #ifdef REENTRANT_FPU
  29.     subl    $28,%esp    /* Needed by divide_kernel */
  30. #endif REENTRANT_FPU
  31.  
  32.     pushl    %esi
  33.     pushl    %edi
  34.     pushl    %ebx
  35.  
  36.     movl    PARAM1,%esi
  37.     movl    PARAM2,%ebx
  38.     movl    PARAM3,%edi
  39.  
  40.     movb    TAG(%esi),%al
  41.     orb    TAG(%ebx),%al
  42.  
  43.     jne    L_div_special        /* Not (both numbers TW_Valid) */
  44.  
  45. #ifdef DENORM_OPERAND
  46. /* Check for denormals */
  47.     cmpl    EXP_UNDER,EXP(%esi)
  48.     jg    xL_arg1_not_denormal
  49.  
  50.     call    _denormal_operand
  51.     orl    %eax,%eax
  52.     jnz    fpu_Arith_exit
  53.  
  54. xL_arg1_not_denormal:
  55.     cmpl    EXP_UNDER,EXP(%ebx)
  56.     jg    xL_arg2_not_denormal
  57.  
  58.     call    _denormal_operand
  59.     orl    %eax,%eax
  60.     jnz    fpu_Arith_exit
  61.  
  62. xL_arg2_not_denormal:
  63. #endif DENORM_OPERAND
  64.  
  65. /* Both arguments are TW_Valid */
  66.     movb    TW_Valid,TAG(%edi)
  67.  
  68.     movb    SIGN(%esi),%cl
  69.     cmpb    %cl,SIGN(%ebx)
  70.     setne    (%edi)          /* Set the sign, requires SIGN_NEG=1, SIGN_POS=0 */
  71.  
  72.     movl    EXP(%esi),%edx
  73.     movl    EXP(%ebx),%eax
  74.     subl    %eax,%edx
  75.     addl    EXP_BIAS,%edx
  76.     movl    %edx,EXP(%edi)
  77.  
  78.     jmp    _divide_kernel
  79.  
  80.  
  81. /*-----------------------------------------------------------------------*/
  82. L_div_special:
  83.     cmpb    TW_NaN,TAG(%esi)    /* A NaN with anything to give NaN */
  84.     je    L_arg1_NaN
  85.  
  86.     cmpb    TW_NaN,TAG(%ebx)    /* A NaN with anything to give NaN */
  87.     jne    L_no_NaN_arg
  88.  
  89. /* Operations on NaNs */
  90. L_arg1_NaN:
  91. L_arg2_NaN:
  92.     pushl    %edi            /* Destination */
  93.     pushl    %esi
  94.     pushl    %ebx            /* Ordering is important here */
  95.     call    _real_2op_NaN
  96.     jmp    LDiv_exit
  97.  
  98. /* Invalid operations */
  99. L_zero_zero:
  100. L_inf_inf:
  101.     pushl    %edi            /* Destination */
  102.     call    _arith_invalid        /* 0/0 or Infinity/Infinity */
  103.     jmp    LDiv_exit
  104.  
  105. L_no_NaN_arg:
  106.     cmpb    TW_Infinity,TAG(%esi)
  107.     jne    L_arg1_not_inf
  108.  
  109.     cmpb    TW_Infinity,TAG(%ebx)
  110.     je    L_inf_inf        /* invalid operation */
  111.  
  112.     cmpb    TW_Valid,TAG(%ebx)
  113.     je    L_inf_valid
  114.  
  115. #ifdef PARANOID
  116.     /* arg2 must be zero or valid */
  117.     cmpb    TW_Zero,TAG(%ebx)
  118.     ja    L_unknown_tags
  119. #endif PARANOID
  120.  
  121.     /* Note that p16-9 says that infinity/0 returns infinity */
  122.     jmp    L_copy_arg1        /* Answer is Inf */
  123.  
  124. L_inf_valid:
  125. #ifdef DENORM_OPERAND
  126.     cmpl    EXP_UNDER,EXP(%ebx)
  127.     jg    L_copy_arg1        /* Answer is Inf */
  128.  
  129.     call    _denormal_operand
  130.     orl    %eax,%eax
  131.     jnz    fpu_Arith_exit
  132. #endif DENORM_OPERAND
  133.  
  134.     jmp    L_copy_arg1        /* Answer is Inf */
  135.  
  136. L_arg1_not_inf:
  137.     cmpb    TW_Zero,TAG(%ebx)    /* Priority to div-by-zero error */
  138.     jne    L_arg2_not_zero
  139.  
  140.     cmpb    TW_Zero,TAG(%esi)
  141.     je    L_zero_zero        /* invalid operation */
  142.  
  143. #ifdef PARANOID
  144.     /* arg1 must be valid */
  145.     cmpb    TW_Valid,TAG(%esi)
  146.     ja    L_unknown_tags
  147. #endif PARANOID
  148.  
  149. /* Division by zero error */
  150.     pushl    %edi            /* destination */
  151.     movb    SIGN(%esi),%al
  152.     xorb    SIGN(%ebx),%al
  153.     pushl    %eax            /* lower 8 bits have the sign */
  154.     call    _divide_by_zero
  155.     jmp    LDiv_exit
  156.  
  157. L_arg2_not_zero:
  158.     cmpb    TW_Infinity,TAG(%ebx)
  159.     jne    L_arg2_not_inf
  160.  
  161. #ifdef DENORM_OPERAND
  162.     cmpb    TW_Valid,TAG(%esi)
  163.     jne    L_return_zero
  164.  
  165.     cmpl    EXP_UNDER,EXP(%esi)
  166.     jg    L_return_zero        /* Answer is zero */
  167.  
  168.     call    _denormal_operand
  169.     orl    %eax,%eax
  170.     jnz    fpu_Arith_exit
  171. #endif DENORM_OPERAND
  172.  
  173.     jmp    L_return_zero        /* Answer is zero */
  174.  
  175. L_arg2_not_inf:
  176.  
  177. #ifdef PARANOID
  178.     cmpb    TW_Zero,TAG(%esi)
  179.     jne    L_unknown_tags
  180. #endif PARANOID
  181.  
  182.     /* arg1 is zero, arg2 is not Infinity or a NaN */
  183.  
  184. #ifdef DENORM_OPERAND
  185.     cmpl    EXP_UNDER,EXP(%ebx)
  186.     jg    L_copy_arg1        /* Answer is zero */
  187.  
  188.     call    _denormal_operand
  189.     orl    %eax,%eax
  190.     jnz    fpu_Arith_exit
  191. #endif DENORM_OPERAND
  192.  
  193. L_copy_arg1:
  194.     movb    TAG(%esi),%ax
  195.     movb    %ax,TAG(%edi)
  196.     movl    EXP(%esi),%eax
  197.     movl    %eax,EXP(%edi)
  198.     movl    SIGL(%esi),%eax
  199.     movl    %eax,SIGL(%edi)
  200.     movl    SIGH(%esi),%eax
  201.     movl    %eax,SIGH(%edi)
  202.  
  203. LDiv_set_result_sign:
  204.     movb    SIGN(%esi),%cl
  205.     cmpb    %cl,SIGN(%ebx)
  206.     jne    LDiv_negative_result
  207.  
  208.     movb    SIGN_POS,SIGN(%edi)
  209.     xorl    %eax,%eax        /* Valid result */
  210.     jmp    LDiv_exit
  211.  
  212. LDiv_negative_result:
  213.     movb    SIGN_NEG,SIGN(%edi)
  214.     xorl    %eax,%eax        /* Valid result */
  215.  
  216. LDiv_exit:
  217. #ifdef REENTRANT_FPU
  218.     leal    -40(%ebp),%esp
  219. #else
  220.     leal    -12(%ebp),%esp
  221. #endif REENTRANT_FPU
  222.  
  223.     popl    %ebx
  224.     popl    %edi
  225.     popl    %esi
  226.     leave
  227.     ret
  228.  
  229.  
  230. L_return_zero:
  231.     xorl    %eax,%eax
  232.     movl    %eax,SIGH(%edi)
  233.     movl    %eax,SIGL(%edi)
  234.     movl    EXP_UNDER,EXP(%edi)
  235.     movb    TW_Zero,TAG(%edi)
  236.     jmp    LDiv_set_result_sign
  237.  
  238. #ifdef PARANOID
  239. L_unknown_tags:
  240.     pushl    EX_INTERNAL | 0x208
  241.     call    EXCEPTION
  242.  
  243.     /* Generate a NaN for unknown tags */
  244.     movl    _CONST_QNaN,%eax
  245.     movl    %eax,(%edi)
  246.     movl    _CONST_QNaN+4,%eax
  247.     movl    %eax,SIGL(%edi)
  248.     movl    _CONST_QNaN+8,%eax
  249.     movl    %eax,SIGH(%edi)
  250.     jmp    LDiv_exit        /* %eax is nz */
  251. #endif PARANOID
  252.